Reputation: 1333
I'm working on a simple API using Laravel. At the moment working on the update endpoint for my categories
resource. A name
for a category
must be unique and that seems to be working just fine, but when performing an update it is failing even though I'm using ignore
.
Here's my controller method:
public function update(
UpdateCategoryRequest $request,
CategoryData $data) : CategoriesResource
{
$category = UpsertCategoryAction::execute($data, $request);
return new CategoriesResource($category);
}
Here's my execute
method in UpsertCategoryAction
:
public static function execute(
CategoryData $categoryData,
Request $request) : Category
{
return Category::updateOrCreate(
[
'id' => $categoryData->id,
],
[
...$categoryData->all()
]
);
}
and finally here's my validation rules which are declared on my DTO (I'm using spatie's laraveldata package):
<?php
namespace Domain\Category\DataTransferObjects;
use Illuminate\Validation\Rule;
use Spatie\LaravelData\Data;
/**
* DTO to represent a Category
*/
class CategoryData extends Data
{
public function __construct(
public readonly ?int $id,
public readonly string $name,
public readonly int $parent,
public readonly ?string $description,
public readonly ?string $image
){}
public static function rules(): array
{
return [
'name' => [
'required',
'string',
Rule::unique('categories', 'name')
->ignore(request('category'))
],
'parent' => ['required', 'integer', 'gte:0'],
'description' => ['nullable', 'sometimes', 'string'],
'image' => ['nullable', 'sometimes', 'string'],
];
}
}
As you can see, name
is required and unique but should be ignored for an update. I'm using request('category')
since this is a static method and I have no access to $this
. Yes, I've confirmed already and request('category')
is returning the correct id for the request.
When I try PUT categories/5
for instance, with the following body:
{
"name": "Winnifred Funk DDS",
"parent": 1,
"description": "Sit debitis necessitatibus quam. Molestiae voluptas sit at qui atque provident id. Animi et qui veritatis veniam laborum facilis. Rerum occaecati quasi ut hic nam dolor aspernatur.",
"image": "875e2438e3ae806bd14c16adaf5155c5.jpg"
}
In which the only field updated was parent
, I'm getting the following response:
{
"message": "SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'Winnifred Funk DDS' for key 'categories.categories_name_unique' (SQL: insert into `categories` (`name`, `parent`, `description`, `image`, `updated_at`, `created_at`) values (Winnifred Funk DDS, 1, Sit debitis necessitatibus quam. Molestiae voluptas sit at qui atque provident id. Animi et qui veritatis veniam laborum facilis. Rerum occaecati quasi ut hic nam dolor aspernatur., 875e2438e3ae806bd14c16adaf5155c5.jpg, 2022-08-10 11:47:52, 2022-08-10 11:47:52))",
"exception": "Illuminate\\Database\\QueryException",
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Connection.php",
"line": 759,
"trace": [
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Connection.php",
"line": 719,
"function": "runQueryCallback",
"class": "Illuminate\\Database\\Connection",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Connection.php",
"line": 545,
"function": "run",
"class": "Illuminate\\Database\\Connection",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Connection.php",
"line": 497,
"function": "statement",
"class": "Illuminate\\Database\\Connection",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Query/Processors/Processor.php",
"line": 32,
"function": "insert",
"class": "Illuminate\\Database\\Connection",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php",
"line": 3246,
"function": "processInsertGetId",
"class": "Illuminate\\Database\\Query\\Processors\\Processor",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php",
"line": 1834,
"function": "insertGetId",
"class": "Illuminate\\Database\\Query\\Builder",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php",
"line": 1220,
"function": "__call",
"class": "Illuminate\\Database\\Eloquent\\Builder",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php",
"line": 1185,
"function": "insertAndSetId",
"class": "Illuminate\\Database\\Eloquent\\Model",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php",
"line": 1026,
"function": "performInsert",
"class": "Illuminate\\Database\\Eloquent\\Model",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php",
"line": 568,
"function": "save",
"class": "Illuminate\\Database\\Eloquent\\Model",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Support/helpers.php",
"line": 302,
"function": "Illuminate\\Database\\Eloquent\\{closure}",
"class": "Illuminate\\Database\\Eloquent\\Builder",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php",
"line": 569,
"function": "tap"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php",
"line": 23,
"function": "updateOrCreate",
"class": "Illuminate\\Database\\Eloquent\\Builder",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php",
"line": 2176,
"function": "forwardCallTo",
"class": "Illuminate\\Database\\Eloquent\\Model",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php",
"line": 2188,
"function": "__call",
"class": "Illuminate\\Database\\Eloquent\\Model",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/src/Domain/Category/Actions/UpsertCategoryAction.php",
"line": 20,
"function": "__callStatic",
"class": "Illuminate\\Database\\Eloquent\\Model",
"type": "::"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/app/Http/Controllers/API/CategoriesController.php",
"line": 67,
"function": "execute",
"class": "Domain\\Category\\Actions\\UpsertCategoryAction",
"type": "::"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Routing/Controller.php",
"line": 54,
"function": "update",
"class": "App\\Http\\Controllers\\API\\CategoriesController",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php",
"line": 45,
"function": "callAction",
"class": "Illuminate\\Routing\\Controller",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Routing/Route.php",
"line": 261,
"function": "dispatch",
"class": "Illuminate\\Routing\\ControllerDispatcher",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Routing/Route.php",
"line": 204,
"function": "runController",
"class": "Illuminate\\Routing\\Route",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 725,
"function": "run",
"class": "Illuminate\\Routing\\Route",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 141,
"function": "Illuminate\\Routing\\{closure}",
"class": "Illuminate\\Routing\\Router",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php",
"line": 50,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 180,
"function": "handle",
"class": "Illuminate\\Routing\\Middleware\\SubstituteBindings",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php",
"line": 126,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php",
"line": 102,
"function": "handleRequest",
"class": "Illuminate\\Routing\\Middleware\\ThrottleRequests",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php",
"line": 54,
"function": "handleRequestUsingNamedLimiter",
"class": "Illuminate\\Routing\\Middleware\\ThrottleRequests",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 180,
"function": "handle",
"class": "Illuminate\\Routing\\Middleware\\ThrottleRequests",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php",
"line": 33,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 141,
"function": "Laravel\\Sanctum\\Http\\Middleware\\{closure}",
"class": "Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 116,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php",
"line": 34,
"function": "then",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 180,
"function": "handle",
"class": "Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 116,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 726,
"function": "then",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 703,
"function": "runRouteWithinStack",
"class": "Illuminate\\Routing\\Router",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 667,
"function": "runRoute",
"class": "Illuminate\\Routing\\Router",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 656,
"function": "dispatchToRoute",
"class": "Illuminate\\Routing\\Router",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
"line": 167,
"function": "dispatch",
"class": "Illuminate\\Routing\\Router",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 141,
"function": "Illuminate\\Foundation\\Http\\{closure}",
"class": "Illuminate\\Foundation\\Http\\Kernel",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php",
"line": 21,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php",
"line": 31,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 180,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php",
"line": 21,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php",
"line": 40,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 180,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\TrimStrings",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php",
"line": 27,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 180,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php",
"line": 86,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 180,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Http/Middleware/HandleCors.php",
"line": 62,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 180,
"function": "handle",
"class": "Illuminate\\Http\\Middleware\\HandleCors",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php",
"line": 39,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 180,
"function": "handle",
"class": "Illuminate\\Http\\Middleware\\TrustProxies",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 116,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
"line": 142,
"function": "then",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
"line": 111,
"function": "sendRequestThroughRouter",
"class": "Illuminate\\Foundation\\Http\\Kernel",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/public/index.php",
"line": 52,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Kernel",
"type": "->"
},
{
"file": "/Users/hansgruber/Desktop/webdev/projects/dundermifflin-be/vendor/laravel/framework/src/Illuminate/Foundation/resources/server.php",
"line": 16,
"function": "require_once"
}
]
}
Any ideas what's going on?
Upvotes: 0
Views: 1533
Reputation: 1031
I had a similar issue I solved it with the following Rule facade change:
Rule::unique('categories')->ignore(request('category'), 'id')
Upvotes: 0