At one point in development these functions were working, but today the form populates if there's data, but changes don't make it to the database. Similarly new data aren't inserted. hook_insert doesn't even seem to be called, as a message from drupal_set_message in the function doesn't display. All suggestions welcome. These are long functions so I haven't included everything.

function cpo_form($form_state) {
  global $user;

  if(is_object($form_state) && isset($form_state->nid)) {
    $nid = $form_state->nid;
  } else {
    $query = "select nid from {cpo} where cpo_id = '$user->name'";
    $nid = db_result(db_query($query));
  }

  $node = node_load($nid);
.
.
.

  // handle standard fields (conditionally)
  $type = node_get_types('type', $node);
  if ($type->has_title) {
    $form['title'] = array(
                           '#type' => 'textfield',
                           '#title' => check_plain($type->title_label),
                           '#required' => TRUE,
                           '#default_value' => $node->title,
                           '#description' => t("First name, middle initial, last name"),
                           '#required' => TRUE,
                           '#weight' => -10,
                           );
  }
  if ($type->has_body) {
    $form['body_field'] = node_body_field(
           $node,
                                          $type->body_label,
                                          $type->min_word_count
                                          );
  }

  // custom content fields

  $form['cpo_id'] = array(
                          '#type' => 'value',
                          '#value' => $user->name,
                          );

  $form['cpo_title'] = array(
                             '#type' => 'textfield',
                             '#title' => t('Title'),
                             '#default_value' => isset($node->cpo_title) ? $node->cpo_title : '',
                             );

  $form['cpo_first_name'] = array(
                                  '#type' => 'textfield',
                                  '#title' => t('First name'),
                                  '#default_value' => isset($node->cpo_first_name) ? $node->cpo_first_name : '',
                                  );

  $form['cpo_middle_initial'] = array(
                                      '#type' => 'textfield',
                                      '#title' => t('Middle initial'),
                                      '#default_value' => isset($node->cpo_middle_initial) ? $node->cpo_middle_initial : '',
                                      );

  $form['cpo_last_name'] = array(
                                 '#type' => 'textfield',
                                 '#title' => t('Last name'),
                                 '#default_value' => isset($node->cpo_last_name) ? $node->cpo_last_name : '',
                                 );
.
.
.                             
 $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));

  return $form;
}

function cpo_insert($node) {
  drupal_set_message('in insert');
  if (!isset($node->cpo_association_memberships_other)) {
    $node->cpo_association_memberships_other = '';
  }

  if (!isset($node->cpo_company_bio)) {
    $node->cpo_company_bio = '';
  }

  db_query(
           'INSERT INTO {cpo} (vid, nid, cpo_id, cpo_title, cpo_first_name, cpo_middle_initial, cpo_last_name, cpo_degrees, cpo_company_name, cpo_company_website, cpo_association_memberships_other, cpo_email, cpo_phone_day, cpo_phone_cell, cpo_fax, cpo_annual_maintenance_fee, cpo_paid_through, cpo_certified_since, cpo_address1, cpo_address2, cpo_city, cpo_state, cpo_zip, cpo_country, cpo_company_bio, cpo_approved_directory_display, cpo_is_for_admin_use_only)'
           . "VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %f, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d)",
           $node->vid,
           $node->nid,
           $node->cpo_id,
           $node->cpo_title,
           $node->cpo_first_name,
           $node->cpo_middle_initial,
           $node->cpo_last_name,
           $node->cpo_degrees,
           $node->cpo_company_name,
           $node->cpo_company_website,
           $node->cpo_association_memberships_other,
           $node->cpo_email,
           $node->cpo_phone_day,
           $node->cpo_phone_cell,
           $node->cpo_fax,
           $node->cpo_annual_maintenance_fee,
           $node->cpo_paid_through,
           $node->cpo_certified_since,
           $node->cpo_address1,
           $node->cpo_address2,
           $node->cpo_city,
           $node->cpo_state,
           $node->cpo_zip,
           $node->cpo_country,
           $node->cpo_company_bio,
           $node->cpo_approved_directory_display,
           $node->cpo_is_for_admin_use_only
        );
}

Comments

ckee’s picture

Hoping this means something to someone: with hook_insert not working, the path in hook_menu was 'cpo-edit'. Because the node-type is cpo I changed the path in hook_menu to node/add/cpo to see what would happen. (1) The form now had Save and Preview buttons in addition to the module-specific Save (submit) button from the form. (2) The data now inserted to the db, but as a new node, rather than updating.

ckee’s picture

I see now that the form works when invoked via paths referencing the node, e.g. node/999/edit will load the form with the correct node. So I'm guessing that the problem in terms of what I was trying to do -- i.e. invoke the form from a more generic path and populate it programmatically -- might be related to the code at the top of the form:

function cpo_form($form_state) {
  global $user;

  if(is_object($form_state) && isset($form_state->nid)) {
    $nid = $form_state->nid;
  } else {
    $query = "select nid from {cpo} where cpo_id = '$user->name'";
    $nid = db_result(db_query($query));
  }

  $node = node_load($nid);
.
.
.

I read the reference here http://drupal.org/node/158237 to explicit invocations of node_load interfering with hook_insert, although I don't see the direct connection to my issue.

ckee’s picture

I realized that I had a fundamental misunderstanding of the interaction between the menu system and the node system. I thought that because my module implemented a content type, that invoking the form via the path in the module's hook_menu would result in the behavior I'd expect of a node -- specifically, inserting new ones and updating existing ones on submitting the form. Not necessarily true, as I'm sure experienced Drupallers know ....

My solution was to add the following to my theme's template.php file:

function phptemplate_menu_item_link($link) {
  global $user;

  // customize cpo-edit link by user
  //
  if ($link['href'] == 'cpo-edit') {
    $nid = db_result(db_query('select nid from {cpo} where cpo_id = "%s"', $user->name));
    if ($nid) {
      $link['href'] = "node/$nid/edit";
    } else {
      $link['href'] = "node/add/cpo";
    }
  }

  if (empty($link['localized_options'])) {
    $link['localized_options'] = array();
  }
  return l($link['title'], $link['href'], $link['localized_options']);
}

The effect is that when a user hits the menu item whose link is cpo-edit (which is the path in the cpo module's hook_menu) the function checks to see if the user has cpo data or not, and inserts the correct path as the menu item's link. If only the add link was needed, the change could be made via the menu admin page, but inserting the nid requires a lookup, hence the function.

Thanks to zeropx on the irc #drupal-support chat for pointing me in the right direction.