references.feeds.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. <?php
  2. /**
  3. * @file
  4. * Mapper that handles any fields added by the References module (node_reference, user_reference)
  5. *
  6. * Code is effectively a port of the mapper_for_nodereference_field patch to drupal 7, and borrows
  7. * heavily from the nodereference patch
  8. *
  9. */
  10. /**
  11. * Implements hook_feeds_parser_sources_alter().
  12. */
  13. function node_reference_feeds_parser_sources_alter(&$sources, $content_type) {
  14. if (!empty($content_type)) {
  15. $fields = field_info_fields();
  16. foreach ($fields as $field) {
  17. if ($field['type'] == 'node_reference' && isset($field['bundles']['node']) && in_array($content_type, $field['bundles']['node'])) {
  18. $sources['parent:node_reference:'. $field['field_name']] = array(
  19. 'name' => t('Feed node: Node Reference (nid): @field_name', array('@field_name' => $field['field_name'])),
  20. 'description' => t('Node References from the parent feed node.'),
  21. 'callback' => 'node_reference_feeds_get_source',
  22. );
  23. }
  24. }
  25. }
  26. return $sources;
  27. }
  28. /**
  29. * Callback for mapping parent node references to child node reference values.
  30. *
  31. * @param $source
  32. * A FeedsSource object.
  33. * @param $result
  34. * FeedsParserResult object.
  35. * @param $key
  36. * The key as defined in the _feeds_parser_sources_alter() hook defined above.
  37. * @return array
  38. * The node ids that the parent node references.
  39. */
  40. function node_reference_feeds_get_source(FeedsSource $source, FeedsParserResult $result, $key) {
  41. if ($node = node_load($source->feed_nid)) {
  42. $results = array();
  43. $field = substr($key, 22);
  44. if (!empty($node->{$field}['und'])) {
  45. foreach ($node->{$field}['und'] as $delta => $value) {
  46. $results[] = $value['nid'];
  47. }
  48. }
  49. return $results;
  50. }
  51. }
  52. /**
  53. * Implements hook_feeds_processor_targets_alter() for node_reference fields
  54. *
  55. * @see FeedsNodeProcessor::getMappingTargets().
  56. */
  57. function node_reference_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
  58. foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
  59. $info = field_info_field($name);
  60. if ($info['type'] == 'node_reference') {
  61. $targets[$name . ':title'] = array(
  62. 'name' => $instance['label'] . t(' (Node reference by node title)'),
  63. 'callback' => 'references_feeds_set_target',
  64. 'description' => t('The @label field of the node matched by node title.', array('@label' => $instance['label'])),
  65. 'real_target' => $name);
  66. $targets[$name . ':nid'] = array(
  67. 'name' => $instance['label'] . t(' (Node reference by node ID)'),
  68. 'callback' => 'references_feeds_set_target',
  69. 'description' => t('The @label field of the node matched by node ID.', array('@label' => $instance['label'])),
  70. 'real_target' => $name);
  71. $targets[$name . ':url'] = array(
  72. 'name' => $instance['label'] . t(' (Node reference by Feeds URL)'),
  73. 'callback' => 'references_feeds_set_target',
  74. 'description' => t('The @label field of the node matched by Feeds URL.', array('@label' => $instance['label'])),
  75. 'real_target' => $name);
  76. $targets[$name . ':guid'] = array(
  77. 'name' => $instance['label'] . t(' (Node reference by Feeds GUID)'),
  78. 'callback' => 'references_feeds_set_target',
  79. 'description' => t('The @label field of the node matched by Feeds GUID.', array('@label' => $instance['label'])),
  80. 'real_target' => $name);
  81. $targets[$name . ':title:duplicates'] = array(
  82. 'name' => $instance['label'] . t(' (Node reference by node title) -- allow duplicate nodes'),
  83. 'callback' => 'references_feeds_set_target',
  84. 'description' => t('The @label field of the node matched by node title. This target allows duplicate nodes (nodes can appear more than once in a field).', array('@label' => $instance['label'])),
  85. 'real_target' => $name);
  86. $targets[$name . ':nid:duplicates'] = array(
  87. 'name' => $instance['label'] . t(' (Node reference by node ID) -- allow duplicate nodes'),
  88. 'callback' => 'references_feeds_set_target',
  89. 'description' => t('The @label field of the node matched by node ID. This target allows duplicate nodes (nodes can appear more than once in a field).', array('@label' => $instance['label'])),
  90. 'real_target' => $name);
  91. $targets[$name . ':url:duplicates'] = array(
  92. 'name' => $instance['label'] . t(' (Node reference by Feeds URL) -- allow duplicate nodes'),
  93. 'callback' => 'references_feeds_set_target',
  94. 'description' => t('The @label field of the node matched by Feeds URL.', array('@label' => $instance['label'])),
  95. 'real_target' => $name);
  96. $targets[$name . ':guid:duplicates'] = array(
  97. 'name' => $instance['label'] . t(' (Node reference by Feeds GUID) -- allow duplicate nodes'),
  98. 'callback' => 'references_feeds_set_target',
  99. 'description' => t('The @label field of the node matched by Feeds GUID.', array('@label' => $instance['label'])),
  100. 'real_target' => $name);
  101. }
  102. }
  103. }
  104. /**
  105. * Implements hook_feeds_processor_targets_alter() for user_reference fields
  106. *
  107. * @see FeedsNodeProcessor::getMappingTargets().
  108. *
  109. */
  110. function user_reference_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
  111. foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
  112. $info = field_info_field($name);
  113. if ($info['type'] == 'user_reference') {
  114. $targets[$name . ':name'] = array(
  115. 'name' => $instance['label'] . t(' (User reference by user name)'),
  116. 'callback' => 'references_feeds_set_target',
  117. 'description' => t('The @label field of the user matched by user name. ', array('@label' => $instance['label'])),
  118. 'real_target' => $name);
  119. $targets[$name . ':uid'] = array(
  120. 'name' => $instance['label'] . t(' (User reference by user ID)'),
  121. 'callback' => 'references_feeds_set_target',
  122. 'description' => t('The @label field of the user matched by user ID.', array('@label' => $instance['label'])),
  123. 'real_target' => $name);
  124. $targets[$name . ':url'] = array(
  125. 'name' => $instance['label'] . t(' (User reference by Feeds URL)'),
  126. 'callback' => 'references_feeds_set_target',
  127. 'description' => t('The @label field of the node matched by Feeds URL.', array('@label' => $instance['label'])),
  128. 'real_target' => $name);
  129. $targets[$name . ':guid'] = array(
  130. 'name' => $instance['label'] . t(' (User reference by Feeds GUID)'),
  131. 'callback' => 'references_feeds_set_target',
  132. 'description' => t('The @label field of the node matched by Feeds GUID.', array('@label' => $instance['label'])),
  133. 'real_target' => $name);
  134. $targets[$name . ':name:duplicates'] = array(
  135. 'name' => $instance['label'] . t(' (User reference by user name) -- allow duplicate users'),
  136. 'callback' => 'references_feeds_set_target',
  137. 'description' => t('The @label field of the user matched by user name. This target allows duplicate users (users can appear more than once in a field).', array('@label' => $instance['label'])),
  138. 'real_target' => $name);
  139. $targets[$name . ':uid:duplicates'] = array(
  140. 'name' => $instance['label'] . t(' (User reference by user ID) -- allow duplicate users'),
  141. 'callback' => 'references_feeds_set_target',
  142. 'description' => t('The @label field of the user matched by user ID. This target allows duplicate users (users can appear more than once in a field).', array('@label' => $instance['label'])),
  143. 'real_target' => $name);
  144. $targets[$name . ':url:duplicates'] = array(
  145. 'name' => $instance['label'] . t(' (User reference by Feeds URL) -- allow duplicate users'),
  146. 'callback' => 'references_feeds_set_target',
  147. 'description' => t('The @label field of the node matched by Feeds URL.', array('@label' => $instance['label'])),
  148. 'real_target' => $name);
  149. $targets[$name . ':guid:duplicates'] = array(
  150. 'name' => $instance['label'] . t(' (User reference by Feeds GUID) -- allow duplicate users'),
  151. 'callback' => 'references_feeds_set_target',
  152. 'description' => t('The @label field of the node matched by Feeds GUID.', array('@label' => $instance['label'])),
  153. 'real_target' => $name);
  154. }
  155. }
  156. }
  157. /**
  158. * Callback for mapping both node reference and user_reference fields
  159. *
  160. * Implementation of hook_feeds_set_target().
  161. *
  162. * @param $source
  163. * A FeedsSource object.
  164. * @param $entity
  165. * The entity to map to.
  166. * @param $target
  167. * The target key on $entity to map to.
  168. * @param $value
  169. * The value to map. Can be an array or a string.
  170. */
  171. function references_feeds_set_target($source, $entity, $target, $value) {
  172. if (empty($value) || empty($value[key($value)])) {
  173. return;
  174. }
  175. // Handle comma delimited or non-multiple values.
  176. if (!is_array($value)) {
  177. $value = array($value);
  178. }
  179. // Determine the field we are matching against, and whether duplicates are allowed.
  180. $target_info = explode(':', $target, 3);
  181. if (sizeof($target_info) == 3) {
  182. list($target, $match_key, $duplicates) = $target_info;
  183. }
  184. else {
  185. list($target, $match_key) = $target_info;
  186. }
  187. // Load field definition.
  188. $info = field_info_field($target);
  189. // Parameters to handle differences between node references and user references
  190. if ($info['type'] == 'user_reference') {
  191. $idname = 'uid';
  192. $typename = 'user';
  193. $validate_function = 'user_reference_potential_references';
  194. }
  195. else {
  196. $idname = 'nid';
  197. $typename = 'node';
  198. $validate_function = 'node_reference_potential_references';
  199. }
  200. $field = isset($entity->$target) ? $entity->$target : array();
  201. if (!isset($field['und'])) {
  202. $field['und'] = array();
  203. }
  204. // Match values against nodes and add to field.
  205. foreach ($value as $v) {
  206. // Create options.
  207. $options = array(
  208. 'string' => $v,
  209. 'match' => 'equals',
  210. 'ids' => array(),
  211. 'limit' => 1,
  212. );
  213. switch ($match_key) {
  214. case 'title':
  215. case 'name':
  216. // Validate node title or user name.
  217. if ((is_string($options['string']) && $options['string'] != '') || is_numeric($options['string'])) {
  218. // Lookup potential exact matches for the value (limit to one result).
  219. $matches = $validate_function($info,$options);
  220. // Use the first element of the potential matches.
  221. $options['ids']= key($matches);
  222. }
  223. // Alert if no match is found.
  224. if (empty($options['ids'])) {
  225. drupal_set_message(t('%title does not match an existing '.$typename, array('%title' => $options['string'])));
  226. }
  227. break;
  228. case 'nid':
  229. case 'uid':
  230. // Make sure it is a positive integer.
  231. if ((is_int($options['string']) || ctype_digit($options['string'])) && $options['string'] > 0 && $options['string'] !== '') {
  232. // Make sure it is a valid node id or user id for this field.
  233. $matches = $validate_function($info, array($options['string']));
  234. foreach ($matches as $k => $v) {
  235. if ($options['string'] == $k) {
  236. $options['ids'] = $k;
  237. }
  238. }
  239. }
  240. // Alert if no match is found.
  241. if (empty($options['ids'])) {
  242. drupal_set_message(t('%id is not a valid '.$typename.' id for this field.', array('%id' => $options['string'])));
  243. }
  244. break;
  245. case 'guid':
  246. case 'url':
  247. // get the value from table feeds-item.
  248. $result = db_query('SELECT f.entity_id FROM {feeds_item} f WHERE f.'.$match_key.' = :v', array( ':v' => $v) );
  249. $options['ids'] = $result->fetchField();
  250. // Alert if no match is found.
  251. if (empty($options['ids'])) {
  252. drupal_set_message(t('%id is not a valid '.$typename.' id for this field.', array('%id' => $v)));
  253. }
  254. break;
  255. }
  256. if (!empty($options['ids'])) {
  257. $reference = array($idname => $options['ids']);
  258. if (!empty($duplicates)) {
  259. // Add the reference, ignoring duplicates.
  260. $field['und'][] = $reference;
  261. }
  262. else if (!in_array($reference, $field['und'])) {
  263. // Add the reference only if it doesn't already exist.
  264. $field['und'][] = $reference;
  265. }
  266. if ($info['cardinality'] == 1) {
  267. break;
  268. }
  269. }
  270. }
  271. $entity->{$target} = $field;
  272. }