feeds_mapper_multilingual_fields.test 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053
  1. <?php
  2. /**
  3. * @file
  4. * Contains FeedsMapperMultilingualFieldsTestCase.
  5. */
  6. /**
  7. * Tests field mapping with multiple languages.
  8. */
  9. class FeedsMapperMultilingualFieldsTestCase extends FeedsMapperTestCase {
  10. /**
  11. * Name of created content type.
  12. *
  13. * @var string
  14. */
  15. private $contentType;
  16. /**
  17. * @var array
  18. */
  19. protected $fields = array();
  20. public static function getInfo() {
  21. return array(
  22. 'name' => 'Mapper: Multilingual fields',
  23. 'description' => 'Tests Feeds multilingual support.',
  24. 'group' => 'Feeds',
  25. 'dependencies' => array('date', 'entity_translation', 'i18n_taxonomy', 'link'),
  26. );
  27. }
  28. public function setUp() {
  29. $modules = array(
  30. 'locale',
  31. 'entity_translation',
  32. 'date',
  33. 'link',
  34. 'list',
  35. 'number',
  36. );
  37. $permissions = array(
  38. 'administer entity translation',
  39. 'translate any entity',
  40. 'administer languages',
  41. );
  42. parent::setUp($modules, $permissions);
  43. // Include FeedsProcessor.inc so processor related constants are available.
  44. module_load_include('inc', 'feeds', 'plugins/FeedsProcessor');
  45. // Add French language.
  46. $this->addLanguage('fr', 'French');
  47. // Add Categories vocabulary.
  48. $edit = array(
  49. 'name' => 'Categories',
  50. 'machine_name' => 'categories',
  51. );
  52. $this->drupalPost('admin/structure/taxonomy/add', $edit, 'Save');
  53. // Create content type.
  54. $this->fields = array(
  55. 'date' => array(
  56. 'type' => 'date',
  57. 'settings' => array(
  58. 'field[settings][granularity][hour]' => FALSE,
  59. 'field[settings][granularity][minute]' => FALSE,
  60. 'field[settings][tz_handling]' => 'none',
  61. ),
  62. ),
  63. 'datestamp' => array(
  64. 'type' => 'datestamp',
  65. 'settings' => array(
  66. 'field[settings][granularity][second]' => TRUE,
  67. 'field[settings][tz_handling]' => 'utc',
  68. ),
  69. ),
  70. 'datetime' => array(
  71. 'type' => 'datetime',
  72. 'settings' => array(
  73. 'field[settings][granularity][second]' => TRUE,
  74. 'field[settings][tz_handling]' => 'utc',
  75. ),
  76. ),
  77. 'image' => array(
  78. 'type' => 'image',
  79. 'instance_settings' => array(
  80. 'instance[settings][alt_field]' => 1,
  81. 'instance[settings][title_field]' => 1,
  82. ),
  83. ),
  84. 'link' => 'link_field',
  85. 'list_boolean' => 'list_boolean',
  86. 'number_integer' => 'number_integer',
  87. 'number_decimal' => 'number_decimal',
  88. 'number_float' => 'number_float',
  89. 'text' => 'text',
  90. );
  91. $this->contentType = $this->createContentType(array(), $this->fields);
  92. // Create term reference field.
  93. $field = array(
  94. 'field_name' => 'field_category',
  95. 'type' => 'taxonomy_term_reference',
  96. 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
  97. 'settings' => array(
  98. 'allowed_values' => array(
  99. array(
  100. 'vocabulary' => 'categories',
  101. 'parent' => 0,
  102. ),
  103. ),
  104. ),
  105. );
  106. field_create_field($field);
  107. // Add term reference field to article bundle.
  108. $this->instance = array(
  109. 'field_name' => 'field_category',
  110. 'bundle' => $this->contentType,
  111. 'entity_type' => 'node',
  112. 'widget' => array(
  113. 'type' => 'taxonomy_autocomplete',
  114. ),
  115. 'display' => array(
  116. 'default' => array(
  117. 'type' => 'taxonomy_term_reference_link',
  118. ),
  119. ),
  120. );
  121. field_create_instance($this->instance);
  122. // Make content type and fields multilingual.
  123. $field_names = array(
  124. 'body',
  125. 'field_category',
  126. );
  127. foreach ($this->fields as $field_name => $field_type) {
  128. $field_names[] = 'field_' . $field_name;
  129. }
  130. $this->setupMultilingual($this->contentType, $field_names);
  131. // Copy directory of source files, CSV file expects them in public://images.
  132. $this->copyDir($this->absolutePath() . '/tests/feeds/assets', 'public://images');
  133. // Create an importer configuration with basic mapping.
  134. $this->createImporterConfiguration('Test multilingual fields import from CSV', 'node');
  135. $this->setPlugin('node', 'FeedsCSVParser');
  136. $this->setPlugin('node', 'FeedsFileFetcher');
  137. $this->setSettings('node', 'FeedsNodeProcessor', array(
  138. 'bundle' => $this->contentType,
  139. 'language' => 'en',
  140. ));
  141. // Add language neutral mappings.
  142. $this->addMappings('node', array(
  143. 0 => array(
  144. 'source' => 'guid',
  145. 'target' => 'guid',
  146. 'unique' => 1,
  147. ),
  148. 1 => array(
  149. 'source' => 'title',
  150. 'target' => 'title',
  151. ),
  152. ));
  153. }
  154. /**
  155. * Tests multilingual mappings to translatable fields (entity translation).
  156. */
  157. public function testMultilingualFieldMappings() {
  158. // Add English mappers.
  159. $index = 2;
  160. $mappings = $this->getMappingsInLanguage('en', $index);
  161. // Append "_en" to each source name.
  162. foreach ($mappings as &$mapping) {
  163. $mapping['source'] .= '_en';
  164. }
  165. $this->addMappings('node', $mappings);
  166. $index += count($mappings);
  167. // Add French mappers.
  168. $mappings = $this->getMappingsInLanguage('fr', $index);
  169. // Append "_fr" to each source name.
  170. foreach ($mappings as &$mapping) {
  171. $mapping['source'] .= '_fr';
  172. }
  173. $this->addMappings('node', $mappings);
  174. // Import file that has items with both English and French field values.
  175. $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual_en_fr.csv');
  176. $this->assertText(t('Created 1 node'));
  177. // Load node.
  178. $node = node_load(1, NULL, TRUE);
  179. // Inspect availability of English values.
  180. $english = $this->getEnglishValues($node) + array(
  181. 'field_category' => array(
  182. 'expected' => 1,
  183. 'actual' => $node->field_category['en'][0]['tid'],
  184. ),
  185. );
  186. foreach ($english as $field_name => $value) {
  187. $this->assertEqual($value['expected'], $value['actual'], format_string('The English field %field has the expected value (actual: @actual).', array('%field' => $field_name, '@actual' => $value['actual'])));
  188. }
  189. // Inspect availability of French values.
  190. $french = $this->getFrenchValues($node) + array(
  191. 'field_category' => array(
  192. 'expected' => 2,
  193. 'actual' => $node->field_category['fr'][0]['tid'],
  194. ),
  195. );
  196. foreach ($french as $field_name => $value) {
  197. $this->assertEqual($value['expected'], $value['actual'], format_string('The French field %field has the expected value (actual: @actual).', array('%field' => $field_name, '@actual' => $value['actual'])));
  198. }
  199. }
  200. /**
  201. * Tests if values of fields in other languages are kept when not importing
  202. * in that language.
  203. */
  204. public function testChangedLanguageImport() {
  205. // Add Dutch language.
  206. $this->addLanguage('nl', 'Dutch');
  207. // Import an item first in the Dutch language.
  208. $this->setSettings('node', 'FeedsNodeProcessor', array(
  209. 'language' => 'nl',
  210. ));
  211. $mappings = $this->getMappingsInLanguage('nl', 2);
  212. $this->addMappings('node', $mappings);
  213. $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual_nl.csv');
  214. $this->assertText(t('Created 1 node'));
  215. // Assert that Dutch values were created.
  216. $node = node_load(1, NULL, TRUE);
  217. $dutch = $this->getDutchValues($node) + array(
  218. 'field_category' => array(
  219. 'expected' => 1,
  220. 'actual' => $node->field_category['nl'][0]['tid'],
  221. ),
  222. );
  223. foreach ($dutch as $field_name => $value) {
  224. $this->assertEqual($value['expected'], $value['actual'], format_string('The Dutch field %field has the expected value (actual: @actual).', array('%field' => $field_name, '@actual' => $value['actual'])));
  225. }
  226. // Set import to update existing nodes.
  227. $this->setSettings('node', 'FeedsNodeProcessor', array(
  228. 'update_existing' => FEEDS_UPDATE_EXISTING,
  229. ));
  230. // Change mappers language to French.
  231. $path = 'admin/structure/feeds/node/mapping';
  232. foreach ($mappings as $i => $mapping) {
  233. $this->drupalPostAJAX($path, array(), 'mapping_settings_edit_' . $i);
  234. $edit = array("config[$i][settings][field_language]" => 'fr');
  235. $this->drupalPostAJAX(NULL, $edit, 'mapping_settings_update_' . $i);
  236. $this->drupalPost(NULL, array(), t('Save'));
  237. }
  238. // Import French item.
  239. $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual_fr.csv');
  240. $this->assertText(t('Updated 1 node'));
  241. // Assert that French values were created.
  242. $node = node_load(1, NULL, TRUE);
  243. $french = $this->getFrenchValues($node) + array(
  244. 'field_category' => array(
  245. 'expected' => 2,
  246. 'actual' => $node->field_category['fr'][0]['tid'],
  247. ),
  248. );
  249. foreach ($french as $field_name => $value) {
  250. $this->assertEqual($value['expected'], $value['actual'], format_string('The French field %field has the expected value (actual: @actual).', array('%field' => $field_name, '@actual' => $value['actual'])));
  251. }
  252. // Assert that Dutch values still exist.
  253. $dutch = $this->getDutchValues($node) + array(
  254. 'field_category' => array(
  255. 'expected' => 1,
  256. 'actual' => $node->field_category['nl'][0]['tid'],
  257. ),
  258. );
  259. foreach ($dutch as $field_name => $value) {
  260. $this->assertEqual($value['expected'], $value['actual'], format_string('The Dutch field %field has the expected value (actual: @actual).', array('%field' => $field_name, '@actual' => $value['actual'])));
  261. }
  262. }
  263. /**
  264. * Tests if values of fields in other languages are kept when not importing
  265. * in that language for nodes that were not created by Feeds.
  266. */
  267. public function testChangedLanguageImportForExistingNode() {
  268. // Add Dutch language.
  269. $this->addLanguage('nl', 'Dutch');
  270. // Date settings.
  271. foreach (array('datestamp', 'datetime') as $field) {
  272. $field = 'field_' . $field;
  273. $edit = array(
  274. 'field[settings][granularity][second]' => 1,
  275. );
  276. $this->drupalPost('admin/structure/types/manage/' . $this->contentType . '/fields/' . $field . '/field-settings', $edit, 'Save field settings');
  277. }
  278. // Hack to get date fields to not round to every 15 seconds.
  279. foreach (array('date', 'datestamp', 'datetime') as $field) {
  280. $field = 'field_' . $field;
  281. $edit = array(
  282. 'widget_type' => 'date_select',
  283. );
  284. $this->drupalPost('admin/structure/types/manage/' . $this->contentType . '/fields/' . $field . '/widget-type', $edit, 'Continue');
  285. $edit = array(
  286. 'instance[widget][settings][increment]' => 1,
  287. 'field[settings][enddate_get]' => 1,
  288. );
  289. $this->drupalPost('admin/structure/types/manage/' . $this->contentType . '/fields/' . $field, $edit, 'Save settings');
  290. $edit = array(
  291. 'widget_type' => 'date_text',
  292. );
  293. $this->drupalPost('admin/structure/types/manage/' . $this->contentType . '/fields/' . $field . '/widget-type', $edit, 'Continue');
  294. }
  295. // Create a node with Dutch values.
  296. $edit = array(
  297. 'title' => 'Teste Feeds Multilingue 1',
  298. 'body[und][0][value]' => 'Dit is de berichttekst',
  299. 'field_date[und][0][value][date]' => '07/29/1985',
  300. 'field_datestamp[und][0][value][date]' => '07/29/1985 - 04:48:12',
  301. 'field_datetime[und][0][value][date]' => '07/29/1985 - 04:48:12',
  302. 'field_link[und][0][url]' => 'http://google.nl',
  303. 'field_list_boolean[und]' => '1',
  304. 'field_number_decimal[und][0][value]' => '30.3',
  305. 'field_number_float[und][0][value]' => '30.2795',
  306. 'field_number_integer[und][0][value]' => '30',
  307. 'field_text[und][0][value]' => 'Wortelen',
  308. 'files[field_image_und_0]' => drupal_realpath('public://images/attersee.jpeg'),
  309. 'field_category[und]' => 'Nieuws',
  310. 'language' => 'nl',
  311. );
  312. $this->drupalPost('node/add/' . $this->contentType, $edit, t('Save'));
  313. // Add alt/title to the image.
  314. $edit = array(
  315. 'field_image[nl][0][alt]' => 'Bij het zien',
  316. 'field_image[nl][0][title]' => 'Bij het zien van de groene vloeistof',
  317. );
  318. $this->drupalPost('node/1/edit/nl', $edit, t('Save'));
  319. $this->drupalGet('node/1/edit/nl');
  320. // Assert that the Dutch values were put in as expected.
  321. $node = node_load(1, NULL, TRUE);
  322. $dutch = $this->getDutchValues($node) + array(
  323. 'field_category' => array(
  324. 'expected' => 1,
  325. 'actual' => $node->field_category['nl'][0]['tid'],
  326. ),
  327. );
  328. foreach ($dutch as $field_name => $value) {
  329. $this->assertEqual($value['expected'], $value['actual'], format_string('The Dutch field %field has the expected value (actual: @actual).', array('%field' => $field_name, '@actual' => $value['actual'])));
  330. }
  331. // Change unique target from guid (0) to title (1).
  332. $path = 'admin/structure/feeds/node/mapping';
  333. $this->drupalPostAJAX($path, array(), 'mapping_settings_edit_0');
  334. $edit = array("config[0][settings][unique]" => FALSE);
  335. $this->drupalPostAJAX(NULL, $edit, 'mapping_settings_update_0');
  336. $this->drupalPost(NULL, array(), t('Save'));
  337. $this->drupalPostAJAX($path, array(), 'mapping_settings_edit_1');
  338. $edit = array("config[1][settings][unique]" => 1);
  339. $this->drupalPostAJAX(NULL, $edit, 'mapping_settings_update_1');
  340. $this->drupalPost(NULL, array(), t('Save'));
  341. // Update this item with Feeds.
  342. $this->setSettings('node', 'FeedsNodeProcessor', array(
  343. 'update_existing' => FEEDS_UPDATE_EXISTING,
  344. ));
  345. $this->addMappings('node', $this->getMappingsInLanguage('fr'));
  346. $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual_fr.csv');
  347. $this->assertText(t('Updated 1 node'));
  348. // Assert that French values were created.
  349. $node = node_load(1, NULL, TRUE);
  350. $french = $this->getFrenchValues($node) + array(
  351. 'field_category' => array(
  352. 'expected' => 2,
  353. 'actual' => $node->field_category['fr'][0]['tid'],
  354. ),
  355. );
  356. foreach ($french as $field_name => $value) {
  357. $this->assertEqual($value['expected'], $value['actual'], format_string('The French field %field has the expected value (actual: @actual).', array('%field' => $field_name, '@actual' => $value['actual'])));
  358. }
  359. // Assert that Dutch values still exist.
  360. $dutch = $this->getDutchValues($node) + array(
  361. 'field_category' => array(
  362. 'expected' => 1,
  363. 'actual' => $node->field_category['nl'][0]['tid'],
  364. ),
  365. );
  366. foreach ($dutch as $field_name => $value) {
  367. $this->assertEqual($value['expected'], $value['actual'], format_string('The Dutch field %field has the expected value (actual: @actual).', array('%field' => $field_name, '@actual' => $value['actual'])));
  368. }
  369. }
  370. /**
  371. * Tests if fields still are imported in their language when the
  372. * entity_translation module gets disabled.
  373. *
  374. * The entity_translation module is mainly an UI module for configuring field
  375. * language and disabling that module should not have effect on importing
  376. * values in a specific language for fields.
  377. */
  378. public function testWithDisabledEntityTranslationModule() {
  379. module_disable(array('entity_translation'));
  380. // Make sure that entity info is reset.
  381. drupal_flush_all_caches();
  382. drupal_static_reset();
  383. // Configure importer to import in French language.
  384. $this->setSettings('node', 'FeedsNodeProcessor', array(
  385. 'language' => 'fr',
  386. ));
  387. $this->addMappings('node', $this->getMappingsInLanguage('fr'));
  388. // Import content.
  389. $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual_fr.csv');
  390. $this->assertText(t('Created 1 node'));
  391. // Assert that the fields were all created in French.
  392. $node = node_load(1, NULL, TRUE);
  393. $french = $this->getFrenchValues($node) + array(
  394. 'field_category' => array(
  395. 'expected' => 1,
  396. 'actual' => $node->field_category['fr'][0]['tid'],
  397. ),
  398. );
  399. foreach ($french as $field_name => $value) {
  400. $this->assertEqual($value['expected'], $value['actual'], format_string('The field %field has the expected value (actual: @actual).', array('%field' => $field_name, '@actual' => $value['actual'])));
  401. }
  402. }
  403. /**
  404. * Tests if fields are still imported in their language when the
  405. * entity_translation module gets uninstalled.
  406. *
  407. * @see testWithDisabledEntityTranslationModule()
  408. */
  409. public function testWithUninstalledEntityTranslationModule() {
  410. module_disable(array('entity_translation'));
  411. drupal_uninstall_modules(array('entity_translation'));
  412. // Make sure that entity info is reset.
  413. drupal_flush_all_caches();
  414. drupal_static_reset();
  415. // Configure importer to import in French language.
  416. $this->setSettings('node', 'FeedsNodeProcessor', array(
  417. 'language' => 'fr',
  418. ));
  419. $this->addMappings('node', $this->getMappingsInLanguage('fr'));
  420. // Import content.
  421. $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual_fr.csv');
  422. $this->assertText(t('Created 1 node'));
  423. // Assert that the fields were all created in French.
  424. $node = node_load(1, NULL, TRUE);
  425. $french = $this->getFrenchValues($node) + array(
  426. 'field_category' => array(
  427. 'expected' => 1,
  428. 'actual' => $node->field_category['fr'][0]['tid'],
  429. ),
  430. );
  431. foreach ($french as $field_name => $value) {
  432. $this->assertEqual($value['expected'], $value['actual'], format_string('The field %field has the expected value (actual: @actual).', array('%field' => $field_name, '@actual' => $value['actual'])));
  433. }
  434. }
  435. /**
  436. * Tests if fields are imported in LANGUAGE_NONE if the field's language gets
  437. * disabled after configuring.
  438. */
  439. public function testDisabledLanguage() {
  440. // Configure importer to import in French language.
  441. $this->setSettings('node', 'FeedsNodeProcessor', array(
  442. 'language' => 'fr',
  443. ));
  444. $this->addMappings('node', $this->getMappingsInLanguage('fr'));
  445. // Now disable the French language.
  446. $path = 'admin/config/regional/language';
  447. $edit = array(
  448. 'enabled[fr]' => FALSE,
  449. );
  450. $this->drupalPost($path, $edit, t('Save configuration'));
  451. // Reset static cache to update the available languages.
  452. drupal_static_reset();
  453. // Ensure no error messages are shown on the mappings page.
  454. $this->drupalGet('admin/structure/feeds/node/mapping');
  455. // Import content.
  456. $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual_fr.csv');
  457. $this->assertText(t('Created 1 node'));
  458. // Assert that the fields were all created in LANGUAGE_NONE.
  459. $node = node_load(1, NULL, TRUE);
  460. $french = $this->getFrenchValues($node, LANGUAGE_NONE) + array(
  461. 'field_category' => array(
  462. 'expected' => 1,
  463. 'actual' => $node->field_category[LANGUAGE_NONE][0]['tid'],
  464. ),
  465. );
  466. foreach ($french as $field_name => $value) {
  467. $this->assertEqual($value['expected'], $value['actual'], format_string('The field %field has the expected value (actual: @actual).', array('%field' => $field_name, '@actual' => $value['actual'])));
  468. }
  469. }
  470. /**
  471. * Tests if fields are imported in LANGUAGE_NONE if the field's language gets
  472. * removed after configuring.
  473. */
  474. public function testRemovedLanguage() {
  475. // Configure importer to import in French language.
  476. $this->setSettings('node', 'FeedsNodeProcessor', array(
  477. 'language' => 'fr',
  478. ));
  479. $this->addMappings('node', $this->getMappingsInLanguage('fr'));
  480. // Now remove the French language.
  481. $path = 'admin/config/regional/language/delete/fr';
  482. $this->drupalPost($path, array(), t('Delete'));
  483. // Reset static cache to update the available languages.
  484. drupal_static_reset();
  485. // Import content.
  486. $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual_fr.csv');
  487. $this->assertText(t('Created 1 node'));
  488. // Assert that the fields were all created in LANGUAGE_NONE.
  489. $node = node_load(1, NULL, TRUE);
  490. $french = $this->getFrenchValues($node, LANGUAGE_NONE) + array(
  491. 'field_category' => array(
  492. 'expected' => 1,
  493. 'actual' => $node->field_category[LANGUAGE_NONE][0]['tid'],
  494. ),
  495. );
  496. foreach ($french as $field_name => $value) {
  497. $this->assertEqual($value['expected'], $value['actual'], format_string('The field %field has the expected value (actual: @actual).', array('%field' => $field_name, '@actual' => $value['actual'])));
  498. }
  499. }
  500. /**
  501. * Tests if autocreated terms are in the language that was set on the target configuration
  502. * in case the taxonomy is multilingual.
  503. */
  504. public function testAutocreatedTermLanguage() {
  505. module_enable(array('i18n_taxonomy'));
  506. // Make sure that entity info is reset.
  507. drupal_flush_all_caches();
  508. drupal_static_reset();
  509. // Enable multilingual taxonomy.
  510. $edit = array('i18n_mode' => 4);
  511. $this->drupalPost('admin/structure/taxonomy/categories/edit', $edit, 'Save');
  512. // Configure importer to import in French language.
  513. $this->setSettings('node', 'FeedsNodeProcessor', array(
  514. 'language' => 'fr',
  515. ));
  516. $this->addMappings('node', array(
  517. 2 => array(
  518. 'source' => 'term',
  519. 'target' => 'field_category',
  520. 'autocreate' => TRUE,
  521. 'field_language' => 'fr',
  522. ),
  523. ));
  524. // Import French item.
  525. $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual_fr.csv');
  526. $this->assertText(t('Created 1 node'));
  527. // Assert that the created term is in the French language.
  528. $term = taxonomy_term_load(1);
  529. $this->assertEqual('fr', entity_language('taxonomy_term', $term));
  530. }
  531. /**
  532. * Tests if values are cleared out when an empty value or no value is
  533. * provided.
  534. */
  535. public function testClearOutValues() {
  536. // Set to update existing nodes.
  537. $this->setSettings('node', 'FeedsNodeProcessor', array(
  538. 'update_existing' => FEEDS_UPDATE_EXISTING,
  539. ));
  540. // Add English mappers.
  541. $index = 2;
  542. $mappings = $this->getMappingsInLanguage('en', $index);
  543. // Append "_en" to each source name.
  544. foreach ($mappings as &$mapping) {
  545. $mapping['source'] .= '_en';
  546. }
  547. $this->addMappings('node', $mappings);
  548. $index += count($mappings);
  549. // Add French mappers.
  550. $mappings = $this->getMappingsInLanguage('fr', $index);
  551. // Append "_fr" to each source name.
  552. foreach ($mappings as &$mapping) {
  553. $mapping['source'] .= '_fr';
  554. }
  555. $this->addMappings('node', $mappings);
  556. // Import file that has items with both English and French field values.
  557. $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual_en_fr.csv');
  558. $this->assertText(t('Created 1 node'));
  559. // Now import a file where the French remained, but the English values were
  560. // removed.
  561. $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual_en_fr_empty.csv');
  562. $this->assertText(t('Updated 1 node'));
  563. // Load node.
  564. $node = node_load(1, NULL, TRUE);
  565. // Check that the English values are gone, but the French values are still
  566. // there.
  567. $fields = array(
  568. 'body',
  569. 'field_date',
  570. 'field_datestamp',
  571. 'field_datetime',
  572. 'field_image',
  573. 'field_link',
  574. 'field_list_boolean',
  575. 'field_number_decimal',
  576. 'field_number_float',
  577. 'field_number_integer',
  578. 'field_category',
  579. 'field_text',
  580. );
  581. foreach ($fields as $field_name) {
  582. $this->assertTrue(empty($node->{$field_name}['en']), format_string('The field %field is empty.', array('%field' => $field_name)));
  583. }
  584. // Inspect availability of French values.
  585. $french = $this->getFrenchValues($node) + array(
  586. 'field_category' => array(
  587. 'expected' => 2,
  588. 'actual' => $node->field_category['fr'][0]['tid'],
  589. ),
  590. );
  591. // Since the image was placed on the node again, its file name is now
  592. // "la fayette_0.jpeg."
  593. $french['field_image']['expected'] = 'la fayette_0.jpeg';
  594. foreach ($french as $field_name => $value) {
  595. $this->assertEqual($value['expected'], $value['actual'], format_string('The French field %field has the expected value (actual: @actual).', array('%field' => $field_name, '@actual' => $value['actual'])));
  596. }
  597. }
  598. /**
  599. * Tests if values are cleared out when an empty value is provided for a
  600. * language that got disabled.
  601. */
  602. public function testClearOutValuesWithDisabledLanguage() {
  603. // Set to update existing nodes.
  604. $this->setSettings('node', 'FeedsNodeProcessor', array(
  605. 'update_existing' => FEEDS_UPDATE_EXISTING,
  606. ));
  607. // Configure importer to import in French language.
  608. $this->setSettings('node', 'FeedsNodeProcessor', array(
  609. 'language' => 'fr',
  610. ));
  611. $this->addMappings('node', $this->getMappingsInLanguage('fr'));
  612. // Now disable the French language.
  613. $path = 'admin/config/regional/language';
  614. $edit = array(
  615. 'enabled[fr]' => FALSE,
  616. );
  617. $this->drupalPost($path, $edit, t('Save configuration'));
  618. // Ensure no error messages are shown on the mappings page.
  619. $this->drupalGet('admin/structure/feeds/node/mapping');
  620. // Import content. Since the French language was disabled, the content
  621. // should be imported as LANGUAGE_NONE.
  622. // @see ::testDisabledLanguage()
  623. $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual_fr.csv');
  624. $this->assertText(t('Created 1 node'));
  625. // Now import a file with empty values.
  626. $this->importFile('node', $this->absolutePath() . '/tests/feeds/multilingual_empty.csv');
  627. $this->assertText(t('Updated 1 node'));
  628. // Load node.
  629. $node = node_load(1, NULL, TRUE);
  630. // Check that the values in LANGUAGE_NONE are gone.
  631. $fields = array(
  632. 'body',
  633. 'field_date',
  634. 'field_datestamp',
  635. 'field_datetime',
  636. 'field_image',
  637. 'field_link',
  638. 'field_list_boolean',
  639. 'field_number_decimal',
  640. 'field_number_float',
  641. 'field_number_integer',
  642. 'field_category',
  643. 'field_text',
  644. );
  645. foreach ($fields as $field_name) {
  646. $this->assertTrue(empty($node->{$field_name}[LANGUAGE_NONE]), format_string('The field %field is empty.', array('%field' => $field_name)));
  647. }
  648. }
  649. /**
  650. * Adds a language to test with.
  651. *
  652. * @param string $langcode
  653. * The language's langcode.
  654. * @param string $label
  655. * The language human readable name.
  656. */
  657. protected function addLanguage($langcode, $label) {
  658. $edit = array(
  659. 'langcode' => $langcode,
  660. );
  661. $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
  662. $this->assertText(format_string('The language @language has been created and can now be used.', array('@language' => $label)));
  663. }
  664. /**
  665. * Sets given content type and fields to be translatable.
  666. *
  667. * @param string $typename
  668. * The machine name of the node type.
  669. * @param array $field_names
  670. * The fields to enable multilingual support for.
  671. */
  672. protected function setupMultilingual($typename, array $field_names) {
  673. // Enable entity field translation for content type.
  674. $edit = array(
  675. 'language_content_type' => 4,
  676. 'entity_translation_hide_translation_links' => 1,
  677. 'entity_translation_node_metadata' => 0,
  678. );
  679. $this->drupalPost('admin/structure/types/manage/' . $typename, $edit, t('Save content type'));
  680. // Enable field translation on fields.
  681. $edit = array(
  682. 'field[translatable]' => 1,
  683. );
  684. foreach ($field_names as $field_name) {
  685. $this->drupalPost("admin/structure/types/manage/{$typename}/fields/{$field_name}", $edit, t('Save settings'));
  686. }
  687. // Reset static cache so that all languages are available when
  688. // field_available_languages() is called during node_load().
  689. drupal_static_reset();
  690. }
  691. /**
  692. * Adds mappings for each field in specified language.
  693. *
  694. * @param string $langcode
  695. * The code of the desired language.
  696. * @param int $start
  697. * The index number to start the array with. This must be
  698. * specified in order to add mappings to the right index when
  699. * calling FeedsWebTestCase::addMappings().
  700. */
  701. protected function getMappingsInLanguage($langcode, $start = 2) {
  702. $mappings = array(
  703. $start => array(
  704. 'source' => 'body',
  705. 'target' => 'body',
  706. ),
  707. array(
  708. 'source' => 'date',
  709. 'target' => 'field_date:start',
  710. ),
  711. array(
  712. 'source' => 'datestamp',
  713. 'target' => 'field_datestamp:start',
  714. ),
  715. array(
  716. 'source' => 'datetime',
  717. 'target' => 'field_datetime:start',
  718. ),
  719. array(
  720. 'source' => 'image',
  721. 'target' => 'field_image:uri',
  722. ),
  723. array(
  724. 'source' => 'image_alt',
  725. 'target' => 'field_image:alt',
  726. ),
  727. array(
  728. 'source' => 'image_title',
  729. 'target' => 'field_image:title',
  730. ),
  731. array(
  732. 'source' => 'link',
  733. 'target' => 'field_link:url',
  734. ),
  735. array(
  736. 'source' => 'list_boolean',
  737. 'target' => 'field_list_boolean',
  738. ),
  739. array(
  740. 'source' => 'number_decimal',
  741. 'target' => 'field_number_decimal',
  742. ),
  743. array(
  744. 'source' => 'number_float',
  745. 'target' => 'field_number_float',
  746. ),
  747. array(
  748. 'source' => 'number_integer',
  749. 'target' => 'field_number_integer',
  750. ),
  751. array(
  752. 'source' => 'term',
  753. 'target' => 'field_category',
  754. 'autocreate' => TRUE,
  755. ),
  756. array(
  757. 'source' => 'text',
  758. 'target' => 'field_text',
  759. ),
  760. );
  761. foreach ($mappings as &$mapping) {
  762. $mapping['field_language'] = $langcode;
  763. }
  764. return $mappings;
  765. }
  766. /**
  767. * Returns expected and actual values of given node for the Dutch language.
  768. *
  769. * @param object $node
  770. * The multilingual node.
  771. * @param string $langcode
  772. * The used language code.
  773. *
  774. * @return array
  775. * The expected and actual Dutch values.
  776. */
  777. protected function getDutchValues($node, $langcode = 'nl') {
  778. return array(
  779. 'body' => array(
  780. 'expected' => 'Dit is de berichttekst',
  781. 'actual' => $node->body[$langcode][0]['value'],
  782. ),
  783. 'field_date' => array(
  784. 'expected' => '1985-07-29T00:00:00',
  785. 'actual' => $node->field_date[$langcode][0]['value'],
  786. ),
  787. 'field_datestamp' => array(
  788. 'expected' => '491460492',
  789. 'actual' => $node->field_datestamp[$langcode][0]['value'],
  790. ),
  791. 'field_datetime' => array(
  792. 'expected' => '1985-07-29 04:48:12',
  793. 'actual' => $node->field_datetime[$langcode][0]['value'],
  794. ),
  795. 'field_image' => array(
  796. 'expected' => 'attersee.jpeg',
  797. 'actual' => $node->field_image[$langcode][0]['filename'],
  798. ),
  799. 'field_image:alt' => array(
  800. 'expected' => 'Bij het zien',
  801. 'actual' => $node->field_image[$langcode][0]['alt'],
  802. ),
  803. 'field_image:title' => array(
  804. 'expected' => 'Bij het zien van de groene vloeistof',
  805. 'actual' => $node->field_image[$langcode][0]['title'],
  806. ),
  807. 'field_link' => array(
  808. 'expected' => 'http://google.nl',
  809. 'actual' => $node->field_link[$langcode][0]['url'],
  810. ),
  811. 'field_list_boolean' => array(
  812. 'expected' => '1',
  813. 'actual' => $node->field_list_boolean[$langcode][0]['value'],
  814. ),
  815. 'field_number_decimal' => array(
  816. 'expected' => 30.3,
  817. 'actual' => $node->field_number_decimal[$langcode][0]['value'],
  818. ),
  819. 'field_number_float' => array(
  820. 'expected' => 30.2795,
  821. 'actual' => $node->field_number_float[$langcode][0]['value'],
  822. ),
  823. 'field_number_integer' => array(
  824. 'expected' => 30,
  825. 'actual' => $node->field_number_integer[$langcode][0]['value'],
  826. ),
  827. 'field_text' => array(
  828. 'expected' => 'Wortelen',
  829. 'actual' => $node->field_text[$langcode][0]['value'],
  830. ),
  831. );
  832. }
  833. /**
  834. * Returns expected and actual values of given node for the English language.
  835. *
  836. * @param object $node
  837. * The multilingual node.
  838. * @param string $langcode
  839. * The used language code.
  840. *
  841. * @return array
  842. * The expected and actual English values.
  843. */
  844. protected function getEnglishValues($node, $langcode = 'en') {
  845. return array(
  846. 'body' => array(
  847. 'expected' => 'This is the body',
  848. 'actual' => $node->body[$langcode][0]['value'],
  849. ),
  850. 'field_date' => array(
  851. 'expected' => '2015-10-21T00:00:00',
  852. 'actual' => $node->field_date[$langcode][0]['value'],
  853. ),
  854. 'field_datestamp' => array(
  855. 'expected' => '1445470140',
  856. 'actual' => $node->field_datestamp[$langcode][0]['value'],
  857. ),
  858. 'field_datetime' => array(
  859. 'expected' => '2015-10-21 23:29:00',
  860. 'actual' => $node->field_datetime[$langcode][0]['value'],
  861. ),
  862. 'field_image' => array(
  863. 'expected' => 'foosball.jpeg',
  864. 'actual' => $node->field_image[$langcode][0]['filename'],
  865. ),
  866. 'field_image:alt' => array(
  867. 'expected' => 'Foosball',
  868. 'actual' => $node->field_image[$langcode][0]['alt'],
  869. ),
  870. 'field_image:title' => array(
  871. 'expected' => 'Foosball played by two guys',
  872. 'actual' => $node->field_image[$langcode][0]['title'],
  873. ),
  874. 'field_link' => array(
  875. 'expected' => 'http://google.ca',
  876. 'actual' => $node->field_link[$langcode][0]['url'],
  877. ),
  878. 'field_list_boolean' => array(
  879. 'expected' => '0',
  880. 'actual' => $node->field_list_boolean[$langcode][0]['value'],
  881. ),
  882. 'field_number_decimal' => array(
  883. 'expected' => 4.2,
  884. 'actual' => $node->field_number_decimal[$langcode][0]['value'],
  885. ),
  886. 'field_number_float' => array(
  887. 'expected' => 3.1416,
  888. 'actual' => $node->field_number_float[$langcode][0]['value'],
  889. ),
  890. 'field_number_integer' => array(
  891. 'expected' => 1000,
  892. 'actual' => $node->field_number_integer[$langcode][0]['value'],
  893. ),
  894. 'field_text' => array(
  895. 'expected' => 'Carrots',
  896. 'actual' => $node->field_text[$langcode][0]['value'],
  897. ),
  898. );
  899. }
  900. /**
  901. * Returns expected and actual values of given node for the French language.
  902. *
  903. * @param object $node
  904. * The multilingual node.
  905. * @param string $langcode
  906. * The used language code.
  907. *
  908. * @return array
  909. * The expected and actual French values.
  910. */
  911. protected function getFrenchValues($node, $langcode = 'fr') {
  912. return array(
  913. 'body' => array(
  914. 'expected' => 'Ceci est la corps',
  915. 'actual' => $node->body[$langcode][0]['value'],
  916. ),
  917. 'field_date' => array(
  918. 'expected' => '1955-11-05T00:00:00',
  919. 'actual' => $node->field_date[$langcode][0]['value'],
  920. ),
  921. 'field_datestamp' => array(
  922. 'expected' => '-446731187',
  923. 'actual' => $node->field_datestamp[$langcode][0]['value'],
  924. ),
  925. 'field_datetime' => array(
  926. 'expected' => '1955-11-05 12:00:13',
  927. 'actual' => $node->field_datetime[$langcode][0]['value'],
  928. ),
  929. 'field_image' => array(
  930. 'expected' => 'la fayette.jpeg',
  931. 'actual' => $node->field_image[$langcode][0]['filename'],
  932. ),
  933. 'field_image:alt' => array(
  934. 'expected' => 'La Fayette',
  935. 'actual' => $node->field_image[$langcode][0]['alt'],
  936. ),
  937. 'field_image:title' => array(
  938. 'expected' => 'la Fayette dans les bois',
  939. 'actual' => $node->field_image[$langcode][0]['title'],
  940. ),
  941. 'field_link' => array(
  942. 'expected' => 'http://google.fr',
  943. 'actual' => $node->field_link[$langcode][0]['url'],
  944. ),
  945. 'field_list_boolean' => array(
  946. 'expected' => '1',
  947. 'actual' => $node->field_list_boolean[$langcode][0]['value'],
  948. ),
  949. 'field_number_decimal' => array(
  950. 'expected' => 1.2,
  951. 'actual' => $node->field_number_decimal[$langcode][0]['value'],
  952. ),
  953. 'field_number_float' => array(
  954. 'expected' => 5.6295,
  955. 'actual' => $node->field_number_float[$langcode][0]['value'],
  956. ),
  957. 'field_number_integer' => array(
  958. 'expected' => 2000,
  959. 'actual' => $node->field_number_integer[$langcode][0]['value'],
  960. ),
  961. 'field_text' => array(
  962. 'expected' => 'Carottes',
  963. 'actual' => $node->field_text[$langcode][0]['value'],
  964. ),
  965. );
  966. }
  967. }