Skip to content

This package is an alternative to the Laravel built-in validation rules exists and unique. It uses Eloquent models instead of directly querying the database.

License

Notifications You must be signed in to change notification settings

korridor/laravel-model-validation-rules

Repository files navigation

Laravel model validation rules

Latest Version on Packagist License Supported PHP versions GitHub Workflow Lint GitHub Workflow Tests Codecov

This package is an alternative to the Laravel built-in validation rules exists and unique. It uses Eloquent models instead of directly querying the database.

Advantages

  • The rule can be easily extended with the Eloquent builder. (scopes etc.)
  • Soft deletes are working out of the box.
  • Logic implemented into the models work in the validation as well. (multi tenancy system, etc.)

Note

Check out solidtime - The modern Open Source Time-Tracker at solidtime.io

Installation

You can install the package via composer with following command:

composer require korridor/laravel-model-validation-rules

If you want to use this package with older Laravel/PHP version please install the 2.1.* version.

composer require korridor/laravel-model-validation-rules "^2.1"

Requirements

This package is tested for the following Laravel and PHP versions:

  • 10.* (PHP 8.1, 8.2, 8.3)
  • 11.* (PHP 8.2, 8.3)

Usage examples

PostStoreRequest

use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
// ...
public function rules(): array
{
    $postId = $this->post->id;
    
    return [
        'username' => [new UniqueEloquent(User::class, 'username')],
        'title' => ['string'],
        'content' => ['string'],
        'comments.*.id' => [
            'nullable',
            new ExistsEloquent(Comment::class, null, function (Builder $builder) use ($postId) {
                return $builder->where('post_id', $postId);
            }),
        ],
        'comments.*.content' => ['string']
    ];
}

PostUpdateRequest

use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
// ...
public function rules(): array
{
    $postId = $this->post->id;
    
    return [
        'id' => [new ExistsEloquent(Post::class)],
        'username' => [(new UniqueEloquent(User::class, 'username'))->ignore($postId)],
        'title' => ['string'],
        'content' => ['string'],
        'comments.*.id' => [
            'nullable',
            new ExistsEloquent(Comment::class, null, function (Builder $builder) use ($postId) {
                return $builder->where('post_id', $postId);
            }),
        ],
        'comments.*.content' => ['string']
    ];
}

Custom validation message

If you want to change the validation message for one specific case, you can use the withMessage(...) function to add a custom validation message. With withCustomTranslation(...) you can set a custom translation key for the validation message. As described in detail in the next example (Customize default validation message), it is possible to use :attribute, :model and :value in the translation.

use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
// ...
public function rules(): array
{
    $postId = $this->post->id;
    
    return [
        'id' => [(new ExistsEloquent(Post::class))->withMessage('The ID already exists.')],
        'username' => [
            (new UniqueEloquent(User::class, 'username'))
                ->ignore($postId)
                ->withCustomTranslation('validation.custom.username.unique_eloquent')
        ],
        'title' => ['string'],
        'content' => ['string'],
        'comments.*.id' => [
            'nullable',
            new ExistsEloquent(Comment::class, null, function (Builder $builder) use ($postId) {
                return $builder->where('post_id', $postId);
            }),
        ],
        'comments.*.content' => ['string']
    ];
}

Customize default validation message

If you want to customize the translations of the default validation errors you can publish the translations of the package to the resources/lang/vendor/modelValidationRules folder.

php artisan vendor:publish --provider="Korridor\LaravelModelValidationRules\ModelValidationServiceProvider"

You can use the following attributes in the validation message:

  • attribute
  • model
  • value
return [
    'exists_model' => 'A :model with the :attribute ":value" does not exist.',
    'unique_model' => 'A :model with the :attribute ":value" already exists.',
];

Example outputs would be:

  • A user with the id "2" does not exist.
  • A user with the id "2" already exists.

Contributing

I am open for suggestions and contributions. Just create an issue or a pull request.

Local docker environment

The docker folder contains a local docker environment for development. The docker workspace has composer and xdebug installed.

docker-compose run workspace bash

Testing

The composer test command runs all tests with phpunit. The composer test-coverage command runs all tests with phpunit and creates a coverage report into the coverage folder.

Codeformatting/Linting

The composer fix command formats the code with php-cs-fixer. The composer lint command checks the code with phpcs.

Credits

The structure of the repository and the TestClass is inspired by the project laravel-validation-rules by spatie.

License

This package is licensed under the MIT License (MIT). Please see license file for more information.