记一次 Laravel-Admin 的 Debug 过程
缘由
最近在使用Laravel-Admin后台进行开发时,发现了框架的一个Bug。那就是编辑的时候无法回显。然后偶然的机会,我将驼峰和下划线都写上了,最后震惊了。
下划线有值,驼峰的反而没值????emmmmmm
直接使用下划线而不用驼峰就没值,真是头疼呢?
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
$form = new Form(new Students);
$form->text('classInfo.grade', '年级');
$form->text('class_info.grade', '年级');
$form->text('classInfo.class', '班级');
$form->text('class_info.class', '班级');
return $form;
}
classInfo模型
class ClassInfo extends Model
{
protected $table = 'class_info';
protected $fillable = ['grade', 'class'];
public function students()
{
return $this->belongsTo(Students::class);
}
}
students模型
class Students extends Model
{
protected $table = 'students';
public function contacts()
{
return $this->hasMany(Contacts::class, 'student_id');
}
public function classInfo()
{
return $this->hasOne(ClassInfo::class, 'student_id');
}
}
无奈
只能是自己Debug了,因为找了很多文章也没解决方案,项目issue也没有一对一模型出错的文章。我就奇怪了,为什么这么常用的功能有Bug呢?还是只是我在用而已(逃)
首先思路要清晰,毕竟要找问题究竟出在哪里。因为是我是用form组件的text方法,首先就会想到是form排查。所以我找到了src/Form.php
这个文件。
在使用Laravel-Admin命令生成的控制器会带上一个修改函数
/**
* Edit interface.
*
* @param mixed $id
* @param Content $content
* @return Content
*/
public function edit($id, Content $content)
{
return $content
->header('Edit')
->description('description')
->body($this->form()->edit($id));
}
然后我们会看见$this->form()
这个函数不就是我们编写字段的函数吗?然后调用了edit
函数
/**
* Generate a edit form.
*
* @param $id
*
* @return $this
*/
public function edit($id)
{
$this->builder->setMode(Builder::MODE_EDIT);
$this->builder->setResourceId($id);
$this->setFieldValue($id);
return $this;
}
这个函数会设置编辑模式,然后设置资源id
这些其实都不是我们要管的。毕竟我们是value
值没有.那么当我看见setFieldValue
函数后就突然兴奋,这不就是设置input
输入框的value
值吗?
/**
* Set all fields value in form.
*
* @param $id
*
* @return void
*/
protected function setFieldValue($id)
{
$relations = $this->getRelations();
$builder = $this->model();
if ($this->isSoftDeletes) {
$builder = $builder->withTrashed();
}
$this->model = $builder->with($relations)->findOrFail($id);
$this->callEditing();
// static::doNotSnakeAttributes($this->model);
$data = $this->model->toArray();
$this->builder->fields()->each(function (Field $field) use ($data) {
if (!in_array($field->column(), $this->ignored)) {
$field->fill($data);
}
});
}
这里面要关注的点还有就是获取依赖的
getRelations
函数,这个函数其实就是上面模型的函数名称。所以我们的$relations=['classInfo, contacts']
。
重点来了,我们将$data
打印出来看看
array:13 [▼
"id" => 5
"name" => "s1"
"gender" => 0
"enrol" => 2019
"birth" => "2019-04-22"
"address" => "test"
"avatar" => null
"status" => 0
"desc" => "test"
"created_at" => "2019-04-22 15:42:20"
"updated_at" => "2019-04-22 15:42:20"
"class_info" => array:7 [▼
"id" => 1
"student_id" => 5
"grade" => "1"
"director" => null
"class" => "2"
"created_at" => "2019-04-22 15:42:20"
"updated_at" => "2019-05-20 14:37:40"
]
"contacts" => array:2 [▶]
]
emmmmm,依赖传进去后得到的数据竟然是以表名来做键的呀。
结论
这是因为驼峰和下划线的问题。我在数据库使用下划线class_info
,然后我的form
函数里面写的是
$form->text('classInfo.grade', '年级');
$form->text('classInfo.class', '班级');
然后这个是对应在模型中的函数名的,然后在field->fill
填充$data
数据进去赋值时,就会发现找不到classInfo
,只有class_info
。然后这里的解决方案有两种:
- 直接将模型函数使用下划线,不用驼峰,那么数据字段就对得上了
- 添加代码,将data变量填充
classInfo
变量进来foreach ($this->model->getRelations() as $k => $v) { if ($v instanceof Model && isset($data[$v->getTable()])) { $data[$k] = $data[$v->getTable()]; } }
以上就是我的Debug思路,可能解决方案有点差,欢迎提出更好的方案一起交流~
本作品采用《CC 协议》,转载必须注明作者和本文链接
input 标签的 name 属性,用驼峰标记,之前我也遇到过获取不到值的问题。现在我一般在 PHP 中的数组键和数据库字段中使用下划线,PHP 变量使用驼峰法。
@yuanshang 这个想法不错 :+1:
issue
里很早就有关于 使用驼峰法命名模型关联 的问题了,作者也回应了(链接),也有很多提PR的,可能改动影响较大,一直没改。看了你提的PR,作者可能也不会合并
不过,在
v1.6.15
版本后,新增了方法customFormat()
用来处理数据,你可以试一试。模型里面加上
public static $snakeAttributes = false; // 设置关联模型在打印输出的时候是否自动转为蛇型命名
就可以了,默认会自动把驼峰转蛇形
@showcj 嗯额,我也挺奇怪的,作者文档也不解释一下,出问题后一脸懵逼
@生活无限好 好的,学习了