uuid.core.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. <?php
  2. /**
  3. * @file
  4. * Implementation of UUID hooks for all core modules.
  5. *
  6. * @todo
  7. * Replace all these hook implementations with a generic solution that uses
  8. * info from hook_entity_field_info() and hook_entity_property_info(). That
  9. * info should contain info about how UUIDs are mapped.
  10. */
  11. /**
  12. * @defgroup uuid_property Propery implementations
  13. * @{
  14. */
  15. /**
  16. * Implements hook_entity_uuid_load().
  17. */
  18. function node_entity_uuid_load(&$entities, $entity_type) {
  19. if ($entity_type == 'node') {
  20. entity_property_id_to_uuid($entities, 'user', array('uid', 'revision_uid'));
  21. entity_property_id_to_uuid($entities, 'node', 'tnid');
  22. }
  23. }
  24. /**
  25. * Implements hook_entity_uuid_presave().
  26. */
  27. function node_entity_uuid_presave(&$entity, $entity_type) {
  28. if ($entity_type == 'node') {
  29. entity_property_uuid_to_id($entity, 'user', array('uid', 'revision_uid'));
  30. entity_property_uuid_to_id($entity, 'node', 'tnid');
  31. // A node always must have an author.
  32. if (empty($entity->uid)) {
  33. global $user;
  34. $entity->uid = $user->uid;
  35. }
  36. }
  37. }
  38. /**
  39. * Implements hook_entity_uuid_save().
  40. */
  41. function node_entity_uuid_save(&$entity, $entity_type) {
  42. /*
  43. * When a node is translated, the source node's tnid is set to it's own nid.
  44. * When deploying the node for the first time the tnid can't be translated
  45. * to an nid until after the node has been saved. So if the entity's tnid
  46. * is still a uuid at this point it needs to be translated to an nid.
  47. */
  48. if ($entity_type == 'node' && uuid_is_valid($entity->tnid)) {
  49. entity_property_uuid_to_id($entity, 'node', 'tnid');
  50. db_update('node')
  51. ->fields(array('tnid' => $entity->tnid))
  52. ->condition('nid', $entity->nid)
  53. ->execute();
  54. }
  55. }
  56. /**
  57. * Implements hook_entity_uuid_load().
  58. */
  59. function book_uuid_entities_features_export_entity_alter(&$entity, $entity_type) {
  60. if ($entity_type == 'node') {
  61. if (!empty($entity->book)) {
  62. $entity->book['bid'] = current(entity_get_uuid_by_id($entity_type, array($entity->book['bid'])));
  63. }
  64. }
  65. }
  66. /**
  67. * Implements hook_entity_uuid_presave().
  68. */
  69. function book_entity_uuid_presave(&$entity, $entity_type) {
  70. if ($entity_type == 'node') {
  71. if (!empty($entity->book)) {
  72. $entity->book['bid'] = current(entity_get_id_by_uuid($entity_type, array($entity->book['bid'])));
  73. if (!$entity->book['bid']) {
  74. $entity->book['bid'] = 'new';
  75. }
  76. }
  77. }
  78. }
  79. /**
  80. * Implements hook_entity_uuid_presave().
  81. */
  82. function user_entity_uuid_presave(&$entity, $entity_type) {
  83. if ($entity_type != 'user') {
  84. return;
  85. }
  86. /*
  87. * We need to ensure new user's passwords are encrypted. The Services module
  88. * transparently encrypts the password for new users. md5() is used by
  89. * users who's accounts were migrated from Drupal 6 and who haven't updated
  90. * their password.
  91. */
  92. if (isset($entity->pass)
  93. && (!('$S$D' == substr($entity->pass, 0, 4)) || preg_match('/^[a-f0-9]{32}$/', $entity->pass))) {
  94. // Ensure user's password is hashed.
  95. $entity->pass = user_hash_password($entity->pass);
  96. }
  97. if (empty($entity->picture)) {
  98. return;
  99. }
  100. $uuids = entity_get_id_by_uuid('file', array($entity->picture['uuid']));
  101. $fid = current($uuids);
  102. if (!$entity->is_new) {
  103. $entity->picture = file_load($fid);
  104. }
  105. else {
  106. $entity->picture = $fid;
  107. }
  108. }
  109. /**
  110. * Implements hook_entity_uuid_load().
  111. */
  112. function comment_entity_uuid_load(&$entities, $entity_type) {
  113. switch ($entity_type) {
  114. case 'node':
  115. entity_property_id_to_uuid($entities, 'user', 'last_comment_uid');
  116. break;
  117. case 'comment':
  118. entity_property_id_to_uuid($entities, 'user', array('uid', 'u_uid'));
  119. entity_property_id_to_uuid($entities, 'node', 'nid');
  120. break;
  121. }
  122. }
  123. /**
  124. * Implements hook_entity_uuid_presave().
  125. */
  126. function comment_entity_uuid_presave(&$entity, $entity_type) {
  127. switch ($entity_type) {
  128. case 'node':
  129. entity_property_uuid_to_id($entity, 'user', 'last_comment_uid');
  130. break;
  131. case 'comment':
  132. // entity_make_entity_local() may have unset cid, add back if necessary.
  133. if (!isset($entity->cid)) {
  134. $entity->cid = NULL;
  135. }
  136. entity_property_uuid_to_id($entity, 'user', array('uid', 'u_uid'));
  137. entity_property_uuid_to_id($entity, 'node', 'nid');
  138. break;
  139. }
  140. }
  141. /**
  142. * Implements hook_entity_uuid_load().
  143. */
  144. function file_entity_uuid_load(&$entities, $entity_type) {
  145. if ($entity_type == 'file') {
  146. entity_property_id_to_uuid($entities, 'user', 'uid');
  147. }
  148. }
  149. /**
  150. * Implements hook_entity_uuid_presave().
  151. */
  152. function file_entity_uuid_presave(&$entity, $entity_type) {
  153. if ($entity_type == 'file') {
  154. // entity_make_entity_local() may have unset fid, add back if necessary.
  155. if (!isset($entity->fid)) {
  156. $entity->fid = NULL;
  157. }
  158. entity_property_uuid_to_id($entity, 'user', 'uid');
  159. // Write the new file to the local filesystem.
  160. if (isset($entity->file_contents) && !empty($entity->filesize)) {
  161. // Don't try to write it if it uses a stream wrapper that isn't writeable
  162. // (for example, if it is a remotely-hosted video).
  163. $scheme = file_uri_scheme($entity->uri);
  164. $wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE);
  165. if (empty($wrappers[$scheme])) {
  166. return;
  167. }
  168. // Check for an existing file with the same URI.
  169. $existing_files = file_load_multiple(array(), array('uri' => $entity->uri));
  170. $existing = (object) array('uri' => NULL, 'uuid' => NULL);
  171. if (count($existing_files)) {
  172. $existing = reset($existing_files);
  173. }
  174. // If this is a new file and there is an existing file with the same URI,
  175. // but a different uuid then rename this file.
  176. if ($entity->is_new && $entity->uri == $existing->uri && $entity->uuid != $existing->uuid) {
  177. $uri = $entity->uri;
  178. $replace = FILE_EXISTS_RENAME;
  179. }
  180. // If this has an id, meaning UUID has already matched the uuid to an
  181. // existing file, but it has a URI that matches a file with a different
  182. // uuid, then load the file with the matching uuid and use the URI from
  183. // that file. The existing file with the matching uuid is most likely a
  184. // file that was previously renamed, e.g. as in the condition above, to
  185. // avoid conflict. The uuid matches because they are the same file, but
  186. // the URI does not because an incrementing number was added as part of
  187. // the renaming.
  188. elseif ($entity->uri == $existing->uri && $entity->uuid != $existing->uuid) {
  189. $file = file_load($entity->fid);
  190. $uri = $file->uri;
  191. $replace = FILE_EXISTS_REPLACE;
  192. }
  193. // Otherwise create a new file or replace the existing file contents.
  194. else {
  195. $uri = $entity->uri;
  196. $replace = FILE_EXISTS_REPLACE;
  197. }
  198. $directory = drupal_dirname($uri);
  199. if (!empty($directory) && file_prepare_directory($directory, FILE_CREATE_DIRECTORY)) {
  200. $entity->uri = file_unmanaged_save_data(base64_decode($entity->file_contents), $uri, $replace);
  201. }
  202. }
  203. }
  204. }
  205. /**
  206. * Implements hook_entity_uuid_load().
  207. */
  208. function taxonomy_entity_uuid_load(&$entities, $entity_type) {
  209. if ($entity_type == 'taxonomy_term') {
  210. foreach ($entities as &$entity) {
  211. if (isset($entity->parent)) {
  212. if (!is_array($entity->parent)) {
  213. $entity->parent = array($entity->parent);
  214. }
  215. $uuids = entity_get_uuid_by_id('taxonomy_term', $entity->parent);
  216. $entity->parent = array_values($uuids);
  217. }
  218. unset($entity->vid);
  219. }
  220. }
  221. }
  222. /**
  223. * Implements hook_entity_uuid_presave().
  224. */
  225. function taxonomy_entity_uuid_presave(&$entity, $entity_type) {
  226. if ($entity_type == 'taxonomy_term') {
  227. if (isset($entity->parent)) {
  228. if (!is_array($entity->parent)) {
  229. $entity->parent = array($entity->parent);
  230. }
  231. $ids = entity_get_id_by_uuid('taxonomy_term', $entity->parent);
  232. $entity->parent = array_values($ids);
  233. }
  234. $vocabulary = taxonomy_vocabulary_machine_name_load($entity->vocabulary_machine_name);
  235. $entity->vid = $vocabulary->vid;
  236. }
  237. }
  238. /**
  239. * Implements hook_entity_uuid_load().
  240. */
  241. function field_entity_uuid_load(&$entities, $entity_type) {
  242. foreach ($entities as $entity) {
  243. list(, , $bundle_name) = entity_extract_ids($entity_type, $entity);
  244. $instances = field_info_instances($entity_type, $bundle_name);
  245. foreach ($instances as $field_name => $instance) {
  246. $field = field_info_field($field_name);
  247. if (!empty($field) && isset($entity->{$field_name})) {
  248. foreach ($entity->{$field_name} as $langcode => &$items) {
  249. // Invoke 'hook_field_uuid_load'. We can't use module_invoke() since
  250. // that is not passing by reference.
  251. $function = $field['module'] . '_field_uuid_load';
  252. if (function_exists($function)) {
  253. $function($entity_type, $entity, $field, $instance, $langcode, $items);
  254. }
  255. }
  256. }
  257. }
  258. }
  259. }
  260. /**
  261. * Implements hook_entity_uuid_presave().
  262. */
  263. function field_entity_uuid_presave(&$entity, $entity_type) {
  264. list(, , $bundle_name) = entity_extract_ids($entity_type, $entity);
  265. $instances = field_info_instances($entity_type, $bundle_name);
  266. foreach ($instances as $field_name => $instance) {
  267. $field = field_info_field($field_name);
  268. if (!empty($field) && isset($entity->{$field_name})) {
  269. foreach ($entity->{$field_name} as $langcode => &$items) {
  270. // Invoke 'hook_field_uuid_load'. We can't use module_invoke() since
  271. // that is not passing by reference.
  272. $function = $field['module'] . '_field_uuid_presave';
  273. if (function_exists($function)) {
  274. $function($entity_type, $entity, $field, $instance, $langcode, $items);
  275. }
  276. }
  277. }
  278. }
  279. }
  280. /**
  281. * @} End of "Property implementations"
  282. */
  283. /**
  284. * @defgroup uuid_field Field implementations
  285. * @{
  286. */
  287. /**
  288. * Implements hook_field_uuid_load().
  289. */
  290. function taxonomy_field_uuid_load($entity_type, $entity, $field, $instance, $langcode, &$items) {
  291. entity_property_id_to_uuid($items, 'taxonomy_term', 'tid');
  292. }
  293. /**
  294. * Implements hook_field_uuid_presave().
  295. */
  296. function taxonomy_field_uuid_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
  297. entity_property_uuid_to_id($items, 'taxonomy_term', 'tid');
  298. }
  299. /**
  300. * Implements hook_field_uuid_load().
  301. */
  302. function file_field_uuid_load($entity_type, $entity, $field, $instance, $langcode, &$items) {
  303. entity_property_id_to_uuid($items, 'file', 'fid');
  304. entity_property_id_to_uuid($items, 'user', 'uid');
  305. }
  306. /**
  307. * Implements hook_field_uuid_presave().
  308. */
  309. function file_field_uuid_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
  310. entity_property_uuid_to_id($items, 'file', 'fid');
  311. entity_property_uuid_to_id($items, 'user', 'uid');
  312. }
  313. /**
  314. * Implements hook_field_uuid_load().
  315. */
  316. function image_field_uuid_load($entity_type, $entity, $field, $instance, $langcode, &$items) {
  317. file_field_uuid_load($entity_type, $entity, $field, $instance, $langcode, $items);
  318. }
  319. /**
  320. * Implements hook_field_uuid_presave().
  321. */
  322. function image_field_uuid_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
  323. file_field_uuid_presave($entity_type, $entity, $field, $instance, $langcode, $items);
  324. }
  325. /**
  326. * Implements hook_field_uuid_load().
  327. *
  328. * Kept here because it is in D8 core.
  329. */
  330. function entityreference_field_uuid_load($entity_type, $entity, $field, $instance, $langcode, &$items) {
  331. // TODO: This is not really good, but as of now 'entity_property_id_to_uuid()'
  332. // can't handle a single $item.
  333. entity_property_id_to_uuid($items, $field['settings']['target_type'], 'target_id');
  334. }
  335. /**
  336. * Implements hook_field_uuid_presave().
  337. *
  338. * Kept here because it is in D8 core.
  339. */
  340. function entityreference_field_uuid_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
  341. // TODO: This is not really good, but as of now 'entity_property_id_to_uuid()'
  342. // can't handle a single $item.
  343. entity_property_uuid_to_id($items, $field['settings']['target_type'], 'target_id');
  344. }
  345. /**
  346. * @} End of "Field implementations"
  347. */
  348. /**
  349. * @defgroup uuid_export Export alterations
  350. * @{
  351. */
  352. /**
  353. * Implements hook_uuid_entities_features_export_entity_alter().
  354. */
  355. function node_uuid_entities_features_export_entity_alter(&$entity, $entity_type) {
  356. if ('node' != $entity_type) {
  357. return;
  358. }
  359. $properties = array(
  360. 'data',
  361. 'name',
  362. 'picture',
  363. 'revision_uid',
  364. 'last_comment_timestamp',
  365. );
  366. foreach ($properties as $property) {
  367. if (property_exists($entity, $property)) {
  368. unset($entity->{$property});
  369. }
  370. }
  371. }
  372. /**
  373. * Implements hook_uuid_entities_features_export_entity_alter().
  374. */
  375. function user_uuid_entities_features_export_entity_alter(&$entity, $entity_type) {
  376. if ('user' != $entity_type) {
  377. return;
  378. }
  379. foreach (array('data', 'access', 'login') as $property) {
  380. if (property_exists($entity, $property)) {
  381. unset($entity->{$property});
  382. }
  383. }
  384. }
  385. /**
  386. * Implements hook_uuid_entities_features_export_alter().
  387. */
  388. function file_uuid_entities_features_export_field_alter($entity_type, $entity, $field, $instance, $langcode, &$items) {
  389. foreach ($items as &$item) {
  390. if (isset($item['timestamp'])) {
  391. unset($item['timestamp']);
  392. }
  393. }
  394. }
  395. /**
  396. * @} End of "Export alterations"
  397. */