3

I implemented hook_form_alter() to insert few fields. I implemented hook_node_insert() to save the field data, hook_node_load(), and hook_node_view().

Everything works fine, but when I edit the node, the edit form appears with no data.

How can I fix this?

function mymodule_form_ABC_node_form_alter(&$form, &$form_state, $form_id) {
  $options_first = _mymodule_get_first_dropdown_options();
  $selected = isset($form_state['values']['filed_1']) ? $form_state['values']['field_1'] : key($options_first);

  $form['field_1'] = array(
    // …
  );
  $form['field_2'] = array(
    // …
  );

  return $form;    
}

/**
 * Implements hook_node_insert().
 */
function mymodule_node_insert($node) {    
    db_insert('my_custom_table')
      ->fields(array('nid' => $node->nid, 'field_1' => $node->field_1, 'field_2' => $node->field_2,))
      ->execute();
}

/**
 * Implements hook_node_load().
 */
function mymodule_node_load($nodes, $types) {
  foreach ($nodes as $node) {
    $nids[] = $node->nid;
  }

  $result = db_select('custom_table', 'e')
    ->fields('e', array('nid', 'filed_1', 'field_2'))
    ->where('e.nid IN (:nids)', array(':nids' => $nids))
    ->execute();

  foreach ($result as $record) {
    $nodes[$record->nid]->field_1 = $record->field_1;
    $nodes[$record->nid]->field_2 = $record->field_2;
  }
}


/**
 * Implements hook_node_update().
 */
function mymodule_node_update($node) {
  if ($node->type == 'abc') {
    // Delete the existing values.
    db_delete('custom_table')
      ->condition('nid', $node->nid)
      ->execute();

    db_insert('custom_table')
      ->fields(array('nid' => $node->nid, 'field_1' => $node->field_1, 'field_2' => $node->field_2,))
      ->execute();
  }
}
0

2 Answers 2

1

What your code does is similar to what the Book module does with book_form_node_form_alter(), book_node_load(), and book_node_insert().

What is wrong in your code is that:

  • In mymodule_form_ABC_node_form_alter(), you don't initialize the form fields from the values you loaded with mymodule_node_load(), which means the form fields you are using are always set to an empty string. The Book module uses $form_state['values']['book'] to initialize $node->book, but the comment on _book_add_form_elements() explains why that is done.

    // If the form is being processed during the Ajax callback of our book bid
    // dropdown, then $form_state will hold the value that was selected.
    if (isset($form_state['values']['book'])) {
      $node->book = $form_state['values']['book'];
    }
    
  • You implement hook_node_insert(), but not hook_node_update(). This means the value of the node properties you are using are saved when a node is created, not when a node is updated.

It is true that the Book module implements hook_node_prepare() (book_node_prepare()), but its purpose is only setting the default value for the node properties it handles, which is useful in the case a node is not created through the user interface.

Since you are interested in saving those node properties when the content type is abc, I would implement the code as follows.

function mymodule_form_abc_node_form_alter(&$form, &$form_state, $form_id) {
  $node = $form['#node'];
  $options_first = _mymodule_get_first_dropdown_options();
  $selected = !empty($node->field_1) ? $node->field_1 : key($options_first);

  $form['field_1'] = array(
    // …
  );
  $form['field_2'] = array(
    // …
  );

  return $form;    
}

function mymodule_node_prepare($node) {
  if ($node->type == 'abc') {
    $node->field_1 = '';
    $node->field_2 = '';
  }
}

function mymodule_node_load($nodes, $types) {
  $nids = array();

  foreach ($nodes as $nid => $node) {
    if ($node->type == 'abc') {
      $nids[] = $nid;
    }
  }

  if (!empty($nids)) {
    db_query('SELECT e.nid, e.field_1, e.field_2 FROM {custom_table} e WHERE e.nid IN :nids'), array(':nids' => $nids), array('fetch' => PDO::FETCH_ASSOC));

    foreach ($result as $record) {
      $nodes[$record['nid']]->field_1 = $record['field_1'];
      $nodes[$record['nid']]->field_2 = $record['field_2'];
    }
  }
}

