在研究 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
的