Addnode

Last modified: March 16, 2007 - 10:28

Addnode is a widget which allows users to create nodes, rather than select them from a list.

Acknowledgements

Development was aided by help and moral support from:

merlinofchaos, fago, eaton, jacobredding, emspace, eric_, webchick and others.

The project is funded by obslogic

Creating the form

Summary

The main idea is that the function retrieves the form arrays for the various types that node-reference can reference (by calling the _retrieve_subform_function below).

These subforms are then added to the main form, in a 'branch' of the tree (to avoid conflicts with the items already in the array).

Fixed Problems

  • Concerned names still conflict on page.
  • Originally just regexp and shoved in html into form to add the subforms (this didn't work - not surprising :)
  • Form returned appears to just be the basic node creation form and not the whole form. This seems to be because static $forms in the drupal_retrieve_form function is already populated. Hence it thinks it doesn't need to make the form maybe???? Need to know how to get around this: I needed to call "function drupal_prepare_form($form_id, &$form)" to finish the form off.
  • Unexpectedly $op=='form' in the call to the function! This breaks stuff
  • Something breaks in submission - probably in validation? (but it silently fails...)
  • It is displayed in the configuration window. Why is $op == 'form' even called in the config window?!?
  • Submitted form was handled by the subform handler! Fixed by replacing drupal_prepare_form with home-made code.
  • Added node needs selecting from the list once it's made
  • Need to test multiple addnodes work on the same form

The _retrieve_subform function

Creates a node and retrieves the subform using it.

<?php
function _retrieve_subform($type)
{
  global
$user;
 
$node = array(
   
'uid' => $user->uid,
   
'name' => $user->name,
   
'type' => $type,
  );

 
$args = array(
   
$type.'_node_form',
   
$node);
 
$form = call_user_func_array('drupal_retrieve_form', $args);
  return
$form;
}
?>

Step by Step

Below I've gone through the addnode_widget function, cutting just the most relevant code, to try to explain its function...

If $op = 'form'... Then we need to generate and return a form array, describing how to build the widget:

First we get a list of potentially selected items: (put it in $options)

<?php
        $options
= _nodereference_potential_references($field, true);

        foreach (
$options as $key => $value) {
         
$options[$key] = _nodereference_item($field, $value);
        }
?>

We also get the list of types we can select (or create!): (put it in $type_list)

<?php
       
foreach ($field['referenceable_types'] as $ref_type)
        {
          if (
$ref_type)
          {
           
$type_list[] = $ref_type;
          }
        }
?>

Next a load of prefix and suffix stuff is made to surround our select list.

<?php
        $fieldname
=$field['field_name'];
       
$createmsg=_create_new_message($type_count, $fieldname, $typedesc, $type_list);
       
$title=t($field['widget']['label']);
       
$prefix = "";
       
$prefix.= "<b>$title:</b>";
            ...
blah...
            ...
blah...
       
$subsuffix.= "</table>";
?>

We next create the form array:

<?php
        $form
[$fieldname] = array('#tree' => TRUE);
       
$form[$fieldname]['nids'] = array(
         
'#type' => 'select',
         
'#title' => '',//$title
         
'#default_value' => $node_field['default nids'],
         
'#multiple' => $field['multiple'],
         
'#options' => $options,
         
'#required' => $field['required'],
         
'#description' => $field['widget']['description'],
         
'#prefix' => $prefix,
         
'#suffix' => $suffix,
         
'#size' => 15,
         
'#weight' => $field['weight'],
         
'#attributes' => array(
           
'style' => 'width:100%',
           
'class' => "addnode_select",
           
'id' => "$fieldname",
          ),
        );
?>

Now we need to add the subforms (of the items we could create).
The _add_subform function is called add the subform to the form.

<?php
       
foreach ($type_list as $atype)
        {
          
$subform = _retrieve_subform($atype);
          
//manipulate subform items and add to the main form
         
_add_subform($form, $subform, $fieldname, $atype, $subprefix, $usesuffix, $weight);
        }
?>

The form has its standard submit method overridden:

<?php
        $form
['#submit']['node_form_submit'] = array();
       
$form['#submit']['addnode_subform_submit'] = array();
?>

And that's it, for creating the form.

Submission

Current code: Currently hardwired for 'pots'.

<?php
function addnode_subform_submit($form_id, &$form_values)
{
 
$node = array ('type' => 'pot');
 
$vals = _form_values_flatten($form_values['field_test']['pot']);
 
$errors = drupal_execute('pot_node_form',$vals,$node);
}
?>

 
 

Drupal is a registered trademark of Dries Buytaert.