Index: field_collection/field_collection.module =================================================================== --- field_collection/field_collection.module (revision 1136) +++ field_collection/field_collection.module (working copy) @@ -1859,3 +1859,167 @@ return array('value' => $field_collection->item_id); } + +/** + * Implements hook_feeds_processor_targets_alter() + */ +function field_collection_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) { + foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) { + $info = field_info_field($name); + if ($info['type'] == 'field_collection') { + $new_targets = array(); + feeds_alter('feeds_processor_targets', $new_targets, 'field_collection_item', $info['field_name']); + foreach ($new_targets as $sub_name => $target) { + $new_name = $info['field_name'] . ':' . $sub_name; + $targets[$new_name] = $target; + if (isset($target['name'])) { + $targets[$new_name]['name'] = $instance['label'] . ': ' . $target['name']; + } + + // We override callback for now and retrieve original later. + $targets[$new_name]['callback'] = 'field_collection_feeds_set_target'; + } + } + } +} + +/** + * Process Field Collection items + */ +function field_collection_feeds_set_target($source, $entity, $target, $value) { + static $sub_targets = array(); + + $args = explode(':', $target); + $target = array_shift($args); + $sub_target = implode(':', $args); + + // Now we retrieve old callbacks and keep then on a static cache + if (!isset($sub_targets[$target])) { + feeds_alter('feeds_processor_targets', $sub_targets[$target], 'field_collection_item', $target); + } + $_sub_targets = $sub_targets[$target]; + + $value = is_array($value) ? $value : array($value); + $info = field_info_field($target); + + // Iterate over all values. + $delta = 0; + $field = isset($entity->$target) ? $entity->$target : array(); + + // we need to + // 1 .look over the field info first + // 2. look at it's cardinality + $importer = $source->importer(); + $importer->load(); + $config = $importer->config; + + // look to see how many times we mapped fields to the field collection + $field_collection_map = array(); + foreach ($config['processor']['config']['mappings'] as $mapping) { + if (stristr($mapping['target'], $target)) { + $field_collection_map[] = $mapping['target']; + } + } + + // if there are field collection import of just 1 cardinality, it will always be one regardless. + $mapping_count = 1; + if (!empty($field_collection_map)) { + // to count how many times a field collection has been mapped (assuming same number of fields mapped for each field collection item) + $mapping_count = count($field_collection_map) / count(array_unique($field_collection_map)); + } + + // Important, for multiple mapping of the field collection, start with the next delta and not + // overwrite it. + if (!isset($entity->count)) { + if (isset($entity->$target)) { + $entity->count = 1; + } else { + $entity->count = 0; + } + } else { + if (isset($entity->$target)) { + $entity->count++; + } + } + + if (!isset($entity->delta)) { + $entity->delta = 0; + } + + $delta = $entity->delta; + + foreach ($value as $v) { + if (isset($field['und'][$delta]['entity'])) { + $field_collection_item = $field['und'][$delta]['entity']; + } + elseif (isset($field['und'][$delta]['value'])) { + $field_collection_item = field_collection_item_load($field['und'][$delta]['value']); + } + if (empty($field_collection_item)) { + $field_collection_item = entity_create('field_collection_item', array('field_name' => $target)); + } + + if (isset($_sub_targets[$sub_target]['callback']) && function_exists($_sub_targets[$sub_target]['callback'])) { + $callback = $_sub_targets[$sub_target]['callback']; + $callback($source, $field_collection_item, $sub_target, $v); + } + + $field['und'][$delta]['entity'] = $field_collection_item; + $field['und'][$delta]['value'] = $field_collection_item->item_id; + + unset($field_collection_item); + + if ($info['cardinality'] == 1) { + break; + } + $delta++; + } + + // increase entity delta count + if (($entity->count + 1) % $mapping_count == 0) { + $entity->delta++; + } + + $entity->{$target} = $field; +} + +/** + * Implements hook_feeds_presave(). + */ +function field_collection_feeds_presave($source, $entity) { + // Do not save any empty field collection items that may have been created + // during the mapping process. Since the mapping is done field by field in + // field_collection_feeds_set_target(), we have to wait until this hook (when + // the field collection item is fully built up) before we can check if it's + // empty. + $config = $source->importer()->getConfig(); + if (!empty($config['processor']['config']['mappings'])) { + // Find all field collection mappings. + foreach ($config['processor']['config']['mappings'] as $mapping) { + if (isset($mapping['target'])) { + $args = explode(':', $mapping['target']); + $field_name = array_shift($args); + if (($field = field_info_field($field_name)) && $field['type'] == 'field_collection') { + // If the field collection item is empty, do not save it. + if (!empty($entity->{$field_name})) { + foreach ($entity->{$field_name} as $langcode => &$items) { + foreach ($items as $delta => $item) { + if (isset($item['entity']) && field_collection_item_is_empty($item['entity'])) { + unset($items[$delta]); + } + } + // Clean up the final array. + if (empty($items)) { + unset($entity->{$field_name}[$langcode]); + } + else { + $items = array_values($items); + } + } + } + } + } + } + } +} +