OmgDef / yii2-multilingual-behavior

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

Localized bug (2.0) #17

Closed andreCatita closed 9 years ago

andreCatita commented 9 years ago

Hello @OmgDef

This is my first issue to you, that I have little info to give you.. But I'm going to explain what I think it might be:

-> localized('ru') worked in version 1.0.

So my team and I implemented your multilingual in a now almost production project. I told you in another bug I reported, that I'm still using the two tables with repeated columns, because like I said, when you changed that we decided it was too late for this project.

Still, I adapted your version 2.0 for other bugs, to support properly the two table system without repeating unnecessary queries. (Basically added an IF, to not query "postLang" for the "default" language)

But we haven't been using localized, and now that I tried it always returns me the values from the 'left' table.

I thought it would be because I have title in both "post" and "postLang" table still, but version 1.0 worked in that system, and from what I could tell, localized works the same way.

I thought it could be that, but while typing this, I decided to remove the 'title' column from "post", and it returned empty now, so it didn't grab from postLang.

Seeing the DB Log from Yii2, the queries were performed successfully. So it's something after the find, and the filling of the columns.

How can I debug this further? You have any idea? I suppose localized is working fine for everyone else?

Thanks for any help.

OmgDef commented 9 years ago

Hi @andreCatita

My code

    public function testCreate()
    {
        $post = Post::find()->localized('en')->where(['id' => 4])->one();
        $this->printInfo($post);

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

        $post = Post::find()->where(['id' => 4])->asArray()->one();

        echo $post['title'];
    }

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

Schema

DROP TABLE IF EXISTS "post";

CREATE TABLE "post" (
  "id"    INTEGER NOT NULL PRIMARY KEY,
  "title"      TEXT,
  "body"      TEXT
);

DROP TABLE IF EXISTS "postLang";

CREATE TABLE "postLang" (
  "id"        INTEGER NOT NULL PRIMARY KEY,
  "post_id" INTEGER NOT NULL,
  "language" varchar(6) NOT NULL,
  "title"      TEXT,
  "body"      TEXT
);

Data

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <post id="1"/>
    <post id="2"/>
    <post id="3"/>
    <post id="4" title="No translation" body="No translation"/>
    <postLang id="1" post_id="1" language="ru" title="Post title 1 ru" body="Post body 1 ru"/>
    <postLang id="2" post_id="1" language="en" title="Post title 1 en" body="Post body 1 en"/>
    <postLang id="3" post_id="2" language="ru" title="Post title 2 ru" body="Post body 2 ru"/>
    <postLang id="4" post_id="2" language="en" title="Post title 2 en" body="Post body 2 en"/>
    <postLang id="5" post_id="3" language="ru" title="Post title 3 ru" body="Post body 3 ru"/>
    <postLang id="6" post_id="3" language="en" title="Post title 3 en" body="Post body 3 en"/>
    <postLang id="7" post_id="4" language="ru" title="Post title 4 ru" body="Post body 4 ru"/>
    <postLang id="8" post_id="4" language="en" title="Post title 4 en" body="Post body 4 en"/>
</dataset>

Output

The language is en-US
Title is Post title 4 en
The language is en-US
Title is Post title 4 ru
No translation
OmgDef commented 9 years ago

@andreCatita In 2.0 version column dublication is used just for fallback (if translation is empty)

andreCatita commented 9 years ago

Thanks @OmgDef

I figured what the problem is, I had a misconception about a variable, and now I don't know how to make this exception.

My exception was to not go to postLang table, if we are in my "defualtLanguage" (as I defined in params).

So in the MultilingualBehavior -> afterFind(), I have the following:

public function afterFind() {
....
if ($owner->isRelationPopulated('translations') && $related = $owner->getRelatedRecords()['translations']) {
     ...
     ...
} else {
     // I HAVE THIS LINE HERE
     if ($this->getCurrentLanguage() != \Yii::$app->params['defaultLanguage']) {
     ...
    }
}

I assumed this->getCurrentLanguage() when using: $post = Post::find()->localized('ru')->where(['id' => 4])->one(); would return 'ru', but apparently it always returns the \Yii::$app->language

How can I make this exception, that is to avoid going to the postLang table for the defaultLanguage?

Thanks

OmgDef commented 9 years ago

@andreCatita In case currentLanguage property should be public. I think i can do it for you. Problem is here https://github.com/OmgDef/yii2-multilingual-behavior/blob/master/src/MultilingualBehavior.php#L137 But I have no idea when you will assign a value to it. Model and behavior don't know anything about Query scopes.

andreCatita commented 9 years ago

@OmgDef Not sure I understood

Isn't there any way to retrieve the language filter that was applied in localized in afterFind? Meaning, get localized('ru') -> retrieve ru in afterFind? Or could we perhaps somehow define it so we can access it inside localized in MultilingualTrait ?

Thanks.

OmgDef commented 9 years ago

@andreCatita I think something like this

class Post extends \yii\db\ActiveRecord
{
    protected static $currentLanguage;

    public static function findLocalized($language)
    {
        static::$currentLanguage = $language;
        return static::find()->localized($language);
    }

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'post';
    }

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

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['title', 'body'], 'required'],
            ['title', 'string'],
        ];
    }

    /**
     * @inheritdoc
     */
    public function transactions()
    {
        return [
            self::SCENARIO_DEFAULT => self::OP_ALL,
        ];
    }

    /**
     * @inheritdoc
     */
    public static function find()
    {
        return new MultilingualQuery(get_called_class());
    }

    /**
     * @inheritdoc
     */
    public function afterFind()
    {
        parent::afterFind();
        static::$currentLanguage = null;
    }
}
andreCatita commented 9 years ago

Yeah I thought something like that.. But I don't really like it.. I'll sleep on this, for later..