Skip to content

UpdateRelationsHelper

The UpdateRelationsHelper class provides an api that allows you to update any relation of a model via a single endpoint.

Laravel doesn't cover all relation updating scenarios out of the box (for example there is no associate method for HasMany or HasOne relations). This helper aims to provide a single endpoint that can handle all relation updates.

updateRelation

It offers a single method updateRelation that takes a model instance and relation update parameters and updates the model relation accordingly.

php
<?php

$entity = User::find(1);

UpdateRelationsHelper::updateRelation($entity, 'posts', 'associate', [1]);

associate

The associate method is used to associate a model with another model via the HasOne, HasMany or BelongsTo relation.

php
<?php

$entity = User::find(1);

UpdateRelationsHelper::updateRelation($entity, 'posts', 'associate', [1]);

The implementation of this logic works like this:

php
<?php

// Ensure relation is either HasOne, HasMany, or BelongsTo
if (! (
    $model->{$relation}() instanceof HasOne ||
    $model->{$relation}() instanceof HasMany ||
    $model->{$relation}() instanceof BelongsTo
)) {
    throw new \InvalidArgumentException('The associate method is not supported for '.get_class($model->{$relation}()).' relation');
}

// Associate method for BelongsTo relation
if (! ($model->{$relation}() instanceof HasMany || $model->{$relation}() instanceof HasOne)) {
    // Ensure only one id is passed for BelongsTo relation
    if (count($params) > 1) {
        throw new \InvalidArgumentException('The associate method only supports one id for BelongsTo relation');
    }

    $model->{$relation}()->$method($params[0])->save();
    break;
}

// Ensure only one id is passed for HasOne relation
if ($model->{$relation}() instanceof HasOne && count($params) > 1) {
    throw new \InvalidArgumentException('The associate method only supports one id for HasOne relation');
}

// Dissociate first if relation is HasOne
if ($model->{$relation}() instanceof HasOne && ! is_null($model->{$relation})) {
    // Dissociate method for HasOne relation
    $model->{$relation}->update([
        $model->{$relation}()->getForeignKeyName() => null,
    ]);
}

// Associate method for HasMany and HasOne relations
foreach ($params as $param) {
    $model
        ->{$relation}()
        ->getRelated()
        ->findOrFail($param)
        ->update([
            $model->{$relation}()->getForeignKeyName() => $model->id,
        ]);
}

dissociate

The dissociate method is used to dissociate a model from another model via the HasOne, HasMany or BelongsTo relation.

php
<?php

$entity = User::find(1);

UpdateRelationsHelper::updateRelation($entity, 'posts', 'dissociate', [1]);

The implementation of this logic works like this:

php
<?php

// Ensure relation is either HasOne, HasMany, or BelongsTo
if (! (
    $model->{$relation}() instanceof HasOne ||
    $model->{$relation}() instanceof HasMany ||
    $model->{$relation}() instanceof BelongsTo
)) {
    throw new \InvalidArgumentException('The dissociate method is not supported for '.get_class($model->{$relation}()).' relation');
}

// Dissociate method for BelongsTo relation
if (! ($model->{$relation}() instanceof HasMany || $model->{$relation}() instanceof HasOne)) {
    $model->{$relation}()->dissociate()->save();
    break;
}

if ($model->{$relation}() instanceof HasOne) {
    // Dissociate method for HasOne relation
    $model->{$relation}()->update([
        $model->{$relation}()->getForeignKeyName() => null,
    ]);
    break;
} else {
    // Dissociate method for HasMany relation
    foreach ($params as $param) {
        $model
            ->{$relation}()
            ->getRelated()
            ->findOrFail($param)
            ->update([
                $model->{$relation}()->getForeignKeyName() => null,
            ]);
    }
}

attach

The attach method is used to attach a model to another model via the BelongsToMany relation.

php
<?php

$entity = User::find(1);

UpdateRelationsHelper::updateRelation($entity, 'roles', 'attach', [1]);

The implementation of this logic works like this:

php
<?php

// Ensure relation is BelongsToMany
if (! $model->{$relation}() instanceof BelongsToMany) {
    throw new \InvalidArgumentException('The attach method is not supported for '.get_class($model->{$relation}()).' relation');
}

// Attach method for BelongsToMany relation
$model->{$relation}()->$method($params);

detach

The detach method is used to detach a model from another model via the BelongsToMany relation.

php
<?php

$entity = User::find(1);

UpdateRelationsHelper::updateRelation($entity, 'roles', 'detach', [1]);

The implementation of this logic works like this:

php
<?php

// Ensure relation is BelongsToMany
if (! $model->{$relation}() instanceof BelongsToMany) {
    throw new \InvalidArgumentException('The detach method is not supported for '.get_class($model->{$relation}()).' relation');
}

// Detach method for BelongsToMany relation
$model->{$relation}()->$method($params);

sync

The sync method is used to sync a model with another model via the BelongsToMany relation.

php
<?php

$entity = User::find(1);

UpdateRelationsHelper::updateRelation($entity, 'roles', 'sync', [1, 2, 3]);

The implementation of this logic works like this:

php
<?php

// Ensure relation is BelongsToMany
if (! $model->{$relation}() instanceof BelongsToMany) {
    throw new \InvalidArgumentException('The sync method is not supported for '.get_class($model->{$relation}()).' relation');
}

// Sync method for BelongsToMany relation
$model->{$relation}()->$method($params);

toggle

The toggle method is used to toggle a model with another model via the BelongsToMany relation.

php
<?php

$entity = User::find(1);

UpdateRelationsHelper::updateRelation($entity, 'roles', 'toggle', [1]);

The implementation of this logic works like this:

php
<?php

// Ensure relation is BelongsToMany
if (! $model->{$relation}() instanceof BelongsToMany) {
    throw new \InvalidArgumentException('The toggle method is not supported for '.get_class($model->{$relation}()).' relation');
}

// Toggle method for BelongsToMany relation
$model->{$relation}()->$method($params);

syncWithoutDetaching

The syncWithoutDetaching method is used to sync a model with another model via the BelongsToMany relation without detaching any existing models.

php
<?php

$entity = User::find(1);

UpdateRelationsHelper::updateRelation($entity, 'roles', 'syncWithoutDetaching', [1, 2, 3]);

The implementation of this logic works like this:

php
<?php

// Ensure relation is BelongsToMany
if (! $model->{$relation}() instanceof BelongsToMany) {
    throw new \InvalidArgumentException('The syncWithoutDetaching method is not supported for '.get_class($model->{$relation}()).' relation');
}

// SyncWithoutDetaching method for BelongsToMany relation
$model->{$relation}()->$method($params);

Review

The UpdateRelationsHelper class is a powerful tool that allows you to easily update relations of a model via a single endpoint.

It's used in the CRUDControllerHelper to update relations of a model entity.