Laravel 10中不修改库表结构实现字段与模型属性映射
字段名映射:Laravel模型中实现程序内字段别名,数据库查询用原字段
我正在为第三方不可修改的数据库构建Laravel 10模型,希望在程序内将数据库字段名映射为其他名称——让模型功能都用新名称,但数据库查询仍使用原字段名。
我的尝试
迁移文件
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. */ public function up(): void { Schema::create('test_models', function (Blueprint $table) { $table->id(); $table->string('test'); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('test_models'); } };
模型文件
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class TestModel extends Model { use HasFactory; protected $appends = ['test_changed']; public $hidden = ['test']; public function __call($method, $parameters) { if($method === 'getTestChangedAttribute'){ return $this->getAttribute('test'); } else if ($method === 'serTestChangedAttribute'){ return $this->setAttribute('test', $parameters[0]); } return parent::__call($method, $parameters); } public function getAttribute($key) { if($key === 'test_changed'){ $key = 'test'; } return parent::getAttribute($key); } public function setAttribute($key, $value) { if($key === 'test_changed'){ $key = 'test'; } return parent::setAttribute($key, $value); } }
TestModel::all()可以正常工作,但执行TestModel::where('test_changed', 'test 1')->get()时出现错误:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'test_changed' in 'where clause' (Connection: mysql, SQL: select * from
test_modelswheretest_changed= test 1)
需要实现新属性test_changed在所有场景下的有效替换。
解决方案
要让查询构造器也识别别名,需要重写模型的字段解析逻辑,同时保留属性访问/设置的映射。以下是优化后的实现:
优化后的模型代码
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class TestModel extends Model { use HasFactory; // 统一管理字段别名与原字段的映射 protected array $columnAliases = [ 'test_changed' => 'test', ]; protected $hidden = ['test']; // 覆盖Laravel的字段解析方法,处理查询中的别名 protected function resolveColumn($column) { return $this->columnAliases[$column] ?? parent::resolveColumn($column); } // 处理模型实例的属性获取 public function getAttribute($key) { if (isset($this->columnAliases[$key])) { $key = $this->columnAliases[$key]; } return parent::getAttribute($key); } // 处理模型实例的属性赋值 public function setAttribute($key, $value) { if (isset($this->columnAliases[$key])) { $key = $this->columnAliases[$key]; } return parent::setAttribute($key, $value); } }
关键说明
$columnAliases数组:集中管理所有字段别名和原字段的映射,后续新增别名只需修改这个数组,维护更方便。resolveColumn方法:Laravel查询构造器在生成SQL时会调用该方法解析字段名,这里自动将别名替换为原字段名,确保where('test_changed', ...)能生成正确的SQL。getAttribute/setAttribute:处理模型实例的属性读写,直接通过别名访问或赋值时,会自动映射到原字段。
现在所有场景都能正常工作:
TestModel::all():模型实例可通过$model->test_changed访问字段值TestModel::where('test_changed', 'test 1')->get():生成的SQL会使用原字段test查询$model->test_changed = 'new value'; $model->save();:值会保存到原字段test中
内容的提问来源于stack exchange,提问作者Rager
相关产品推荐
相关产品推荐

