OmgDef / yii2-multilingual-behavior

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

[QUESTION][ENHANCEMENT] Multiple models but one table #16

Closed timmy78 closed 9 years ago

timmy78 commented 9 years ago

Hi ! I'm interesting in using this behavior, but I have some questions : I will have to use this behavior with multiple models (News, Event, Post for exemple). But I won't have to create 3 tables for the translations (NewsLang, EventLang, PostLang). I would like to use only one translation table which will have these attributes :

Do you think it is possible to make it with your behavior ? Is it easy to enhance your behavior ?

Thank you !

OmgDef commented 9 years ago

@timmy78 Hi! You can easily to do this. You just need to inherit from MultilingualBehavior class and override getTranslations() and getTranslation($language = null) relations or you can just implement this relations in your models

OmgDef commented 9 years ago

@timmy78 In f857dec31e8cfdcdfe98c82aa5355635034c2512 i implemented method getCurrentLanguage for this case

timmy78 commented 9 years ago

Ok, thank you for your answer ! I will check it latter !

timmy78 commented 9 years ago

I tried but there are some errors (that's normal, I think it's more complicated). $this->setLangAttribute($attribute . '_' . $lang, $translation->{$attributeName}); (l.203) returns an error because the attribute doesn't exist in the table.

Can you send me an example of the new class if you have time ? :yum:

Thank you !

OmgDef commented 9 years ago

@timmy78 You just need to implement getTranslations() and getTranslation($language = null) directly in your model

Example Model class:

class Post extends \yii\db\ActiveRecord
{
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'post';
    }

    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            'ml' => [
                'class' => MultilingualBehavior::className(),
                'languages' => [
                    'ru' => 'Russian',
                    'en-US' => 'English',
                ],
                'dynamicLangClass' => false,
                'defaultLanguage' => 'ru',
                'langForeignKey' => 'post_id',
                '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());
    }

    /**
     * Relation to model translations
     * @return ActiveQuery
     */
    public function getTranslations()
    {
        return $this->hasMany(PostLang::className(), ['post_id' => 'id']);
    }

    /**
     * Relation to model translation
     * @param $language
     * @return ActiveQuery
     */
    public function getTranslation($language = null)
    {
        $language = $language ?: $this->getCurrentLanguage();
        return $this->owner->hasOne(PostLang::className(), ['post_id' => 'id'])
            ->where(['language' => $language]);
    }
}

Lang class

class PostLang extends \yii\db\ActiveRecord
{
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'postLang';
    }
}
timmy78 commented 9 years ago

I don't know if you exactly understood what I would like. There is this error, and that's normal : Getting unknown property: app\components\Translation::name Because in my table "translation" I have not this attribute.

CREATE TABLE IF NOT EXISTS `translation` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `table` varchar(100) NOT NULL, -- Contains the name of the table
  `foreign_key` int(11) NOT NULL, -- Contains the foreign ID
  `column` varchar(100) NOT NULL, -- Contains the name of the attribute
  `language` varchar(15) NOT NULL,
  `translation` text NOT NULL, -- Contains the value translated
  PRIMARY KEY (`id`),
  KEY `table` (`table`,`foreign_key`,`column`,`language`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

I have to override the function _get in translation like this :

/**
 * @property string $table
 * @property integer $foreign_key
 * @property string $column
 * @property string $language
 * @property string $translation
 */
class Translation extends \yii\db\ActiveRecord
{
    public static function tableName()
    {
        return 'translation';
    }

    public function __get($name)
    {
        $translation = self::find()->where(['column' => $name])->select('translation')->one();
        return $translation ? $translation->translation : parent::__get($name);
    }
}

And it partially works.

OmgDef commented 9 years ago

@timmy78 Yes I Am. Looks like I did not really understand what you want. Use __get in the model translation is a good idea in your case

timmy78 commented 9 years ago

@OmgDef What I whant is to have only one table which store translations for all the other tables. No EventLang, no NewsLang, no PostLang etc.. but just Translation

The table will contains something like this : id table foreign_key column language transation
1 post 1 title en My title
2 post 1 title fr Mon titre
3 event 36 content en My content
OmgDef commented 9 years ago

@timmy78

Example of the config

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