Here's a quicky. Let's say you've created some exportable content (using CTools) which references a term ID and you have to go from your dev site to the production site. And your taxonomy is also being exported using UUID.
Somehow you have to tie them together because sure as eggs is eggs the term IDs created on the production site are not going to be the same as the local ones. That's why you used UUID in the first place. Right?
Here's what you do: in your local exportable you will have a column for the term ID so include a column for the term UUID as well.
In your add/edit form for the exportable you'll have to include some code to automatically add the selected term's UUID - I did it in the form validation. Basically you read the selected term ID, load the selected term which will have the UUID in it (because it's added to the base table). Set the term UUID value in $form_state['values']. Assuming you're using CTools Export UI the UUID will be saved automatically.
Also, in the module install, add "no export" => TRUE to the TID field, so that Export UI does not include it in the feature. (This code works for Features, it doesn't work for single imports, I'll leave that as an exercise for the reader - hint: you can specify an "import callback".)
That's the easy bit, when you export your content it will be saved with the term's UUID and not the term's ID. The difficult bit is how to link the UUID of exported content when Features loads it into the new site.
Except it's not hard at all. In your export specification, in the schema, you have the "default hook", well CTools Export UI very kindly calls an drupal_alter() on the default items after it's loaded them. So we can do this:
/**
* Implements hook_DEFAULT_HOOK_alter().
*
* This intercepts any defaults picked up from code and converts
* their UUID category into the local TID (which might be different
* on every site).
*
*/
function mymodule_my_default_hook_alter(&$items) {
$uuids = db_select('taxonomy_term_data', 't')
->fields('t', array('uuid', 'tid'))
->execute()->fetchAllKeyed();
foreach ($items as $item) {
if (empty($item->tid) && !empty($uuids[$item->uuid])) {
$item->tid= $uuids[$item->uuid];
}
}
}
The database call creates an array which maps all UUIDs to TIDs in one go. If your site uses a lot of taxonomy terms - perhaps you have user tagging - you might want to restrict this call to a specific vocabulary.
The exact item property names will depend on what you set up in your schema.
Sorted.
Showing posts with label chaos tools. Show all posts
Showing posts with label chaos tools. Show all posts
Thursday, 11 July 2013
Wednesday, 16 November 2011
Ssssh
I've not posted recently because my current job involves Drupal 6 so I've done virtually no D7 work for a while. However I do have a new set of modules for developers coming soon which will be in both D6 and D7 varieties.
Essentially it's a system that does a similar job to CTools plugins but is lightweight and standalone. It's very good for de-coupling dependent custom modules, essentially very simple but very versatile.
There's a core module that provides the API (a very small module indeed) and then some other modules that demonstrate how to use it and provide handy facilities at the same time.
Hopefully I'll have that out by Christmas. I'm also happy to say that my field_extract module is doing very nicely in the module usage charts currently standing at 99 sites.
Essentially it's a system that does a similar job to CTools plugins but is lightweight and standalone. It's very good for de-coupling dependent custom modules, essentially very simple but very versatile.
There's a core module that provides the API (a very small module indeed) and then some other modules that demonstrate how to use it and provide handy facilities at the same time.
Hopefully I'll have that out by Christmas. I'm also happy to say that my field_extract module is doing very nicely in the module usage charts currently standing at 99 sites.
Tuesday, 8 February 2011
Extending Chaos Tools Wizard
The Chaos tools form wizard is a very nice piece of code but I had the need to extend it by adding a control button - which turned out to be a lot easier than you might think.
Adding the control button itself was simple enough:
$form['buttons']['update'] = array(
'#type' => 'submit',
'#value' => t('Update'),
'#next' => $current_step,
'#wizard type' => 'update',
'#weight' => -500,
);
But notice I have given this button a wizard type of "update" (as opposed to 'next', 'cancel' or 'finish').
Now you can either add a new line to your $form_info array:
$form_info['update callback'] = 'mywizard_update';
Or not, in which case the function $form_info['id'] . '_update' will be called.
Your function will get called when this button is clicked with &$form_state as the parameter. Cool.
As an additional point, I'm using 'update' here which means that I do want to validate the form entries and save the values. However by adding these element attributes:
'#limit_validation_errors' => array(),
'#submit' => array('ctools_wizard_submit'),
You can prevent all validation and ensure the proper Chaos tools wizard function is executed.
Adding the control button itself was simple enough:
$form['buttons']['update'] = array(
'#type' => 'submit',
'#value' => t('Update'),
'#next' => $current_step,
'#wizard type' => 'update',
'#weight' => -500,
);
But notice I have given this button a wizard type of "update" (as opposed to 'next', 'cancel' or 'finish').
Now you can either add a new line to your $form_info array:
$form_info['update callback'] = 'mywizard_update';
Or not, in which case the function $form_info['id'] . '_update' will be called.
Your function will get called when this button is clicked with &$form_state as the parameter. Cool.
As an additional point, I'm using 'update' here which means that I do want to validate the form entries and save the values. However by adding these element attributes:
'#limit_validation_errors' => array(),
'#submit' => array('ctools_wizard_submit'),
You can prevent all validation and ensure the proper Chaos tools wizard function is executed.
Thursday, 27 January 2011
Next and previous
The decision about which page of the multi-page form to go to next is given to the calling code.
You can set up a 'next callback' in $form_info, but not a 'previous callback'. The 'next callback' is called in both cases. The default function name is FORM_ID_next(&$form_state).
In here you control where to go next. The simplest solution is either you want to go to the next, or to the previous. Like this:
<?php
function mywizard_next(&$form_state) {
if (isset($form_state['triggering_element']['#next'])) {
$form_state['my_storage']['step'] = $form_state['triggering_element']['#next'];
}
// set the values built by this page
$form_state['my_storage'][$form_state['step']] = $form_state['values'];
// Update the cache with any changes.
mywizard_cache_set('form_values', $form_state['my_storage']);
}
?>
Why do it like this? Because, being one for elegance and aesthetics, I do not want the current step to appear in the URL (mywizard/step1). I want just the one URL (mywizard). Also notice the use of "triggering_element" which is an addition for Drupal 7, and is identical to "clicked_button". However "clicked_button" will be discontinued in Drupal 8.
The Chaos Tools form wizard needs you to build the $form_info array and call its function 'ctools_wizard_multistep_form' each time the page is to be rebuilt. So, in my function that gets called for the page I do some interesting things.
<?php
function mywizard_wizard() {
ctools_include('wizard');
// Fetch the form info array
$form_info = mywizard_form_info();
// Fetch the current form values from the cache...
$form_values = mywizard_cache_get('form_values');
if (empty($form_values)) {
// ...but if they aren't there, build the initial values
$form_values = array(
// set the first step
'step' => array_shift(array_keys($form_info['order'])),
// and my default start values (if any)
'mywizard_values' => array(),
);
mywizard_cache_set('form_values', $form_values);
}
// Build $form_state array
$form_state = array(
'my_storage' => $form_values,
);
// And build the current step
return ctools_wizard_multistep_form($form_info, $form_values['step'], $form_state);
}
?>
So, if you can follow this, when we enter the function we build the $form_info array which describes the whole multi-page form. If this was a complicated process (it could be) you could also cache the $form_info array so it only needs to be done once.
Then we either fetch the cached form data, which contains the next step, or build a new one if we don't have one (in other words this is the first time through).
We save this information in $form_state and then call the ctools multi-step form builder which finds the right form and builds it.
When "next" is clicked (or "back") we save the current step and cache it. To be picked up when the page is built next time.
Voila.
Edited later to remove some unnecessarily complex code. This should be viewed in conjunction with the Chaos Tools Advanced Help.
No back validate
Here's an undocumented option for your Chaos Tools form wizard (not sure if it's in the D6 code): 'no back validate'.
It prevents validation of the current form when you click the back button which means you can use #required fields and prevent Drupal from insisting the user fills them in before going back through the form.
You can either put it in the root level of the $form_info array, or in one or more of the form description entries. The former means that the back button will always prevent validation, with the latter you can control which forms do and don't have validation on the back button.
Handy.
No form output with Chaos Tools multi-step form wizard
Hey this is my thrilling new Drupal 7 blog - it's for hints and tips and Drupal philosophy which I'll add as I go along.
So here's something on the Chaos Tools multi-step form implementation which might easily catch you out and leave you swearing at the screen for an hour or two (like it did me):
So, are you wondering why your D7 multi-step form doesn't produce any output at all?
The form step builders must "return $form;" instead of having the form passed by reference:
<?php
function mymodule_step_form($form, &$form_state) {
// add my fields
return $form;
}
?>
Hope that saves others some time.
I also posted this in the Chaos Tools issue queue here.
Subscribe to:
Posts (Atom)