最近在写底代码编程,写到关联关系保存的时候,想一下其实可以参考Laravel-admin 关联保存,因为他很简单的通过 ->hasMany 一个函数就解决了平常我们写的麻烦的关联模型。所以别人优秀的代码和思想是值得借鉴的。
关联保存肯定是在Form 模块中编写的,所以我很快的定位到了 vendor\encore\laravel-admin\src\Form.php
在update() 方法中写了关联模型的数据保存
先 通过预加载的方式,把关联的模型的数据加载出来,
$this->model = $builder->with($this->getRelations())->findOrFail($id); $this->setFieldOriginalValue();
验证数据,如果报错则结束
$validationMessages = $this->validationMessages($data)
DB::transaction(function () { $updates = $this->prepareUpdate($this->updates); foreach ($updates as $column => $value) { /* @var Model $this ->model */ $this->model->setAttribute($column, $value); } $this->model->save(); $this->updateRelation($this->relations); });
先保存主表的数据,再更新关联数据
/** * Update relation data. * * @param array $relationsData * * @return void */ protected function updateRelation($relationsData) { foreach ($relationsData as $name => $values) { if (!method_exists($this->model, $name)) { continue; } $relation = $this->model->$name(); $oneToOneRelation = $relation instanceof Relations\HasOne || $relation instanceof Relations\MorphOne || $relation instanceof Relations\BelongsTo; $prepared = $this->prepareUpdate([$name => $values], $oneToOneRelation); if (empty($prepared)) { continue; } switch (true) { case $relation instanceof Relations\BelongsToMany: case $relation instanceof Relations\MorphToMany: if (isset($prepared[$name])) { $relation->sync($prepared[$name]); } break; case $relation instanceof Relations\HasOne: case $relation instanceof Relations\MorphOne: $related = $this->model->getRelationValue($name) ?: $relation->getRelated(); foreach ($prepared[$name] as $column => $value) { $related->setAttribute($column, $value); } // save child $relation->save($related); break; case $relation instanceof Relations\BelongsTo: case $relation instanceof Relations\MorphTo: $related = $this->model->getRelationValue($name) ?: $relation->getRelated(); foreach ($prepared[$name] as $column => $value) { $related->setAttribute($column, $value); } // save parent $related->save(); // save child (self) $relation->associate($related)->save(); break; case $relation instanceof Relations\HasMany: case $relation instanceof Relations\MorphMany: foreach ($prepared[$name] as $related) { /** @var Relations\HasOneOrMany $relation */ $relation = $this->model->$name(); $keyName = $relation->getRelated()->getKeyName(); /** @var Model $child */ $child = $relation->findOrNew(Arr::get($related, $keyName)); if (Arr::get($related, static::REMOVE_FLAG_NAME) == 1) { $child->delete(); continue; } Arr::forget($related, static::REMOVE_FLAG_NAME); $child->fill($related); $child->save(); } break; } } }
通过模型调用,可以查询这个关联是用了哪种关联模型
$relation = $this->model->$name(); $oneToOneRelation = $relation instanceof Relations\HasOne || $relation instanceof Relations\MorphOne || $relation instanceof Relations\BelongsTo;
BelongsToMany 和 MorphToMany 方式保存方式:
case $relation instanceof Relations\BelongsToMany: case $relation instanceof Relations\MorphToMany: if (isset($prepared[$name])) { $relation->sync($prepared[$name]); } break;
HasOne 和MorphOne 保存方式:
case $relation instanceof Relations\HasOne: case $relation instanceof Relations\MorphOne: $related = $this->model->getRelationValue($name) ?: $relation->getRelated(); foreach ($prepared[$name] as $column => $value) { $related->setAttribute($column, $value); } // save child $relation->save($related);
BelongsTo 和 MorphTo 方式:
case $relation instanceof Relations\BelongsTo: case $relation instanceof Relations\MorphTo: $related = $this->model->getRelationValue($name) ?: $relation->getRelated(); foreach ($prepared[$name] as $column => $value) { $related->setAttribute($column, $value); } // save parent $related->save(); // save child (self) $relation->associate($related)->save(); break;
HasMany 和 MorphMany 保存方式
case $relation instanceof Relations\HasMany: case $relation instanceof Relations\MorphMany: foreach ($prepared[$name] as $related) { /** @var Relations\HasOneOrMany $relation */ $relation = $this->model->$name(); $keyName = $relation->getRelated()->getKeyName(); /** @var Model $child */ $child = $relation->findOrNew(Arr::get($related, $keyName)); if (Arr::get($related, static::REMOVE_FLAG_NAME) == 1) { $child->delete(); continue; } Arr::forget($related, static::REMOVE_FLAG_NAME); $child->fill($related); $child->save(); } break;