This was supposed to be fixed in https://www.drupal.org/node/1107522 but appears not to be the case.

My schema structure for field in question is:

      'n_factor' => array(
        'description' => 'Factor for converting nitrogen to protein.',
        'type' => 'numeric',
        'precision' => 4,
        'scale' => 2,
        'unsigned' => TRUE,
        'not null' => FALSE,
      ),

The desired effect from import is that if the feed item contains empty value for that field, it should result in NULL but it appears to be trying to pass an empty string and resulting in the following error in feeds log:

SQLSTATE[HY000]: General error: 1366 Incorrect decimal value: '' for column 'n_factor' at row 1
Original item

array(
  'ndb_no' => '09383',
  'fdgrp_cd' => '0900',
  'long_desc' => 'Tangerines, (mandarin oranges), canned, juice pack, drained',
  'shrt_desc' => 'TANGERINES,(MANDARIN ORANGES),CND,JUC PK,DRND',
  'comname' => '',
  'manufacname' => '',
  'survey' => 'Y',
  'ref_desc' => '',
  'refuse' => '0',
  'sciname' => '',
  'n_factor' => '',
  'pro_factor' => '3.36',
  'fat_factor' => '8.37',
  'cho_factor' => '3.7',
)

Entity

(object) array(
  'vid' => '17307',
  'uid' => '0',
  'title' => 'Tangerines, (mandarin oranges), canned, juice pack, drained',
  'log' => 'Updated by FeedsNodeProcessor',
  'status' => '1',
  'comment' => '0',
  'promote' => '1',
  'sticky' => '0',
  'nid' => '17307',
  'type' => 'food',
  'language' => 'und',
  'created' => '1442946028',
  'changed' => 1442946033,
  'tnid' => '0',
  'translate' => '0',
  'revision_timestamp' => '1442946033',
  'revision_uid' => '1',
  'name' => '',
  'picture' => '0',
  'date' => '2015-09-22 12:20:28 -0600',
  'revision' => FALSE,
  'is_new' => FALSE,
  'timestamp' => 1442946033,
)

I can pass NULL as value if field is empty on manual node add/edit and database gets updated accurately so not sure what the issue is with feeds import... Is there anything i can do in the target callback function to only set value if there is one? I've tried checking for empty in if clause and seems to be ignored.

function food_import_n_factor ($source, $entity, $target, $value, $mapping) {
    $entity->$target = $value;
}
CommentFileSizeAuthor
#4 FOOD_DES_0.xml_.zip11.68 KBapmsooner
#4 feed_importer.txt4.98 KBapmsooner
#4 food.zip11.93 KBapmsooner
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

apmsooner created an issue. See original summary.

apmsooner’s picture

I think what I'm ultimately trying to get at is, if my table allows a null value and I explicitly set NULL as value in the target callback for empty $value, why is feeds kicking back an error and skipping the feed item?

My callback function:

function food_import_n_factor ($source, $entity, $target, $value, $mapping) {
  if (empty($value)) {
    $entity->$target = NULL;
  }
  else {
    $entity->$target = $value;
  }
}

Again, my defaults in form with NULL as fallback for empty field works fine and no problems saving node. Not sure what part of feeds module may be interrupting what I would expect to happen.

MegaChriz’s picture

Status: Active » Postponed (maintainer needs more info)

I have tried to reproduce this, but I didn't got this error. I tried it with both a decimal and a float field and the following XML file:

<?xml version="1.0" ?>
<root>
  <item>
    <title>Item 1</title>
    <float>3.42</float>
  </item>
  <item>
    <title>Item 2</title>
    <float></float>
  </item>
</root>

Can you provide the following:

  • An export of your feeds importer.
  • The source file you were trying to import.
  • An export of your content type + field bases and field instances and put inside a feature module. (The feeds importer may be put in the feature as well.)
apmsooner’s picture

FileSize
11.93 KB
4.98 KB
11.68 KB

@MegaChriz,

Thanks for helping out. Just to clarify, my module creates a node type of "food" that has a custom table that gets filled/updated upon node save so the fields in question are not CCK fields but rather from a custom table. Attached is my module as well as the feeds importer. I'm using Feeds XPath Parser for the feed however i've tried doing it as csv as well and the same errors occur. I've attached small sample xml file as well for testing.

Note: i know i could set values to 0 for empty result and would import just fine but that is undesirable for my needs. As you will see, manually saving a new node or existing node with empty decimal field returns NULL as desired. Feeds seems to bypass that and make it conform otherwise. I've tried playing with the feeds target callback to return NULL if empty but it seems to be ignored. I appreciate any workaround suggestions if you know of any....

