diff --git a/src/Execution/Arguments/UpsertModel.php b/src/Execution/Arguments/UpsertModel.php index f8c481f90..bc1984888 100644 --- a/src/Execution/Arguments/UpsertModel.php +++ b/src/Execution/Arguments/UpsertModel.php @@ -2,6 +2,7 @@ namespace Nuwave\Lighthouse\Execution\Arguments; +use Illuminate\Database\Eloquent\Model; use Nuwave\Lighthouse\Support\Contracts\ArgResolver; class UpsertModel implements ArgResolver @@ -22,14 +23,11 @@ public function __construct(callable $previous) public function __invoke($model, $args): mixed { // TODO consider Laravel native ->upsert(), available from 8.10 - $id = $args->arguments['id'] - ?? $args->arguments[$model->getKeyName()] - ?? null; - $idValue = $id?->value; - if ($idValue) { + $id = $this->retrieveID($model, $args); + if ($id) { $existingModel = $model->newQuery() - ->find($idValue); + ->find($id); if ($existingModel !== null) { $model = $existingModel; @@ -38,4 +36,24 @@ public function __invoke($model, $args): mixed return ($this->previous)($model, $args); } + + /** @return mixed The value of the ID or null */ + protected function retrieveID(Model $model, ArgumentSet $args) + { + foreach (['id', $model->getKeyName()] as $key) { + if (! isset($args->arguments[$key])) { + continue; + } + + $id = $args->arguments[$key]->value; + if ($id) { + return $id; + } + + // Prevent passing along empty IDs that would be filled into the model + unset($args->arguments[$key]); + } + + return null; + } } diff --git a/tests/Utils/Models/Post.php b/tests/Utils/Models/Post.php index e48825f01..ae77420df 100644 --- a/tests/Utils/Models/Post.php +++ b/tests/Utils/Models/Post.php @@ -2,6 +2,7 @@ namespace Tests\Utils\Models; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; @@ -48,6 +49,15 @@ final class Post extends Model use Searchable; use SoftDeletes; + /** @return Attribute */ + protected function id(): Attribute + { + return Attribute::make( + get: fn (mixed $_, array $attributes): int => $attributes[$this->primaryKey], + set: fn (int $id) => [$this->primaryKey => $id], + ); + } + /** @return \Illuminate\Database\Eloquent\Relations\MorphMany<\Tests\Utils\Models\Activity, $this> */ public function activity(): MorphMany {