加入Model的翻譯機制
This commit is contained in:
parent
c68e25de0a
commit
9ebaa6fcd2
25
app/ModelTranslation.php
Normal file
25
app/ModelTranslation.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ModelTranslation extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'model_type',
|
||||
'model_id',
|
||||
'locale',
|
||||
'text'
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
'model_type',
|
||||
'model_id',
|
||||
];
|
||||
|
||||
public function model()
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
}
|
||||
66
app/Observers/TranslatableModelOberserver.php
Normal file
66
app/Observers/TranslatableModelOberserver.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Repositories\ModelTranslationRepository;
|
||||
use App\TranslatableModel;
|
||||
|
||||
class TranslatableModelOberserver
|
||||
{
|
||||
/**
|
||||
* Handle the translatable model "created" event.
|
||||
*
|
||||
* @param \App\TranslatableModel $translatableModel
|
||||
* @return void
|
||||
*/
|
||||
public function created(TranslatableModel $translatableModel)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the translatable model "updated" event.
|
||||
*
|
||||
* @param \App\TranslatableModel $translatableModel
|
||||
* @return void
|
||||
*/
|
||||
public function updated(TranslatableModel $translatableModel)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the translatable model "deleted" event.
|
||||
*
|
||||
* @param \App\TranslatableModel $translatableModel
|
||||
* @return void
|
||||
*/
|
||||
public function deleted(TranslatableModel $translatableModel)
|
||||
{
|
||||
$modelTranslationRepository = app(ModelTranslationRepository::class);
|
||||
$modelTranslationRepository->setTranslatedModel($translatableModel);
|
||||
$modelTranslationRepository->deleteModelTranslations($translatableModel->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the translatable model "restored" event.
|
||||
*
|
||||
* @param \App\TranslatableModel $translatableModel
|
||||
* @return void
|
||||
*/
|
||||
public function restored(TranslatableModel $translatableModel)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the translatable model "force deleted" event.
|
||||
*
|
||||
* @param \App\TranslatableModel $translatableModel
|
||||
* @return void
|
||||
*/
|
||||
public function forceDeleted(TranslatableModel $translatableModel)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
334
app/Reposotories/ModelTranslationRepository.php
Normal file
334
app/Reposotories/ModelTranslationRepository.php
Normal file
@ -0,0 +1,334 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\TranslatableModel;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use App\ModelTranslation;
|
||||
use Cache;
|
||||
|
||||
class ModelTranslationRepository extends BaseRepository
|
||||
{
|
||||
/**
|
||||
* @var Model $translatedModel
|
||||
*/
|
||||
private $translatedModel = '';
|
||||
|
||||
public function __construct(ModelTranslation $modelTranslation)
|
||||
{
|
||||
$this->setModel($modelTranslation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 產生Cache key
|
||||
*
|
||||
* @param $model
|
||||
* @param $modelId
|
||||
* @param $attribute
|
||||
* @param string $locale
|
||||
* @return string
|
||||
*/
|
||||
private function getCacheKey($model, $modelId, $attribute, $locale = '')
|
||||
{
|
||||
return "model_translation_{$model}_{$modelId}_{$attribute}_{$locale}";
|
||||
}
|
||||
|
||||
/**
|
||||
* 設定當前的Model
|
||||
*
|
||||
* @param $model
|
||||
*/
|
||||
public function setTranslatedModel($model)
|
||||
{
|
||||
if(is_string($model)) {
|
||||
$this->translatedModel = $model;
|
||||
} elseif($model instanceof TranslatableModel) {
|
||||
$this->translatedModel = get_class($model);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新一項翻譯,需傳入目標model
|
||||
*
|
||||
* @param $model
|
||||
* @param $modelId
|
||||
* @param $attribute
|
||||
* @param $locale
|
||||
* @param $content
|
||||
*/
|
||||
public function updateTranslation($model, $modelId, $attribute, $locale, $content)
|
||||
{
|
||||
$updated = $this->model->updateOrInsert([
|
||||
'model_type' => $model,
|
||||
'model_id' => $modelId,
|
||||
'attribute' => $attribute,
|
||||
'locale' => $locale,
|
||||
], [
|
||||
'model_type' => $model,
|
||||
'model_id' => $modelId,
|
||||
'attribute' => $attribute,
|
||||
'locale' => $locale,
|
||||
'content' => $content
|
||||
]);
|
||||
Cache::forget($this->getCacheKey($model, $modelId, $attribute, $locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新一項翻譯
|
||||
*
|
||||
* @param $modelId
|
||||
* @param $attribute
|
||||
* @param $locale
|
||||
* @param $content
|
||||
*/
|
||||
public function updateModelTranslation($modelId, $attribute, $locale, $content)
|
||||
{
|
||||
return $this->updateTranslation($this->translatedModel, $modelId, $attribute, $locale, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得一項翻譯,需傳入目標model
|
||||
*
|
||||
* @param $model
|
||||
* @param $modelId
|
||||
* @param $attribute
|
||||
* @param $locale
|
||||
* @return string|null
|
||||
*/
|
||||
public function getTranslation($model, $modelId, $attribute, $locale)
|
||||
{
|
||||
$cacheKey = $this->getCacheKey($model, $modelId, $attribute, $locale);
|
||||
if(Cache::has($cacheKey)) {
|
||||
return Cache::get($cacheKey);
|
||||
}
|
||||
$record = $this->model->where([
|
||||
'model_type' => $model,
|
||||
'model_id' => $modelId,
|
||||
'attribute' => $attribute,
|
||||
'locale' => $locale,
|
||||
])->first();
|
||||
if($record) {
|
||||
Cache::put($cacheKey, $record->content);
|
||||
return $record->content;
|
||||
} else {
|
||||
Cache::put($cacheKey, null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得一項翻譯
|
||||
*
|
||||
* @param $modelId
|
||||
* @param $attribute
|
||||
* @param $locale
|
||||
* @return string|null
|
||||
*/
|
||||
public function getModelTranslation($modelId, $attribute, $locale)
|
||||
{
|
||||
return $this->getTranslation($this->translatedModel, $modelId, $attribute, $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得所有語系的翻譯內容,需傳入目標model
|
||||
*
|
||||
* @param $model
|
||||
* @param $modelId
|
||||
* @param $attribute
|
||||
* @return array
|
||||
*/
|
||||
public function getTranslations($model, $modelId, $attribute)
|
||||
{
|
||||
$cacheKey = $this->getCacheKey($model, $modelId, $attribute);
|
||||
if(Cache::has($cacheKey)) {
|
||||
return Cache::get($cacheKey);
|
||||
}
|
||||
$record = $this->model->where([
|
||||
'model_type' => $model,
|
||||
'model_id' => $modelId,
|
||||
'attribute' => $attribute,
|
||||
])
|
||||
->get()
|
||||
->mapWithKeys(function($model){
|
||||
/** @var \App\ModelTranslation $model */
|
||||
return [$model->locale => $model->content];
|
||||
})
|
||||
->toArray();
|
||||
Cache::put($cacheKey, $record);
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得所有語系的翻譯內容
|
||||
*
|
||||
* @param $modelId
|
||||
* @param $attribute
|
||||
* @return array
|
||||
*/
|
||||
public function getModelTranslations($modelId, $attribute)
|
||||
{
|
||||
return $this->getTranslations($this->translatedModel, $modelId, $attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得所有屬性的所有語系翻譯,需傳入目標model
|
||||
*
|
||||
* @param $model
|
||||
* @param $modeId
|
||||
* @return array
|
||||
*/
|
||||
public function getAllTranslations($model, $modeId)
|
||||
{
|
||||
/** @var TranslatableModel $modelInstance */
|
||||
$modelInstance = app($model);
|
||||
$translatableAttributes = $modelInstance->getTranslatableAttributes();
|
||||
|
||||
$translations = [];
|
||||
$modelTranslations = $this->model->where([
|
||||
'model_type' => $model,
|
||||
'model_id' => $modeId
|
||||
])
|
||||
->whereIn('attribute', $translatableAttributes)
|
||||
->get();
|
||||
|
||||
foreach ($modelTranslations as $modelTranslation) {
|
||||
$translations[$modelTranslation->attribute][$modelTranslation->locale] = $modelTranslation->content;
|
||||
}
|
||||
|
||||
return $translations;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得所有屬性的所有語系翻譯
|
||||
*
|
||||
* @param $modelId
|
||||
* @return array
|
||||
*/
|
||||
public function getModelAllTranslations($modelId)
|
||||
{
|
||||
return $this->getAllTranslations($this->translatedModel, $modelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刪除所有語系的翻譯,可指定屬性,需傳入目標model
|
||||
*
|
||||
* @param $model
|
||||
* @param $modelId
|
||||
* @param null $attribute
|
||||
* @return bool|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function deleteTranslations($model, $modelId, $attribute = null)
|
||||
{
|
||||
$cacheKey = $this->getCacheKey($model, $modelId, $attribute);
|
||||
$whereArg = [
|
||||
'model_type' => $model,
|
||||
'model_id' => $modelId
|
||||
];
|
||||
|
||||
if(!empty($attribute)) {
|
||||
$whereArg['attribute'] = $attribute;
|
||||
}
|
||||
|
||||
$translations = $this->model->where($whereArg)->delete();
|
||||
Cache::forget($cacheKey);
|
||||
return $translations;
|
||||
}
|
||||
|
||||
/**
|
||||
* 刪除所有語系的翻譯,可指定屬性
|
||||
*
|
||||
* @param $modelId
|
||||
* @param null $attribute
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function deleteModelTranslations($modelId, $attribute = null)
|
||||
{
|
||||
$this->deleteTranslations($this->translatedModel, $modelId, $attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批次取得指定屬性群的指定語系翻譯,需傳入目標model
|
||||
*
|
||||
* @param $model
|
||||
* @param $modelId
|
||||
* @param $locale
|
||||
* @param $attributes
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTranslationsWithAttributesInLocale($model, $modelId, $locale, $attributes)
|
||||
{
|
||||
$translations = $this->model->where([
|
||||
'model_type' => $model,
|
||||
'model_id' => $modelId,
|
||||
'locale' => $locale,
|
||||
])
|
||||
->whereIn('attribute', $attributes)
|
||||
->get();
|
||||
|
||||
return $translations;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批次取得指定屬性群與指定ID群的指定語系翻譯,需傳入目標model
|
||||
*
|
||||
* @param $model
|
||||
* @param $locale
|
||||
* @param $ids
|
||||
* @param $attributes
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTranslationsWithIdsAndAttributesInLocale($model, $locale, $ids, $attributes)
|
||||
{
|
||||
$translations = $this->model->select(['model_id', 'attribute', 'content'])
|
||||
->where([
|
||||
'model_type' => $model,
|
||||
'locale' => $locale,
|
||||
])
|
||||
->whereIn('attribute', $attributes)
|
||||
->whereIn('model_id', $ids)
|
||||
->orderBy('model_id')
|
||||
->get();
|
||||
return $translations;
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜尋指定屬性的所有語系翻譯,需傳入目標model,可指定語系
|
||||
*
|
||||
* @param $model
|
||||
* @param $attribute
|
||||
* @param $search
|
||||
* @param string $compare
|
||||
* @param null $locale
|
||||
* @return mixed
|
||||
*/
|
||||
public function searchAttribute($model, $attribute, $search, $compare = '=', $locale = null)
|
||||
{
|
||||
$modelQuery = $this->model
|
||||
->where('model_type', $model)
|
||||
->where('attribute', $attribute)
|
||||
->where('content', $compare, $search);
|
||||
|
||||
if($locale) {
|
||||
$modelQuery->where('locale', $locale);
|
||||
}
|
||||
|
||||
|
||||
return $modelQuery->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜尋指定屬性的所有語系翻譯,可指定語系
|
||||
*
|
||||
* @param $attribute
|
||||
* @param $search
|
||||
* @param string $compare
|
||||
* @param null $locale
|
||||
* @return mixed
|
||||
*/
|
||||
public function searchModelAttribute($attribute, $search, $compare = '=', $locale = null)
|
||||
{
|
||||
return $this->searchAttribute($this->translatedModel, $attribute, $search, $compare, $locale);
|
||||
}
|
||||
}
|
||||
69
app/TranslatableModel.php
Normal file
69
app/TranslatableModel.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Repositories\ModelTranslationRepository;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use App\Observers\TranslatableModelOberserver;
|
||||
|
||||
class TranslatableModel extends Model
|
||||
{
|
||||
protected $translatableAttributes = [];
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::observe(TranslatableModelOberserver::class);
|
||||
}
|
||||
|
||||
public function __get($attribute)
|
||||
{
|
||||
return $this->trans($attribute, app()->getLocale());
|
||||
}
|
||||
|
||||
public function defaultValue($attribute)
|
||||
{
|
||||
return parent::__get($attribute);
|
||||
}
|
||||
|
||||
public function trans($attribute, $locale = null)
|
||||
{
|
||||
if(in_array($attribute, $this->translatableAttributes)) {
|
||||
$currentLocale = $locale ? $locale : app()->getLocale();
|
||||
|
||||
$transRepo = app(ModelTranslationRepository::class);
|
||||
|
||||
$transRepo->setTranslatedModel($this);
|
||||
|
||||
$value = $transRepo->getModelTranslation($this->id, $attribute, $currentLocale);
|
||||
|
||||
if($value === null) {
|
||||
$value = $this->defaultValue($attribute);
|
||||
}
|
||||
|
||||
return $value;
|
||||
} else {
|
||||
return $this->defaultValue($attribute);
|
||||
}
|
||||
}
|
||||
|
||||
public function getTranslatableAttributes()
|
||||
{
|
||||
return $this->translatableAttributes;
|
||||
}
|
||||
|
||||
public function translations()
|
||||
{
|
||||
return $this->morphMany(ModelTranslation::class, 'model');
|
||||
}
|
||||
|
||||
public function scopeSearchInTranslation($query, $attribute, $keyword)
|
||||
{
|
||||
$keyword = '%' . implode('%', preg_split('//u', $keyword, -1, PREG_SPLIT_NO_EMPTY)) . '%';
|
||||
|
||||
return $query->whereHas('translations', function($query) use($attribute, $keyword) {
|
||||
$query->where('attribute', $attribute)->where('content', 'LIKE', $keyword);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateModelTranslationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('model_translations', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('model_type')->comment('Model名稱');
|
||||
$table->unsignedInteger('model_id')->comment('Model ID');
|
||||
$table->string('attribute')->comment('Model屬性');
|
||||
$table->string('locale')->comment('語系');
|
||||
$table->text('content')->nullable()->comment('翻譯的值');
|
||||
$table->unique(['model_type', 'model_id', 'attribute', 'locale'], 'model_locale_group');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('model_translations');
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user