简体   繁体   中英

Best practice of mass update relations in Laravel

Which is the best practice of mass update relations?

For example, I have Post model which has such relations: Lists (Many to many), Tags (Many to many morph), Author (One to one). When I edit Post I want to attach several Lists , several Tags and set author_id .

  1. Simple way:
$post->fill($request->all);
$post->saveOrFail();
$post->lists()->sync($request->lists);
$post->tags()->sync($request->tags);

Not bad, but if relation more then two, for example 10. IMHO, not good. Maybe I'm wrong.

  1. Hard way:
$post->fill($request->all);
$post->saveOrFail();
$post->massUpdateRelations($request->only(['lists', 'tags']));

function massUpdateRelations($data)
{
    $this->massFill($data);
    $this->massSave();
}

function massFill($data, $model = null)
{
    $uses = array_flip(class_uses_recursive(static::class));
    $relationModels = [];
    if (is_null($model)) {
        $model = $this;
    }
    if (!$model->wasRecentlyCreated) {
        $relationModels[] = $model;
    }
    foreach ($data as $name => $value) {
        if (is_array($value)) {
            $relationInfo = $model->{$name}();
            if ($relationInfo instanceof BelongsToMany) {
                $relationInfo->sync($value);
            } elseif ($relationInfo instanceof HasMany) {
                $this->afterMassSave[] = function () use ($relationInfo, $value) {
                    $relationInfo->delete();
                    $relationInfo->createMany($value);
                };
            } elseif ($relationInfo instanceof HasOne) {
                $this->afterMassSave[] = function () use ($relationInfo, $value) {
                    $relationInfo->delete();
                    $relationInfo->create($value);
                };
            } else {
                $relation = $model->{$name};
                $relationModels = array_merge($relationModels, $this->massFill($value, $relation));
            }
        } else {
            if ($model->isFillable($name)) {
                $model->setAttribute($name, $value);
            }
        }
    }
    $this->relationModels = $relationModels;

    return $relationModels;
}

function massSave()
{
    foreach ($this->relationModels as $relationModel) {
        $relationModel->save();
    }
    foreach ($this->afterMassSave as $item) {
        call_user_func($item);
    }
}

Maybe good for many relations, but looks like bad. And have problem with validation of relationships array of data.

I'm trying to search an answer in my question but without effect.

I think what you described in 1) is fine. If it gets more complicated, maybe have a look at events and specifically in this case observers where you get events like created, updated, ... out of the box. With observers you could do something like this:

class PostObserver
{
    public function updated(User $user)
    {
        // Make appropriate updates on lists and tags here
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM