TranslateBehaviorTest.php 33 KB

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