CakePHP действа като преводач и $Model::find()

Прикачих поведението на Translate към един от моите модели и имам някои недостатъци по отношение на това:

1) Ако не запазя данни във всички полета, предадени като параметри, когато прикача поведението към модела, методът $Model::find() не получава вмъкнатите редове.

public $actsAs = array(
    'Translate' => array(
        'title' => 'title_Translation',
        'description' => 'description_Translation',
        'description_long' => 'description_long_Translation'
    )
);

Пример: ако предам на метода $Model::save() само стойност за 'title', данните се записват дори в таблицата i18n, но $Model::find() не получава нищо. Трябва да предам данни за всички полета.

Мога ли да го принудя да извлече тези записи?

2) Как мога да получа всички записи в администраторската страна на приложението (независимо от езика, на който е записан запис), за да ги изброя, така че потребителят да може да ги променя (редактиране на данни, запазване на данни на няколко езика)? В момента мога да получа само записите, които съответстват на текущия език (прочетени от Configure или зададени изрично)..

Благодаря ти!


person Michael    schedule 27.09.2012    source източник
comment
Същият проблем тук. Генерираната заявка прави вътрешно свързване с таблицата за преводи за всяко преведено поле, така че ако поне едно от тях не присъства в таблицата за превод, тогава дори оригиналният запис не се извлича. Ако трябва да добавите ново преведено поле към съществуващия си модел, сте готови.   -  person eleonzx    schedule 16.11.2012
comment
Имах същия проблем и написах някакъв код, за да го поправя... по същество, след като добавите ново преводимо поле, вие изпълнявате този код, за да преминете и добавите новите записи за превод в DB за всички съществуващи редове. Вижте тук: stackoverflow.com/questions/13243785/   -  person joshua.paling    schedule 16.11.2012


Отговори (4)


Добре, може да закъснея малко, но както и да е...

1) Cake използва INNER JOIN при извличане на ред и свързаните с него преводи, така че по принцип няма лесен начин за заобикаляне на това. Трябва да се уверите, че запазвате всяко преводимо поле, всеки път - дори ако просто го запазите като празно. Единствената алтернатива би била да хакнете ядрото, за да го накарате да използва ляво съединение, а не вътрешно съединение - но не го правете.

2) Готварската книга обяснява как да извлечете всички записи тук: http://book.cakephp.org/2.0/en/core-libraries/behaviors/translate.html#retrieve-all-translation-records-for-a-field

Вероятно през повечето време искате да получите само един превод, така че не искате да променяте дефиницията на вашия масив $actsAs['Translate'] във вашия модел. И така, това, което направих, беше да настроя метод в AppModel.php, който променя масива $actsAs['Translate'] в движение:

/*  
 * See http://book.cakephp.org/2.0/en/core-libraries/behaviors/translate.html#using-the-bindtranslation-method
 * This is for making it so we fetch all translations, as opposed to just that of the current locale.
 * Used for eg. editing (multiple translations) via the admin interface.
 */
public function bindAllTranslations(){
    $translatableFields = $this->actsAs['Translate'];

    $keyValueFields = array();
    foreach($translatableFields as $field){
        $keyValueFields[$field] = $field.'Translation';
    }

    $this->bindTranslation($keyValueFields,false);  // false means it will be changed for all future DB transactions in this page request - and won't be reset after the next transaction.
}

Така че, ако това е администраторски метод (или всяка друга ситуация, в която искате всички преводи), вие извиквате този код, преди да направите намиране:

$this->MyModel->bindAllTranslations();
$this->MyModel->find('all');

Надявам се това да помогне!

person joshua.paling    schedule 16.11.2012

Някак си го реших, копирах TranslateBehavior в app/Model/Behavior (само за да избегна проблеми при бъдещи надстройки и да запазя оригиналния за всеки случай), след което промених метода _addJoin(...) на поведението, просто промених типът на съединението от INNER към LEFT на ред 255 (използвам торта 2.2.3).

Сега, ако съществува запис, той винаги се извлича, дори ако преведените полета липсват.

Не виждам никакви недостатъци, освен необходимостта да проверявате дали полето за превод е празно.

person eleonzx    schedule 16.11.2012

Не съм съвсем сигурен дали ще помогне във вашия случай, но можете също да използвате array, за да зададете локал, преди да извикате find()

$this->YourModel->locale = array("ENG", "GER", "JAP");

По този начин винаги ще получавате всички записи, дори и да нямат всички възможни преводи.

person Zbigniew Ledwoń    schedule 04.05.2015

Благодаря много eleonzx, имам този проблем от десетилетие и с вашия прост отговор вече мога да продължа напред! Така че благодаря отново.

И може би този код може да помогне на много хора:

в моя метод AppController beforeFilter извиквам _setLanguage

private function _setLanguage() {
    if($this->Session->read('Config.language')){
        $locale = $this->Session->read('Config.language');
        $this->{$this->modelClass}->setLocale($locale);
    }else{
        $this->{$this->modelClass}->Behaviors->disable('Translate');
    }
}

С условието else деактивирам поведението на превода в движение, за да получа оригиналното съдържание, ако в сесията няма зададен локал (използвам основни връзки за превключване между езици).

person Chris Carton    schedule 11.01.2017