記一次 Laravel-Admin 的 Debug 過程

梧桐樹下發表於2019-05-22

緣由

最近在使用Laravel-Admin後臺進行開發時,發現了框架的一個Bug。那就是編輯的時候無法回顯。然後偶然的機會,我將駝峰和下劃線都寫上了,最後震驚了。

記一次Laravel-Admin的Debug過程
下劃線有值,駝峰的反而沒值????emmmmmm

記一次Laravel-Admin的Debug過程

直接使用下劃線而不用駝峰就沒值,真是頭疼呢?

/**
 * 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。然後這裡的解決方案有兩種:

  1. 直接將模型函式使用下劃線,不用駝峰,那麼資料欄位就對得上了
  2. 新增程式碼,將data變數填充classInfo變數進來
        foreach ($this->model->getRelations() as $k => $v) {
            if ($v instanceof Model && isset($data[$v->getTable()])) {
                $data[$k] = $data[$v->getTable()];
            }
        }

以上就是我的Debug思路,可能解決方案有點差,歡迎提出更好的方案一起交流~

相關文章