TranslateBehaviorTest.php 32 KB

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