cer.module 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. <?php
  2. /**
  3. * @file
  4. * Main module file.
  5. */
  6. /**
  7. * Implements hook_menu().
  8. */
  9. function cer_menu() {
  10. $items = array();
  11. $items['admin/config/system/cer'] = array(
  12. 'title' => 'Corresponding entity references',
  13. 'page callback' => 'drupal_get_form',
  14. 'page arguments' => array('cer_settings_form'),
  15. 'access arguments' => array('administer cer settings'),
  16. 'file' => 'cer.admin.inc',
  17. 'type' => MENU_NORMAL_ITEM,
  18. );
  19. $items['admin/config/system/cer/references'] = array(
  20. 'title' => 'References',
  21. 'page callback' => 'drupal_get_form',
  22. 'page arguments' => array('cer_settings_form'),
  23. 'access arguments' => array('administer cer settings'),
  24. 'file' => 'cer.admin.inc',
  25. 'type' => MENU_DEFAULT_LOCAL_TASK,
  26. );
  27. $items['admin/config/system/cer/update'] = array(
  28. 'title' => 'Update existing entities',
  29. 'page callback' => 'drupal_get_form',
  30. 'page arguments' => array('cer_update_form'),
  31. 'access arguments' => array('administer cer settings'),
  32. 'file' => 'cer.admin.inc',
  33. 'type' => MENU_LOCAL_TASK,
  34. );
  35. return $items;
  36. }
  37. /**
  38. * Implements hook_permission().
  39. */
  40. function cer_permission() {
  41. return array(
  42. 'administer cer settings' => array(
  43. 'title' => t('Administer corresponding entity reference settings'),
  44. )
  45. );
  46. }
  47. /**
  48. * Implements hook_help().
  49. */
  50. function cer_help($path, $arg) {
  51. $output = '';
  52. if ($path == 'admin/config/system/cer') {
  53. $output .= t('Check which entity references should listen to each other. When checking a check box a reference on entity type A to entity B will automatically update the entity reference field on entity B adding an entry which points to entity A.');
  54. }
  55. elseif ($path == 'admin/config/system/cer/update') {
  56. $output .= t('This will update all the existing entities for the selected content types so that their entity reference fields are in sync.');
  57. $output .= '<br />';
  58. $output .= t('This process may take a long time depending on the number of entities you are updating.');
  59. $output .= '<br /><br />';
  60. $output .= t('When the process is finished you will see a count of the number of entities that were updated.');
  61. }
  62. return $output;
  63. }
  64. /**
  65. * Implements hook_field_delete_instance().
  66. */
  67. function cer_field_delete_instance($instance) {
  68. foreach (cer_preset_load_enabled() as $row) {
  69. $keys = explode('*', $row->entity_types_content_fields);
  70. if (($keys[0] == $instance['entity_type'] && $keys[1] == $instance['bundle'] && $keys[2] == $instance['field_name']) || ($keys[3] == $instance['entity_type'] && $keys[4] == $instance['bundle'] && $keys[5] == $instance['field_name'])) {
  71. cer_preset_delete($row->entity_types_content_fields);
  72. }
  73. }
  74. }
  75. /**
  76. * Implements hook_field_delete_field().
  77. */
  78. function cer_field_delete_field($field) {
  79. foreach (cer_preset_load_enabled() as $row) {
  80. $keys = explode('*', $row->entity_types_content_fields);
  81. if ($keys[2] == $field['field_name'] || $keys[5] == $field['field_name']) {
  82. cer_preset_delete($row->entity_types_content_fields);
  83. }
  84. }
  85. }
  86. /**
  87. * Implements hook_theme().
  88. */
  89. function cer_theme() {
  90. return array(
  91. 'cer_label' => array(
  92. 'variables' => array('key' => ''),
  93. ),
  94. );
  95. }
  96. function theme_cer_label($variables) {
  97. $key = explode(' ', $variables['key']);
  98. $local = field_info_instance($key[0], $key[2], $key[1]);
  99. $remote = field_info_instance($key[3], $key[5], $key[4]);
  100. $message = 'Correspond <span title="!local_field">%local_label</span> on !local_entity(s) of type %local_bundle with <span title="!remote_field">%remote_label</span> on !remote_entity(s) of type %remote_bundle.';
  101. $variables = array(
  102. '%local_label' => $local['label'],
  103. '!local_field' => $local['field_name'],
  104. '!local_entity' => $local['entity_type'],
  105. '%local_bundle' => $local['bundle'],
  106. '%remote_label' => $remote['label'],
  107. '!remote_field' => $remote['field_name'],
  108. '!remote_entity' => $remote['entity_type'],
  109. '%remote_bundle' => $remote['bundle'],
  110. );
  111. return t($message, $variables);
  112. }
  113. /**
  114. * Implements hook_entity_insert().
  115. */
  116. function cer_entity_insert($entity, $type) {
  117. cer_processing_entity('insert', $entity, $type);
  118. }
  119. /**
  120. * Implements hook_entity_update().
  121. */
  122. function cer_entity_update($entity, $type) {
  123. cer_processing_entity('update', $entity, $type);
  124. }
  125. /**
  126. * Implements hook_entity_delete().
  127. */
  128. function cer_entity_delete($entity, $type) {
  129. cer_processing_entity('delete', $entity, $type);
  130. }
  131. /**
  132. * Load enabled CER presets.
  133. */
  134. function cer_preset_load_enabled() {
  135. ctools_include('export');
  136. return ctools_export_load_object('cer', 'conditions', array('enabled' => 1));
  137. }
  138. /**
  139. * Return CER preset by key.
  140. */
  141. function cer_preset_load($key) {
  142. ctools_include('export');
  143. return ctools_export_crud_load('cer', $key);
  144. }
  145. /**
  146. * Return 1 if CER preset specified by given key is enabled.
  147. */
  148. function cer_preset_enabled($key) {
  149. $preset = cer_preset_load($key);
  150. return empty($preset) ? 0 : $preset->enabled;
  151. }
  152. /**
  153. * Deletes or disables a given CER preset.
  154. */
  155. function cer_preset_delete($key) {
  156. ctools_include('export');
  157. ctools_export_crud_delete('cer', $key);
  158. ctools_export_crud_disable('cer', $key);
  159. ctools_export_load_object_reset('cer');
  160. }
  161. /**
  162. * Process a entity's corresponding entity references.
  163. *
  164. * @param string $op
  165. * The operation being performed on the entity (insert, update, or delete).
  166. *
  167. * @param object $entity
  168. * The entity or the entity's id.
  169. *
  170. * @param string $entity_type
  171. * The entity type.
  172. *
  173. * @param array $context
  174. * Either the Batch API context (since this is the callback function used
  175. * during bulk update) or NULL if we're not in a batch job.
  176. */
  177. function cer_processing_entity($op, $entity, $entity_type, &$context = NULL) {
  178. // Load the entity if we're given an ID rather than an entity.
  179. if (!is_object($entity)) {
  180. $entity = entity_load($entity_type, array($entity));
  181. $entity = reset($entity);
  182. }
  183. // If the entity is of the wrong type, entity_extract_IDs() will throw
  184. // EntityMalformedException and rightfully bail out here.
  185. list (, , $bundle) = entity_extract_IDs($entity_type, $entity);
  186. $result = cer_preset_load_enabled();
  187. foreach ($result as $row) {
  188. $keys = explode('*', $row->entity_types_content_fields);
  189. if ($keys[0] == $entity_type && $keys[1] == $bundle) {
  190. try {
  191. $handler = new CerHandler($row->entity_types_content_fields, $entity);
  192. call_user_func(array($handler, $op));
  193. }
  194. catch (CerException $e) {
  195. if (isset($context)) {
  196. $context['results']['errors'][] = $e;
  197. }
  198. else {
  199. throw $e;
  200. }
  201. }
  202. }
  203. if ($keys[3] == $entity_type && $keys[4] == $bundle) {
  204. $preset = implode('*', array($keys[3], $keys[4], $keys[5], $keys[0], $keys[1], $keys[2]));
  205. try {
  206. $handler = new CerHandler($preset, $entity);
  207. call_user_func(array($handler, $op));
  208. }
  209. catch (CerException $e) {
  210. if (isset($context)) {
  211. $context['results']['errors'][] = $e;
  212. }
  213. else {
  214. throw $e;
  215. }
  216. }
  217. }
  218. }
  219. if (isset($context)) {
  220. $context['results']['count']++;
  221. }
  222. }
  223. /**
  224. * Batch 'finished' callback.
  225. */
  226. function cer_batch_update_existing_finished($success, $results, $operations) {
  227. if ($success) {
  228. $message = format_plural($results['count'], '1 entity processed.', '@count entities processed.');
  229. if (isset($results['errors'])) {
  230. $type = 'warning';
  231. foreach ($results['errors'] as $e) {
  232. drupal_set_message($e->getMessage(), 'error');
  233. }
  234. }
  235. else {
  236. $type = 'status';
  237. }
  238. drupal_set_message($message, $type);
  239. }
  240. else {
  241. // An error occurred. $operations contains the operations that remained unprocessed.
  242. $error_operation = reset($operations);
  243. $message = 'An error occurred while processing ' . $error_operation[0] . ' with arguments:' . print_r($error_operation[0], TRUE);
  244. drupal_set_message($message, 'error');
  245. }
  246. }
  247. /**
  248. * Implements hook_ctools_plugin_api().
  249. */
  250. function cer_ctools_plugin_api($owner, $api) {
  251. if ($owner == 'cer' && $api == 'default_cer_presets') {
  252. return array('version' => 1);
  253. }
  254. }
  255. /**
  256. * Update field data.
  257. *
  258. * @param $node the referenced node to be updated.
  259. */
  260. function _cer_update($entity_type, $entity) {
  261. $entity->original = isset($entity->original) ? $entity->original : NULL;
  262. $extract_ids = entity_extract_IDs($entity_type, $entity);
  263. $id = array_shift($extract_ids);
  264. field_attach_presave($entity_type, $entity);
  265. field_attach_update($entity_type, $entity);
  266. // Issue #2212499.
  267. if ($entity_type == 'node') {
  268. $entity->changed = time();
  269. db_update('node')
  270. ->fields(array(
  271. 'changed' => $entity->changed,
  272. ))
  273. ->condition('nid', $id)
  274. ->execute();
  275. }
  276. entity_get_controller($entity_type)->resetCache(array($id));
  277. }