references.feeds.inc 13 KB

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