Thanks!

MegaChriz’s picture

Category: Bug report » Support request
Status: Postponed (maintainer needs more info) » Fixed

The fourth parameter of the mapping target callback $value is an array since Feeds 7.x-2.0-beta1. This was done to handle multivalued fields in consistent way. Therefore, your node object will for example become $node->food_n_factor = array(0 => ''). See also the change record.

Since your targets are single-valued, you could change your code to the following, for example:

function food_import_n_factor ($source, $entity, $target, array $values, $mapping) {
  $entity->$target = reset($values);
}

And instead of the hook hook_feeds_processor_targets_alter() you can now also use the hook hook_feeds_processor_targets() to specify new targets.

apmsooner’s picture

Thanks for the reply @MegaChriz, first off I tried your suggestion but the result is only some of the items get imported and the rest signal an error of "Missing bundle property on entity of type node."

Is the above example proper syntax? The documentation is difficult to decipher on proper useage... perhaps i'm missing something simple.
Additionally, tried changing to hook_feeds_processor_targets and get an error for paramater 1 being supplied as value. Again, where exactly is the documentation for this new hook?

Thanks

MegaChriz’s picture

The documentation for the hook hook_feeds_processor_targets is in feeds.api.php. It has one parameter less.

/**
 * Adds mapping targets for processors.
 *
 * This hook allows additional target options to be added to the processors
 * mapping form.
 *
 * If the key in $targets[] does not correspond to the actual key on the node
 * object ($node->key), real_target MUST be specified. See mappers/link.inc
 *
 * For an example implementation, see mappers/text.inc
 *
 * @param string $entity_type
 *   The entity type of the target, for instance a 'node' entity.
 * @param string $bundle
 *   The entity bundle to return targets for.
 *
 * @return array
 *   Array containing the targets to be offered to the user. This function must
 *   return an array, even an empty one.
 */
function hook_feeds_processor_targets($entity_type, $bundle) {
  $targets = array();

  if ($entity_type == 'node') {
    $targets['my_node_field'] = array(
      'name' => t('My custom node field'),
      'description' => t('Description of what my custom node field does.'),
      'callback' => 'my_module_set_target',

      // Specify both summary_callback and form_callback to add a per mapping
      // configuration form.
      'summary_callbacks' => array('my_module_summary_callback'),
      'form_callbacks' => array('my_module_form_callback'),
    );
    $targets['my_node_field2'] = array(
      'name' => t('My Second custom node field'),
      'description' => t('Description of what my second custom node field does.'),
      'callback' => 'my_module_set_target2',
      'real_target' => 'my_node_field_two', // Specify real target field on node.
    );
    $targets['my_node_field3'] = array(
      'name' => t('My third custom node field'),
      'description' => t('Description of what my third custom node field does.'),
      'callback' => 'my_module_set_target3',

      // Set optional_unique to TRUE and specify unique_callbacks to allow the
      // target to be unique. Existing entities can be updated based on unique
      // targets.
      'optional_unique' => TRUE,
      'unique_callbacks' => array('my_module_mapper_unique'),

      // Preprocess callbacks are called before the actual callback allowing you
      // to prepare values on the entity or mapping array.
      'preprocess_callbacks' => array('my_module_preprocess_callback'),
    );
    $targets['deprecated_target'] = array(
      'name' => t('A target that cannot be chosen in the UI.'),

      // Set deprecated to TRUE to hide the target from the UI. This can be
      // useful if you want to rename targets for consistency, but don't want to
      // break importers that are using the old target name.
      // If an importer uses this target it will show up as "DEPRECATED" in the
      // UI.
      'deprecated' => TRUE,
    );
  }

  return $targets;
}
apmsooner’s picture

Just wanted to post back that by changing to proper parameters for hook_feeds_preprocessor_targets as outlined above is now working for me. Additionally, my decimal fields are importing just fine now as null values if empty in source. I didn't need to reset $value but rather just pull $value out of the $values array and seems to not be an issue for me anymore. I suppose the new function is what has fixed all this up for me now. Here is my callback revision for reference:

function food_set_target3 ($source, $entity, $target, array $values, $mapping) {
  foreach ($values as $value) {
    $entity->$target = $value;
  }
}

Thanks for all the help MegaChriz!

MegaChriz’s picture

The reset() function just returns the first element of an array. It does not make changes to anything what is in the array.

apmsooner’s picture

Ahh! okay, i misunderstood its use. Thanks for the clarification.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.