OmgDef / yii2-multilingual-behavior

Yii2 port of the yii-multilingual-behavior.
146 stars 60 forks source link

Issue while saving model #15

Closed gagvirus closed 9 years ago

gagvirus commented 9 years ago

I am trying to integrate CKEditor with yii2-multilingual-behavior. Reading translations from database is done with no problem, but when trying to save the data with $model->save() or $model->update() it always returns 0 (no changes made).

    public function actionEdit($slug)
    {
        if(Yii::$app->request->post()) {
            if(isset(Yii::$app->request->post()['editabledata'])) {
                $model = Page::findOne(['slug' => $slug]);
                $model->content = Yii::$app->request->post()['editabledata'];
                if($model->validate()) {
                    // $model->update();
                    var_dump($model->update()); // return 0
                }
            }
        } else {
            return $this->goHome($url);
        }
    }

After observing MultilingualBehavior class, I found out that inside afterUpdate() method (on line 315), when checking if model is relation populated, returns false.

    public function afterUpdate()
    {
        /** @var ActiveRecord $owner */
        $owner = $this->owner;

        if ($owner->isRelationPopulated('translations')) {
            echo ('populated'); // does not come here
            $translations = $this->indexByLanguage($owner->getRelatedRecords()['translations']);
            $this->saveTranslations($translations);
        }
    }

And here is the behaviors() method in my page model

    public function behaviors()
    {
        return [
            'ml' => [
                'class' => MultilingualBehavior::className(),
                'languages' => [
                    'hy' => 'Armenian',
                    'ru' => 'Russian',
                    'en-US' => 'English',
                ],
                'defaultLanguage' => 'hy',
                'langForeignKey' => 'page_id',
                'tableName' => "{{%pageLang}}",
                'attributes' => [
                    'title', 'content', 'menu_name'
                ]
            ],
        ];
    }

Thanks in advance

gagvirus commented 9 years ago

Here is another snippet of testing code code.

    public function actionTest()
    {
        $model = Page::findOne(10);
        $model->title = 'something new';
        $model->save();

    }

Am I doing something wrong ?

gagvirus commented 9 years ago

After debugging about 2 hours I found out, that one reason of such problem is the using of eager loading. So i changed the model request:

$model = Page::find()->with('translations')->where(['slug' => $slug])->one();

Afterwards for some reason the relational find query returns wrong PageLang model. For example, current language is ru, but it returns the ActiveRecord model for hy translation.

    public function actionEdit($slug)
    {
        if(Yii::$app->request->post()) {
            // This is the data collected from CKEditor, and it looks fine
            $data = Yii::$app->request->post()['editabledata']; 

            // The relational query
            $model = Page::find()->with('translations')->where(['slug' => $slug])->one();

            echo $model->title; 
            // this returns the title of wrong language 
            //   (current is ru, returns for hy, same goes for other languages)

        } else {
            ...
        }
    }
OmgDef commented 9 years ago

@gagvirus Please read the documentation. First of all, you should use the scope Page::find()->multilingual()->where(['slug' => $slug])->one(); when you updating your model. And it's better to use save() method on ActiveRecord class, because update method returns number of changed fields in parent table. In actionEdit it will always return 0 Example

public function actionEdit($slug)
{
    if(Yii::$app->request->isPost && isset(Yii::$app->request->post()['editabledata'])) {
        $model = Page::find()->multilingual()->where(['slug' => $slug])->limit(1)->one();
        if (is_null($model)) {
            //throw not found exception here
        }

        $model->content = Yii::$app->request->post()['editabledata'];
        if($model->save()) {  // save() === validate() + update()
            return $this->redirect(['somewhere']);
        }
    } else {
        return $this->goHome($url);
    }
}

Also, when the translations relation populated your title attribute will always the same as defaultLanguage. In your case it equals hy If for any reason you are not satisfied with this behavior, you should not specify the default language. Then the default language will always be equal to the current language.

gagvirus commented 9 years ago

@OmgDef thank you for response. Actually, I read your documentation. I forgot to mention that current site is multilingual (can change current language with language switcher), the selected language is displayed like example.com/ru/page.

While displaying the post when I call echo $model->title it returns the related ActiveRecords (translation) title, as is mentioned in the documentation. I just dont understand why reading is OK, but updating is not.

After using Your code snippet, when I var_dump the model $model = Page::find()->multilingual()->where(['slug' => $slug])->limit(1)->one();, it returns the armenian translation, instead of russian (which is actually selected and displayed properly).

Thank you in advance.

OmgDef commented 9 years ago

@gagvirus Sorry, it's my fault. You should remove limit(1)

gagvirus commented 9 years ago

Well, that did not solve the problem actually...

        // current language is Russian
        $model = Page::find()->multilingual()->where(['slug' => $slug])->one();

        // Returns 'ru'
        var_dump(Yii::$app->language);

        // echoes 'content' for Armenian
        echo $model->content;

        $model->content = 'Something for Russian';
        $model->save();
        // Saves the content in row for Armenian
OmgDef commented 9 years ago

@gagvirus submit the issue. I have the same problem in this case

gagvirus commented 9 years ago

First of all, there is no actual form. I am using CKEditor with inlineSave plugin for it, This plugin requires a file or url, which will handle the request sent by the CKEditor, and it sends as $_POST['editabledata']. In the plugin configuration I have set 'page/edit/'.$slug. In the page/edit action method I wrote the code, which I sent You before.

Well, mainly I don't understand one thing: why while reading right results are returned, but while updating, it works only for default, as the (Yii::$app->language); property has always the right value.

here are some sample rows

1 2

from the db

OmgDef commented 9 years ago

@gagvirus

public function testCreate()
    {
        $post = new Post();

        $data = [
            'title' => 'EN title',
            'body' => 'En body',
        ];
        $formName = $post->formName();
        if (!empty($formName)) {
            $data = [$formName => $data];
        }
        $post->load($data);
        $post->save();

        $post = Post::find()->multilingual()->where(['id' => $post->id])->one();
        $this->printInfo($post);

        Yii::$app->language = 'ru';
        $post = Post::find()->multilingual()->where(['id' => $post->id])->one();
        $post->title = 'ru title';
        $post->body = 'ru body';
        $post->save();

        $post = Post::find()->multilingual()->where(['id' => $post->id])->one();
        $this->printInfo($post);
    }

    protected function printInfo($post)
    {
        echo "The language is " . Yii::$app->language . "\n";
        echo "Title is " . $post->title . "\n";
    }

Output

The language is en-US
Title is EN title
The language is ru
Title is ru title
OmgDef commented 9 years ago

@gagvirus Configuration

    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            'ml' => [
                'class' => MultilingualBehavior::className(),
                'languages' => [
                    'ru' => 'Russian',
                    'en-US' => 'English',
                ],
                'langForeignKey' => 'post_id',
                'tableName' => "{{%postLang}}",
                'attributes' => [
                    'title', 'body',
                ]
            ],
        ];
    }
gagvirus commented 9 years ago

Well, actually removing the default language partially solved the problem. Though the other problem is not concerned with this repository. @OmgDef thank You very much for Your help.