entity_translation_export_import.admin.inc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. <?php
  2. /**
  3. * Menu Callback. Handles the export of the translatable entities.
  4. */
  5. function entity_translation_export_import_admin_export_form($form, $form_state){
  6. $form = array('#tree' => TRUE);
  7. // Get translatable entity types.
  8. $enabled = variable_get('entity_translation_entity_types', array());
  9. $info = entity_get_info();
  10. $entities_options = array();
  11. $bundles_options = array();
  12. $fields_options = array();
  13. // Get the translatable fields foreach translatable entity_type.
  14. foreach ($enabled as $entity_type) {
  15. if (entity_translation_enabled($entity_type)) {
  16. $bundles = !empty($info[$entity_type]['bundles']) ? array_keys($info[$entity_type]['bundles']) : array($entity_type);
  17. foreach ($bundles as $bundle) {
  18. $settings = entity_translation_settings($entity_type, $bundle);
  19. if (entity_translation_enabled_bundle($entity_type, $bundle) && ($handler = entity_translation_get_handler($entity_type, $bundle))) {
  20. $fields_info = field_info_instances($entity_type, $bundle);
  21. foreach ($fields_info as $field_name => $value) {
  22. $field = field_info_field($field_name);
  23. if(field_is_translatable($entity_type, $field) and in_array($field['type'], array('text', 'text_long', 'text_with_summary')) and $field['cardinality'] == 1){
  24. if(!array_key_exists($entity_type, $entities_options)){
  25. $entities_options[$entity_type] = $info[$entity_type]['label'];
  26. }
  27. if(!isset($bundles_options[$entity_type][$bundle])){
  28. $bundles_options[$entity_type][$bundle] = $info[$entity_type]['bundles'][$bundle]['label'];
  29. }
  30. $field_value = $entity_type . ':' . $bundle . ':' . $field_name;
  31. if(!isset($fields_options[$entity_type][$bundle][$field_value])){
  32. $fields_options[$entity_type][$bundle][$field_value] = $value['label'];
  33. }
  34. }
  35. }
  36. }
  37. }
  38. }
  39. }
  40. // If there is no translatable field yet.
  41. if(empty($fields_options)){
  42. $form['no_result'] = array('#markup' => '<p>' . t('You need to enable entity translation for at least one field.') . '</p>');
  43. }
  44. else{
  45. drupal_set_title(t('Export entity translations'));
  46. $form['export'] = array(
  47. '#type' => 'fieldset',
  48. '#title' => t('Export Settings'),
  49. '#collapsible' => FALSE,
  50. '#collapsed' => FALSE,
  51. );
  52. $form['export']['entity_type'] = array(
  53. '#type' => 'checkboxes',
  54. '#options' => $entities_options,
  55. '#ajax' => array(
  56. 'callback' => 'entity_translation_export_import_admin_export_bundle_callback',
  57. 'wrapper' => 'entity-type-wrapper',
  58. ),
  59. );
  60. $form['export']['entity_type_wrapper'] = array(
  61. '#type' => 'container',
  62. '#id' => 'entity-type-wrapper',
  63. );
  64. if(isset($form_state['values']['export']['entity_type'])){
  65. foreach($form_state['values']['export']['entity_type'] as $entity_type => $entity_type_value){
  66. if($entity_type_value){
  67. $form['export']['entity_type_wrapper'][$entity_type] = array(
  68. '#type' => 'fieldset',
  69. '#title' => $entities_options[$entity_type],
  70. '#collapsible' => TRUE,
  71. '#collapsed' => FALSE,
  72. );
  73. foreach($bundles_options[$entity_type] as $bundle_option){
  74. $form['export']['entity_type_wrapper'][$entity_type]['bundle'] = array(
  75. '#type' => 'checkboxes',
  76. '#options' => $bundles_options[$entity_type],
  77. '#ajax' => array(
  78. 'callback' => 'entity_translation_export_import_admin_export_fields_callback',
  79. 'wrapper' => drupal_html_class($entity_type . '-bundle-wrapper'),
  80. ),
  81. );
  82. $form['export']['entity_type_wrapper'][$entity_type]['bundle_wrapper'] = array(
  83. '#type' => 'container',
  84. '#id' => drupal_html_class($entity_type . '-bundle-wrapper'),
  85. );
  86. if(isset($form_state['values']['export']['entity_type_wrapper'][$entity_type]['bundle'])){
  87. foreach($form_state['values']['export']['entity_type_wrapper'][$entity_type]['bundle'] as $bundle => $bundle_value){
  88. if($bundle_value){
  89. $form['export']['entity_type_wrapper'][$entity_type]['bundle_wrapper'][$bundle] = array(
  90. '#type' => 'fieldset',
  91. '#title' => $bundles_options[$entity_type][$bundle],
  92. '#collapsible' => TRUE,
  93. '#collapsed' => FALSE,
  94. );
  95. foreach($bundles_options[$entity_type] as $bundle_option){
  96. $form['export']['entity_type_wrapper'][$entity_type]['bundle_wrapper'][$bundle]['field'] = array(
  97. '#type' => 'checkboxes',
  98. '#options' => $fields_options[$entity_type][$bundle],
  99. );
  100. }
  101. }
  102. }
  103. }
  104. }
  105. }
  106. }
  107. }
  108. $form['submit'] = array(
  109. '#type' => 'submit',
  110. '#value' => t('Export Translations'),
  111. );
  112. }
  113. return $form;
  114. }
  115. /**
  116. * Ajax callback.
  117. */
  118. function entity_translation_export_import_admin_export_bundle_callback($form, $form_state){
  119. $parents = array_slice($form_state['triggering_element']['#array_parents'], 0, -2);
  120. $element = drupal_array_get_nested_value($form, $parents);
  121. return $element['entity_type_wrapper'];
  122. }
  123. /**
  124. * Ajax callback.
  125. */
  126. function entity_translation_export_import_admin_export_fields_callback($form, $form_state){
  127. $parents = array_slice($form_state['triggering_element']['#array_parents'], 0, -2);
  128. $element = drupal_array_get_nested_value($form, $parents);
  129. return $element['bundle_wrapper'];
  130. }
  131. /**
  132. * Submit callback.
  133. */
  134. function entity_translation_export_import_admin_export_form_validate($form, $form_state){
  135. // Get all entities to export.
  136. $at_least_one_field = FALSE;
  137. if(isset($form_state['values']['export']['entity_type_wrapper'])){
  138. foreach($form_state['values']['export']['entity_type_wrapper'] as $entity_type => $entity_type_value) {
  139. if($entity_type_value and isset($entity_type_value['bundle_wrapper'])){
  140. foreach($entity_type_value['bundle_wrapper'] as $bundle => $bundle_value) {
  141. if($bundle_value){
  142. foreach($bundle_value['field'] as $field_value){
  143. if($field_value){
  144. $at_least_one_field = TRUE;
  145. }
  146. }
  147. }
  148. }
  149. }
  150. }
  151. }
  152. if(!$at_least_one_field){
  153. form_set_error('', t('You need to select at least one field.'));
  154. }
  155. }
  156. /**
  157. * Submit callback.
  158. */
  159. function entity_translation_export_import_admin_export_form_submit($form, $form_state){
  160. // Get all entities to export.
  161. $entities = array();
  162. foreach($form_state['values']['export']['entity_type_wrapper'] as $entity_type => $entity_type_value) {
  163. if($entity_type_value){
  164. foreach($entity_type_value['bundle_wrapper'] as $bundle => $bundle_value) {
  165. if($bundle_value){
  166. foreach($bundle_value['field'] as $field_value){
  167. if($field_value){
  168. $parts = explode(':', $field_value);
  169. $entities[$parts[0]][$parts[1]][] = $parts[2];
  170. }
  171. }
  172. }
  173. }
  174. }
  175. }
  176. $limit = 500;
  177. $filename = 'public://entity_translation_export.csv';
  178. variable_set('entity_translation_export_import_file', '');
  179. $batch = array(
  180. 'operations' => array(
  181. array('entity_translation_export_import_export_process', array($entities, $limit, $filename)),
  182. ),
  183. 'finished' => 'entity_translation_export_import_export_finished',
  184. 'title' => t('Export Translations'),
  185. 'init_message' => t('Retrieving Entities...'),
  186. 'progress_message' => t('Processed @current out of @total.'),
  187. 'error_message' => t('Exporting has encountered an error.'),
  188. 'file' => drupal_get_path('module', 'entity_translation_export_import') . '/entity_translation_export_import.admin.inc',
  189. );
  190. batch_set($batch);
  191. batch_process('admin/config/regional/entity_translation/export');
  192. }
  193. /**
  194. * Batch process callback.
  195. */
  196. function entity_translation_export_import_export_process($entities, $limit, $filename, &$context){
  197. // Set the default progress data.
  198. if (!isset($context['sandbox']['progress'])) {
  199. $context['results']['file'] = file_save_data('', $filename);
  200. $context['sandbox']['progress'] = array();
  201. $context['sandbox']['progress_total']['max'] = 0;
  202. $context['sandbox']['progress_total']['current'] = 0;
  203. foreach($entities as $entity_type => $bundles){
  204. foreach($bundles as $bundle => $fields){
  205. $query = new EntityFieldQuery();
  206. $context['sandbox']['progress'][$entity_type][$bundle]['max'] = $query->entityCondition('entity_type', $entity_type)->entityCondition('bundle', $bundle)->count()->execute();
  207. $context['sandbox']['progress'][$entity_type][$bundle]['current'] = 0;
  208. $context['sandbox']['progress_total']['max'] += $context['sandbox']['progress'][$entity_type][$bundle]['max'];
  209. }
  210. }
  211. }
  212. if(!empty($context['sandbox']['progress'])){
  213. $entity_type = key($context['sandbox']['progress']);
  214. $bundle = key(current($context['sandbox']['progress']));
  215. $progress = current(current($context['sandbox']['progress']));
  216. // Receive items.
  217. $items = _entity_translation_export_import_export_entity($entity_type, $bundle, $progress['current'], $limit, $entities[$entity_type][$bundle]);
  218. $is_header = ($context['sandbox']['progress_total']['current'] === 0);
  219. $data = _entity_translation_export_import_csv($items, $is_header);
  220. file_put_contents($context['results']['file']->uri, $data, FILE_APPEND);
  221. $progress['current'] += $limit;
  222. $context['sandbox']['progress_total']['current'] += ($progress['current'] > $progress['max'] ? ($progress['max'] - ($progress['current']-$limit)) : $limit);
  223. $context['sandbox']['progress'][$entity_type][$bundle]['current'] = $progress['current'];
  224. if($progress['current'] >= $progress['max']){
  225. unset($context['sandbox']['progress'][$entity_type][$bundle]);
  226. if(empty($context['sandbox']['progress'][$entity_type])){
  227. unset($context['sandbox']['progress'][$entity_type]);
  228. }
  229. }
  230. if(!empty($context['sandbox']['progress'])){
  231. reset($context['sandbox']['progress']);
  232. $entity_type = key($context['sandbox']['progress']);
  233. $bundle = key(current($context['sandbox']['progress']));
  234. $progress = current(current($context['sandbox']['progress']));
  235. $percentage = '';
  236. if(isset($progress['current']) and $progress['current'] > 0){
  237. $percentage = ' (' . $progress['current'] . '/' . $progress['max'] . ')';
  238. }
  239. $info = entity_get_info();
  240. $context['message'] = t('Exporting ' . $info[$entity_type]['label'] . ' - ' . $info[$entity_type]['bundles'][$bundle]['label'] . $percentage);
  241. }
  242. }
  243. $context['finished'] = ($context['sandbox']['progress_total']['current']/$context['sandbox']['progress_total']['max']);
  244. }
  245. /**
  246. * batch process finish callback.
  247. */
  248. function entity_translation_export_import_export_finished($success, $results){
  249. $link = file_create_url($results['file']->uri);
  250. drupal_set_message(t('Export has been created! Download the <a href="@link">file</a>.', array('@link' => $link)));
  251. }
  252. /**
  253. * Get the field values of an entity.
  254. */
  255. function _entity_translation_export_import_export_entity($entity_type, $bundle, $limitstart, $limit, $fields){
  256. $query = new EntityFieldQuery();
  257. $result = $query->entityCondition('entity_type', $entity_type)
  258. ->entityCondition('bundle', $bundle)
  259. ->entityOrderBy('entity_id')
  260. ->range($limitstart, $limit)
  261. ->execute();
  262. // Force Default Language to be first.
  263. $languages = language_list();
  264. $language_default = language_default();
  265. unset($languages[$language_default->language]);
  266. $languages = array_merge(array($language_default->language => $language_default), $languages);
  267. $export = array();
  268. foreach($result as $entity_type => $items){
  269. foreach($items as $entity_id => $item){
  270. foreach($languages as $language){
  271. $entity = current(entity_load($entity_type, array($entity_id)));
  272. $export[$entity_id]['Entity Type (Not Editable)'] = $entity_type;
  273. $export[$entity_id]['Bundle (Not Editable)'] = $bundle;
  274. $export[$entity_id]['Entity ID (Not Editable)'] = $entity_id;
  275. $handler = entity_translation_get_handler($entity_type, $entity, TRUE);
  276. $translations = $handler->getTranslations();
  277. foreach($fields as $field){
  278. $value = '';
  279. if(isset($translations->data[$language->language])){
  280. $value = $entity->{$field}[$language->language][0]['value'];
  281. }
  282. $export[$entity_id][$field][$language->language] = $value;
  283. }
  284. }
  285. }
  286. }
  287. return $export;
  288. }
  289. /**
  290. * Format entity values as csv.
  291. */
  292. function _entity_translation_export_import_csv($items, $is_header = FALSE){
  293. $data = '';
  294. // Render Header.
  295. if($is_header){
  296. $titles = array();
  297. foreach(reset($items) as $field_name => $value){
  298. if(is_array($value)){
  299. foreach($value as $lang_code => $language_value){
  300. $titles[] = $field_name . '_' . $lang_code;
  301. }
  302. }
  303. else{
  304. $titles[] = $field_name;
  305. }
  306. }
  307. $data .= implode(",", $titles) . "\n";
  308. }
  309. foreach($items as $item){
  310. $row = array();
  311. foreach($item as $field_name => $value){
  312. if(is_array($value)){
  313. foreach($value as $language_value){
  314. $row[] = '"' . str_replace('"', '""', $language_value) . '"';
  315. }
  316. }
  317. else{
  318. $row[] = '"' . str_replace('"', '""', $value) . '"';
  319. }
  320. }
  321. $data .= implode(",", $row) . "\n";
  322. }
  323. return $data;
  324. }
  325. /**
  326. * Import form callback.
  327. */
  328. function entity_translation_export_import_admin_import_form($form, $form_state){
  329. $form = array('#attributes' => array('enctype' => "multipart/form-data"));
  330. $form['fid'] = array(
  331. '#type' => 'managed_file',
  332. '#title' => 'Translation File for Import',
  333. '#upload_validators' => array('file_validate_extensions' => array('csv')),
  334. '#description' => t('WARNING! Do not upload any file that is not formated as needed. Please try to export the translations first.'),
  335. );
  336. $fid = variable_get('entity_translation_export_import_file', '');
  337. if(file_load($fid)){
  338. $form['fid']['#default_value'] = $fid;
  339. }
  340. $form['submit'] = array(
  341. '#type' => 'submit',
  342. '#value' => 'Import Translations'
  343. );
  344. return $form;
  345. }
  346. /**
  347. * Import form submit callback.
  348. */
  349. function entity_translation_export_import_admin_import_form_submit($form, $form_state){
  350. $file = file_load($form_state['values']['fid']);
  351. variable_set('entity_translation_export_import_file', $file->fid);
  352. $batch = array(
  353. 'operations' => array(
  354. array('entity_translation_export_import_import_process', array($file)),
  355. ),
  356. 'finished' => 'entity_translation_export_import_import_finished',
  357. 'title' => t('Import Translations'),
  358. 'init_message' => t('Retrieving Entities...'),
  359. 'progress_message' => t('Processed @current out of @total.'),
  360. 'error_message' => t('Importing has encountered an error.'),
  361. 'file' => drupal_get_path('module', 'entity_translation_export_import') . '/entity_translation_export_import.admin.inc',
  362. );
  363. batch_set($batch);
  364. batch_process('admin/config/regional/entity_translation/import');
  365. }
  366. /**
  367. * Batch process callback.
  368. */
  369. function entity_translation_export_import_import_process($file, &$context){
  370. // Initialize Sandbox Data.
  371. if (!isset($context['sandbox']['current'])) {
  372. $context['sandbox']['total'] = filesize($file->uri);
  373. $context['sandbox']['current'] = 0;
  374. }
  375. if($context['sandbox']['current'] < $context['sandbox']['total']){
  376. $fp = @fopen($file->uri, "r");
  377. // Set the current csv pointer.
  378. @fseek($fp, $context['sandbox']['current']);
  379. if($data = fgetcsv($fp)){
  380. if(!isset($context['sandbox']['header'])){
  381. $context['sandbox']['header'] = $data;
  382. }
  383. else{
  384. entity_translation_export_import_import_translation(array_combine($context['sandbox']['header'], $data));
  385. }
  386. }
  387. // Get the current csv pointer.
  388. $context['sandbox']['current'] = @ftell($fp);
  389. }
  390. $context['finished'] = ($context['sandbox']['current']/$context['sandbox']['total']);
  391. }
  392. /**
  393. * Batch process finish callback.
  394. */
  395. function entity_translation_export_import_import_finished($success, $results){
  396. drupal_set_message(t('Entity Translations have been imported successfully!'));
  397. }
  398. /**
  399. * Imports entity translations.
  400. */
  401. function entity_translation_export_import_import_translation($data){
  402. $entity_type = $data['Entity Type (Not Editable)'];
  403. $bundle = $data['Bundle (Not Editable)'];
  404. $entity_id = $data['Entity ID (Not Editable)'];
  405. if(empty($entity_id)) {
  406. if ($entity_type == 'taxonomy_term') {
  407. // Handle taxonomy term entity.
  408. $vocab = taxonomy_vocabulary_machine_name_load($bundle);
  409. $term = new stdClass();
  410. $term->name = '';
  411. $term->vid = $vocab->vid;
  412. taxonomy_term_save($term);
  413. $entities = entity_load($entity_type, array($term->tid));
  414. }
  415. else if($entity_type == 'node') {
  416. // Handle node entity.
  417. $node = new stdClass();
  418. $node->type = $bundle;
  419. node_object_prepare($node); //Set some default values
  420. $node->status = 1;
  421. $node->promote = 0;
  422. $node->sticky = 0;
  423. $node->uid = $user->uid;
  424. node_save($node);
  425. $entities = entity_load($entity_type, array($node->nid));
  426. }
  427. }
  428. else {
  429. $entities = entity_load($entity_type, array($entity_id));
  430. }
  431. // Get the entity.
  432. $entity = current($entities);
  433. // Get the default entity's language.
  434. $source_language = entity_language($entity_type, $entity);
  435. // Get the current entity's field info.
  436. $fields_info = field_info_instances($entity_type, $bundle);
  437. $values = array();
  438. $languages = array();
  439. foreach($data as $key => $value){
  440. if(strstr($key, '_') and !empty($value)){
  441. $parts = explode('_', $key);
  442. $field_language = array_pop($parts);
  443. $field_name = implode('_', $parts);
  444. // If field is translatable.
  445. if(array_key_exists($field_name, $fields_info)){
  446. $field = field_info_field($field_name);
  447. if(field_is_translatable($entity_type, $field) and in_array($field['type'], array('text', 'text_long', 'text_with_summary')) and $field['cardinality'] == 1){
  448. if(!in_array($field_language, $languages)){
  449. $languages[] = $field_language;
  450. }
  451. if(!isset($entity->{$field_name}[$field_language])){
  452. $entity->{$field_name}[$field_language] = $entity->{$field_name}[$source_language];
  453. }
  454. $entity->{$field_name}[$field_language][0]['value'] = $value;
  455. }
  456. }
  457. }
  458. }
  459. $handler = entity_translation_get_handler($entity_type, $entity, TRUE);
  460. if($handler){
  461. foreach($languages as $langcode){
  462. $translation = array(
  463. 'translate' => 0,
  464. 'status' => 1,
  465. 'source' => ($source_language != $langcode) ? $source_language : '',
  466. 'language' => $langcode,
  467. );
  468. $handler->setTranslation($translation);
  469. // If original entity and module title exists then do the replacements.
  470. if($source_language == $langcode and module_exists('title')){
  471. $fr_info = title_field_replacement_info($entity_type);
  472. foreach($fr_info as $legacy_field => $info) {
  473. if(isset($entity->{$info['field']['field_name']})){
  474. drupal_static_reset('field_language');
  475. title_field_sync_get($entity_type, $entity, $legacy_field, $info, $langcode);
  476. }
  477. }
  478. }
  479. }
  480. }
  481. entity_save($entity_type, $entity);
  482. }