MrCujo
MrCujo

Reputation: 1333

Laravel Ignore not working for unique validation rule

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

Answers (1)

dz0nika
dz0nika

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

Related Questions