TranslatableBackend 多语言基类控制器
介绍
TranslatableBackend 类继承自 Backend 基类,专门用于支持多语言数据管理的后台控制器。它通过关联的翻译模型,将多语言字段(如标题、内容等)存储到独立的翻译表中,并提供统一的 CRUD 操作、搜索、数据权限控制等功能。 通过继承此类,可以快速实现多语言数据模型的后台管理,无需重复编写多语言处理逻辑。
属性说明
多语言相关属性
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| $translationForeignMethod | string | 'translations' | 主模型与翻译模型的关联方法名 |
| $translationForeignKey | string | 'main_id' | 翻译表中的外键字段,关联主表主键 |
| $translationLocaleKey | string | 'locale' | 翻译表中标识语言的字段名 |
| $supportedLocales | array | ['zh-cn', 'en-us'] | 支持的语言列表 |
| $multilingualFields | array | [] | 需要多语言支持的字段名数组 |
| $translationModel | Model | null | 翻译模型类实例 |
继承自 Backend 的重要属性
$model: 主模型实例
$dataLimit: 数据权限控制
$dataLimitField: 数据权限字段
$searchable: 搜索配置(支持多语言字段搜索)
$with: 关联预加载(自动包含翻译关联)
其他属性参考 Backend 文档
方法说明
重写的方法
applyWhere($query, $params)
扩展了父类的查询条件处理,支持对多语言字段的搜索。
多语言字段搜索逻辑:
如果字段在 $multilingualFields 中,则通过 whereHas 在翻译关联上添加条件。
index(Request $request)
获取数据列表,自动预加载翻译关联,并对返回结果进行多语言字段格式化。
返回格式:
多语言字段会转换为以语言代码为键的对象,例如:
{
"id": 1,
"title": {
"zh-cn": "标题中文",
"en-us": "English Title"
},
"status": 1
}selectpage(Request $request)
Selectpage 下拉选择方法,同样支持多语言字段的格式化。
add(Request $request)
添加数据,处理多语言字段的拆分与保存。
请求数据格式:
{
"status": 1,
"title": {
"zh-cn": "标题中文",
"en-us": "English Title"
},
"content": {
"zh-cn": "内容中文",
"en-us": "English Content"
}
}处理流程:
使用 extractMultilingualData() 分离主表字段和多语言字段。
分别对主模型和翻译模型进行验证(如果启用 $modelValidate)。
保存主记录。
遍历 $supportedLocales,为每个语言创建翻译记录。
edit(Request $request)
编辑数据,更新主表字段和多语言翻译。
处理流程:
提取多语言数据。
验证主表和翻译数据。
更新主记录。
使用 updateOrCreate 更新或创建各语言翻译。
del(Request $request)
软删除数据,同时软删除关联的翻译记录(需模型支持软删除)。
destroy(Request $request)
真实删除数据,同时硬删除翻译记录。
restore(Request $request)
恢复软删除的数据,同时恢复翻译记录。
multi(Request $request)
批量更新(仅支持主表字段,不支持多语言字段)。
新增方法
extractMultilingualData(array $data): array
从请求数据中分离主表字段和多语言翻译数据。
返回:
[$masterData, $translations]
$masterData: 主表字段数组
$translations: 以语言代码为键的翻译数据数组
renderTranslations($list)
格式化列表数据,将翻译关联数据转换为以语言为键的多语言字段格式。
使用示例
1. 定义主模型
<?php
namespace plugin\condoradmin\app\model;
use support\Model;
use Respect\Validation\Validator as v;
use Illuminate\Database\Eloquent\SoftDeletes;
class SystemTest extends Model
{
use SoftDeletes;
/**
* @var string
*/
protected $table = 'system_test';
/**
* @var string
*/
protected $primaryKey = 'id';
/**
* 指示是否自动维护时间戳
*
* @var bool
*/
public $timestamps = true;
protected $dateFormat = 'U';
// 定义时间戳字段名
const CREATED_AT = 'createtime';
const UPDATED_AT = 'updatetime';
// 让所有属性都可以批量分配
protected $guarded = [];
protected function serializeDate(\DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
}
public function rules()
{
return [
'price' => v::optional(v::notEmpty())->setName(trans('fields.price', [], 'test')),
'views' => v::optional(v::notEmpty())->setName(trans('fields.views', [], 'test')),
'activitytime' => v::optional(v::notEmpty())->setName(trans('fields.activitytime', [], 'test')),
'refreshtime' => v::optional(v::notEmpty())->setName(trans('fields.refreshtime', [], 'test')),
];
}
public function getPriceAttribute($value)
{
return floatval($value);
}
/**
* 关联翻译
*/
public function translations()
{
return $this->hasMany(SystemTestTranslations::class, 'main_id', 'id');
}
}2. 定义翻译模型
<?php
namespace plugin\condoradmin\app\model;
use support\Model;
use Respect\Validation\Validator as v;
class SystemTestTranslations extends Model
{
/**
* @var string
*/
protected $table = 'system_test_translations';
/**
* @var string
*/
protected $primaryKey = 'id';
/**
* 指示是否自动维护时间戳
*
* @var bool
*/
public $timestamps = true;
protected $dateFormat = 'U';
// 定义时间戳字段名
const CREATED_AT = 'createtime';
const UPDATED_AT = 'updatetime';
// 让所有属性都可以批量分配
protected $guarded = [];
protected function serializeDate(\DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
}
public function rules()
{
return [
'name' => v::optional(v::notEmpty())->setName(trans('fields.name', [], 'test')),
'target' => v::optional(v::notEmpty())->setName(trans('fields.target', [], 'test')),
'title' => v::optional(v::notEmpty())->setName(trans('fields.title', [], 'test')),
'content' => v::optional(v::notEmpty())->setName(trans('fields.content', [], 'test')),
'image' => v::optional(v::notEmpty())->setName(trans('fields.image', [], 'test')),
'images' => v::optional(v::notEmpty())->setName(trans('fields.images', [], 'test')),
'attachfile' => v::optional(v::notEmpty())->setName(trans('fields.attachfile', [], 'test')),
'keywords' => v::optional(v::notEmpty())->setName(trans('fields.keywords', [], 'test')),
'description' => v::optional(v::notEmpty())->setName(trans('fields.description', [], 'test')),
];
}
}3. 定义控制器
<?php
namespace plugin\condoradmin\app\controller;
use plugin\condoradmin\app\library\TranslatableBackend;
use plugin\condoradmin\app\model\SystemTest;
use plugin\condoradmin\app\model\SystemTestTranslations;
class SystemTestController extends TranslatableBackend
{
protected array $searchable = [
'name' => ['type' => 'string'],
'title' => ['type' => 'string'],
'price' => ['type' => 'int'],
'views' => ['type' => 'int'],
'activitytime' => ['type' => 'int'],
'refreshtime' => ['type' => 'int'],
'createtime' => ['type' => 'int'],
];
// 多语言字段
protected array $multilingualFields = ['name', 'target', 'title', 'content', 'image', 'images', 'attachfile', 'keywords', 'description'];
public function __construct()
{
parent::__construct();
// 主表模型
$this->model = new SystemTest();
// 多语言表模型
$this->translationModel = new SystemTestTranslations();
}
}