entity_translation_upgrade.admin.inc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <?php
  2. /**
  3. * @file
  4. * Converts node translations into field-based translations.
  5. */
  6. /**
  7. * The number of node translations that should be processed for each batch step.
  8. */
  9. define('ENTITY_TRANSLATION_UPGRADE_BATCH_SIZE', 10);
  10. /**
  11. * Starts the batch process to perform the upgrade.
  12. */
  13. function entity_translation_upgrade_start($types) {
  14. $batch = array(
  15. 'operations' => array(
  16. array('entity_translation_upgrade_do', array($types)),
  17. array('entity_translation_upgrade_complete', array()),
  18. ),
  19. 'finished' => 'entity_translation_upgrade_end',
  20. 'title' => t('Entity Translation Upgrade'),
  21. 'init_message' => t('Entity Translation Upgrade is starting.'),
  22. 'error_message' => t('Entity Translation Upgrade has encountered an error.'),
  23. 'file' => drupal_get_path('module', 'entity_translation_upgrade') . '/entity_translation_upgrade.admin.inc',
  24. );
  25. batch_set($batch);
  26. batch_process('admin/config/regional/entity_translation');
  27. }
  28. /**
  29. * Finshed batch callback.
  30. */
  31. function entity_translation_upgrade_end($success, $results, $operations, $elapsed) {
  32. if (!empty($results)) {
  33. $message = format_plural($results['total'], '1 node translation successfully upgraded.', '@count node translations successfully upgraded.');
  34. watchdog('entity translation upgrade', '@count node translations successfully upgraded.', array('@count' => $results['total']), WATCHDOG_INFO);
  35. }
  36. else {
  37. $message = t('No node translation available for the upgrade.');
  38. }
  39. drupal_set_message($message);
  40. }
  41. /**
  42. * Batch process to convert node translations to field-based translations.
  43. */
  44. function entity_translation_upgrade_do($types, &$context) {
  45. $query = db_select('node', 'n');
  46. $query->addJoin('LEFT', 'entity_translation_upgrade_history', 'etuh', 'n.nid = etuh.nid');
  47. $query
  48. ->fields('n', array('nid', 'tnid'))
  49. ->where('etuh.complete IS NULL OR etuh.complete = 0')
  50. ->condition('n.tnid', 0, '<>')
  51. ->condition('n.tnid <> n.nid', array(), '')
  52. ->condition('n.type', $types)
  53. ->orderBy('n.nid');
  54. // Initialize the batch process.
  55. if (empty($context['sandbox'])) {
  56. $total = $query
  57. ->countQuery()
  58. ->execute()
  59. ->fetchField();
  60. $context['sandbox']['count'] = 0;
  61. $context['sandbox']['total'] = $total;
  62. $context['finished'] = $total == 0;
  63. }
  64. else {
  65. $batch_size = variable_get('entity_translation_upgrade_batch_size', ENTITY_TRANSLATION_UPGRADE_BATCH_SIZE);
  66. $result = $query
  67. ->range($context['sandbox']['count'], $batch_size)
  68. ->execute()
  69. ->fetchAllKeyed();
  70. // Here we load original nodes and translations all together, but the batch
  71. // size is determined only by node translations.
  72. $nids = array_keys($result);
  73. $nodes = node_load_multiple($nids + array_unique($result));
  74. $updated_nodes = array();
  75. $node_translations = array();
  76. $node_translation_sets = array();
  77. $instances = array();
  78. $field_info = array();
  79. foreach ($nids as $nid) {
  80. $node = $nodes[$nid];
  81. $original = $nodes[$node->tnid];
  82. $handler = entity_translation_get_handler('node', $original);
  83. // Instantiate the data and original properties of the translations.
  84. if (empty($handler->getTranslations()->data)) {
  85. $handler->initTranslations();
  86. }
  87. if (!isset($instances[$node->type])) {
  88. $instances[$node->type] = field_info_instances('node', $node->type);
  89. }
  90. reset($instances[$node->type]);
  91. foreach ($instances[$node->type] as $instance) {
  92. $field_name = $instance['field_name'];
  93. $field = isset($field_info[$field_name]) ? $field_info[$field_name] : $field_info[$field_name] = field_info_field($field_name);
  94. // Copy field data.
  95. if ($field['translatable']) {
  96. $langcode = isset($node->{$field_name}[$node->language]) ? $node->language : LANGUAGE_NONE;
  97. if (isset($node->{$field_name}[$langcode])) {
  98. $original->{$field_name}[$node->language] = $node->{$field_name}[$langcode];
  99. }
  100. }
  101. }
  102. // Add the new translation.
  103. $handler->setTranslation(array(
  104. 'translate' => $node->translate,
  105. 'status' => $node->status,
  106. 'language' => $node->language,
  107. 'source' => $original->language,
  108. 'uid' => $node->uid,
  109. 'created' => $node->created,
  110. 'changed' => $node->changed,
  111. ));
  112. // Build a list of updated nodes. They will be saved after all the node
  113. // translation conversions.
  114. $updated_nodes[$original->nid] = $original;
  115. // Build a list of obsolete node translations to be unpublished.
  116. $node_translations[$node->nid] = $node;
  117. // Build a list of obsolete translations sets to be passed to module hook
  118. // implementations.
  119. $node_translation_sets[$original->nid][$node->nid] = $node;
  120. $context['sandbox']['count']++;
  121. }
  122. // Ensure that the multilingual support configuration is set to the right
  123. // value for the current node type.
  124. foreach ($instances as $type_name => $data) {
  125. variable_set("language_content_type_$type_name", ENTITY_TRANSLATION_ENABLED);
  126. }
  127. // Save field data and translations for the updated nodes.
  128. foreach ($updated_nodes as $nid => $node) {
  129. field_attach_presave('node', $node);
  130. field_attach_update('node', $node);
  131. entity_translation_get_handler('node', $node)->saveTranslations();
  132. foreach ($node_translation_sets[$nid] as $translation) {
  133. // Allow modules to upgrade their node additions, if possible.
  134. module_invoke_all('entity_translation_upgrade', $node, $translation);
  135. }
  136. }
  137. if (!empty($node_translations)) {
  138. $nids = array_keys($node_translations);
  139. // Unpublish the obsolete node translations.
  140. db_update('node')
  141. ->fields(array('status' => 0))
  142. ->condition('nid', $nids)
  143. ->execute();
  144. db_update('node_revision')
  145. ->fields(array('status' => 0))
  146. ->condition('nid', $nids)
  147. ->execute();
  148. // Populate history table.
  149. $columns = array('nid', 'tnid', 'language');
  150. $query = db_insert('entity_translation_upgrade_history')->fields($columns);
  151. foreach ($node_translations as $node) {
  152. $query->values((array) $node);
  153. }
  154. $query->execute();
  155. // Flush the modified nodes from the entity load cache.
  156. entity_get_controller('node')->resetCache($nids);
  157. }
  158. $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total'];
  159. if ($context['finished'] >= 1) {
  160. $context['results']['total'] = $context['sandbox']['total'];
  161. }
  162. }
  163. }
  164. /**
  165. * Removes the translation sets for all the upgraded nodes.
  166. */
  167. function entity_translation_upgrade_complete(&$context) {
  168. if ($nids = db_query('SELECT DISTINCT etuh.tnid FROM {entity_translation_upgrade_history} etuh WHERE etuh.complete = 0')->fetchCol()) {
  169. // Remove translation sets for migrated nodes.
  170. db_query('UPDATE {node} SET tnid = 0 WHERE nid IN (:nids)', array(':nids' => $nids));
  171. entity_get_controller('node')->resetCache($nids);
  172. // Mark nodes as migrated.
  173. db_query('UPDATE {entity_translation_upgrade_history} SET complete = 1 WHERE complete = 0');
  174. }
  175. }
  176. /**
  177. * Implementations of hook_entity_translation_upgrade() on behalf of core
  178. * modules.
  179. */
  180. /**
  181. * Implements hook_entity_translation_upgrade().
  182. */
  183. function path_entity_translation_upgrade($node, $translation) {
  184. // Update URL aliases.
  185. db_update('url_alias')
  186. ->fields(array('source' => 'node/' . $node->nid))
  187. ->condition('source', 'node/' . $translation->nid)
  188. ->execute();
  189. }
  190. /**
  191. * Implements hook_entity_translation_upgrade().
  192. */
  193. function comment_entity_translation_upgrade($node, $translation) {
  194. // Attach comments to the original node.
  195. db_update('comment')
  196. ->fields(array('nid' => $node->nid, 'language' => $translation->language))
  197. ->condition('nid', $translation->nid)
  198. ->execute();
  199. // Update node-comment statistics.
  200. $ncs = db_select('node_comment_statistics', 'ncs')
  201. ->fields('ncs')
  202. ->condition('nid', array($node->nid, $translation->nid))
  203. ->execute()
  204. ->fetchAllAssoc('nid');
  205. $last = $ncs[$node->nid]->last_comment_timestamp > $ncs[$translation->nid]->last_comment_timestamp;
  206. $ncs_updated = $last ? $ncs[$node->nid] : $ncs[$translation->nid];
  207. $ncs_updated->nid = $node->nid;
  208. $ncs_updated->comment_count = $ncs[$node->nid]->comment_count + $ncs[$translation->nid]->comment_count;
  209. db_update('node_comment_statistics')
  210. ->fields((array) $ncs_updated)
  211. ->condition('nid', $node->nid)
  212. ->execute();
  213. }