/**
 * Implements hook_node_insert().
 */
function mymodule_node_insert($node) {
  // hook_node_insert() is called for any node.
  // Check the content type of the node is the one for which the form fields have been added.
  if ($node->type == 'abc') {
    $values['field_1'] = !empty($node->field_1) ? $node->field_1 : '';
    $values['field_2'] = !empty($node->field_2) ? $node->field_2 : '';

    db_insert('my_custom_table')
      ->fields(array('nid' => $node->nid, 'field_1' => $values['field_1'], 'field_2' => $values['field_2']))
      ->execute();
  }
}

/**
 * Implements hook_node_update().
 */
function mymodule_node_update($node) {
  if ($node->type == 'abc') {
    db_update('custom_table')
      ->condition('nid' => $node->nid)
      ->fields(array('field_1' => $node->field_1, 'field_2' => $node->field_2))
      ->execute();
  }
}

Dynamic queries should be used when strictly necessary, for example because another module alters them. If you need to use a dynamic query, I would rather rewrite it as the following one.

$result = db_select('custom_table', 'e')
  ->fields('e', array('nid', 'filed_1', 'field_2'))
  ->condition('nid', $nids, 'IN')
  ->execute();

To update the values in a database, you should use db_update(), not deleting the values already present in the database, and inserting the new values. db_update() looks for the database rows matching the condition expressed in $query->condition(), and updates the fields given in $query->fields() with the new values.

As side note, if you are editing a module that is already installed, and enabled, you need to disable, and re-enable it, or Drupal will not notice the code has been changed, and it implements new hooks. Drupal keeps the list of implemented hooks from the enabled modules in cache; disabling a module, and re-enabling it, forces Drupal to update that cache.

7
  • thanks you very much for such a detailed answer kiamlaluno. you mean that i need to implement hook_node_prepare().but when i do that i can see all values in node object by doing krumo($node). but point here is how to assign them to form fields.
    – Waqas
    Nov 27, 2012 at 14:16
  • I mean that you need to implement hook_node_update(), since hook_node_insert() is invoked only for nodes that are created. hook_node_prepare() is useful when nodes are not created through the user interface. Implementing it is useful, but for the issue you are having hook_node_update() is the hook you should implement.
    – apaderno
    Nov 27, 2012 at 14:20
  • i have implemented that as well but what it actually do is just update the custom_table if the values are changed. how can i make it show those values in the form (form which we are editing). i have updated the question with the new code at the end. thnaks
    – Waqas
    Nov 27, 2012 at 14:29
  • I have updated my answer.
    – apaderno
    Nov 27, 2012 at 17:07
  • hi Kiamlaluno, all working great now apart from this callback function. when i change value of field1, other fields(field2 to field5) suppose to change but they are not in this case. please see if you can help. thanks
    – Waqas
    Nov 28, 2012 at 16:41
1

You need implement hook_node_prepare. This hook is used to load additional data before a node object is shown on the add/edit form.

6
  • thanks for your help Eugene. but i am still having problems suing hook_node_prepare but no luck. i have updated my question with the code. please have a look. thanks
    – Waqas
    Nov 27, 2012 at 12:42
  • I don't see implementation of hook_node_prepare in your code Nov 27, 2012 at 13:46
  • thanks Eugene. i have done that locally and in the node object i can see the required values for example $node->field_1 and $node->field_2. but i dont know how to assign them to form fields as there is no form_state object available here.
    – Waqas
    Nov 27, 2012 at 14:22
  • You need assign these values in hook_form_alter $form['field_1']['#default_value] = $form_state['node']->field_1; Nov 27, 2012 at 16:21
  • do i need to create a new hook_form_alter or the the one i already have. mymodule_form_ABC_node_form_alter(). $node object is not available in the hook_form_alter is it?
    – Waqas
    Nov 27, 2012 at 17:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.