diff --git a/field_collection.module b/field_collection.module index a64e9c3..9ce59ca 100644 --- a/field_collection.module +++ b/field_collection.module @@ -1869,3 +1869,161 @@ function field_collection_entity_translation_insert($entity_type, $entity, $tran } } } + + +/** + * Implements hook_feeds_processor_targets_alter() + */ +function field_collection_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) { + + // Load up. + $loaded = &drupal_static(__FUNCTION__, FALSE); + + if (!$loaded) { + $loaded = TRUE; + $path = drupal_get_path('module', 'feeds') . '/mappers'; + $files = drupal_system_listing('/.*\.inc$/', $path, 'name', 0); + foreach ($files as $file) { + if (strstr($file->uri, '/mappers/')) { + require_once (DRUPAL_ROOT . '/' . $file->uri); + } + } + } + + foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) { + $info = field_info_field($name); + if ($info['type'] == 'field_collection') { + + $sub_type = 'field_collection_item'; + $new_targets = module_invoke_all('feeds_processor_targets', $sub_type, $info['field_name']); + drupal_alter('feeds_processor_targets', $new_targets, $sub_type, $info['field_name']); + + foreach ($new_targets as $sub_name => $target) { + $new_name = t($info['field_name']) . ':' . t($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. + * + * @param [type] $source [description] + * @param [type] $entity [description] + * @param [type] $target [description] + * @param [type] $value [description] + * @param [type] $main_mapping [description] + * @return [type] [description] + */ +function field_collection_feeds_set_target($source, $entity, $target, $value, $main_mapping) { + $sub_targets = &drupal_static(__FUNCTION__, array()); + + $args = explode(':', $target); + $target = array_shift($args); + $sub_target = implode(':', $args); + + $sub_type = 'field_collection_item'; + $new_targets = module_invoke_all('feeds_processor_targets', $sub_type, $target); + drupal_alter('feeds_processor_targets', $new_targets, $sub_type, $target); + + // Now we retrieve old callbacks and keep then on a static cache. + if (!isset($sub_targets[$target])) { + $sub_targets[$target] = array(); + drupal_alter('feeds_processor_targets', $sub_targets[$target], $sub_type, $target); + } + + $_sub_targets = $new_targets; + + $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(); + try { + + while ($value[$delta]) { + + 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)); + $field_collection_item->setHostEntity($entity->feeds_item->entity_type, $entity); + } + + $sub_mapping = array(); + $config = $source->importer()->getConfig(); + if (!empty($config['processor']['config']['mappings'])) { + foreach ($config['processor']['config']['mappings'] as $mapping) { + if ($mapping['target'] == $target . ':' . $sub_target) { + $sub_mapping = $mapping; + $sub_mapping['target'] = $sub_target; + // Needs language or feeds mappers shout php notices. + $sub_mapping['language'] = $config['processor']['config']['language']; + break; + } + } + } + + if (isset($_sub_targets[$sub_target]['callback']) && function_exists($_sub_targets[$sub_target]['callback'])) { + $callback = $_sub_targets[$sub_target]['callback']; + + // Normalize + if (!is_array($value[$delta])) { + $value[$delta] = array($value[$delta]); + } + + // Check for a limit and force that limit. + if ($info["cardinality"] !== "-1") { + $value[$delta] = array_slice($value[$delta], 0, $info["cardinality"]); + } + + // HiJack the file callback so we can make it work. + if ($callback == "file_feeds_set_target") { + $callback = "stanford_feeds_helper_field_collection_file_feeds_set_target"; + } + + // Allow altering with many parameters. Cannot use drupal_alter here. + $implements = module_implements("sub_target_pre_callback_parse"); + foreach ($implements as $module_name) { + $hook = $module_name . "_" . "sub_target_pre_callback_parse"; + $hook($target, $sub_target, $entity, $field, $field_collection_item, $value[$delta]); + } + + $callback($source, $field_collection_item, $sub_target, $value[$delta], $sub_mapping); + } + + // No need to save the field collection here. Just wait until the node is saved. + // If we save the FC here we get a huge performance degregation. + $field['und'][$delta]['entity'] = $field_collection_item; + + // Break when only hitting the max delta. + if ($info['cardinality'] == $delta) { + break; + } + + $delta++; + } + + } + catch (Exception $e) { + drupal_set_message($e->getMessage(), 'error'); + watchdog_exception('field_collection', $e, $e->getMessage()); + throw $e; + } + + $entity->{$target} = $field; +}