在研究 TwillCMS 的時候 發現他的多語系 model 功能很好用

比方說 posts 的資料表 可以建立 post_translations 資料表

然後多語系資料存裡面 就能用一般存取 eloquent attribute 的方式取得翻譯

這是怎麼做到的呢?


首先 使用多語的 model 要先使用 Trait A17\Twill\Models\Behaviors\HasTranslation

然後要在 $translatedAttributes 裡面設定好

查看那個 Trait 的原始碼 會發現要使用 另一個 Trait Astrotomic\Translatable\Translatable

原來,底層其實用到了另一個套件

https://github.com/Astrotomic/laravel-translatable


繼續翻閱那個套件的原始碼 Astrotomic\Translatable\Translatable

會看到 public function getAttribute 實際上的功能,就是實作在這邊!

因為在 laravel eloquent 的原始碼 Illuminate\Database\Eloquent\Model 有下面這段

    public function __get($key)
    {
        return $this->getAttribute($key);
    }

也就是讀取 model attribute 時,其實有經過 php magic function __get()

所以 Translatable 這個 Trait 就是擴充了這個函數

    public function getAttribute($key)
    {
        [$attribute, $locale] = $this->getAttributeAndLocale($key);

        if ($this->isTranslationAttribute($attribute)) {
            if ($this->getTranslation($locale) === null) {
                return $this->getAttributeValue($attribute);
            }

            // 這邊省略
        }

        return parent::getAttribute($key);
    }

然後會去呼叫 public function getTranslation 這樣,答案揭曉!


題外話,翻閱 eloquent model source code 的時候

我發現 getAttribute 不是直接寫在 model 內

而是在 Illuminate\Database\Eloquent\Concerns\HasAttributes 裡面

eloquent 因為功能太豐富 所以打散在 Concerns 資料夾內

其實就是 Traits 的意思

只是因為 Seperation of Concerns 原則太有名 所以用 Concerns 來命名

其實也有道理 就好像我們不會把放了一堆類別的資料夾 命名為 Classes 這樣

在 laravel source code 放了一堆 interface 的資料夾也是命名為 Contracts


共有 0 則留言