Save data to custom field columns using entity_metadata_wrapper

I have a simple custom module that creates a new field type. The field has multiple columns in the database; the idea is that a user (or code) will enter a single value, and then that value is converted into several different formats and saved to the database columns.

Currently, this is working by using a method from the book Drupal 7 Module Development, where the user’s original value is converted using a widget validate function.

It works great when a human is filling out a form; but the problem is, when I try to create an entity in code, using entity_metadata_wrapper, there’s no widget, and thus, no widget validate function runs.

It looks like I need to look at hook_field_info and specify a property_type of ‘struct’ with a custom setter callback, but I can’t find any documentation that describes how to use the property or getter/setter callbacks.

How can I use entity metadata wrappers with custom field database columns?

/**  * Implements hook_field_info().  */ function device_id_field_info() {   return array(     'device_id' => array(       'label' => t('Device ID'),       'description' => t('Converts the input device ID and saves it to the          database in various formats.'),       'default_widget' => 'device_id_simple',       'default_formatter' => 'device_id_raw',       'default_token_formatter' => 'device_id_combined',       'property_type' => 'device_id',       'property_callback' => array('_device_id_property_callback'),       ),   ); }  /**  * Callback to alter the property info of device id fields.  *  * @see device_id_field_info().  */ function _device_id_property_callback(&$info, $entity_type, $field, $instance, $field_type) {   $name = $field['field_name'];   $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];    $property['type'] = ($field['cardinality'] != 1) ? 'list<deviceid>' : 'deviceid';   $property['getter callback'] = 'entity_metadata_field_verbatim_get';   $property['setter callback'] = 'entity_metadata_field_verbatim_set';   $property['property info'] = device_id_property_info();    unset($property['query callback']); }  /**  * Defines info for the properties of the device ID field data structure.  */ function device_id_property_info($name = NULL) {   // Build an array of basic property information for the device ID field.   $properties = array(     'raw_id' => array(       'label' => t('Raw input ID'),     ),     'esn_hex' => array(       'label' => t('Converted ESN in hexadecimal format'),     ),     'esn_dec' => array(       'label' => t('Converted ESN in decimal format'),     ),     'meid_hex' => array(       'label' => t('Converted MEID in hexadecimal format'),     ),     'meid_dec' => array(       'label' => t('Converted MEID in decimal format'),     ),     'imei_hex' => array(       'label' => t('Converted IMEI in hexadecimal format'),     ),     'imei_dec' => array(       'label' => t('Converted IMEI in decimal format'),     ),     'iccid_hex' => array(       'label' => t('Converted ICCID in hexadecimal format'),     ),     'iccid_dec' => array(       'label' => t('Converted ICCID in decimal format'),     ),   ); }  /**  * Implements hook_field_is_empty().  *  * Pseudo-hook.  */ function device_id_field_is_empty($item, $field) {   if ($field['type'] == 'device_id') {     if (       empty($item['raw_id']) &&       empty($item['cap_dec']) &&        empty($item['cap_hex']) &&        empty($item['meid_dec']) &&        empty($item['meid_hex']) &&        empty($item['imei_dec']) &&        empty($item['imei_hex']) &&        empty($item['iccid_dec']) &&        empty($item['iccid_hex'])) {        return TRUE;     }   }   return FALSE; }  /**  * Implements hook_field_widget_info().  */ function device_id_field_widget_info() {   return array(     'device_id_simple' => array(       'label' => t('Device ID text field'),       'description' => t(         'Allow the user to enter the device ID, and display it in          whatever format it was entered'),       'field types' => array('device_id'),       'behaviors' => array(         'multiple values' => FIELD_BEHAVIOR_DEFAULT,         'default value' => FIELD_BEHAVIOR_DEFAULT,         ),       ),     ); }  /**  * Implements hook_field_widget_form().  *  * Pseudo hook  **/ function device_id_field_widget_form(   &$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {    switch ($instance['widget']['type'] == 'device_id_simple') {      case 'device_id_simple':       $element += array(         '#element_validate' => array('_device_id_wrapper_validate'),         'device_id_wrapper' => array(           'input_id' => array(             '#title' => t('Device ID'),             '#type' => 'textfield',             '#default_value' => isset($items[$delta]['raw_id']) ?                $items[$delta]['raw_id'] : '',           ),         )       );     break;   }   return $element; }  function _device_id_wrapper_validate($element, &$form_state) {   //This function is also called when submitting the field   //configuration form.  If so, skip validation since it    //won't work anyway   if ($form_state['complete form']['#form_id'] == 'field_ui_field_edit_form') {     return;   }    $values = $form_state['values'];   $language = $element['#language'];   $field_name = $element['#field_name'];   $item = $values[$field_name][$language][$element['#delta']]['device_id_wrapper'];    foreach ($values[$field_name][$language] as $delta => $item) {     if (is_array($item)) {       if (array_key_exists('device_id_wrapper', $item)) {         $conversion = new deviceIDConversion($item['device_id_wrapper']['input_id']);         $conversion_values = $conversion->calculate();         if ($conversion_values) {           $new_values = array(             'esn_hex' => isset($conversion_values['ESN_HEX']) ? $conversion_values['ESN_HEX'] : NULL,             'esn_dec' => isset($conversion_values['ESN_DEC']) ? $conversion_values['ESN_DEC'] : NULL,             'meid_hex' => isset($conversion_values['MEID_HEX']) ? $conversion_values['MEID_HEX'] : NULL,             'meid_dec' => isset($conversion_values['MEID_DEC']) ? $conversion_values['MEID_DEC'] : NULL,             'imei_hex' => isset($conversion_values['IMEI_HEX']) ? $conversion_values['IMEI_HEX'] : NULL,             'imei_dec' => isset($conversion_values['IMEI_DEC']) ? $conversion_values['IMEI_DEC'] : NULL,             'iccid_hex' => isset($conversion_values['ICCID_HEX']) ? $conversion_values['ICCID_HEX'] : NULL,             'iccid_dec' => isset($conversion_values['ICCID_DEC']) ? $conversion_values['ICCID_DEC'] : NULL,             'raw_id' => $item['device_id_wrapper']['input_id'],             );           form_set_value($element, $new_values, $form_state);         } else {           form_set_error($field_name, t('Your device ID doesn't match a valid format.  Check             the device ID, verify it's correct, and type/scan it again.'));         }       }     }   } }  /**  * Implements hook_field_validate().  *  * Pseudo-hook.  */ function device_id_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {   foreach ($items as $delta => $item) {     if (!empty($item['raw_id'])) {       $conversion = new deviceIDConversion($item['raw_id']);       $conversion_values = $conversion->calculate();       if (!$conversion_values) {         $errors[$field['field_name']][$langcode][$delta][] = array(           'error' => 'device_id_invalid_format',           'message' => t('Your device ID doesn't match a valid format.  Check             the device ID, verify it's correct, and type/scan it again.'),         );       }      }   } } 

Here is some example code I’m using in a test page to work with this content; when I do entity_load(), I can view the contents of the custom field, including the database columns I defined in hook_info(). When I wrap this in entity_metadata_wrapper() and try setting the field value, nothing happens. Also, after wrapping, I can no longer see the field values, even with getPropertyInfo().

$ent = entity_load('node', array('2955')); $new_ent = entity_metadata_wrapper('node', $ent['2955']); $new_ent->field_device_id->meid_hex = 'a1000002747883'; $new_ent->save(); dsm($new_ent->getPropertyInfo()); 
Sponsored by SupremePR
This article was republished from its original source.
Call Us: 1(800)730-2416

Pixeldust is a 20-year-old web development agency specializing in Drupal and WordPress and working with clients all over the country. With our best in class capabilities, we work with small businesses and fortune 500 companies alike. Give us a call at 1(800)730-2416 and let’s talk about your project.

FREE Drupal SEO Audit

Test your site below to see which issues need to be fixed. We will fix them and optimize your Drupal site 100% for Google and Bing. (Allow 30-60 seconds to gather data.)

Powered by

Save data to custom field columns using entity_metadata_wrapper

On-Site Drupal SEO Master Setup

We make sure your site is 100% optimized (and stays that way) for the best SEO results.

With Pixeldust On-site (or On-page) SEO we make changes to your site’s structure and performance to make it easier for search engines to see and understand your site’s content. Search engines use algorithms to rank sites by degrees of relevance. Our on-site optimization ensures your site is configured to provide information in a way that meets Google and Bing standards for optimal indexing.

This service includes:

  • Pathauto install and configuration for SEO-friendly URLs.
  • Meta Tags install and configuration with dynamic tokens for meta titles and descriptions for all content types.
  • Install and fix all issues on the SEO checklist module.
  • Install and configure XML sitemap module and submit sitemaps.
  • Install and configure Google Analytics Module.
  • Install and configure Yoast.
  • Install and configure the Advanced Aggregation module to improve performance by minifying and merging CSS and JS.
  • Install and configure Schema.org Metatag.
  • Configure robots.txt.
  • Google Search Console setup snd configuration.
  • Find & Fix H1 tags.
  • Find and fix duplicate/missing meta descriptions.
  • Find and fix duplicate title tags.
  • Improve title, meta tags, and site descriptions.
  • Optimize images for better search engine optimization. Automate where possible.
  • Find and fix the missing alt and title tag for all images. Automate where possible.
  • The project takes 1 week to complete.