views:

54

answers:

2

I'm writing a Drupal module and have run into what should be a trivial problem;

Consider a 'Person' type node which includes a 'Date of Birth' property. I've configured the database table to use an int field to store the date in UNIX format (same as Drupal Core) but of course I need to provide a method for the user to specify the value in a more friendly format, i.e. dd/mm/yyyy.

In my modules Person_form function I have configured the date element thus:

$form['dob'] = array(
    '#type' => 'date',
    '#title' => 'Date of Birth',
    '#required' => TRUE,
    '#default_value' => array(
       'day' => format_date($node->dob, 'custom', 'j'),
       'month' => format_date($node->dob, 'custom', 'n'),
       'year' => format_date($node->dob, 'custom', 'Y'),
    ),
);

which displays the UNIX date in the database in three dropdown lists, oneeach for day, month and year - this is just what I wanted, so far so good.

Now I need to be able to access this elements values when the user clicks on the 'Save' button - but I now have two problems:

  1. The signature of the _form function is Person_form($node) so how do I access the $form['dob']['day'/'month'/'year'] values. $form is not passed as an argument to the function.
  2. Once I have the values, what is the best way of generating a UNIX date value?

I've Googled about for a while but the terms 'drupal' and 'date' just seem to point me to the Date module extension - surely I don't need an extension to handle simple dates like this :-o

Thanks in advance

A: 

The signature of the function that gets called upon save should be Person_form_submit($form, &$form_state). From this you can use the $form_state array to retrieve your values and process them how you want. I'm not about your use of Person_form($node), as to build the form you should be using Person_form($form_state) as the form builder function. Check out the documentation for building forms in Drupal: http://drupal.org/node/751826.

To get a timestamp from a date, I would use the php function strtotime().

bkildow
Is hook_form_submit only called on Save or do I need to check for the 'action' somewhere?
DilbertDave
The submission handler of a form (Drupal doesn't use any `hook_form_submit()` hooks) is called each time a form is submitted. You can use different submission handlers, one for each submission buttons. In Example, if you have the buttons "Save" and "Preview", you can attach a submission handler to "Preview", and one to the form. In that way, you know exactly for which action the handler has been called.
kiamlaluno
Not 100% sure what you mean by attach one to 'Preview' and one to the form.
DilbertDave
[`hook_form()`](http://api.drupal.org/api/function/hook_form/6) is invoked as `hook_form($node, $form_state)`, not `hook_form($form_state)`.
kiamlaluno
Right (I think) I'll look into it a little further, thanks guys.
DilbertDave
It is `hook_form(
kiamlaluno
+2  A: 

hook_form() is invoked to show the form fields to edit an existing node, or creating a new one. In the first case, the values to show are the ones already present in $node. hook_load() is before invoked to load the values associate with the node; the return value is an array of items that will be added to the node object (in example, if the returned array is array('extra_field' => 'value'), then the node will have the property $node->extra_field). hook_update() is invoked when the node is saved in the database (a module implementing a content type should save its own values in its database table), while hook_validate() is invoked to validate the values entered from the users.

As you have day, month, and year, you can use mktime() to get a Unix timestamp; the timestamp you get will be set to midnight of that day.

To clear what I said in my comment about different submission handlers for different buttons, this is the code used by node_form():

$form['buttons'] = array();
$form['buttons']['submit'] = array(
  '#type' => 'submit',
  '#access' => !variable_get('node_preview', 0) || (!form_get_errors() && isset($form_state['node_preview'])),
  '#value' => t('Save'),
  '#weight' => 5,
  '#submit' => array('node_form_submit'),
);
$form['buttons']['preview'] = array(
  '#type' => 'submit',
  '#value' => t('Preview'),
  '#weight' => 10,
  '#submit' => array('node_form_build_preview'),
);
if (!empty($node->nid) && node_access('delete', $node)) {
  $form['buttons']['delete'] = array(
    '#type' => 'submit',
    '#value' => t('Delete'),
    '#weight' => 15,
    '#submit' => array('node_form_delete_submit'),
  );
}

Each button has its own submission handler (defined with the item #submit). If you would set the submission handler for $form with $form['#submit'] = 'submission_function', that submission handler would be used for every button that doesn't define its own submission handler.

I need to provide a method for the user to specify the value in a more friendly format, i.e. dd/mm/yyyy.

You could use three textfields for day, month, and year (it is possible to show them inline, and the / to place between them would be set using '#field_suffix' => '/'). The pro of using the date form field is that day, month, and year fields are ordered basing on the date format set for the site; if the date format shows the year before day and month, then also the date field would show the year before the other two fields. Another pro is that you don't need to create custom code to validate the input obtained from the user.
The value of the date field is an array containing the indexes day, month, and year.

kiamlaluno
hmm, probably a better answer than mine for your situation. My answer was giving the example of building a custom form. Kiamlaluno's answer gives more specifics on building a content type in code. Here is a the complete documentation link for this: http://drupal.org/node/231019. I would at least look through the code examples at the bottom of this page.
bkildow
Thanks to both of you for your help on this one, I've got it working as I want now. It seemed so trivial that I thought I was missing something simple. Fact is that some of the examples on the web took me in the wrong direction.
DilbertDave
See also [node_example.module](http://api.drupal.org/api/drupal/developer--examples--node_example--node_example.module/6); looking at the page reported by bkildow and this one, you should understand better the code to use to implement a content type module.
kiamlaluno
I'm working through the APress Pro Drupal Development book and it seems to have some shortcomings.
DilbertDave