TranslateBehaviorTest.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\ORM\Behavior;
  16. use Cake\Collection\Collection;
  17. use Cake\Event\Event;
  18. use Cake\I18n\I18n;
  19. use Cake\ORM\Behavior\TranslateBehavior;
  20. use Cake\ORM\Behavior\Translate\TranslateTrait;
  21. use Cake\ORM\Entity;
  22. use Cake\ORM\TableRegistry;
  23. use Cake\TestSuite\TestCase;
  24. /**
  25. * Stub entity class
  26. */
  27. class Article extends Entity
  28. {
  29. use TranslateTrait;
  30. }
  31. /**
  32. * Translate behavior test case
  33. */
  34. class TranslateBehaviorTest extends TestCase
  35. {
  36. /**
  37. * fixtures
  38. *
  39. * @var array
  40. */
  41. public $fixtures = [
  42. 'core.translates',
  43. 'core.articles',
  44. 'core.comments',
  45. 'core.authors'
  46. ];
  47. public function tearDown()
  48. {
  49. parent::tearDown();
  50. I18n::locale(I18n::defaultLocale());
  51. TableRegistry::clear();
  52. }
  53. /**
  54. * Returns an array with all the translations found for a set of records
  55. *
  56. * @param array|\Traversable $data
  57. * @return Collection
  58. */
  59. protected function _extractTranslations($data)
  60. {
  61. return (new Collection($data))->map(function ($row) {
  62. $translations = $row->get('_translations');
  63. if (!$translations) {
  64. return [];
  65. }
  66. return array_map(function ($t) {
  67. return $t->toArray();
  68. }, $translations);
  69. });
  70. }
  71. /**
  72. * Tests that custom translation tables are respected
  73. *
  74. * @return void
  75. */
  76. public function testCustomTranslationTable()
  77. {
  78. $table = TableRegistry::get('Articles');
  79. $table->addBehavior('Translate', [
  80. 'translationTable' => '\TestApp\Model\Table\I18nTable',
  81. 'fields' => ['title', 'body']
  82. ]);
  83. $items = $table->associations();
  84. $i18n = $items->getByProperty('_i18n');
  85. $this->assertEquals('TestApp-Model-Table-I18nTable', $i18n->name());
  86. $this->assertEquals('custom_i18n_table', $i18n->target()->table());
  87. $this->assertEquals('test_custom_i18n_datasource', $i18n->target()->connection()->configName());
  88. }
  89. /**
  90. * Tests that the strategy can be changed for i18n
  91. *
  92. * @return void
  93. */
  94. public function testStrategy()
  95. {
  96. $table = TableRegistry::get('Articles');
  97. $table->addBehavior('Translate', [
  98. 'strategy' => 'select',
  99. 'fields' => ['title', 'body']
  100. ]);
  101. $items = $table->associations();
  102. $i18n = $items->getByProperty('_i18n');
  103. $this->assertEquals('select', $i18n->strategy());
  104. }
  105. /**
  106. * Tests that fields from a translated model are overriden
  107. *
  108. * @return void
  109. */
  110. public function testFindSingleLocale()
  111. {
  112. $table = TableRegistry::get('Articles');
  113. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  114. $table->locale('eng');
  115. $results = $table->find()->combine('title', 'body', 'id')->toArray();
  116. $expected = [
  117. 1 => ['Title #1' => 'Content #1'],
  118. 2 => ['Title #2' => 'Content #2'],
  119. 3 => ['Title #3' => 'Content #3'],
  120. ];
  121. $this->assertSame($expected, $results);
  122. }
  123. /**
  124. * Tests that fields from a translated model use the I18n class locale
  125. * and that it propogates to associated models
  126. *
  127. * @return void
  128. */
  129. public function testFindSingleLocaleAssociatedEnv()
  130. {
  131. I18n::locale('eng');
  132. $table = TableRegistry::get('Articles');
  133. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  134. $table->hasMany('Comments');
  135. $table->Comments->addBehavior('Translate', ['fields' => ['comment']]);
  136. $results = $table->find()
  137. ->select(['id', 'title', 'body'])
  138. ->contain(['Comments' => ['fields' => ['article_id', 'comment']]])
  139. ->hydrate(false)
  140. ->toArray();
  141. $expected = [
  142. [
  143. 'id' => 1,
  144. 'title' => 'Title #1',
  145. 'body' => 'Content #1',
  146. 'comments' => [
  147. ['article_id' => 1, 'comment' => 'Comment #1', '_locale' => 'eng'],
  148. ['article_id' => 1, 'comment' => 'Comment #2', '_locale' => 'eng'],
  149. ['article_id' => 1, 'comment' => 'Comment #3', '_locale' => 'eng'],
  150. ['article_id' => 1, 'comment' => 'Comment #4', '_locale' => 'eng']
  151. ],
  152. '_locale' => 'eng'
  153. ],
  154. [
  155. 'id' => 2,
  156. 'title' => 'Title #2',
  157. 'body' => 'Content #2',
  158. 'comments' => [
  159. ['article_id' => 2, 'comment' => 'First Comment for Second Article', '_locale' => 'eng'],
  160. ['article_id' => 2, 'comment' => 'Second Comment for Second Article', '_locale' => 'eng']
  161. ],
  162. '_locale' => 'eng'
  163. ],
  164. [
  165. 'id' => 3,
  166. 'title' => 'Title #3',
  167. 'body' => 'Content #3',
  168. 'comments' => [],
  169. '_locale' => 'eng'
  170. ]
  171. ];
  172. $this->assertSame($expected, $results);
  173. I18n::locale('spa');
  174. $results = $table->find()
  175. ->select(['id', 'title', 'body'])
  176. ->contain([
  177. 'Comments' => [
  178. 'fields' => ['article_id', 'comment'],
  179. 'sort' => ['Comments.id' => 'ASC']
  180. ]
  181. ])
  182. ->hydrate(false)
  183. ->toArray();
  184. $expected = [
  185. [
  186. 'id' => 1,
  187. 'title' => 'First Article',
  188. 'body' => 'First Article Body',
  189. 'comments' => [
  190. ['article_id' => 1, 'comment' => 'First Comment for First Article', '_locale' => 'spa'],
  191. ['article_id' => 1, 'comment' => 'Second Comment for First Article', '_locale' => 'spa'],
  192. ['article_id' => 1, 'comment' => 'Third Comment for First Article', '_locale' => 'spa'],
  193. ['article_id' => 1, 'comment' => 'Comentario #4', '_locale' => 'spa']
  194. ],
  195. '_locale' => 'spa'
  196. ],
  197. [
  198. 'id' => 2,
  199. 'title' => 'Second Article',
  200. 'body' => 'Second Article Body',
  201. 'comments' => [
  202. ['article_id' => 2, 'comment' => 'First Comment for Second Article', '_locale' => 'spa'],
  203. ['article_id' => 2, 'comment' => 'Second Comment for Second Article', '_locale' => 'spa']
  204. ],
  205. '_locale' => 'spa'
  206. ],
  207. [
  208. 'id' => 3,
  209. 'title' => 'Third Article',
  210. 'body' => 'Third Article Body',
  211. 'comments' => [],
  212. '_locale' => 'spa'
  213. ]
  214. ];
  215. $this->assertSame($expected, $results);
  216. }
  217. /**
  218. * Tests that fields from a translated model are not overriden if translation
  219. * is null
  220. *
  221. * @return void
  222. */
  223. public function testFindSingleLocaleWithNullTranslation()
  224. {
  225. $table = TableRegistry::get('Comments');
  226. $table->addBehavior('Translate', ['fields' => ['comment']]);
  227. $table->locale('spa');
  228. $results = $table->find()
  229. ->where(['Comments.id' => 6])
  230. ->combine('id', 'comment')->toArray();
  231. $expected = [6 => 'Second Comment for Second Article'];
  232. $this->assertSame($expected, $results);
  233. }
  234. /**
  235. * Tests that overriding fields with the translate behavior works when
  236. * using conditions and that all other columns are preserved
  237. *
  238. * @return void
  239. */
  240. public function testFindSingleLocaleWithConditions()
  241. {
  242. $table = TableRegistry::get('Articles');
  243. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  244. $table->locale('eng');
  245. $results = $table->find()
  246. ->where(['Articles.id' => 2])
  247. ->all();
  248. $this->assertCount(1, $results);
  249. $row = $results->first();
  250. $expected = [
  251. 'id' => 2,
  252. 'title' => 'Title #2',
  253. 'body' => 'Content #2',
  254. 'author_id' => 3,
  255. 'published' => 'Y',
  256. '_locale' => 'eng'
  257. ];
  258. $this->assertEquals($expected, $row->toArray());
  259. }
  260. /**
  261. * Tests that translating fields work when other formatters are used
  262. *
  263. * @return void
  264. */
  265. public function testFindList()
  266. {
  267. $table = TableRegistry::get('Articles');
  268. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  269. $table->locale('eng');
  270. $results = $table->find('list')->toArray();
  271. $expected = [1 => 'Title #1', 2 => 'Title #2', 3 => 'Title #3'];
  272. $this->assertSame($expected, $results);
  273. }
  274. /**
  275. * Tests that the query count return the correct results
  276. *
  277. * @return void
  278. */
  279. public function testFindCount()
  280. {
  281. $table = TableRegistry::get('Articles');
  282. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  283. $table->locale('eng');
  284. $this->assertEquals(3, $table->find()->count());
  285. }
  286. /**
  287. * Tests that it is possible to get all translated fields at once
  288. *
  289. * @return void
  290. */
  291. public function testFindTranslations()
  292. {
  293. $table = TableRegistry::get('Articles');
  294. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  295. $results = $table->find('translations');
  296. $expected = [
  297. [
  298. 'eng' => ['title' => 'Title #1', 'body' => 'Content #1', 'locale' => 'eng'],
  299. 'deu' => ['title' => 'Titel #1', 'body' => 'Inhalt #1', 'locale' => 'deu'],
  300. 'cze' => ['title' => 'Titulek #1', 'body' => 'Obsah #1', 'locale' => 'cze']
  301. ],
  302. [
  303. 'eng' => ['title' => 'Title #2', 'body' => 'Content #2', 'locale' => 'eng'],
  304. 'deu' => ['title' => 'Titel #2', 'body' => 'Inhalt #2', 'locale' => 'deu'],
  305. 'cze' => ['title' => 'Titulek #2', 'body' => 'Obsah #2', 'locale' => 'cze']
  306. ],
  307. [
  308. 'eng' => ['title' => 'Title #3', 'body' => 'Content #3', 'locale' => 'eng'],
  309. 'deu' => ['title' => 'Titel #3', 'body' => 'Inhalt #3', 'locale' => 'deu'],
  310. 'cze' => ['title' => 'Titulek #3', 'body' => 'Obsah #3', 'locale' => 'cze']
  311. ]
  312. ];
  313. $translations = $this->_extractTranslations($results);
  314. $this->assertEquals($expected, $translations->toArray());
  315. $expected = [
  316. 1 => ['First Article' => 'First Article Body'],
  317. 2 => ['Second Article' => 'Second Article Body'],
  318. 3 => ['Third Article' => 'Third Article Body']
  319. ];
  320. $grouped = $results->combine('title', 'body', 'id');
  321. $this->assertEquals($expected, $grouped->toArray());
  322. }
  323. /**
  324. * Tests that it is possible to request just a few translations
  325. *
  326. * @return void
  327. */
  328. public function testFindFilteredTranslations()
  329. {
  330. $table = TableRegistry::get('Articles');
  331. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  332. $results = $table->find('translations', ['locales' => ['deu', 'cze']]);
  333. $expected = [
  334. [
  335. 'deu' => ['title' => 'Titel #1', 'body' => 'Inhalt #1', 'locale' => 'deu'],
  336. 'cze' => ['title' => 'Titulek #1', 'body' => 'Obsah #1', 'locale' => 'cze']
  337. ],
  338. [
  339. 'deu' => ['title' => 'Titel #2', 'body' => 'Inhalt #2', 'locale' => 'deu'],
  340. 'cze' => ['title' => 'Titulek #2', 'body' => 'Obsah #2', 'locale' => 'cze']
  341. ],
  342. [
  343. 'deu' => ['title' => 'Titel #3', 'body' => 'Inhalt #3', 'locale' => 'deu'],
  344. 'cze' => ['title' => 'Titulek #3', 'body' => 'Obsah #3', 'locale' => 'cze']
  345. ]
  346. ];
  347. $translations = $this->_extractTranslations($results);
  348. $this->assertEquals($expected, $translations->toArray());
  349. $expected = [
  350. 1 => ['First Article' => 'First Article Body'],
  351. 2 => ['Second Article' => 'Second Article Body'],
  352. 3 => ['Third Article' => 'Third Article Body']
  353. ];
  354. $grouped = $results->combine('title', 'body', 'id');
  355. $this->assertEquals($expected, $grouped->toArray());
  356. }
  357. /**
  358. * Tests that it is possible to combine find('list') and find('translations')
  359. *
  360. * @return void
  361. */
  362. public function testFindTranslationsList()
  363. {
  364. $table = TableRegistry::get('Articles');
  365. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  366. $results = $table
  367. ->find('list', [
  368. 'idField' => 'title',
  369. 'valueField' => '_translations.deu.title',
  370. 'groupField' => 'id'
  371. ])
  372. ->find('translations', ['locales' => ['deu']]);
  373. $expected = [
  374. 1 => ['First Article' => 'Titel #1'],
  375. 2 => ['Second Article' => 'Titel #2'],
  376. 3 => ['Third Article' => 'Titel #3']
  377. ];
  378. $this->assertEquals($expected, $results->toArray());
  379. }
  380. /**
  381. * Tests that you can both override fields and find all translations
  382. *
  383. * @return void
  384. */
  385. public function testFindTranslationsWithFieldOverriding()
  386. {
  387. $table = TableRegistry::get('Articles');
  388. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  389. $table->locale('cze');
  390. $results = $table->find('translations', ['locales' => ['deu', 'cze']]);
  391. $expected = [
  392. [
  393. 'deu' => ['title' => 'Titel #1', 'body' => 'Inhalt #1', 'locale' => 'deu'],
  394. 'cze' => ['title' => 'Titulek #1', 'body' => 'Obsah #1', 'locale' => 'cze']
  395. ],
  396. [
  397. 'deu' => ['title' => 'Titel #2', 'body' => 'Inhalt #2', 'locale' => 'deu'],
  398. 'cze' => ['title' => 'Titulek #2', 'body' => 'Obsah #2', 'locale' => 'cze']
  399. ],
  400. [
  401. 'deu' => ['title' => 'Titel #3', 'body' => 'Inhalt #3', 'locale' => 'deu'],
  402. 'cze' => ['title' => 'Titulek #3', 'body' => 'Obsah #3', 'locale' => 'cze']
  403. ]
  404. ];
  405. $translations = $this->_extractTranslations($results);
  406. $this->assertEquals($expected, $translations->toArray());
  407. $expected = [
  408. 1 => ['Titulek #1' => 'Obsah #1'],
  409. 2 => ['Titulek #2' => 'Obsah #2'],
  410. 3 => ['Titulek #3' => 'Obsah #3']
  411. ];
  412. $grouped = $results->combine('title', 'body', 'id');
  413. $this->assertEquals($expected, $grouped->toArray());
  414. }
  415. /**
  416. * Tests that fields can be overriden in a hasMany association
  417. *
  418. * @return void
  419. */
  420. public function testFindSingleLocaleHasMany()
  421. {
  422. $table = TableRegistry::get('Articles');
  423. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  424. $table->hasMany('Comments');
  425. $comments = $table->hasMany('Comments')->target();
  426. $comments->addBehavior('Translate', ['fields' => ['comment']]);
  427. $table->locale('eng');
  428. $comments->locale('eng');
  429. $results = $table->find()->contain(['Comments' => function ($q) {
  430. return $q->select(['id', 'comment', 'article_id']);
  431. }]);
  432. $list = new Collection($results->first()->comments);
  433. $expected = [
  434. 1 => 'Comment #1',
  435. 2 => 'Comment #2',
  436. 3 => 'Comment #3',
  437. 4 => 'Comment #4'
  438. ];
  439. $this->assertEquals($expected, $list->combine('id', 'comment')->toArray());
  440. }
  441. /**
  442. * Test that it is possible to bring translations from hasMany relations
  443. *
  444. * @return void
  445. */
  446. public function testTranslationsHasMany()
  447. {
  448. $table = TableRegistry::get('Articles');
  449. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  450. $table->hasMany('Comments');
  451. $comments = $table->hasMany('Comments')->target();
  452. $comments->addBehavior('Translate', ['fields' => ['comment']]);
  453. $results = $table->find('translations')->contain([
  454. 'Comments' => function ($q) {
  455. return $q->find('translations')->select(['id', 'comment', 'article_id']);
  456. }
  457. ]);
  458. $comments = $results->first()->comments;
  459. $expected = [
  460. [
  461. 'eng' => ['comment' => 'Comment #1', 'locale' => 'eng']
  462. ],
  463. [
  464. 'eng' => ['comment' => 'Comment #2', 'locale' => 'eng']
  465. ],
  466. [
  467. 'eng' => ['comment' => 'Comment #3', 'locale' => 'eng']
  468. ],
  469. [
  470. 'eng' => ['comment' => 'Comment #4', 'locale' => 'eng'],
  471. 'spa' => ['comment' => 'Comentario #4', 'locale' => 'spa']
  472. ]
  473. ];
  474. $translations = $this->_extractTranslations($comments);
  475. $this->assertEquals($expected, $translations->toArray());
  476. }
  477. /**
  478. * Tests that it is possible to both override fields with a translation and
  479. * also find separately other translations
  480. *
  481. * @return void
  482. */
  483. public function testTranslationsHasManyWithOverride()
  484. {
  485. $table = TableRegistry::get('Articles');
  486. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  487. $table->hasMany('Comments');
  488. $comments = $table->hasMany('Comments')->target();
  489. $comments->addBehavior('Translate', ['fields' => ['comment']]);
  490. $table->locale('cze');
  491. $comments->locale('eng');
  492. $results = $table->find('translations')->contain([
  493. 'Comments' => function ($q) {
  494. return $q->find('translations')->select(['id', 'comment', 'article_id']);
  495. }
  496. ]);
  497. $comments = $results->first()->comments;
  498. $expected = [
  499. 1 => 'Comment #1',
  500. 2 => 'Comment #2',
  501. 3 => 'Comment #3',
  502. 4 => 'Comment #4'
  503. ];
  504. $list = new Collection($comments);
  505. $this->assertEquals($expected, $list->combine('id', 'comment')->toArray());
  506. $expected = [
  507. [
  508. 'eng' => ['comment' => 'Comment #1', 'locale' => 'eng']
  509. ],
  510. [
  511. 'eng' => ['comment' => 'Comment #2', 'locale' => 'eng']
  512. ],
  513. [
  514. 'eng' => ['comment' => 'Comment #3', 'locale' => 'eng']
  515. ],
  516. [
  517. 'eng' => ['comment' => 'Comment #4', 'locale' => 'eng'],
  518. 'spa' => ['comment' => 'Comentario #4', 'locale' => 'spa']
  519. ]
  520. ];
  521. $translations = $this->_extractTranslations($comments);
  522. $this->assertEquals($expected, $translations->toArray());
  523. $this->assertEquals('Titulek #1', $results->first()->title);
  524. $this->assertEquals('Obsah #1', $results->first()->body);
  525. }
  526. /**
  527. * Tests that it is possible to translate belongsTo associations
  528. *
  529. * @return void
  530. */
  531. public function testFindSingleLocaleBelongsto()
  532. {
  533. $table = TableRegistry::get('Articles');
  534. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  535. $authors = $table->belongsTo('Authors')->target();
  536. $authors->addBehavior('Translate', ['fields' => ['name']]);
  537. $table->locale('eng');
  538. $authors->locale('eng');
  539. $results = $table->find()
  540. ->select(['title', 'body'])
  541. ->order(['title' => 'asc'])
  542. ->contain(['Authors' => function ($q) {
  543. return $q->select(['id', 'name']);
  544. }]);
  545. $expected = [
  546. [
  547. 'title' => 'Title #1',
  548. 'body' => 'Content #1',
  549. 'author' => ['id' => 1, 'name' => 'May-rianoh', '_locale' => 'eng'],
  550. '_locale' => 'eng'
  551. ],
  552. [
  553. 'title' => 'Title #2',
  554. 'body' => 'Content #2',
  555. 'author' => ['id' => 3, 'name' => 'larry', '_locale' => 'eng'],
  556. '_locale' => 'eng'
  557. ],
  558. [
  559. 'title' => 'Title #3',
  560. 'body' => 'Content #3',
  561. 'author' => ['id' => 1, 'name' => 'May-rianoh', '_locale' => 'eng'],
  562. '_locale' => 'eng'
  563. ]
  564. ];
  565. $results = array_map(function ($r) {
  566. return $r->toArray();
  567. }, $results->toArray());
  568. $this->assertEquals($expected, $results);
  569. }
  570. /**
  571. * Tests that updating an existing record translations work
  572. *
  573. * @return void
  574. */
  575. public function testUpdateSingleLocale()
  576. {
  577. $table = TableRegistry::get('Articles');
  578. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  579. $table->locale('eng');
  580. $article = $table->find()->first();
  581. $this->assertEquals(1, $article->get('id'));
  582. $article->set('title', 'New translated article');
  583. $table->save($article);
  584. $this->assertNull($article->get('_i18n'));
  585. $article = $table->find()->first();
  586. $this->assertEquals(1, $article->get('id'));
  587. $this->assertEquals('New translated article', $article->get('title'));
  588. $this->assertEquals('Content #1', $article->get('body'));
  589. $table->locale(false);
  590. $article = $table->find()->first();
  591. $this->assertEquals(1, $article->get('id'));
  592. $this->assertEquals('First Article', $article->get('title'));
  593. $table->locale('eng');
  594. $article->set('title', 'Wow, such translated article');
  595. $article->set('body', 'A translated body');
  596. $table->save($article);
  597. $this->assertNull($article->get('_i18n'));
  598. $article = $table->find()->first();
  599. $this->assertEquals(1, $article->get('id'));
  600. $this->assertEquals('Wow, such translated article', $article->get('title'));
  601. $this->assertEquals('A translated body', $article->get('body'));
  602. }
  603. /**
  604. * Tests adding new translation to a record
  605. *
  606. * @return void
  607. */
  608. public function testInsertNewTranslations()
  609. {
  610. $table = TableRegistry::get('Articles');
  611. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  612. $table->locale('fra');
  613. $article = $table->find()->first();
  614. $this->assertEquals(1, $article->get('id'));
  615. $article->set('title', 'Le titre');
  616. $table->save($article);
  617. $this->assertEquals('fra', $article->get('_locale'));
  618. $article = $table->find()->first();
  619. $this->assertEquals(1, $article->get('id'));
  620. $this->assertEquals('Le titre', $article->get('title'));
  621. $this->assertEquals('First Article Body', $article->get('body'));
  622. $article->set('title', 'Un autre titre');
  623. $article->set('body', 'Le contenu');
  624. $table->save($article);
  625. $this->assertNull($article->get('_i18n'));
  626. $article = $table->find()->first();
  627. $this->assertEquals('Un autre titre', $article->get('title'));
  628. $this->assertEquals('Le contenu', $article->get('body'));
  629. }
  630. /**
  631. * Tests that it is possible to use the _locale property to specify the language
  632. * to use for saving an entity
  633. *
  634. * @return void
  635. */
  636. public function testUpdateTranslationWithLocaleInEntity()
  637. {
  638. $table = TableRegistry::get('Articles');
  639. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  640. $article = $table->find()->first();
  641. $this->assertEquals(1, $article->get('id'));
  642. $article->set('_locale', 'fra');
  643. $article->set('title', 'Le titre');
  644. $table->save($article);
  645. $this->assertNull($article->get('_i18n'));
  646. $article = $table->find()->first();
  647. $this->assertEquals(1, $article->get('id'));
  648. $this->assertEquals('First Article', $article->get('title'));
  649. $this->assertEquals('First Article Body', $article->get('body'));
  650. $table->locale('fra');
  651. $article = $table->find()->first();
  652. $this->assertEquals(1, $article->get('id'));
  653. $this->assertEquals('Le titre', $article->get('title'));
  654. $this->assertEquals('First Article Body', $article->get('body'));
  655. }
  656. /**
  657. * Tests that translations are added to the whitelist of associations to be
  658. * saved
  659. *
  660. * @return void
  661. */
  662. public function testSaveTranslationWithAssociationWhitelist()
  663. {
  664. $table = TableRegistry::get('Articles');
  665. $table->hasMany('Comments');
  666. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  667. $table->locale('fra');
  668. $article = $table->find()->first();
  669. $this->assertEquals(1, $article->get('id'));
  670. $article->set('title', 'Le titre');
  671. $table->save($article, ['associated' => ['Comments']]);
  672. $this->assertNull($article->get('_i18n'));
  673. $article = $table->find()->first();
  674. $this->assertEquals('Le titre', $article->get('title'));
  675. }
  676. /**
  677. * Tests that after deleting a translated entity, all translations are also removed
  678. *
  679. * @return void
  680. */
  681. public function testDelete()
  682. {
  683. $table = TableRegistry::get('Articles');
  684. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  685. $article = $table->find()->first();
  686. $this->assertTrue($table->delete($article));
  687. $translations = TableRegistry::get('I18n')->find()
  688. ->where(['model' => 'Articles', 'foreign_key' => $article->id])
  689. ->count();
  690. $this->assertEquals(0, $translations);
  691. }
  692. /**
  693. * Tests saving multiple translations at once when the translations already
  694. * exist in the database
  695. *
  696. * @return void
  697. */
  698. public function testSaveMultipleTranslations()
  699. {
  700. $table = TableRegistry::get('Articles');
  701. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  702. $article = $results = $table->find('translations')->first();
  703. $translations = $article->get('_translations');
  704. $translations['deu']->set('title', 'Another title');
  705. $translations['eng']->set('body', 'Another body');
  706. $article->set('_translations', $translations);
  707. $table->save($article);
  708. $this->assertNull($article->get('_i18n'));
  709. $article = $results = $table->find('translations')->first();
  710. $translations = $article->get('_translations');
  711. $this->assertEquals('Another title', $translations['deu']->get('title'));
  712. $this->assertEquals('Another body', $translations['eng']->get('body'));
  713. }
  714. /**
  715. * Tests saving multiple existing translations and adding new ones
  716. *
  717. * @return void
  718. */
  719. public function testSaveMultipleNewTranslations()
  720. {
  721. $table = TableRegistry::get('Articles');
  722. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  723. $article = $results = $table->find('translations')->first();
  724. $translations = $article->get('_translations');
  725. $translations['deu']->set('title', 'Another title');
  726. $translations['eng']->set('body', 'Another body');
  727. $translations['spa'] = new Entity(['title' => 'Titulo']);
  728. $translations['fre'] = new Entity(['title' => 'Titre']);
  729. $article->set('_translations', $translations);
  730. $table->save($article);
  731. $this->assertNull($article->get('_i18n'));
  732. $article = $results = $table->find('translations')->first();
  733. $translations = $article->get('_translations');
  734. $this->assertEquals('Another title', $translations['deu']->get('title'));
  735. $this->assertEquals('Another body', $translations['eng']->get('body'));
  736. $this->assertEquals('Titulo', $translations['spa']->get('title'));
  737. $this->assertEquals('Titre', $translations['fre']->get('title'));
  738. }
  739. /**
  740. * Tests that iterating a resultset twice when using the translations finder
  741. * will not cause any errors nor information loss
  742. *
  743. * @return void
  744. */
  745. public function testUseCountInFindTranslations()
  746. {
  747. $table = TableRegistry::get('Articles');
  748. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  749. $articles = $results = $table->find('translations');
  750. $all = $articles->all();
  751. $this->assertCount(3, $all);
  752. $article = $all->first();
  753. $this->assertNotEmpty($article->get('_translations'));
  754. }
  755. /**
  756. * Tests that multiple translations saved when having a default locale
  757. * are correclty saved
  758. *
  759. * @return void
  760. */
  761. public function testSavingWithNonDefaultLocale()
  762. {
  763. $table = TableRegistry::get('Articles');
  764. $table->addBehavior('Translate', ['fields' => ['title', 'body']]);
  765. $table->entityClass(__NAMESPACE__ . '\Article');
  766. I18n::locale('fra');
  767. $translations = [
  768. 'fra' => ['title' => 'Un article'],
  769. 'spa' => ['title' => 'Un artículo']
  770. ];
  771. $article = $table->get(1);
  772. foreach ($translations as $lang => $data) {
  773. $article->translation($lang)->set($data, ['guard' => false]);
  774. }
  775. $table->save($article);
  776. $article = $table->find('translations')->where(['Articles.id' => 1])->first();
  777. $this->assertEquals('Un article', $article->translation('fra')->title);
  778. $this->assertEquals('Un artículo', $article->translation('spa')->title);
  779. }
  780. /**
  781. * Tests that translation queries are added to union queries as well.
  782. *
  783. * @return void
  784. */
  785. public function testTranslationWithUnionQuery()
  786. {
  787. $table = TableRegistry::get('Comments');
  788. $table->addBehavior('Translate', ['fields' => ['comment']]);
  789. $table->locale('spa');
  790. $query = $table->find()->where(['Comments.id' => 6]);
  791. $query2 = $table->find()->where(['Comments.id' => 5]);
  792. $query->union($query2);
  793. $results = $query->sortBy('id', SORT_ASC)->toList();
  794. $this->assertCount(2, $results);
  795. $this->assertEquals('First Comment for Second Article', $results[0]->comment);
  796. $this->assertEquals('Second Comment for Second Article', $results[1]->comment);
  797. }
  798. /**
  799. * Tests the use of `model` config option.
  800. *
  801. * @return void
  802. */
  803. public function testChangingModelFieldValue()
  804. {
  805. $table = TableRegistry::get('Articles');
  806. $table->hasMany('OtherComments', ['className' => 'Comments']);
  807. $table->OtherComments->addBehavior('Translate', ['fields' => ['comment'], 'model' => 'Comments']);
  808. $items = $table->OtherComments->associations();
  809. $association = $items->getByProperty('comment_translation');
  810. $this->assertNotEmpty($association, 'Translation association not found');
  811. $found = false;
  812. foreach ($association->conditions() as $key => $value) {
  813. if (strpos($key, 'comment_translation.model') !== false) {
  814. $found = true;
  815. $this->assertEquals('Comments', $value);
  816. break;
  817. }
  818. }
  819. $this->assertTrue($found, '`model` field condition on a Translation association was not found');
  820. }
  821. /**
  822. * Tests that onlyTranslated will remove records from the result set
  823. * if they are not fully translated
  824. *
  825. * @return void
  826. */
  827. public function testFilterUntranslated()
  828. {
  829. $table = TableRegistry::get('Articles');
  830. $table->addBehavior('Translate', [
  831. 'fields' => ['title', 'body'],
  832. 'onlyTranslated' => true
  833. ]);
  834. $table->locale('eng');
  835. $results = $table->find()->where(['Articles.id' => 1])->all();
  836. $this->assertCount(1, $results);
  837. $table->locale('fr');
  838. $results = $table->find()->where(['Articles.id' => 1])->all();
  839. $this->assertCount(0, $results);
  840. }
  841. /**
  842. * Tests that records not translated in the current locale will not be
  843. * present in the results for the translations finder, and also proves
  844. * that this can be overridden.
  845. *
  846. * @return void
  847. */
  848. public function testFilterUntranslatedWithFinder()
  849. {
  850. $table = TableRegistry::get('Comments');
  851. $table->addBehavior('Translate', [
  852. 'fields' => ['comment'],
  853. 'onlyTranslated' => true
  854. ]);
  855. $table->locale('eng');
  856. $results = $table->find('translations')->all();
  857. $this->assertCount(4, $results);
  858. $table->locale('spa');
  859. $results = $table->find('translations')->all();
  860. $this->assertCount(1, $results);
  861. $table->locale('spa');
  862. $results = $table->find('translations', ['filterByCurrentLocale' => false])->all();
  863. $this->assertCount(6, $results);
  864. $table->locale('spa');
  865. $results = $table->find('translations')->all();
  866. $this->assertCount(1, $results);
  867. }
  868. }