Commit ead60264 authored by mstenta's avatar mstenta Committed by Ra Mänd
Browse files

Issue #1063434 by sherakama, majorrobot, paulihuhtiniemi, btopro, GaëlG,...

Issue #1063434 by sherakama, majorrobot, paulihuhtiniemi, btopro, GaëlG, veronicaSeveryn, Novitsh, xcf33, arvinsingla, bbdata, David_Rothstein, queenvictoria, m.stenta, arh1, iajay, dpfitzsi, k_zoltan, franz.glauber, humansky, aaronbauman, John Bickar, sir_squall, praandy, junaidpv, lachezar.valchev, alisonjo2786, jrao, Xearwe: Add Feeds integration to FieldCollection
parent 1025fb18
......@@ -1949,3 +1949,288 @@ 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 {
// $delta = which FC instance.
// We iterate by subfield, not by FC.
while (isset($value[$delta])) {
// Zero out.
$field_collection_item = null;
// FC is already set on host entity.
if (isset($field['und'][$delta]['entity'])) {
$field_collection_item = $field['und'][$delta]['entity'];
}
// FC is on host entity, we have FC item_id, but FC is not loaded.
elseif (isset($field['und'][$delta]['value'])) {
$field_collection_item = field_collection_item_load($field['und'][$delta]['value']);
// Zero out field so that we don't just keep accumulating values.
unset($field_collection_item->{$sub_target}['und'] );
}
// Host entity does not have any attached FCs yet.
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'] = !empty($config['processor']['config']['language']) ? $config['processor']['config']['language'] : LANGUAGE_NONE;
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 = "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;
}
/**
* Wrapper function for file_feeds_set_target as it doesn't do the nested stuff.
*/
function field_collection_file_feeds_set_target($source, $entity, $target, $value) {
if (empty($value)) {
return;
}
module_load_include('inc', 'file');
// Make sure $value is an array of objects of type FeedsEnclosure.
if (!is_array($value)) {
$value = array($value);
}
foreach ($value as $k => $v) {
if (!($v instanceof FeedsEnclosure)) {
if (is_string($v)) {
$value[$k] = new FeedsEnclosure($v, file_get_mimetype($v));
}
else {
unset($value[$k]);
}
}
}
if (empty($value)) {
return;
}
$entity_type = "field_collection_item";
$bundle = $entity->field_name;
// Determine file destination.
// @todo This needs review and debugging.
$instance_info = field_info_instance($entity_type, $target, $bundle);
$info = field_info_field($target);
$data = array();
if (!empty($entity->uid)) {
$data[$entity_type] = $entity;
}
$destination = file_field_widget_uri($info, $instance_info, $data);
// Populate entity.
$i = 0;
$field = isset($entity->$target) ? $entity->$target : array();
foreach ($value as $v) {
$file = FALSE;
try {
$v->setAllowedExtensions($instance_info['settings']['file_extensions']);
$file = $v->getFile($destination);
}
catch (Exception $e) {
watchdog('feeds', check_plain($e->getMessage()));
}
if ($file) {
$field['und'][$i] = (array)$file;
$field['und'][$i]['display'] = 1; // @todo: Figure out how to properly populate this field.
if ($info['cardinality'] == 1) {
break;
}
$i++;
}
}
$entity->{$target} = $field;
}
/**
* Implementation of hook_feeds_presave().
* Invoked before a feed item is saved.
*
* @param FeedsSource $source
* FeedsSource object that describes the source that is being imported.
* @param $entity
* The entity object.
* @param array $item
* The parser result for this entity.
* @param int|null $entity_id
* The id of the current item which is going to be updated. If this is a new
* item, then NULL is passed.
*/
function field_collection_feeds_presave(FeedsSource $source, $entity, $item, $entity_id) {
$mappings = $source->importer()->getConfig()['processor']['config']['mappings'];
// Only hook in when updating the entity.
if (empty($entity_id)) {
// Go through $mappings and find the FC fields.
foreach ($mappings as $mapping) {
if (strpos($mapping['target'], ':') !== FALSE) {
$parts = explode(':', $mapping['target']);
$fc_name = array_shift($parts);
$info = field_info_field($fc_name);
// If the field is not a field collection, skip it.
if ($info['type'] != 'field_collection') {
continue;
}
if (isset($entity->{$fc_name})) {
foreach ($entity->{$fc_name}['und'] as $delta => $fc_unloaded) {
// If an FC is not loaded, we don't want it. Unset it so it won't save.
if (!isset($entity->{$fc_name}['und'][$delta]['entity'])) {
unset($entity->{$fc_name}['und'][$delta]);
}
}
}
}
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment