1

Problem

My custom field type will not save data. Every time I save the entity it is attached to (it doesn't matter what entity I do this on) the value always comes out NULL and SQL throws an error because that field can not be NULL in the database.

Research

I'm currently working on a module that will provide a custom field type to be used on entities. I have done my best from looking at the docs for Field Types API and seeing how other modules have implemented this e.g. Entity Reference, Examples, and Address Field.

Attempt

Below is my attempt and can not figure out what is wrong with the code.

.install file

/**
 * Implements hook_field_schema().
 */
function civsearch_code_reference_field_schema($field) {
  $columns = array(
    'target_id' => array(
      'description' => 'The id of the target code.',
      'type' => 'int',
      'unsigned' => TRUE,
      'not null' => TRUE,
    ),
  );

  return array(
    'columns' => $columns,
    'indexes' => array(
      'target_id' => array('target_id'),
    ),
  );
}

.module file

/**
 * Implements hook_field_info().
 */
function civsearch_code_reference_field_info() {
  return array(
    'civsearch_code_reference' => array(
      'label' => t('Code Reference'),
      'description' => t('This field stores the target_id of the referenced code.'),
      'settings' => array(
        'code_type' => '',
      ),
      'instance_settings' => array(),
      'default_widget' => 'civsearch_code_reference_autocomplete_tags',
      'default_formatter' => 'civsearch_code_reference_label',
    ),
  );
}

/**
 * Implements hook_field_settings_form().
 */
function civsearch_code_reference_field_settings_form($field, $instance, $has_data) {
  $settings = $field['settings'];

  $options = array(
    'muni_cloud_bulk' => t('Bulk'),
    'muni_cloud_bulk_exception' => t('Bulk Exception'),
    'muni_cloud_bulk_zoning_district' => t('Bulk Zoning District'),
    'muni_cloud_exception' => t('Exception'),
    'muni_cloud_jurisdiction' => t('Jurisdiction'),
    'muni_cloud_use' => t('Use'),
    'muni_cloud_use_unit' => t('Use Unit'),
    'muni_cloud_use_regulation' => t('Use Regulation'),
    'muni_cloud_use_zoning_district' => t('Use Zoning District'),
    'muni_cloud_zoning_category' => t('Zoning Category'),
    'muni_cloud_zoning_district' => t('Zoning District'),
  );

  $form['code_type'] = array(
    '#type' => 'select',
    '#title' => t('Code Type'),
    '#options' => $options,
    '#description' => t('The code type to be referenced.'),
    '#default_value' => $settings['code_type'],
    '#required' => TRUE,
  );

  return $form;
}

/**
 * Implements hook_field_widget_info().
 */
function civsearch_code_reference_field_widget_info() {
  return array(
    'civsearch_code_reference_autocomplete_tags' => array(
      'label' => t('Autocomplete (Tags style)'),
      'description' => t('An autocomplete text field.'),
      'field types' => array('civsearch_code_reference'),
      'settings' => array(
        'match_operator' => 'CONTAINS',
        'size' => 60,
        'path' => '',
      ),
      'behaviors' => array(
        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
      ),
    ),
  );
}

/**
 * Implements hook_field_widget_settings_form().
 */
function civsearch_code_reference_field_widget_settings_form($field, $instance) {
  $widget = $instance['widget'];
  $settings = $widget['settings'];

  $form = array();

  $form['match_operator'] = array(
    '#type' => 'select',
    '#title' => t('Autocomplete matching'),
    '#default_value' => $settings['match_operator'],
    '#options' => array(
      'STARTS_WITH' => t('Starts with'),
      'CONTAINS' => t('Contains'),
    ),
    '#description' => t('Select the method used to collect autocomplete suggestions.'),
  );
  $form['size'] = array(
    '#type' => 'textfield',
    '#title' => t('Size of textfield'),
    '#default_value' => $settings['size'],
    '#element_validate' => array('_element_validate_integer_positive'),
    '#required' => TRUE,
  );

  return $form;
}

/**
 * Implements hook_field_widget_form().
 */
function civsearch_code_reference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {

  $element += array(
    '#type' => 'textfield',
    '#maxlength' => 1024,
    '#defaul_value' => 'bob',
    '#size' => $instance['widget']['settings']['size'],
  );

  return array('target_id' => $element);
}

/**
 * Implements hook_field_formatter_info().
 */
function civsearch_code_reference_field_formatter_info() {
  return array(
    'civsearch_code_reference_label' => array(
      'label' => t('Label'),
      'description' => t('Display the label of the referenced codes.'),
      'field types' => array('civsearch_code_reference'),
      'settings' => array(
        'link' => FALSE,
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_settings_form().
 */
function civsearch_code_reference_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];

  $element = array();

  if ($display['type'] == 'civsearch_code_reference_label') {
    $element['link'] = array(
      '#title' => t('Link label to the referenced code.'),
      '#type' => 'checkbox',
      '#default_value' => $settings['link'],
    );
  }

  return $element;
}

/**
 * Implements hook_field_formatter_settings_summary().
 */
function civsearch_code_reference_field_formatter_settings_summary($field, $instance, $view_mode) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];

  $summary = array();

  if ($display['type'] == 'civsearch_code_reference_label') {
    $summary[] = $settings['link'] ? t('Link to the referenced code') : t('No link');
  }

  return implode('<br />', $summary);
}

/**
 * Implements hook_field_is_empty().
 */
function civsearch_code_reference_field_is_empty($item, $field) {
  return empty($item);
}

Error

PDOException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column
'field_jurisdiction_target_id' cannot be null: INSERT INTO 
{field_data_field_jurisdiction} (entity_type, entity_id, revision_id, bundle,
delta, language, field_jurisdiction_target_id) VALUES
(:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2,
:db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5, 
:db_insert_placeholder_6); Array ( [:db_insert_placeholder_0] => 
civsearch_property [:db_insert_placeholder_1] => 17 [:db_insert_placeholder_2]
=> 17 [:db_insert_placeholder_3] => test [:db_insert_placeholder_4] => 0 
[:db_insert_placeholder_5] => und [:db_insert_placeholder_6] => ) in 
field_sql_storage_field_storage_write() (line 452 of
/var/dev/modules/field/modules/field_sql_storage/field_sql_storage.module)

Debug Backtrace

15: field_sql_storage_field_storage_write() (Array, 2 elements)
14: call_user_func_array() (Array, 1 element)
13: module_invoke() (Array, 2 elements)
12: field_attach_insert() (Array, 2 elements)
11: EntityAPIController->invoke() (Array, 2 elements)
10: EntityAPIController->save() (Array, 2 elements)
 9: Entity->save() (Array, 2 elements)
 8: civsearch_property_edit_form_submit() (Array, 2 elements)
 7: form_execute_handlers() (Array, 2 elements)
 6: drupal_process_form() (Array, 2 elements)
 5: drupal_build_form() (Array, 2 elements)
 4: drupal_get_form() (Array, 2 elements)
 3: civsearch_property_form_wrapper() (Array, 2 elements)
 2: call_user_func_array() (Array, 1 element)
 1: menu_execute_active_handler() (Array, 2 elements)
 0: main() (Array, 2 elements)
5
  • Show debug_backtrace() stack from place where error occours please. And error message of course.
    – FriOne
    Commented Jul 31, 2014 at 5:19
  • Sorry error message was too long for a comment here. Here is a link to pastebin. Commented Jul 31, 2014 at 14:13
  • As far as the backtrace goes, I'm not sure how to get this information to you as it is way to long for even pastebin. Commented Jul 31, 2014 at 14:14
  • Put error message in post, just edit it. From backtrace I need functions names only.
    – FriOne
    Commented Jul 31, 2014 at 14:21
  • Alright the SQL error and the debug_backtrace function names are added to original message. Commented Jul 31, 2014 at 14:32

2 Answers 2

2

Try this:

/**
 * Implements hook_field_widget_form().
 */
function civsearch_code_reference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $value = isset($items[$delta]['target_id']) ? $items[$delta]['target_id'] : '';

  $element += array(
    '#type' => 'textfield',
    '#maxlength' => 1024,
    '#default_value' => $value,
    '#size' => $instance['widget']['settings']['size'],
  );

  // There are array wrapper because if it is no then value will be cut to one letter.
  // Link to realted toric is under the code block.
  return array(array('target_id' => $element));
}

Letter cutting.. Second array wrap is because of this FIELD_BEHAVIOR_CUSTOM, for default type one time is enough. Also, you have text mistake in code '#defaul_value' => 'bob', there is no 't' at the 'defaul' end, and this value must be integer.

3
  • Still getting the same error. From my understanding it needs to be target_id because that is the column in the field table I am saving the submitted data to. Commented Jul 31, 2014 at 16:23
  • @FatGuyLaughing, I edited the answer, checked this code localy it works. I thought drupal adds validation by itself but It don't.
    – FriOne
    Commented Jul 31, 2014 at 17:28
  • Thanks! this worked. I'll have to look into why I entityreference field isn't double wrapping even though it uses the same custom behavior. Commented Jul 31, 2014 at 18:24
0

Since you specified that target_id is not null in hook_field_schema, therefore and you're actually passing NULL as per db_insert_placeholder_6, it won't let you save the field.

So either this line :

'not null' => TRUE,

needs to be removed (field instance needs to be recreated) or make sure the value is not empty

This line is invalid as per typo:

'#defaul_value' => 'bob',

so it should be:

'#default_value' => 'bob',

That's probably the main reason.

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