In my node form I have a 'date' form element. Its value is converted to a unix timestamp in hook_submit and saved to the database. In hook_view the date is displayed with format_date(). Prior to editing the node the timestamp is converted to an array in hook_prepare.

Up to this point everything is fine.

But if I want to preview the node I get an Unsupported operand types error, because my $node->mydate field is still an array containing day, month and year as separate elements which format_date() in my hook_view does not like.

Since node previews are generated during form building via '#after_build' I don't see any chance (hook, element property) to perform the date conversion to a timestamp before the preview is generated. How could this be done?

CommentFileSizeAuthor
#2 node.validate.patch1.39 KBtenrapid

Comments

tenrapid’s picture

Category: support » bug

Since nobody could answer this support request I make this into a bug. The thing is that I see no straightforward way to alter a node form value before the node preview is generated.

Normally one could alter a form value during form validation with form_set_value() but this is not possible in hook_validate for two reasons:
- the form array is not passed to hook_validate
- node_form_add_preview() gets only a copy of $form_values, calls then drupal_validate_form() and passes the $form_values copy to node_preview() so changes to global $form_values with form_set_value() have no effect to the preview

Or did I miss something?

tenrapid’s picture

StatusFileSize
new1.39 KB

With this patch hook_validate no longer stays behind every other regular form validation callback. It gets the form array passed and you can use form_set_value() in it.

tenrapid’s picture

Status: Active » Needs review

status ...

tenrapid’s picture

The following are some module code extracts to depict what is possible with this patch.

Note that this can already be done with every regular form but with node forms you can't.

Imagine a node that contains a date field. Its value is stored as a unix timestamp in the database. This is how the form hook looks like:

function mymodule_form(&$node) {
  $form['mydate'] = array(
    '#type' => 'date', 
    '#title' => 'my date', 
    '#required' => TRUE, 
    '#default_value' => $node->mydate);
  return $form;
}

To convert the timestamp into the array that is needed for the date form element hook_prepare is used:

function mymodule_prepare(&$node) {
  if ($node->mydate) {
    $node->mydate = array(
      'day' => format_date($node->mydate, 'custom', 'j'),
      'month' => format_date($node->mydate, 'custom', 'n'),
      'year' => format_date($node->mydate, 'custom', 'Y'));
  }
}

This is how hook_view looks like:

function mymodule_view(&$node, $teaser = FALSE, $page = FALSE) {
  $node->body = $node->teaser = format_date($node->mydate);
}

And here hook_validate which is affected by the patch. The date is validated and if it's valid it is converted to a timestamp.
With this $node->mydate is already a timestamp at preview and submit time.

function mymodule_validate($node, $form) {
  $date = mktime(18, 0, 0, $node->mydate['month'], $node->mydate['day'], $node->mydate['year']);
  if ($date > time()) {
    form_set_value($form['mydate'], $date);
  }
  else {
    form_set_error('mydate', t('The specified date is of the past.'));
  }
}

I think this is as straighforward as possible. Plus you get consistent behaviour with all forms in Drupal.

tenrapid’s picture

Status: Needs review » Closed (fixed)

The above is now possible in 4.7 because this patch http://drupal.org/node/59935 got in.