map(function (EntityInterface $row) { $translations = $row->get('_translations'); if (!$translations) { return []; } return array_map(function (EntityInterface $entity) { return $entity->toArray(); }, $translations); }); } /** * Tests that custom translation tables are respected * * @return void */ public function testCustomTranslationTable() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', [ 'translationTable' => '\TestApp\Model\Table\I18nTable', 'fields' => ['title', 'body'], ]); $items = $table->associations(); $i18n = $items->getByProperty('_i18n'); $this->assertEquals('\TestApp\Model\Table\I18nTable', $i18n->getName()); $this->assertInstanceOf('TestApp\Model\Table\I18nTable', $i18n->getTarget()); $this->assertEquals('test_custom_i18n_datasource', $i18n->getTarget()->getConnection()->configName()); $this->assertEquals('custom_i18n_table', $i18n->getTarget()->getTable()); } /** * Tests that the strategy can be changed for i18n * * @return void */ public function testStrategy() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', [ 'strategy' => 'select', 'fields' => ['title', 'body'], ]); $items = $table->associations(); $i18n = $items->getByProperty('_i18n'); $this->assertEquals('select', $i18n->getStrategy()); } /** * Tests that fields from a translated model are overridden * * @return void */ public function testFindSingleLocale() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->setLocale('eng'); $results = $table->find()->combine('title', 'body', 'id')->toArray(); $expected = [ 1 => ['Title #1' => 'Content #1'], 2 => ['Title #2' => 'Content #2'], 3 => ['Title #3' => 'Content #3'], ]; $this->assertSame($expected, $results); } /** * Test that iterating in a formatResults() does not drop data. * * @return void */ public function testFindTranslationsFormatResultsIteration() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->setLocale('eng'); $results = $table->find('translations') ->limit(1) ->formatResults(function ($results) { foreach ($results as $res) { $res->first = 'val'; } foreach ($results as $res) { $res->second = 'loop'; } return $results; }) ->toArray(); $this->assertCount(1, $results); $this->assertSame('Title #1', $results[0]->title); $this->assertSame('val', $results[0]->first); $this->assertSame('loop', $results[0]->second); $this->assertNotEmpty($results[0]->_translations); } /** * Tests that fields from a translated model use the I18n class locale * and that it propagates to associated models * * @return void */ public function testFindSingleLocaleAssociatedEnv() { I18n::setLocale('eng'); $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->hasMany('Comments'); $table->Comments->addBehavior('Translate', ['fields' => ['comment']]); $results = $table->find() ->select(['id', 'title', 'body']) ->contain(['Comments' => ['fields' => ['article_id', 'comment']]]) ->enableHydration(false) ->toArray(); $expected = [ [ 'id' => 1, 'title' => 'Title #1', 'body' => 'Content #1', 'comments' => [ ['article_id' => 1, 'comment' => 'Comment #1', '_locale' => 'eng'], ['article_id' => 1, 'comment' => 'Comment #2', '_locale' => 'eng'], ['article_id' => 1, 'comment' => 'Comment #3', '_locale' => 'eng'], ['article_id' => 1, 'comment' => 'Comment #4', '_locale' => 'eng'], ], '_locale' => 'eng', ], [ 'id' => 2, 'title' => 'Title #2', 'body' => 'Content #2', 'comments' => [ ['article_id' => 2, 'comment' => 'First Comment for Second Article', '_locale' => 'eng'], ['article_id' => 2, 'comment' => 'Second Comment for Second Article', '_locale' => 'eng'], ], '_locale' => 'eng', ], [ 'id' => 3, 'title' => 'Title #3', 'body' => 'Content #3', 'comments' => [], '_locale' => 'eng', ], ]; $this->assertSame($expected, $results); I18n::setLocale('spa'); $results = $table->find() ->select(['id', 'title', 'body']) ->contain([ 'Comments' => [ 'fields' => ['article_id', 'comment'], 'sort' => ['Comments.id' => 'ASC'], ], ]) ->enableHydration(false) ->toArray(); $expected = [ [ 'id' => 1, 'title' => 'First Article', 'body' => 'Contenido #1', 'comments' => [ ['article_id' => 1, 'comment' => 'First Comment for First Article', '_locale' => 'spa'], ['article_id' => 1, 'comment' => 'Second Comment for First Article', '_locale' => 'spa'], ['article_id' => 1, 'comment' => 'Third Comment for First Article', '_locale' => 'spa'], ['article_id' => 1, 'comment' => 'Comentario #4', '_locale' => 'spa'], ], '_locale' => 'spa', ], [ 'id' => 2, 'title' => 'Second Article', 'body' => 'Second Article Body', 'comments' => [ ['article_id' => 2, 'comment' => 'First Comment for Second Article', '_locale' => 'spa'], ['article_id' => 2, 'comment' => 'Second Comment for Second Article', '_locale' => 'spa'], ], '_locale' => 'spa', ], [ 'id' => 3, 'title' => 'Third Article', 'body' => 'Third Article Body', 'comments' => [], '_locale' => 'spa', ], ]; $this->assertSame($expected, $results); } /** * Tests that fields from a translated model are not overridden if translation * is null * * @return void */ public function testFindSingleLocaleWithNullTranslation() { $table = $this->getTableLocator()->get('Comments'); $table->addBehavior('Translate', ['fields' => ['comment']]); $table->setLocale('spa'); $results = $table->find() ->where(['Comments.id' => 6]) ->combine('id', 'comment')->toArray(); $expected = [6 => 'Second Comment for Second Article']; $this->assertSame($expected, $results); } /** * Tests that overriding fields with the translate behavior works when * using conditions and that all other columns are preserved * * @return void */ public function testFindSingleLocaleWithgetConditions() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->setLocale('eng'); $results = $table->find() ->where(['Articles.id' => 2]) ->all(); $this->assertCount(1, $results); $row = $results->first(); $expected = [ 'id' => 2, 'title' => 'Title #2', 'body' => 'Content #2', 'author_id' => 3, 'published' => 'Y', '_locale' => 'eng', ]; $this->assertEquals($expected, $row->toArray()); } /** * Tests the deprecated locale method. * * @group deprecated * @return void */ public function testLocale() { $this->deprecated(function () { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate'); $this->assertEquals('en_US', $table->locale()); $table->locale('fr_FR'); $this->assertEquals('fr_FR', $table->locale()); $table->locale(false); $this->assertEquals('en_US', $table->locale()); I18n::setLocale('fr_FR'); $this->assertEquals('fr_FR', $table->locale()); }); } /** * Tests the locale setter/getter. * * @return void */ public function testSetGetLocale() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate'); $this->assertEquals('en_US', $table->getLocale()); $table->setLocale('fr_FR'); $this->assertEquals('fr_FR', $table->getLocale()); $table->setLocale(null); $this->assertEquals('en_US', $table->getLocale()); I18n::setLocale('fr_FR'); $this->assertEquals('fr_FR', $table->getLocale()); } /** * Tests translationField method for translated fields. * * @return void */ public function testTranslationFieldForTranslatedFields() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', [ 'fields' => ['title', 'body'], 'defaultLocale' => 'en_US', ]); $expectedSameLocale = 'Articles.title'; $expectedOtherLocale = 'Articles_title_translation.content'; $field = $table->translationField('title'); $this->assertSame($expectedSameLocale, $field); I18n::setLocale('es_ES'); $field = $table->translationField('title'); $this->assertSame($expectedOtherLocale, $field); I18n::setLocale('en'); $field = $table->translationField('title'); $this->assertSame($expectedOtherLocale, $field); $table->removeBehavior('Translate'); $table->addBehavior('Translate', [ 'fields' => ['title', 'body'], 'defaultLocale' => 'de_DE', ]); I18n::setLocale('de_DE'); $field = $table->translationField('title'); $this->assertSame($expectedSameLocale, $field); I18n::setLocale('en_US'); $field = $table->translationField('title'); $this->assertSame($expectedOtherLocale, $field); $table->setLocale('de_DE'); $field = $table->translationField('title'); $this->assertSame($expectedSameLocale, $field); $table->setLocale('es'); $field = $table->translationField('title'); $this->assertSame($expectedOtherLocale, $field); } /** * Tests translationField method for other fields. * * @return void */ public function testTranslationFieldForOtherFields() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $expected = 'Articles.foo'; $field = $table->translationField('foo'); $this->assertSame($expected, $field); } /** * Tests that translating fields work when other formatters are used * * @return void */ public function testFindList() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->setLocale('eng'); $results = $table->find('list')->toArray(); $expected = [1 => 'Title #1', 2 => 'Title #2', 3 => 'Title #3']; $this->assertSame($expected, $results); } /** * Tests that the query count return the correct results * * @return void */ public function testFindCount() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->setLocale('eng'); $this->assertEquals(3, $table->find()->count()); } /** * Tests that it is possible to get all translated fields at once * * @return void */ public function testFindTranslations() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $results = $table->find('translations'); $expected = [ [ 'eng' => ['title' => 'Title #1', 'body' => 'Content #1', 'description' => 'Description #1', 'locale' => 'eng'], 'deu' => ['title' => 'Titel #1', 'body' => 'Inhalt #1', 'locale' => 'deu'], 'cze' => ['title' => 'Titulek #1', 'body' => 'Obsah #1', 'locale' => 'cze'], 'spa' => ['body' => 'Contenido #1', 'locale' => 'spa', 'description' => ''], ], [ 'eng' => ['title' => 'Title #2', 'body' => 'Content #2', 'locale' => 'eng'], 'deu' => ['title' => 'Titel #2', 'body' => 'Inhalt #2', 'locale' => 'deu'], 'cze' => ['title' => 'Titulek #2', 'body' => 'Obsah #2', 'locale' => 'cze'], ], [ 'eng' => ['title' => 'Title #3', 'body' => 'Content #3', 'locale' => 'eng'], 'deu' => ['title' => 'Titel #3', 'body' => 'Inhalt #3', 'locale' => 'deu'], 'cze' => ['title' => 'Titulek #3', 'body' => 'Obsah #3', 'locale' => 'cze'], ], ]; $translations = $this->_extractTranslations($results); $this->assertEquals($expected, $translations->toArray()); $expected = [ 1 => ['First Article' => 'First Article Body'], 2 => ['Second Article' => 'Second Article Body'], 3 => ['Third Article' => 'Third Article Body'], ]; $grouped = $results->combine('title', 'body', 'id'); $this->assertEquals($expected, $grouped->toArray()); } /** * Tests that it is possible to request just a few translations * * @return void */ public function testFindFilteredTranslations() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $results = $table->find('translations', ['locales' => ['deu', 'cze']]); $expected = [ [ 'deu' => ['title' => 'Titel #1', 'body' => 'Inhalt #1', 'locale' => 'deu'], 'cze' => ['title' => 'Titulek #1', 'body' => 'Obsah #1', 'locale' => 'cze'], ], [ 'deu' => ['title' => 'Titel #2', 'body' => 'Inhalt #2', 'locale' => 'deu'], 'cze' => ['title' => 'Titulek #2', 'body' => 'Obsah #2', 'locale' => 'cze'], ], [ 'deu' => ['title' => 'Titel #3', 'body' => 'Inhalt #3', 'locale' => 'deu'], 'cze' => ['title' => 'Titulek #3', 'body' => 'Obsah #3', 'locale' => 'cze'], ], ]; $translations = $this->_extractTranslations($results); $this->assertEquals($expected, $translations->toArray()); $expected = [ 1 => ['First Article' => 'First Article Body'], 2 => ['Second Article' => 'Second Article Body'], 3 => ['Third Article' => 'Third Article Body'], ]; $grouped = $results->combine('title', 'body', 'id'); $this->assertEquals($expected, $grouped->toArray()); } /** * Tests that it is possible to combine find('list') and find('translations') * * @return void */ public function testFindTranslationsList() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $results = $table ->find('list', [ 'keyField' => 'title', 'valueField' => '_translations.deu.title', 'groupField' => 'id', ]) ->find('translations', ['locales' => ['deu']]); $expected = [ 1 => ['First Article' => 'Titel #1'], 2 => ['Second Article' => 'Titel #2'], 3 => ['Third Article' => 'Titel #3'], ]; $this->assertEquals($expected, $results->toArray()); } /** * Tests that you can both override fields and find all translations * * @return void */ public function testFindTranslationsWithFieldOverriding() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->setLocale('cze'); $results = $table->find('translations', ['locales' => ['deu', 'cze']]); $expected = [ [ 'deu' => ['title' => 'Titel #1', 'body' => 'Inhalt #1', 'locale' => 'deu'], 'cze' => ['title' => 'Titulek #1', 'body' => 'Obsah #1', 'locale' => 'cze'], ], [ 'deu' => ['title' => 'Titel #2', 'body' => 'Inhalt #2', 'locale' => 'deu'], 'cze' => ['title' => 'Titulek #2', 'body' => 'Obsah #2', 'locale' => 'cze'], ], [ 'deu' => ['title' => 'Titel #3', 'body' => 'Inhalt #3', 'locale' => 'deu'], 'cze' => ['title' => 'Titulek #3', 'body' => 'Obsah #3', 'locale' => 'cze'], ], ]; $translations = $this->_extractTranslations($results); $this->assertEquals($expected, $translations->toArray()); $expected = [ 1 => ['Titulek #1' => 'Obsah #1'], 2 => ['Titulek #2' => 'Obsah #2'], 3 => ['Titulek #3' => 'Obsah #3'], ]; $grouped = $results->combine('title', 'body', 'id'); $this->assertEquals($expected, $grouped->toArray()); } /** * Tests that fields can be overridden in a hasMany association * * @return void */ public function testFindSingleLocaleHasMany() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->hasMany('Comments'); $comments = $table->hasMany('Comments')->getTarget(); $comments->addBehavior('Translate', ['fields' => ['comment']]); $table->setLocale('eng'); $comments->setLocale('eng'); $results = $table->find()->contain(['Comments' => function ($q) { return $q->select(['id', 'comment', 'article_id']); }]); $list = new Collection($results->first()->comments); $expected = [ 1 => 'Comment #1', 2 => 'Comment #2', 3 => 'Comment #3', 4 => 'Comment #4', ]; $this->assertEquals($expected, $list->combine('id', 'comment')->toArray()); } /** * Test that it is possible to bring translations from hasMany relations * * @return void */ public function testTranslationsHasMany() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->hasMany('Comments'); $comments = $table->hasMany('Comments')->getTarget(); $comments->addBehavior('Translate', ['fields' => ['comment']]); $results = $table->find('translations')->contain([ 'Comments' => function ($q) { return $q->find('translations')->select(['id', 'comment', 'article_id']); }, ]); $comments = $results->first()->comments; $expected = [ [ 'eng' => ['comment' => 'Comment #1', 'locale' => 'eng'], ], [ 'eng' => ['comment' => 'Comment #2', 'locale' => 'eng'], ], [ 'eng' => ['comment' => 'Comment #3', 'locale' => 'eng'], ], [ 'eng' => ['comment' => 'Comment #4', 'locale' => 'eng'], 'spa' => ['comment' => 'Comentario #4', 'locale' => 'spa'], ], ]; $translations = $this->_extractTranslations($comments); $this->assertEquals($expected, $translations->toArray()); } /** * Tests that it is possible to both override fields with a translation and * also find separately other translations * * @return void */ public function testTranslationsHasManyWithOverride() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->hasMany('Comments'); $comments = $table->hasMany('Comments')->getTarget(); $comments->addBehavior('Translate', ['fields' => ['comment']]); $table->setLocale('cze'); $comments->setLocale('eng'); $results = $table->find('translations')->contain([ 'Comments' => function ($q) { return $q->find('translations')->select(['id', 'comment', 'article_id']); }, ]); $comments = $results->first()->comments; $expected = [ 1 => 'Comment #1', 2 => 'Comment #2', 3 => 'Comment #3', 4 => 'Comment #4', ]; $list = new Collection($comments); $this->assertEquals($expected, $list->combine('id', 'comment')->toArray()); $expected = [ [ 'eng' => ['comment' => 'Comment #1', 'locale' => 'eng'], ], [ 'eng' => ['comment' => 'Comment #2', 'locale' => 'eng'], ], [ 'eng' => ['comment' => 'Comment #3', 'locale' => 'eng'], ], [ 'eng' => ['comment' => 'Comment #4', 'locale' => 'eng'], 'spa' => ['comment' => 'Comentario #4', 'locale' => 'spa'], ], ]; $translations = $this->_extractTranslations($comments); $this->assertEquals($expected, $translations->toArray()); $this->assertEquals('Titulek #1', $results->first()->title); $this->assertEquals('Obsah #1', $results->first()->body); } /** * Tests that it is possible to translate belongsTo associations * * @return void */ public function testFindSingleLocaleBelongsto() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $authors = $table->belongsTo('Authors')->getTarget(); $authors->addBehavior('Translate', ['fields' => ['name']]); $table->setLocale('eng'); $authors->setLocale('eng'); $results = $table->find() ->select(['title', 'body']) ->order(['title' => 'asc']) ->contain(['Authors' => function ($q) { return $q->select(['id', 'name']); }]); $expected = [ [ 'title' => 'Title #1', 'body' => 'Content #1', 'author' => ['id' => 1, 'name' => 'May-rianoh', '_locale' => 'eng'], '_locale' => 'eng', ], [ 'title' => 'Title #2', 'body' => 'Content #2', 'author' => ['id' => 3, 'name' => 'larry', '_locale' => 'eng'], '_locale' => 'eng', ], [ 'title' => 'Title #3', 'body' => 'Content #3', 'author' => ['id' => 1, 'name' => 'May-rianoh', '_locale' => 'eng'], '_locale' => 'eng', ], ]; $results = array_map(function ($r) { return $r->toArray(); }, $results->toArray()); $this->assertEquals($expected, $results); } /** * Tests that it is possible to translate belongsTo associations using loadInto * * @return void */ public function testFindSingleLocaleBelongstoLoadInto() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $authors = $table->belongsTo('Authors')->getTarget(); $authors->addBehavior('Translate', ['fields' => ['name']]); $table->setLocale('eng'); $authors->setLocale('eng'); $entity = $table->get(1); $result = $table->loadInto($entity, ['Authors']); $this->assertSame($entity, $result); $this->assertNotEmpty($entity->author); $this->assertNotEmpty($entity->author->name); $expected = $table->get(1, ['contain' => ['Authors']]); $this->assertEquals($expected, $result); $this->assertNotEmpty($entity->author); $this->assertNotEmpty($entity->author->name); } /** * Tests that it is possible to translate belongsToMany associations * * @return void */ public function testFindSingleLocaleBelongsToMany() { $table = $this->getTableLocator()->get('Articles'); $specialTags = $this->getTableLocator()->get('SpecialTags'); $specialTags->addBehavior('Translate', ['fields' => ['extra_info']]); $table->belongsToMany('Tags', [ 'through' => $specialTags, ]); $specialTags->setLocale('eng'); $result = $table->get(2, ['contain' => 'Tags']); $this->assertNotEmpty($result); $this->assertNotEmpty($result->tags); $this->assertEquals('Translated Info', $result->tags[0]->special_tags[0]->extra_info); } /** * Tests that updating an existing record translations work * * @return void */ public function testUpdateSingleLocale() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->setLocale('eng'); $article = $table->find()->first(); $this->assertEquals(1, $article->get('id')); $article->set('title', 'New translated article'); $table->save($article); $this->assertNull($article->get('_i18n')); $article = $table->find()->first(); $this->assertEquals(1, $article->get('id')); $this->assertEquals('New translated article', $article->get('title')); $this->assertEquals('Content #1', $article->get('body')); $table->setLocale(false); $article = $table->find()->first(); $this->assertEquals(1, $article->get('id')); $this->assertEquals('First Article', $article->get('title')); $table->setLocale('eng'); $article->set('title', 'Wow, such translated article'); $article->set('body', 'A translated body'); $table->save($article); $this->assertNull($article->get('_i18n')); $article = $table->find()->first(); $this->assertEquals(1, $article->get('id')); $this->assertEquals('Wow, such translated article', $article->get('title')); $this->assertEquals('A translated body', $article->get('body')); } /** * Tests adding new translation to a record * * @return void */ public function testInsertNewTranslations() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->setLocale('fra'); $article = $table->find()->first(); $this->assertEquals(1, $article->get('id')); $article->set('title', 'Le titre'); $table->save($article); $this->assertEquals('fra', $article->get('_locale')); $article = $table->find()->first(); $this->assertEquals(1, $article->get('id')); $this->assertEquals('Le titre', $article->get('title')); $this->assertEquals('First Article Body', $article->get('body')); $article->set('title', 'Un autre titre'); $article->set('body', 'Le contenu'); $table->save($article); $this->assertNull($article->get('_i18n')); $article = $table->find()->first(); $this->assertEquals('Un autre titre', $article->get('title')); $this->assertEquals('Le contenu', $article->get('body')); } /** * Tests adding new translation to a record * * @return void */ public function testAllowEmptyFalse() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title'], 'allowEmptyTranslations' => false]); $article = $table->find()->first(); $this->assertEquals(1, $article->get('id')); $article = $table->patchEntity($article, [ '_translations' => [ 'fra' => [ 'title' => '', ], ], ]); $table->save($article); // Remove the Behavior to unset the content != '' condition $table->removeBehavior('Translate'); $noFra = $table->I18n->find()->where(['locale' => 'fra'])->first(); $this->assertEmpty($noFra); } /** * Tests adding new translation to a record * * @return void */ public function testMixedAllowEmptyFalse() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body'], 'allowEmptyTranslations' => false]); $article = $table->find()->first(); $this->assertEquals(1, $article->get('id')); $article = $table->patchEntity($article, [ '_translations' => [ 'fra' => [ 'title' => '', 'body' => 'Bonjour', ], ], ]); $table->save($article); $fra = $table->I18n->find() ->where([ 'locale' => 'fra', 'field' => 'body', ]) ->first(); $this->assertSame('Bonjour', $fra->content); // Remove the Behavior to unset the content != '' condition $table->removeBehavior('Translate'); $noTitle = $table->I18n->find() ->where([ 'locale' => 'fra', 'field' => 'title', ]) ->first(); $this->assertEmpty($noTitle); } /** * Tests adding new translation to a record * * @return void */ public function testMultipleAllowEmptyFalse() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body'], 'allowEmptyTranslations' => false]); $article = $table->find()->first(); $this->assertEquals(1, $article->get('id')); $article = $table->patchEntity($article, [ '_translations' => [ 'fra' => [ 'title' => '', 'body' => 'Bonjour', ], 'de' => [ 'title' => 'Titel', 'body' => 'Hallo', ], ], ]); $table->save($article); $fra = $table->I18n->find() ->where([ 'locale' => 'fra', 'field' => 'body', ]) ->first(); $this->assertSame('Bonjour', $fra->content); $deTitle = $table->I18n->find() ->where([ 'locale' => 'de', 'field' => 'title', ]) ->first(); $this->assertSame('Titel', $deTitle->content); $deBody = $table->I18n->find() ->where([ 'locale' => 'de', 'field' => 'body', ]) ->first(); $this->assertSame('Hallo', $deBody->content); // Remove the Behavior to unset the content != '' condition $table->removeBehavior('Translate'); $noTitle = $table->I18n->find() ->where([ 'locale' => 'fra', 'field' => 'title', ]) ->first(); $this->assertEmpty($noTitle); } /** * Tests that it is possible to use the _locale property to specify the language * to use for saving an entity * * @return void */ public function testUpdateTranslationWithLocaleInEntity() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $article = $table->find()->first(); $this->assertEquals(1, $article->get('id')); $article->set('_locale', 'fra'); $article->set('title', 'Le titre'); $table->save($article); $this->assertNull($article->get('_i18n')); $article = $table->find()->first(); $this->assertEquals(1, $article->get('id')); $this->assertEquals('First Article', $article->get('title')); $this->assertEquals('First Article Body', $article->get('body')); $table->setLocale('fra'); $article = $table->find()->first(); $this->assertEquals(1, $article->get('id')); $this->assertEquals('Le titre', $article->get('title')); $this->assertEquals('First Article Body', $article->get('body')); } /** * Tests that translations are added to the whitelist of associations to be * saved * * @return void */ public function testSaveTranslationWithAssociationWhitelist() { $table = $this->getTableLocator()->get('Articles'); $table->hasMany('Comments'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->setLocale('fra'); $article = $table->find()->first(); $this->assertEquals(1, $article->get('id')); $article->set('title', 'Le titre'); $table->save($article, ['associated' => ['Comments']]); $this->assertNull($article->get('_i18n')); $article = $table->find()->first(); $this->assertEquals('Le titre', $article->get('title')); } /** * Tests that after deleting a translated entity, all translations are also removed * * @return void */ public function testDelete() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $article = $table->find()->first(); $this->assertTrue($table->delete($article)); $translations = $this->getTableLocator()->get('I18n')->find() ->where(['model' => 'Articles', 'foreign_key' => $article->id]) ->count(); $this->assertEquals(0, $translations); } /** * Tests saving multiple translations at once when the translations already * exist in the database * * @return void */ public function testSaveMultipleTranslations() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $article = $results = $table->find('translations')->first(); $translations = $article->get('_translations'); $translations['deu']->set('title', 'Another title'); $translations['eng']->set('body', 'Another body'); $article->set('_translations', $translations); $table->save($article); $this->assertNull($article->get('_i18n')); $article = $results = $table->find('translations')->first(); $translations = $article->get('_translations'); $this->assertEquals('Another title', $translations['deu']->get('title')); $this->assertEquals('Another body', $translations['eng']->get('body')); } /** * Tests saving multiple existing translations and adding new ones * * @return void */ public function testSaveMultipleNewTranslations() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $article = $results = $table->find('translations')->first(); $translations = $article->get('_translations'); $translations['deu']->set('title', 'Another title'); $translations['eng']->set('body', 'Another body'); $translations['spa'] = new Entity(['title' => 'Titulo']); $translations['fre'] = new Entity(['title' => 'Titre']); $article->set('_translations', $translations); $table->save($article); $this->assertNull($article->get('_i18n')); $article = $results = $table->find('translations')->first(); $translations = $article->get('_translations'); $this->assertEquals('Another title', $translations['deu']->get('title')); $this->assertEquals('Another body', $translations['eng']->get('body')); $this->assertEquals('Titulo', $translations['spa']->get('title')); $this->assertEquals('Titre', $translations['fre']->get('title')); } /** * Tests that iterating a resultset twice when using the translations finder * will not cause any errors nor information loss * * @return void */ public function testUseCountInFindTranslations() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $articles = $results = $table->find('translations'); $all = $articles->all(); $this->assertCount(3, $all); $article = $all->first(); $this->assertNotEmpty($article->get('_translations')); } /** * Tests that multiple translations saved when having a default locale * are correctly saved * * @return void */ public function testSavingWithNonDefaultLocale() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->setEntityClass(__NAMESPACE__ . '\Article'); I18n::setLocale('fra'); $translations = [ 'fra' => ['title' => 'Un article'], 'spa' => ['title' => 'Un artículo'], ]; $article = $table->get(1); foreach ($translations as $lang => $data) { $article->translation($lang)->set($data, ['guard' => false]); } $table->save($article); $article = $table->find('translations')->where(['Articles.id' => 1])->first(); $this->assertEquals('Un article', $article->translation('fra')->title); $this->assertEquals('Un artículo', $article->translation('spa')->title); } /** * Tests that translation queries are added to union queries as well. * * @return void */ public function testTranslationWithUnionQuery() { $table = $this->getTableLocator()->get('Comments'); $table->addBehavior('Translate', ['fields' => ['comment']]); $table->setLocale('spa'); $query = $table->find()->where(['Comments.id' => 6]); $query2 = $table->find()->where(['Comments.id' => 5]); $query->union($query2); $results = $query->sortBy('id', SORT_ASC)->toList(); $this->assertCount(2, $results); $this->assertEquals('First Comment for Second Article', $results[0]->comment); $this->assertEquals('Second Comment for Second Article', $results[1]->comment); } /** * Tests the use of `referenceName` config option. * * @return void */ public function testAutoReferenceName() { $table = $this->getTableLocator()->get('Articles'); $table->hasMany('OtherComments', ['className' => 'Comments']); $table->OtherComments->addBehavior( 'Translate', ['fields' => ['comment']] ); $items = $table->OtherComments->associations(); $association = $items->getByProperty('comment_translation'); $this->assertNotEmpty($association, 'Translation association not found'); $found = false; foreach ($association->getConditions() as $key => $value) { if (strpos($key, 'comment_translation.model') !== false) { $found = true; $this->assertEquals('Comments', $value); break; } } $this->assertTrue($found, '`referenceName` field condition on a Translation association was not found'); } /** * Tests the use of unconventional `referenceName` config option. * * @return void */ public function testChangingReferenceName() { $table = $this->getTableLocator()->get('Articles'); $table->setAlias('FavoritePost'); $table->addBehavior( 'Translate', ['fields' => ['body'], 'referenceName' => 'Posts'] ); $items = $table->associations(); $association = $items->getByProperty('body_translation'); $this->assertNotEmpty($association, 'Translation association not found'); $found = false; foreach ($association->getConditions() as $key => $value) { if (strpos($key, 'body_translation.model') !== false) { $found = true; $this->assertEquals('Posts', $value); break; } } $this->assertTrue($found, '`referenceName` field condition on a Translation association was not found'); } /** * Tests that onlyTranslated will remove records from the result set * if they are not fully translated * * @return void */ public function testFilterUntranslated() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', [ 'fields' => ['title', 'body'], 'onlyTranslated' => true, ]); $table->setLocale('eng'); $results = $table->find()->where(['Articles.id' => 1])->all(); $this->assertCount(1, $results); $table->setLocale('fr'); $results = $table->find()->where(['Articles.id' => 1])->all(); $this->assertCount(0, $results); } /** * Tests that records not translated in the current locale will not be * present in the results for the translations finder, and also proves * that this can be overridden. * * @return void */ public function testFilterUntranslatedWithFinder() { $table = $this->getTableLocator()->get('Comments'); $table->addBehavior('Translate', [ 'fields' => ['comment'], 'onlyTranslated' => true, ]); $table->setLocale('eng'); $results = $table->find('translations')->all(); $this->assertCount(4, $results); $table->setLocale('spa'); $results = $table->find('translations')->all(); $this->assertCount(1, $results); $table->setLocale('spa'); $results = $table->find('translations', ['filterByCurrentLocale' => false])->all(); $this->assertCount(6, $results); $table->setLocale('spa'); $results = $table->find('translations')->all(); $this->assertCount(1, $results); } /** * Tests that allowEmptyTranslations takes effect * * @return void */ public function testEmptyTranslations() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', [ 'fields' => ['title', 'body', 'description'], 'allowEmptyTranslations' => false, ]); $table->setLocale('spa'); $result = $table->find()->first(); $this->assertNull($result->description); } /** * Test save with clean translate fields * * @return void */ public function testSaveWithCleanFields() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title']]); $table->setEntityClass(__NAMESPACE__ . '\Article'); I18n::setLocale('fra'); $article = $table->get(1); $article->set('body', 'New Body'); $table->save($article); $result = $table->get(1); $this->assertEquals('New Body', $result->body); $this->assertSame($article->title, $result->title); } /** * Test save new entity with _translations field * * @return void */ public function testSaveNewRecordWithTranslatesField() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', [ 'fields' => ['title'], 'validator' => (new \Cake\Validation\Validator())->add('title', 'notBlank', ['rule' => 'notBlank']), ]); $table->setEntityClass(__NAMESPACE__ . '\Article'); $data = [ 'author_id' => 1, 'published' => 'N', '_translations' => [ 'en' => [ 'title' => 'Title EN', 'body' => 'Body EN', ], 'es' => [ 'title' => 'Title ES', ], ], ]; $article = $table->patchEntity($table->newEntity(), $data); $result = $table->save($article); $this->assertNotFalse($result); $expected = [ [ 'en' => [ 'title' => 'Title EN', 'locale' => 'en', ], 'es' => [ 'title' => 'Title ES', 'locale' => 'es', ], ], ]; $result = $table->find('translations')->where(['id' => $result->id]); $this->assertEquals($expected, $this->_extractTranslations($result)->toArray()); } /** * Tests adding new translation to a record where the only field is the translated one and it's not the default locale * * @return void */ public function testSaveNewRecordWithOnlyTranslationsNotDefaultLocale() { $table = $this->getTableLocator()->get('Groups'); $table->addBehavior('Translate', [ 'fields' => ['title'], 'validator' => (new \Cake\Validation\Validator())->add('title', 'notBlank', ['rule' => 'notBlank']), ]); $data = [ '_translations' => [ 'es' => [ 'title' => 'Title ES', ], ], ]; $group = $table->newEntity($data); $result = $table->save($group); $this->assertNotFalse($result, 'Record should save.'); $expected = [ [ 'es' => [ 'title' => 'Title ES', 'locale' => 'es', ], ], ]; $result = $table->find('translations')->where(['id' => $result->id]); $this->assertEquals($expected, $this->_extractTranslations($result)->toArray()); } /** * Test that existing records can be updated when only translations * are modified/dirty. * * @return void */ public function testSaveExistingRecordOnlyTranslations() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->setEntityClass(__NAMESPACE__ . '\Article'); $data = [ '_translations' => [ 'es' => [ 'title' => 'Spanish Translation', ], ], ]; $article = $table->find()->first(); $article = $table->patchEntity($article, $data); $this->assertNotFalse($table->save($article)); $results = $this->_extractTranslations( $table->find('translations')->where(['id' => 1]) )->first(); $this->assertArrayHasKey('es', $results, 'New translation added'); $this->assertArrayHasKey('eng', $results, 'Old translations present'); $this->assertEquals('Spanish Translation', $results['es']['title']); } /** * Test update entity with _translations field. * * @return void */ public function testSaveExistingRecordWithTranslatesField() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->setEntityClass(__NAMESPACE__ . '\Article'); $data = [ 'author_id' => 1, 'published' => 'Y', '_translations' => [ 'eng' => [ 'title' => 'First Article1', 'body' => 'First Article content has been updated', ], 'spa' => [ 'title' => 'Mi nuevo titulo', 'body' => 'Contenido Actualizado', ], ], ]; $article = $table->find()->first(); $article = $table->patchEntity($article, $data); $this->assertNotFalse($table->save($article)); $results = $this->_extractTranslations( $table->find('translations')->where(['id' => 1]) )->first(); $this->assertEquals('Mi nuevo titulo', $results['spa']['title']); $this->assertEquals('Contenido Actualizado', $results['spa']['body']); $this->assertEquals('First Article1', $results['eng']['title']); $this->assertEquals('Description #1', $results['eng']['description']); } /** * Tests that default locale saves ok. * * @return void */ public function testSaveDefaultLocale() { $table = $this->getTableLocator()->get('Articles'); $table->hasMany('Comments'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $article = $table->get(1); $data = [ 'title' => 'New title', 'body' => 'New body', ]; $article = $table->patchEntity($article, $data); $table->save($article); $this->assertNull($article->get('_i18n')); $article = $table->get(1); $this->assertEquals('New title', $article->get('title')); $this->assertEquals('New body', $article->get('body')); } /** * Tests that translations are added to the whitelist of associations to be * saved * * @return void */ public function testSaveTranslationDefaultLocale() { $table = $this->getTableLocator()->get('Articles'); $table->hasMany('Comments'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $article = $table->get(1); $data = [ 'title' => 'New title', 'body' => 'New body', '_translations' => [ 'es' => [ 'title' => 'ES title', 'body' => 'ES body', ], ], ]; $article = $table->patchEntity($article, $data); $table->save($article); $this->assertNull($article->get('_i18n')); $article = $table->find('translations')->where(['id' => 1])->first(); $this->assertEquals('New title', $article->get('title')); $this->assertEquals('New body', $article->get('body')); $this->assertEquals('ES title', $article->_translations['es']->title); $this->assertEquals('ES body', $article->_translations['es']->body); } /** * Test that no properties are enabled when the translations * option is off. * * @return void */ public function testBuildMarshalMapTranslationsOff() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $marshaller = $table->marshaller(); $translate = $table->behaviors()->get('Translate'); $result = $translate->buildMarshalMap($marshaller, [], ['translations' => false]); $this->assertSame([], $result); } /** * Test building a marshal map with translations on. * * @return void */ public function testBuildMarshalMapTranslationsOn() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $marshaller = $table->marshaller(); $translate = $table->behaviors()->get('Translate'); $result = $translate->buildMarshalMap($marshaller, [], ['translations' => true]); $this->assertArrayHasKey('_translations', $result); $this->assertInstanceOf('Closure', $result['_translations']); $result = $translate->buildMarshalMap($marshaller, [], []); $this->assertArrayHasKey('_translations', $result); $this->assertInstanceOf('Closure', $result['_translations']); } /** * Test marshalling non-array data * * @return void */ public function testBuildMarshalMapNonArrayData() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $translate = $table->behaviors()->get('Translate'); $map = $translate->buildMarshalMap($table->marshaller(), [], []); $entity = $table->newEntity(); $result = $map['_translations']('garbage', $entity); $this->assertNull($result, 'Non-array should not error out.'); $this->assertEmpty($entity->getErrors()); $this->assertEmpty($entity->get('_translations')); } /** * Test buildMarshalMap() builds new entities. * * @return void */ public function testBuildMarshalMapBuildEntities() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', ['fields' => ['title', 'body']]); $translate = $table->behaviors()->get('Translate'); $map = $translate->buildMarshalMap($table->marshaller(), [], []); $entity = $table->newEntity(); $data = [ 'en' => [ 'title' => 'English Title', 'body' => 'English Content', ], 'es' => [ 'title' => 'Titulo Español', 'body' => 'Contenido Español', ], ]; $result = $map['_translations']($data, $entity); $this->assertEmpty($entity->getErrors(), 'No validation errors.'); $this->assertCount(2, $result); $this->assertArrayHasKey('en', $result); $this->assertArrayHasKey('es', $result); $this->assertEquals('English Title', $result['en']->title); $this->assertEquals('Titulo Español', $result['es']->title); } /** * Test that validation errors are added to the original entity. * * @return void */ public function testBuildMarshalMapBuildEntitiesValidationErrors() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', [ 'fields' => ['title', 'body'], 'validator' => 'custom', ]); $validator = (new Validator())->add('title', 'notBlank', ['rule' => 'notBlank']); $table->setValidator('custom', $validator); $translate = $table->behaviors()->get('Translate'); $entity = $table->newEntity(); $map = $translate->buildMarshalMap($table->marshaller(), [], []); $data = [ 'en' => [ 'title' => 'English Title', 'body' => 'English Content', ], 'es' => [ 'title' => '', 'body' => 'Contenido Español', ], ]; $result = $map['_translations']($data, $entity); $this->assertNotEmpty($entity->getErrors(), 'Needs validation errors.'); $expected = [ 'title' => [ '_empty' => 'This field cannot be left empty', ], ]; $this->assertEquals($expected, $entity->getError('es')); $this->assertEquals('English Title', $result['en']->title); $this->assertEquals('', $result['es']->title); } /** * Test that marshalling updates existing translation entities. * * @return void */ public function testBuildMarshalMapUpdateExistingEntities() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', [ 'fields' => ['title', 'body'], ]); $translate = $table->behaviors()->get('Translate'); $entity = $table->newEntity(); $es = $table->newEntity(['title' => 'Old title', 'body' => 'Old body']); $en = $table->newEntity(['title' => 'Old title', 'body' => 'Old body']); $entity->set('_translations', [ 'es' => $es, 'en' => $en, ]); $map = $translate->buildMarshalMap($table->marshaller(), [], []); $data = [ 'en' => [ 'title' => 'English Title', ], 'es' => [ 'title' => 'Spanish Title', ], ]; $result = $map['_translations']($data, $entity); $this->assertEmpty($entity->getErrors(), 'No validation errors.'); $this->assertSame($en, $result['en']); $this->assertSame($es, $result['es']); $this->assertSame($en, $entity->get('_translations')['en']); $this->assertSame($es, $entity->get('_translations')['es']); $this->assertEquals('English Title', $result['en']->title); $this->assertEquals('Spanish Title', $result['es']->title); $this->assertEquals('Old body', $result['en']->body); $this->assertEquals('Old body', $result['es']->body); } /** * Test that updating translation records works with validations. * * @return void */ public function testBuildMarshalMapUpdateEntitiesValidationErrors() { $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', [ 'fields' => ['title', 'body'], 'validator' => 'custom', ]); $validator = (new Validator())->add('title', 'notBlank', ['rule' => 'notBlank']); $table->setValidator('custom', $validator); $translate = $table->behaviors()->get('Translate'); $entity = $table->newEntity(); $es = $table->newEntity(['title' => 'Old title', 'body' => 'Old body']); $en = $table->newEntity(['title' => 'Old title', 'body' => 'Old body']); $entity->set('_translations', [ 'es' => $es, 'en' => $en, ]); $map = $translate->buildMarshalMap($table->marshaller(), [], []); $data = [ 'en' => [ 'title' => 'English Title', 'body' => 'English Content', ], 'es' => [ 'title' => '', 'body' => 'Contenido Español', ], ]; $result = $map['_translations']($data, $entity); $this->assertNotEmpty($entity->getErrors(), 'Needs validation errors.'); $expected = [ 'title' => [ '_empty' => 'This field cannot be left empty', ], ]; $this->assertEquals($expected, $entity->getError('es')); } /** * Test that the behavior uses associations' locator. * * @return void */ public function testDefaultTableLocator() { $locator = new TableLocator(); $table = $locator->get('Articles'); $table->addBehavior('Translate', [ 'fields' => ['title', 'body'], 'validator' => 'custom', ]); $behaviorLocator = $table->behaviors()->get('Translate')->getTableLocator(); $this->assertSame($locator, $behaviorLocator); $this->assertSame($table->associations()->getTableLocator(), $behaviorLocator); $this->assertNotSame($this->getTableLocator(), $behaviorLocator); } /** * Test that the behavior uses a custom locator. * * @return void */ public function testCustomTableLocator() { $locator = new TableLocator(); $table = $this->getTableLocator()->get('Articles'); $table->addBehavior('Translate', [ 'fields' => ['title', 'body'], 'validator' => 'custom', 'tableLocator' => $locator, ]); $behaviorLocator = $table->behaviors()->get('Translate')->getTableLocator(); $this->assertSame($locator, $behaviorLocator); $this->assertNotSame($table->associations()->getTableLocator(), $behaviorLocator); $this->assertNotSame($this->getTableLocator(), $behaviorLocator); } /** * Tests that using deep matching doesn't cause an association property to be created. * * @return void */ public function testDeepMatchingDoesNotCreateAssociationProperty() { $table = $this->getTableLocator()->get('Articles'); $table->hasMany('Comments'); $table->Comments->belongsTo('Authors')->setForeignKey('user_id'); $table->Comments->addBehavior('Translate', ['fields' => ['comment']]); $table->Comments->setLocale('abc'); $table->Comments->Authors->addBehavior('Translate', ['fields' => ['name']]); $table->Comments->Authors->setLocale('xyz'); $this->assertNotEquals($table->Comments->getLocale(), I18n::getLocale()); $this->assertNotEquals($table->Comments->Authors->getLocale(), I18n::getLocale()); $result = $table ->find() ->contain('Comments') ->matching('Comments.Authors') ->first(); $this->assertArrayNotHasKey('author', $result->comments); } /** * Tests that the _locale property is set on the entity in the _matchingData property. * * @return void */ public function testLocalePropertyIsSetInMatchingData() { $table = $this->getTableLocator()->get('Articles'); $table->hasMany('Comments'); $table->Comments->addBehavior('Translate', ['fields' => ['comment']]); $table->Comments->setLocale('abc'); $this->assertNotEquals($table->Comments->getLocale(), I18n::getLocale()); $result = $table ->find() ->contain('Comments') ->matching('Comments') ->first(); $this->assertArrayNotHasKey('_locale', $result->comments); $this->assertEquals('abc', $result->_matchingData['Comments']->_locale); } /** * Tests that the _locale property is set on the entity in the _matchingData property * when using deep matching. * * @return void */ public function testLocalePropertyIsSetInMatchingDataWhenUsingDeepMatching() { $table = $this->getTableLocator()->get('Articles'); $table->hasMany('Comments'); $table->Comments->belongsTo('Authors')->setForeignKey('user_id'); $table->Comments->addBehavior('Translate', ['fields' => ['comment']]); $table->Comments->setLocale('abc'); $table->Comments->Authors->addBehavior('Translate', ['fields' => ['name']]); $table->Comments->Authors->setLocale('xyz'); $this->assertNotEquals($table->Comments->getLocale(), I18n::getLocale()); $this->assertNotEquals($table->Comments->Authors->getLocale(), I18n::getLocale()); $result = $table ->find() ->contain('Comments.Authors') ->matching('Comments.Authors') ->first(); $this->assertArrayNotHasKey('_locale', $result->comments); $this->assertEquals('abc', $result->_matchingData['Comments']->_locale); $this->assertEquals('xyz', $result->_matchingData['Authors']->_locale); } /** * Tests that the _locale property is set on the entity in the _matchingData property * when using contained matching. * * @return void */ public function testLocalePropertyIsSetInMatchingDataWhenUsingContainedMatching() { $table = $this->getTableLocator()->get('Authors'); $table->hasMany('Articles'); $table->Articles->belongsToMany('Tags'); $table->Articles->addBehavior('Translate', ['fields' => ['title', 'body']]); $table->Articles->setLocale('abc'); $table->Articles->Tags->addBehavior('Translate', ['fields' => ['name']]); $table->Articles->Tags->setLocale('xyz'); $this->assertNotEquals($table->Articles->getLocale(), I18n::getLocale()); $this->assertNotEquals($table->Articles->Tags->getLocale(), I18n::getLocale()); $result = $table ->find() ->contain([ 'Articles' => function ($query) { return $query->matching('Tags'); }, 'Articles.Tags', ]) ->first(); $this->assertArrayNotHasKey('_locale', $result->articles); $this->assertArrayNotHasKey('_locale', $result->articles[0]->tags); $this->assertEquals('abc', $result->articles[0]->_locale); $this->assertEquals('xyz', $result->articles[0]->_matchingData['Tags']->_locale); } }