uuid_term.features.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. <?php
  2. /**
  3. * @file
  4. * Features hooks for the uuid_term features component.
  5. */
  6. /**
  7. * Implements hook_features_export_options().
  8. */
  9. function uuid_term_features_export_options() {
  10. $options = array();
  11. $query = 'SELECT t.tid, t.name, v.name AS vname, t.uuid
  12. FROM {taxonomy_term_data} t
  13. INNER JOIN {taxonomy_vocabulary} v ON t.vid = v.vid
  14. ORDER BY v.name ASC, t.name ASC';
  15. $results = db_query($query);
  16. foreach ($results as $term) {
  17. $options[$term->uuid] = $term->vname . ' - ' . $term->name;
  18. }
  19. return $options;
  20. }
  21. /**
  22. * Implements hook_features_export().
  23. */
  24. function uuid_term_features_export($data, &$export, $module_name = '') {
  25. $export['dependencies']['taxonomy'] = 'taxonomy';
  26. $export['dependencies']['uuid'] = 'uuid';
  27. $export['dependencies']['uuid_features'] = 'uuid_features';
  28. foreach ($data as $uuid) {
  29. uuid_term_features_get_dependencies($export, $uuid);
  30. }
  31. return array();
  32. }
  33. /**
  34. * Adds terms and its dependencies to the export.
  35. *
  36. * Parents and term references are handled recrusively, other references are not
  37. * yet supported.
  38. */
  39. function uuid_term_features_get_dependencies(&$export, $uuid) {
  40. $terms = entity_uuid_load('taxonomy_term', array($uuid));
  41. if (count($terms)) {
  42. $term = reset($terms);
  43. $export['features']['uuid_term'][$uuid] = $uuid;
  44. $export['features']['taxonomy'][$term->vocabulary_machine_name] = $term->vocabulary_machine_name;
  45. // Recursively add all parents and the references of the parents.
  46. foreach (taxonomy_get_parents($term->tid) as $parent) {
  47. if (!in_array($parent->uuid, $export['features']['uuid_term'])) {
  48. uuid_term_features_get_dependencies($export, $parent->uuid);
  49. }
  50. }
  51. // Get term references.
  52. $instances = field_info_instances('taxonomy_term', $term->vocabulary_machine_name);
  53. foreach ($instances as $field_name => $instance) {
  54. $field = field_info_field($field_name);
  55. if ($field['type'] == 'taxonomy_term_reference') {
  56. if (isset($term->$field_name)) {
  57. foreach ($term->$field_name as $lang => $values) {
  58. foreach ($values as $value) {
  59. // $value['tid'] already contains the UUID.
  60. if (!in_array($value['tid'], $export['features']['uuid_term'])) {
  61. uuid_term_features_get_dependencies($export, $value['tid']);
  62. }
  63. }
  64. }
  65. }
  66. }
  67. }
  68. }
  69. }
  70. /**
  71. * Implements hook_features_export_render().
  72. */
  73. function uuid_term_features_export_render($module = 'foo', $data) {
  74. $translatables = $code = array();
  75. $code[] = ' $terms = array();';
  76. $code[] = '';
  77. foreach ($data as $uuid) {
  78. // @todo reset = TRUE as otherwise references (parent, fields) were destroyed.
  79. $terms = entity_uuid_load('taxonomy_term', array($uuid), array(), TRUE);
  80. if (!count($terms)) {
  81. continue;
  82. }
  83. // Export the parent uuids.
  84. foreach ($terms as $term) {
  85. if($parents = taxonomy_get_parents($term->tid)) {
  86. foreach ($parents as $parent) {
  87. $term->parent[] = $parent->uuid;
  88. }
  89. }
  90. }
  91. $export = reset($terms);
  92. // Do not export ids.
  93. unset($export->vid);
  94. unset($export->tid);
  95. // No need to export the rdf mapping.
  96. unset($export->rdf_mapping);
  97. uuid_term_features_file_field_export($export);
  98. $code[] = ' $terms[] = ' . features_var_export($export, ' ') . ';';
  99. }
  100. if (!empty($translatables)) {
  101. $code[] = features_translatables_export($translatables, ' ');
  102. }
  103. // Configuration settings need to be exported along with terms to
  104. // avoid diffs between the default and normal code returned by
  105. // this function.
  106. $code[] = ' variable_set(\'uuid_features_file_types\', ' . features_var_export(variable_get('uuid_features_file_types', array())) . ');';
  107. $code[] = ' variable_set(\'uuid_features_file_mode\', ' . features_var_export(variable_get('uuid_features_file_mode', 'inline')) . ');';
  108. $code[] = ' variable_set(\'uuid_features_file_assets_path\', ' . features_var_export(variable_get('uuid_features_file_assets_path', '')) . ');';
  109. $code[] = ' variable_set(\'uuid_features_file_supported_fields\', ' . features_var_export(variable_get('uuid_features_file_supported_fields', 'file, image')) . ');';
  110. $code[] = ' return $terms;';
  111. $code = implode("\n", $code);
  112. return array('uuid_features_default_terms' => $code);
  113. }
  114. /**
  115. * Implements hook_features_revert().
  116. */
  117. function uuid_term_features_revert($module) {
  118. uuid_term_features_rebuild($module);
  119. }
  120. /**
  121. * Implements hook_features_rebuild().
  122. * Rebuilds terms based on UUID from code defaults.
  123. */
  124. function uuid_term_features_rebuild($module) {
  125. // Import the vocabularies first.
  126. taxonomy_features_rebuild($module);
  127. field_features_rebuild($module);
  128. $terms = module_invoke($module, 'uuid_features_default_terms');
  129. if (!empty($terms)) {
  130. // Verify that term objects is saved before any references are resolved.
  131. foreach ($terms as $data) {
  132. $existing = entity_get_id_by_uuid('taxonomy_term', array($data['uuid']));
  133. if (!count($existing)) {
  134. $voc = taxonomy_vocabulary_machine_name_load($data['vocabulary_machine_name']);
  135. // Only save the term, if the corresponding vocabulary already exisits.
  136. if ($voc) {
  137. $term = new stdClass;
  138. $term->uuid = $data['uuid'];
  139. $term->vid = $voc->vid;
  140. $term->name = $data['name'];
  141. taxonomy_term_save($term);
  142. }
  143. }
  144. }
  145. // Save all other data and resolve references.
  146. foreach ($terms as $data) {
  147. $term = (object) $data;
  148. $voc = taxonomy_vocabulary_machine_name_load($term->vocabulary_machine_name);
  149. if ($voc) {
  150. $term->vid = $voc->vid;
  151. uuid_term_features_file_field_import($term, $voc);
  152. entity_uuid_save('taxonomy_term', $term);
  153. }
  154. }
  155. }
  156. }
  157. /**
  158. * Handle exporting file fields.
  159. */
  160. function uuid_term_features_file_field_export(&$term) {
  161. $vocabularies = array_filter(variable_get('uuid_features_file_types', array()));
  162. if (in_array($term->vocabulary_machine_name, $vocabularies)) {
  163. $orig_assets_path = $assets_path = variable_get('uuid_features_file_assets_path', '');
  164. $export_mode = variable_get('uuid_features_file_mode', 'inline');
  165. switch ($export_mode) {
  166. case 'local':
  167. $export_var = 'uuid_features_file_path';
  168. break;
  169. case 'remote':
  170. $export_var = 'uuid_features_file_url';
  171. break;
  172. default:
  173. case 'inline':
  174. $export_var = 'uuid_features_file_data';
  175. break;
  176. }
  177. // If files are supposed to be copied to the assets path.
  178. if ($export_mode == 'local' && $assets_path) {
  179. // Ensure the assets path is created
  180. if ((!is_dir($assets_path) && mkdir($assets_path, 0777, TRUE) == FALSE)
  181. || !is_writable($assets_path)
  182. ) {
  183. // Try creating a public path if the local path isn't writeable.
  184. // This is a kludgy solution to allow writing file assets to places
  185. // such as the profiles/myprofile directory, which isn't supposed to
  186. // be writeable
  187. $new_assets_path = 'public://' . $assets_path;
  188. if (!is_dir($new_assets_path) && mkdir($new_assets_path, 0777, TRUE) == FALSE) {
  189. drupal_set_message(t("Could not create assets path! '!path'", array('!path' => $assets_path)), 'error');
  190. // Don't continue if the assets path is not ready
  191. return;
  192. }
  193. $assets_path = $new_assets_path;
  194. }
  195. }
  196. // get all fields from this vocabulary
  197. $fields = field_info_instances('taxonomy_term', $term->vocabulary_machine_name);
  198. foreach ($fields as $field_instance) {
  199. // load field infos to check the type
  200. $field = &$term->{$field_instance['field_name']};
  201. $info = field_info_field($field_instance['field_name']);
  202. $supported_fields = array_map('trim', explode(',', variable_get('uuid_features_file_supported_fields', 'file, image')));
  203. // check if this field should implement file import/export system
  204. if (in_array($info['type'], $supported_fields)) {
  205. // we need to loop into each language because i18n translation can build
  206. // fields with different language than the node one.
  207. foreach($field as $language => $files) {
  208. if (is_array($files)) {
  209. foreach($files as $i => $file) {
  210. // convert file to array to stay into the default uuid_features_file format
  211. $file = (object) $file;
  212. // Check the file
  213. if (!isset($file->uri) || !is_file($file->uri)) {
  214. drupal_set_message(t("File field found on term, but file doesn't exist on disk? '!path'", array('!path' => $file->uri)), 'error');
  215. continue;
  216. }
  217. if ($export_mode == 'local') {
  218. if ($assets_path) {
  219. // The writeable path may be different from the path that gets saved
  220. // during the feature export to handle the public path/local path
  221. // dilemma mentioned above.
  222. $writeable_export_data = $assets_path . '/' . basename($file->uri);
  223. $export_data = $orig_assets_path . '/' . basename($file->uri);
  224. if (!copy($file->uri, $writeable_export_data)) {
  225. drupal_set_message(t("Export file error, could not copy '%filepath' to '%exportpath'.", array('%filepath' => $file->uri, '%exportpath' => $writeable_export_data)), 'error');
  226. return FALSE;
  227. }
  228. }
  229. else {
  230. $export_data = $file->uri;
  231. }
  232. }
  233. // Remote export mode
  234. elseif ($export_mode == 'remote') {
  235. $export_data = url($file->uri, array('absolute' => TRUE));
  236. }
  237. // Default is 'inline' export mode
  238. else {
  239. $export_data = base64_encode(file_get_contents($file->uri));
  240. }
  241. // build the field again, and remove fid to be sure that imported node
  242. // will rebuild the file again, or keep an existing one with a different fid
  243. $field[$language][$i]['fid'] = NULL;
  244. $field[$language][$i]['timestamp'] = NULL;
  245. $field[$language][$i][$export_var] = $export_data;
  246. }
  247. }
  248. }
  249. }
  250. }
  251. }
  252. }
  253. /**
  254. * Handle importing file fields.
  255. */
  256. function uuid_term_features_file_field_import(&$term, $voc) {
  257. // Get all fields from this vocabulary.
  258. $fields = field_info_instances('taxonomy_term', $term->vocabulary_machine_name);
  259. foreach($fields as $field_instance) {
  260. // Load field info to check the type.
  261. $field = &$term->{$field_instance['field_name']};
  262. $info = field_info_field($field_instance['field_name']);
  263. $supported_fields = array_map('trim', explode(',', variable_get('uuid_features_file_supported_fields', 'file, image')));
  264. // Check if this field should implement file import/export system.
  265. if (in_array($info['type'], $supported_fields)) {
  266. // We need to loop into each language because i18n translation can build
  267. // fields with different language than the term one.
  268. foreach($field as $language => $files) {
  269. if (is_array($files)) {
  270. foreach($files as $i => $file) {
  271. // Convert file to array to stay into the default uuid_features_file format.
  272. $file = (object)$file;
  273. $result = _uuid_features_file_field_import_file($file);
  274. // The file was saved successfully, update the file field (by reference).
  275. if ($result == TRUE && isset($file->fid)) {
  276. $field[$language][$i] = (array)$file;
  277. }
  278. }
  279. }
  280. }
  281. }
  282. }
  283. }