entity_translation_upgrade.admin.inc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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, '1 node translation successfully upgraded.', '@count node translations successfully upgraded.');
  34. watchdog('entity translation upgrade', '@count node translations successfully upgraded.', array('@count' => $results), 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. if (!isset($instances[$node->type])) {
  84. $instances[$node->type] = field_info_instances('node', $node->type);
  85. }
  86. reset($instances[$node->type]);
  87. foreach ($instances[$node->type] as $instance) {
  88. $field_name = $instance['field_name'];
  89. $field = isset($field_info[$field_name]) ? $field_info[$field_name] : $field_info[$field_name] = field_info_field($field_name);
  90. // Copy field data.
  91. if ($field['translatable']) {
  92. $langcode = isset($node->{$field_name}[$node->language]) ? $node->language : LANGUAGE_NONE;
  93. if (isset($node->{$field_name}[$langcode])) {
  94. $original->{$field_name}[$node->language] = $node->{$field_name}[$langcode];
  95. }
  96. }
  97. }
  98. // Add the new translation.
  99. $handler->setTranslation(array(
  100. 'translate' => $node->translate,
  101. 'status' => $node->status,
  102. 'language' => $node->language,
  103. 'source' => $original->language,
  104. 'uid' => $node->uid,
  105. 'created' => $node->created,
  106. 'changed' => $node->changed,
  107. ));
  108. // Build a list of updated nodes. They will be saved after all the node
  109. // translation conversions.
  110. $updated_nodes[$original->nid] = $original;
  111. // Build a list of obsolete node translations to be unpublished.
  112. $node_translations[$node->nid] = $node;
  113. // Build a list of obsolete translations sets to be passed to module hook
  114. // implementations.
  115. $node_translation_sets[$original->nid][$node->nid] = $node;
  116. $context['sandbox']['count']++;
  117. }
  118. // Ensure that the multilingual support configuration is set to the right
  119. // value for the current node type.
  120. foreach ($instances as $type_name => $data) {
  121. variable_set("language_content_type_$type_name", ENTITY_TRANSLATION_ENABLED);
  122. }
  123. // Save field data and translations for the updated nodes.
  124. foreach ($updated_nodes as $nid => $node) {
  125. field_attach_presave('node', $node);
  126. field_attach_update('node', $node);
  127. entity_translation_get_handler('node', $node)->saveTranslations();
  128. foreach ($node_translation_sets[$nid] as $translation) {
  129. // Allow modules to upgrade their node additions, if possible.
  130. module_invoke_all('entity_translation_upgrade', $node, $translation);
  131. }
  132. }
  133. if (!empty($node_translations)) {
  134. $nids = array_keys($node_translations);
  135. // Unpublish the obsolete node translations.
  136. db_update('node')
  137. ->fields(array('status' => 0))
  138. ->condition('nid', $nids)
  139. ->execute();
  140. db_update('node_revision')
  141. ->fields(array('status' => 0))
  142. ->condition('nid', $nids)
  143. ->execute();
  144. // Populate history table.
  145. $columns = array('nid', 'tnid', 'language');
  146. $query = db_insert('entity_translation_upgrade_history')->fields($columns);
  147. foreach ($node_translations as $node) {
  148. $query->values((array) $node);
  149. }
  150. $query->execute();
  151. // Flush the modified nodes from the entity load cache.
  152. entity_get_controller('node')->resetCache($nids);
  153. }
  154. $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total'];
  155. if ($context['finished'] >= 1) {
  156. $context['results'] = $context['sandbox']['total'];
  157. }
  158. }
  159. }
  160. /**
  161. * Removes the translation sets for all the upgraded nodes.
  162. */
  163. function entity_translation_upgrade_complete(&$context) {
  164. if ($nids = db_query('SELECT DISTINCT etuh.tnid FROM {entity_translation_upgrade_history} etuh WHERE etuh.complete = 0')->fetchCol()) {
  165. // Remove translation sets for migrated nodes.
  166. db_query('UPDATE {node} SET tnid = 0 WHERE nid IN (:nids)', array(':nids' => $nids));
  167. entity_get_controller('node')->resetCache($nids);
  168. // Mark nodes as migrated.
  169. db_query('UPDATE {entity_translation_upgrade_history} SET complete = 1 WHERE complete = 0');
  170. }
  171. }
  172. /**
  173. * Implementations of hook_entity_translation_upgrade() on behalf of core
  174. * modules.
  175. */
  176. /**
  177. * Implements hook_entity_translation_upgrade().
  178. */
  179. function path_entity_translation_upgrade($node, $translation) {
  180. // Update URL aliases.
  181. db_update('url_alias')
  182. ->fields(array('source' => 'node/' . $node->nid))
  183. ->condition('source', 'node/' . $translation->nid)
  184. ->execute();
  185. }
  186. /**
  187. * Implements hook_entity_translation_upgrade().
  188. */
  189. function comment_entity_translation_upgrade($node, $translation) {
  190. // Attach comments to the original node.
  191. db_update('comment')
  192. ->fields(array('nid' => $node->nid, 'language' => $translation->language))
  193. ->condition('nid', $translation->nid)
  194. ->execute();
  195. // Update node-comment statistics.
  196. $ncs = db_select('node_comment_statistics', 'ncs')
  197. ->fields('ncs')
  198. ->condition('nid', array($node->nid, $translation->nid))
  199. ->execute()
  200. ->fetchAllAssoc('nid');
  201. $last = $ncs[$node->nid]->last_comment_timestamp > $ncs[$translation->nid]->last_comment_timestamp;
  202. $ncs_updated = $last ? $ncs[$node->nid] : $ncs[$translation->nid];
  203. $ncs_updated->nid = $node->nid;
  204. $ncs_updated->comment_count = $ncs[$node->nid]->comment_count + $ncs[$translation->nid]->comment_count;
  205. db_update('node_comment_statistics')
  206. ->fields((array) $ncs_updated)
  207. ->condition('nid', $node->nid)
  208. ->execute();
  209. }