entityreference_feeds.module in Entity reference feeds 7
This is the main module file for entity reference feeds.
File
entityreference_feeds.moduleView source
<?php
/**
* @file
* This is the main module file for entity reference feeds.
*/
function _entityreference_feeds_get_targets($field_name, $target_type, $target_bundle) {
$targets_cache =& drupal_static('entityreference_feeds_feeds_processor_targets', array());
$entity_info = entity_get_info($target_type);
if (!isset($targets_cache[$field_name][$target_type][$target_bundle])) {
$info = array(
'bundle' => $target_bundle,
);
$_targets = array();
$target_key = $field_name . ':' . $target_bundle;
$wrapper = entity_metadata_wrapper($target_type, NULL, $info);
// @todo: maybe restrict to data types feeds can deal with.
foreach ($wrapper
->getPropertyInfo() as $name => $property_info) {
/* We leave fields to feeds mappers in accordance with the principle of
least astonishment. They are also more forgiving and "robust" in some
cases, for file/image-fields for example. Node targets for properties
like "title" etc are inaccessable to us as they are found in the
node-processor. Besides, using entity-api for this is a much more
generic approach and will work for more entity-types than just node
*/
if (!isset($property_info['field']) || !$property_info['field']) {
if (!empty($property_info['setter callback'])) {
$_targets[$target_key . ':entityreference_feeds:' . $name] = array(
'name' => t('@field_name (@bundle: @target)', array(
'@field_name' => $field_name,
'@target' => $property_info['label'],
'@bundle' => $target_bundle,
)),
'description' => isset($property['description']) ? t('@field_name: @target in @type type @bundle', array(
'@field_name' => $field_name,
'@target' => $property_info['label'],
'@type' => $target_type,
'@bundle' => $target_bundle,
)) : NULL,
'callback' => 'entityreference_feeds_feeds_set_target',
);
}
}
}
// Add general GUID target.
$_targets[$target_key . ':entityreference_feeds:guid'] = array(
'name' => t('@field_name (@bundle: @target)', array(
'@field_name' => $field_name,
'@target' => t('GUID'),
'@bundle' => $target_bundle,
)),
'description' => t('The globally unique identifier of the item. E. g. the feed item GUID in the case of a syndication feed.'),
//'real_target' => $field_name,
//'optional_unique' => FALSE, //@todo set this to false?
'callback' => 'entityreference_feeds_feeds_set_target',
);
// @todo: this is ugly as hell, but needed because of limitations of
// drupal_alter (taking a maximum of 3 parameters). Should do the job
// though, hopefully with no side-effects
$entity_targets = array(
'entityreference_feeds_processed' => array(),
);
// Let other modules expose mapping targets.
$entity_targets += module_invoke_all('feeds_processor_targets', $target_type, $target_bundle);
drupal_alter('feeds_processor_targets', $entity_targets, $target_type, $target_bundle);
foreach ($entity_targets as $target_target => $entity_target) {
if (isset($entity_target['name'])) {
$entity_target['name'] = t('@field_name (@bundle: @target)', array(
'@field_name' => $field_name,
'@target' => $target_target,
'@bundle' => $target_bundle,
));
}
if (isset($entity_target['description'])) {
$entity_target['description'] = t('@field_name: @target in @type type @bundle', array(
'@field_name' => $field_name,
'@target' => $target_target,
'@type' => $target_type,
'@bundle' => $target_bundle,
));
}
$callback = isset($entity_target['callback']) ? $entity_target['callback'] : 'entityreference_feeds';
$entity_target['callback'] = 'entityreference_feeds_feeds_set_target';
$_targets[$target_key . ':' . $callback . ':' . $target_target] = $entity_target;
}
if (!isset($targets_cache[$field_name])) {
$targets_cache[$field_name] = array();
}
if (!isset($targets_cache[$field_name][$target_type])) {
$targets_cache[$field_name][$target_type] = array();
}
$targets_cache[$field_name][$target_type][$target_bundle] = $_targets;
}
return $targets_cache[$field_name][$target_type][$target_bundle];
}
/**
* Implements hook_feeds_processor_targets_alter().
*
* @see FeedsNodeProcessor::getMappingTargets()
*/
function entityreference_feeds_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
// Prevent infinite function call cycle.
if (isset($targets['entityreference_feeds_processed'])) {
unset($targets['entityreference_feeds_processed']);
return;
}
foreach (field_info_instances($entity_type, $bundle_name) as $field_name => $field_instance) {
$info = field_info_field($field_name);
if ($info['type'] == 'entityreference') {
$target_type = $info['settings']['target_type'];
$target_bundles = $info['settings']['handler_settings']['target_bundles'];
foreach ($target_bundles as $target_bundle) {
$targets += _entityreference_feeds_get_targets($field_name, $target_type, $target_bundle);
}
}
}
}
function entityreference_feeds_processor_mapped_targets($id) {
$static_cache =& drupal_static(__FUNCTION__, array());
if (isset($static_cache[$id])) {
return $static_cache[$id];
}
else {
$static_cache[$id] = array();
}
$importer = feeds_importer($id);
$mappings = $importer->processor
->getMappings();
foreach ($mappings as $mapping) {
$static_cache[$id][] = $mapping['target'];
}
return $static_cache[$id];
}
/**
* Callback for mapping.
*
* @param FeedsSource $source
* A FeedsSource object.
* @param Entity $entity
* The entity to map to.
* @param string $target
* The target key on $entity to map to.
* @param array $value
* The value to map. Should be an array.
*/
function entityreference_feeds_feeds_set_target($source, $entity, $target, $value, $mapping) {
$entity->entityreference_feeds_source_id = $source->id;
//$entity->entityreference_feeds_source_feed_nid = $source->feed_nid;
// Assume that the passed in value could really be any number of values.
if (is_array($value)) {
$values = $value;
}
else {
$values = array(
$value,
);
}
list($field_name, $target_bundle, $target_callback, $target_target) = explode(':', $target, 4);
// Get some useful field information.
$field_info = field_info_field($field_name);
$target_type = $field_info['settings']['target_type'];
if (!isset($entity->entityreference_feeds_items)) {
$entity->entityreference_feeds_items = array();
}
if (!isset($entity->entityreference_feeds_items[$field_name])) {
$entity->entityreference_feeds_items[$field_name] = array();
}
if (!isset($entity->entityreference_feeds_items[$field_name][$target_bundle])) {
$entity->entityreference_feeds_items[$field_name][$target_bundle] = array();
}
$bundle_items =& $entity->entityreference_feeds_items[$field_name][$target_bundle];
foreach ($values as $delta => $target_value) {
if (!isset($bundle_items[$delta])) {
$target_entity_info = entity_get_info($target_type);
$target_entity = new stdClass();
if (!empty($target_entity_info['entity keys']['bundle'])) {
$target_entity->{$target_entity_info['entity keys']['bundle']} = $target_bundle;
}
$bundle_items[$delta]['target_entity'] = $target_entity;
$bundle_items[$delta]['creation_values'] = array();
}
else {
$target_entity =& $bundle_items[$delta]['target_entity'];
}
if (!isset($target_entity->feeds_item)) {
entityreference_feeds_newItemInfo($target_entity, $target_type, $source->id, $source->feed_nid);
}
if ($target_callback !== 'entityreference_feeds' && function_exists($target_callback)) {
//$real_target = isset($targets[$target]['real_target']) ? $targets[$target]['real_target'] : $target_target;
//$bundle_items[$delta]['real_targets'][$real_target] = $real_target;
//Note: Most feed mappers, at least the ones in Feeds > 7.x-2.0-alpha8, assume target value is an array
$target_callback($source, $target_entity, $target_target, array(
$target_value,
), $mapping);
}
else {
switch ($target_target) {
case 'url':
case 'guid':
$target_entity->feeds_item->{$target_target} = $target_value;
break;
default:
$bundle_items[$delta]['creation_values'][$target_target] = $target_value;
break;
}
}
}
}
/**
* Helper function for creating entityreference_feeds entities.
*
* @param string $entity_type
* The entity type of the entity to be created.
* @param string $bundle
* (optional) Name of the bundle of the entity to be created.
* @param array $values
* (optional) An array of values as described by the entity's property info. All entity
* properties of the given entity type that are marked as required, must be
* present.
* If the passed values have no matching property, their value will be
* assigned to the entity directly, without the use of the metadata-wrapper
* property.
*
* @return Entity
* The created entity or FALSE if the entity could not be created.
*/
function _entityreference_feeds_create_entity($entity_type, $bundle = FALSE, $values = array()) {
static $vocabularies = array();
$info = entity_get_info($entity_type);
$default_values = variable_get('entityreference_feeds_entity_default_values', array());
$creation_values = $values + (isset($default_values[$entity_type]['values']) ? array_filter($default_values[$entity_type]['values']) : array());
if (!empty($info['entity keys']['bundle']) && $bundle) {
$creation_values += array(
$info['entity keys']['bundle'] => $bundle,
);
if ($entity_type === 'taxonomy_term') {
// For taxonomy term, add 'vid' property.
if (!isset($vocabularies[$bundle])) {
$vocabulary = taxonomy_vocabulary_machine_name_load($bundle);
$vocabularies[$bundle] = $vocabulary ? $vocabulary->vid : 0;
}
$creation_values['vid'] = $vocabularies[$bundle];
}
}
$entity_wrapper = entity_property_values_create_entity($entity_type, $creation_values);
return $entity_wrapper ? $entity_wrapper
->value() : FALSE;
}
// This function is from FeedsProcessor.inc.
/**
* Adds Feeds specific information on $entity->feeds_item.
*
* @param Entity $entity
* The entity object to be populated with new item info.
* @param string $entity_type
* The type of the entity, for example 'node'.
* @param int $feed_nid
* (optional) The feed nid of the source that produces this entity.
* @param string $hash
* (optional) The fingerprint of the source item.
*/
//TODO: To use or not to use source_id and feed_nid?
function entityreference_feeds_newItemInfo($entity, $entity_type, $id, $feed_nid = 0, $hash = '') {
$entity->feeds_item = new stdClass();
$entity->feeds_item->entity_id = 0;
$entity->feeds_item->entity_type = $entity_type;
$entity->feeds_item->id = 'entityreference_feeds';
$entity->feeds_item->feed_nid = $feed_nid;
$entity->feeds_item->imported = REQUEST_TIME;
$entity->feeds_item->hash = $hash;
$entity->feeds_item->url = NULL;
$entity->feeds_item->guid = NULL;
}
/**
* Implements hook_entity_presave().
*/
function entityreference_feeds_entity_presave($entity, $type) {
// @todo: job queue integration for async batching?
static $property_info = array();
if (isset($entity->entityreference_feeds_items)) {
$mapped_targets = entityreference_feeds_processor_mapped_targets($entity->entityreference_feeds_source_id);
foreach ($entity->entityreference_feeds_items as $field_name => $target_bundles) {
// Get some useful field information.
$info = field_info_field($field_name);
$target_type = $info['settings']['target_type'];
$field = array();
foreach ($target_bundles as $target_bundle => $values) {
//Used for metadata retrieval only
if (!isset($property_info[$target_type][$target_bundle])) {
if (!isset($property_info[$target_type])) {
$property_info[$target_type] = array();
}
$metadata_wrapper = entity_metadata_wrapper($target_type, NULL, array(
'bundle' => $target_bundle,
));
$property_info[$target_type][$target_bundle] = $metadata_wrapper
->getPropertyInfo();
}
$targets = _entityreference_feeds_get_targets($field_name, $type, $target_bundle);
foreach ($values as $value) {
//TODO: This variable name is confusing! $partial_target_entity?
$item = $value['target_entity'];
// @todo load multiple?
// @todo support other unique fields?
// GUID is a requirement, else we will keep adding new entities on every update.
if (!empty($item->feeds_item->guid)) {
// Set aside feeds_item.
$feeds_item = $item->feeds_item;
unset($item->feeds_item);
// Fetch the entity ID resulting from the mapping table look-up.
// Clone query?
$entity_id = db_query('SELECT entity_id FROM {feeds_item} WHERE guid = :guid', array(
':guid' => $feeds_item->guid,
))
->fetchField();
// @todo try catch?
if ($entity_id) {
$target_entity = entity_load_single($target_type, $entity_id);
foreach ($mapped_targets as $target) {
if (isset($targets[$target])) {
$real_target = NULL;
if (isset($targets[$target]['real_target'])) {
//TODO: How is this used?
$real_target = $targets[$target]['real_target'];
}
else {
list($real_target) = explode(':', $target, 2);
}
if (isset($property_info[$target_type][$target_bundle][$real_target]) && isset($property_info[$target_type][$target_bundle][$real_target]['field']) && $property_info[$target_type][$target_bundle][$real_target]['field']) {
// is a field
$target_entity->{$real_target} = array(
'und' => array(),
);
}
else {
unset($target_entity->{$real_target});
}
}
}
$wrapper = entity_metadata_wrapper($target_type, $target_entity);
foreach ($value['creation_values'] as $target_element => $value) {
$wrapper->{$target_element}
->set($value);
}
}
else {
$target_entity = _entityreference_feeds_create_entity($target_type, $target_bundle, $value['creation_values']);
}
foreach (get_object_vars($item) as $target_element => $target_value) {
$target_entity->{$target_element} = $target_value;
}
entity_save($target_type, $target_entity);
list($entity_id) = entity_extract_ids($target_type, $target_entity);
// Restore and save feeds_item.
$target_entity->feeds_item = $feeds_item;
feeds_item_info_save($target_entity, $entity_id);
// Assign the target type and the target ID.
$field_item = array(
'target_type' => $target_type,
'target_id' => $entity_id,
);
// Set the language of the field depending on entity language.
$language = isset($item->language) ? $item->language : LANGUAGE_NONE;
if (!isset($field[$language])) {
$field[$language] = array();
}
$field[$language][] = $field_item;
}
}
}
$entity->{$field_name} = $field;
}
}
}
/**
* Implements hook_menu().
*/
function entityreference_feeds_menu() {
$items = array();
$items['admin/config/content/entityreference_feeds'] = array(
'page callback' => 'drupal_get_form',
'page arguments' => array(
'entityreference_feeds_settings_form',
),
'title' => 'Entityreference feeds',
'description' => 'Configure Entityreference feeds settings',
'access arguments' => array(
'administer site configuration',
),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
/**
* Settings form callback.
*/
function entityreference_feeds_settings_form() {
$info = entity_get_info();
$default_values = variable_get('entityreference_feeds_entity_default_values', array());
$form['entityreference_feeds_entity_default_values'] = array(
'#title' => t('Default values'),
'#type' => 'fieldset',
'#tree' => TRUE,
);
//TODO: check restrictions on which entities can be references in entity reference field to avoid including weird stuff like rules_config etc
foreach ($info as $entity_type => $entity_type_info) {
if (entity_type_supports($entity_type, 'create')) {
$wrapper = entity_metadata_wrapper($entity_type);
if (!is_object($wrapper)) {
continue;
}
$form['entityreference_feeds_entity_default_values'][$entity_type] = array(
'#title' => $entity_type,
'#type' => 'fieldset',
);
$entity_type_settings =& $form['entityreference_feeds_entity_default_values'][$entity_type];
global $user;
$formats = filter_formats($user);
foreach ($formats as $format) {
$format_options[$format->format] = check_plain($format->name);
}
$entity_type_settings['input_format'] = array(
'#type' => 'select',
'#title' => t('Text format'),
'#description' => t('Select the input format for the body field of the nodes to be created.'),
'#options' => $format_options,
'#default_value' => isset($default_values[$entity_type]['input_format']) ? $default_values[$entity_type]['input_format'] : 'plain_text',
);
$bundle_key = $entity_type_info['entity keys']['bundle'];
foreach ($wrapper
->getPropertyInfo() as $name => $property) {
if (!empty($property['required']) && $name != $bundle_key) {
$entity_type_settings['values'][$name] = array(
'#type' => 'textfield',
'#title' => $property['label'],
'#description' => isset($property['description']) ? $property['description'] : '',
'#default_value' => isset($default_values[$entity_type]['values'][$name]) ? $default_values[$entity_type]['values'][$name] : NULL,
);
if (!empty($property['options list'])) {
$entity_type_settings['values'][$name]['#type'] = 'select';
$entity_type_settings['values'][$name]['#options'] = $wrapper->{$name}
->optionsList();
}
// @todo: Maybe implement per data-type forms like Rules does?
$entity_type_settings['values'][$name]['#description'] .= ' ' . t('Expected data type: %type.', array(
'%type' => $wrapper->{$name}
->type(),
));
if ($wrapper->{$name} instanceof EntityDrupalWrapper) {
$info = $wrapper->{$name}
->entityInfo();
if (!empty($info) && isset($info['entity keys']['id'])) {
$id_info = $wrapper->{$name}
->get($info['entity keys']['id'])
->info();
$entity_type_settings['values'][$name]['#description'] .= ' ' . t('Just enter the identifier of the entity, i.e. %id', array(
'%id' => $id_info['label'],
));
}
}
}
}
}
}
return system_settings_form($form);
}
Functions
Name![]() |
Description |
---|---|
entityreference_feeds_entity_presave | Implements hook_entity_presave(). |
entityreference_feeds_feeds_processor_targets_alter | Implements hook_feeds_processor_targets_alter(). |
entityreference_feeds_feeds_set_target | Callback for mapping. |
entityreference_feeds_menu | Implements hook_menu(). |
entityreference_feeds_newItemInfo | |
entityreference_feeds_processor_mapped_targets | |
entityreference_feeds_settings_form | Settings form callback. |
_entityreference_feeds_create_entity | Helper function for creating entityreference_feeds entities. |
_entityreference_feeds_get_targets | @file This is the main module file for entity reference feeds. |