Install cck types, taxonomy, content and roles through multiple AJAX calls

Deploying from a development canada goose rea to a review, staging and live server can be a real pain in the ass with drupal.  You can write custom code in your modules and deploy the changes with CVS or SVN in the way you are used too. But what about the stuff you built through clicking and in drupal, you can click untill you drop.  Suppose you have installed four cck types, a couple of taxonomy Canada Goose Jacka vocabularies and terms, a few roles and you made dummy content to ease your work during development.  Is there a way to deploy these things?

For me this is most important as I really don’t like to click.  You could repeat your clicks in every environment to ensure they are all the same. You can’t just export and import the database because it is commonly known that clients can review on the review server and even publish real content onto the staging server.  Dropping the sql in, would just overwrite that content. And you don’t want to bring your testing dummy content live :)

In a search for the holy grail, I tried to build all these things in my custom module. Adding taxonomy with node relations, roles, content types and even dummy content with code, and just deploy the code with the normal functionality would bring my drupal experience to the next level.  With the module content_copy, I already knew it is possible to export and import cck types.  So let’s take this further.water balls

Installing cck types

If you installed the content_copy module as extension for cck, it is quite easy to export your content-types.  The result from this export can be pasted into the content_copy import textarea. Wouldn’t it be nice to have these exports stored in files. That is exactly what I planned to do. I found a patch that was not yet in the content_module but helped me with the cck import from file.

  1. /**
  2.  * File where the content_copy export is located
  3.  *
  4.  * @param string $file
  5.  */
  6. function file_repository_import_cck_from_file($file) {
  7.   $content = null;
  8.   ob_start ();
  9.   require $file;
  10.   $form_state [‘values’] [‘type_name’] = ;
  11.   $form_state [‘values’] [‘macro’] = ‘$content = ‘ . var_export ( $content, true ) . ‘;’;
  12.   $form_state [‘values’] [‘op’] = t ( ‘Import’ );
  13.   drupal_execute ( ‘content_copy_import_form’, $form_state );
  14. }

This function gets the content of a file (cck export macro) and runs the drupal execute function to call the content_copy_import_form.  This worked great for me. I must say that i have ran some tests with cck types with a bunch of fields and this took rather too long as well.  Running the export throught the import of content_copy directly, had the same result. I guess this is normal behaviour for larger files.

Multiple ajax requests

I made a custom (sub) module in my project that handles the installation of basic content-types and taxonomy used in my project.  I tried to import all these things at once, but got time-out errors.   The sollution I came up with, is a multiple step-based installation running on several ajax requests.  Let’s start off with the hook_menu items to accomplish the task.

  1. $items[‘admin/content/repository/full_install’] = array(
  2.   ‘title’ => ‘full (re)install’,
  3.   ‘description’ => "Full installs all assets for the slideshow project: cck, taxonomy, roles.",
  4.   ‘page callback’ => ‘file_repository_full_install’,
  5.   ‘access callback’ => ‘_administer_slideshow’,
  6.   ‘type’ => MENU_LOCAL_TASK,
  7.   ‘weight’ => 0,
  8.   ‘file’ => ‘file_repository.admin.inc’,
  9. );
  10. $items[‘admin/content/repository/fullinstall/%’] = array(
  11.   ‘description’ => "Installation steps.",
  12.   ‘page callback’ => ‘file_repository_step’,
  13.   ‘page arguments’ => array(4),
  14.   ‘access callback’ => ‘_administer_slideshow’,
  15.   ‘type’ => MENU_CALLBACK,
  16.   ‘file’ => ‘file_repository.admin.inc’,
  17. );

Browsing to ‘admin/content/repository/full_install’ will call ‘file_repository_full_install’. This function only displays a form with an install button.  I did this because the rest is ajax and i had to start somewhere.  The code for function file_repository_full_install:

  1. /**
  2.  * Full reinstall for the whole project
  3.  */
  4. function file_repository_full_install() {
  5.   return drupal_get_form(‘file_repository_full_install_form’);
  6. }
  7.  
  8. /**
  9.  * install form for assets
  10.  */
  11. function file_repository_full_install_form($form_state) {
  12.   $form = array();
  13.   $form[’slide_form’] = array(
  14.     ‘#type’ => ‘markup’,
  15.     ‘#title’ => t(‘Install report’),
  16.     ‘#value’ => ‘Install ccks, taxonomy vocab, terms, roles, … ‘,
  17.     ‘#prefix’ => ‘<div id="install_container">’,
  18.     ‘#suffix’ => ‘</div>’,
  19.     ‘#weight’ => -4,
  20.   );
  21.   $form[’submit’] = array(
  22.     ‘#type’ => ‘button’,
  23.     ‘#value’ => t(‘Install’),
  24.     ‘#weight’ => 5,
  25.     ‘#ahah’ => array(
  26.       ‘path’ => ‘admin/content/repository/fullinstall/0′ ,
  27.       ‘wrapper’ => ‘install_container’,
  28.       ‘method’ => ‘append’,
  29.       ‘effect’ => ‘fade’,
  30.       ‘event’ => ‘click’,
  31.       ‘progress’ => array(
  32.         ‘type’ => ‘throbber’,
  33.         ‘message’ => t(‘installing…’)
  34.       ),
  35.     ),
  36.   );
  37.   drupal_add_js(drupal_get_path(‘module’, ‘file_repository’).‘/file_repository.js’);
  38.   return $form;
  39. }

The javascript file you see included here will have to code to continuously send AJAX requests. The code for this is printed as well.

  1. function file_repository_step(num) {
  2.   $("#install_container").append("
  3. Start with " + num +"
  4. ");
  5.   // post (url, data, callback, type)
  6.   $.post("/admin/content/repository/fullinstall/"+num,
  7.     {install_id: num },
  8.     function(data, textStatus) {
  9.       $("#install_container").append(data);
  10.     },
  11.     "json"
  12.   );
  13. }

So this basically just shows an install button with an ahah property that fires off the first asynchronous call. The parameters in the url will be readable as wildcard and use them as ’step’. The step is a integer passed as parameter to the function file_repository_step. All this does is incrementing the step ‘num’ variable and add a javascript inline script to take the installation to the next step.

  1. /**
  2.  * Install stepping
  3.  */
  4. function file_repository_step($num) {
  5.   $ccks = array(1=>’store’, 2=>‘product’, 3=>‘imagefolder’,4=>‘floating_tag’);
  6.   $new_num = $num +1;
  7.   $js = (‘<script type="text/javascript">file_repository_step(’.$new_num.‘);</script>
  8. );
  9.   switch($num) {
  10.     case 0:
  11.       $json = drupal_json(‘preparing to install … ‘.$js);
  12.       break;
  13.     case 1:
  14.     case 2:
  15.     case 3:
  16.     case 4:      
  17.       $message = file_repository_build_cck ( $ccks[$new_num] , true).
  18. ;
  19.       $json = drupal_json(.$message.‘, continue to step ‘.$new_num.‘ ‘.$ccks[$new_num].‘. ‘.$js);
  20.       break;
  21.     case 5:
  22.       // create taxonomy
  23.       $message = file_repository_create_taxonomy ().
  24. ;
  25.       $json = drupal_json(.$message.‘, continue to step ‘.$new_num.‘ ‘.$ccks[$new_num].‘. ‘.$js);
  26.       break;
  27.     case 6:
  28.       // create roles
  29.       $message = file_repository_create_roles_create ().
  30. ;
  31.       $json = drupal_json(.$message.‘, continue to step ‘.$new_num.‘ ‘.$ccks[$new_num].‘. ‘.$js);
  32.       break;
  33.     case 7:
  34.       $json = drupal_json(‘<strong>Session ended successful</strong>’);
  35.       break;
  36.     default:
  37.       $json = drupal_json(‘<strong>Session aborted. Irregular installation.</strong>’);
  38.   }
  39.   return $json;
  40. }

The function has 7 hardcoded cases or steps that have to be run when clicking the install button. The cases are defined here as example to show you that you can do multiple tasks. You could thus import content types exported by the content copy module, add taxonomy vocabularies and terms, add roles and even build some dummy nodes, with taxonomy attached.
An other important feature is the fact that you determine - maybe in a installation array - which steps will run first. So you determine the order of installation parts. This is important because for instance you have to import cck types before you can assign taxonomy vocabularies to it. Or the dummy content can only be created if the roles, cck’s and taxonomy you are using, already exists.
It is pretty obvious but you have to take this in mind.
When writing this, I felt this is rather fun than it is practical to do it the ajaxian way. If there are other people experimenting with importing and installing drupal assets or are tired of enduring click sessions over and over again, please let me know.

This entry was posted on Sunday, September 28th, 2008 at 8:52 pm and is filed under Drupal. You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings are currently closed.

2 Responses to “Install cck types, taxonomy, content and roles through multiple AJAX calls”

  1. Build sortable nodes in table view in a custom content type | Menhir-effect blog Says:

    [...] a custom content type slideshow that holds slides, which is a custom content type as well.  Check Install cck types, taxonomy, content and roles through multiple AJAX calls, if you want to see an example on how to import an exported cck with all its [...]

  2. Rani Says:

    Hi,

    I am new to drupal, i would like to add categories in my site, I dont know how to add categories in my site. could you pls explain me how to create categories, hope you will consider my request.