From 0df77be4a7040edf6b76ee11bb9535562948062a Mon Sep 17 00:00:00 2001 From: korridor <26689068+korridor@users.noreply.github.com> Date: Wed, 18 Sep 2019 22:15:57 +0200 Subject: [PATCH 01/11] Added UniqueEloquentTest; Renamed ExistEloquent to ExistsEloquent --- composer.json | 2 +- phpunit.xml | 2 +- readme.md | 54 ++++- resources/lang/de/validation.php | 3 +- resources/lang/en/validation.php | 3 +- .../{ExistEloquent.php => ExistsEloquent.php} | 29 ++- src/Rules/UniqueEloquent.php | 136 +++++++++++ ...loquentTest.php => ExistsEloquentTest.php} | 60 +++-- tests/Feature/UniqueEloquentTest.php | 225 ++++++++++++++++++ tests/TestCase.php | 5 + 10 files changed, 491 insertions(+), 28 deletions(-) rename src/Rules/{ExistEloquent.php => ExistsEloquent.php} (71%) create mode 100644 src/Rules/UniqueEloquent.php rename tests/Feature/{ExistEloquentTest.php => ExistsEloquentTest.php} (69%) create mode 100644 tests/Feature/UniqueEloquentTest.php diff --git a/composer.json b/composer.json index 3b00991..90214ed 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ ], "license": "MIT", "require": { - "php": "7.*", + "php": "^7.1|^7.2|^7.3", "illuminate/support": "^5.8|^6.0" }, "require-dev": { diff --git a/phpunit.xml b/phpunit.xml index e8c4211..f550419 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -11,7 +11,7 @@ stopOnFailure="false"> - tests + tests/Feature diff --git a/readme.md b/readme.md index 5db7146..b9cc6f7 100644 --- a/readme.md +++ b/readme.md @@ -1,16 +1,60 @@ # Laravel model validation rules +This package is an alternative to the Laravel built-in validation rules `exist` and `unique`. +This has the following advantages: + + - It uses existing models instead of directly querying the database. + - The rule can be easily extended with the Eloquent builder. + - Softdeletes are working + ## Installation +You can install the package via composer with following command: + ```bash composer require korridor/laravel-model-validation-rules ``` +### Translation + +If you want to customize the translations of the validation errors you can publish the translations +of the package to the `resources/lang/vendor/modelValidationRules` folder. + ```bash php artisan vendor:publish --provider="Korridor\LaravelModelValidationRules\ModelValidationServiceProvider" ``` -## Usage +## Rules + +### ExistEloquent + +### UniqueEloquent + +## Usage examples + +**PostStoreRequest** + +```php +public function rules() +{ + $postId = $this->post->id; + + return [ + 'username' => [new UniqueEloquent(User::class, 'username')], + 'title' => ['string'], + 'content' => ['string'], + 'comments.*.id' => [ + 'nullable', + new ExistEloquent(Comment::class, null, function (Builder $builder) use ($postId) { + return $builder->where('post_id', $postId); + }), + ], + 'comments.*.content' => ['string'] + ]; +} +``` + +**PostUpdateRequest** ```php public function rules() @@ -19,6 +63,7 @@ public function rules() return [ 'id' => [new ExistEloquent(Post::class)], + 'username' => [new UniqueEloquent(User::class, 'username')->ignore($postId)], 'title' => ['string'], 'content' => ['string'], 'comments.*.id' => [ @@ -34,6 +79,8 @@ public function rules() ## Contributing +I am open for suggestions and contributions. Just create an issue or a pull request. + ### Testing ```bash @@ -48,6 +95,11 @@ composer fix composer lint ``` +## Credits + +The structure of the repository and the TestClass is inspired by the +project [laravel-validation-rules](https://github.com/spatie/laravel-validation-rules) by [spatie](https://github.com/spatie). + ## License The MIT License (MIT). Please see [license file](license.md) for more information. diff --git a/resources/lang/de/validation.php b/resources/lang/de/validation.php index e6f9c8c..51da175 100644 --- a/resources/lang/de/validation.php +++ b/resources/lang/de/validation.php @@ -1,5 +1,6 @@ 'Die Ressource existiert nicht.' + 'exists_model' => 'Die Ressource existiert nicht.', + 'unique_model' => 'Die Ressource existiert bereits.', ]; diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index 6fdb2ec..9781d41 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -1,5 +1,6 @@ 'The resource does not exist.' + 'exists_model' => 'The resource does not exist.', + 'unique_model' => 'The resource already exists.', ]; diff --git a/src/Rules/ExistEloquent.php b/src/Rules/ExistsEloquent.php similarity index 71% rename from src/Rules/ExistEloquent.php rename to src/Rules/ExistsEloquent.php index 32e618d..5090d0a 100644 --- a/src/Rules/ExistEloquent.php +++ b/src/Rules/ExistsEloquent.php @@ -3,10 +3,10 @@ namespace Korridor\LaravelModelValidationRules\Rules; use Closure; -use Eloquent; +use Illuminate\Database\Eloquent\Model; use Illuminate\Contracts\Validation\Rule; -class ExistEloquent implements Rule +class ExistsEloquent implements Rule { /** * @var string @@ -44,7 +44,7 @@ public function __construct(string $model, ?string $key = null, ?Closure $builde { $this->model = $model; $this->key = $key; - $this->builderClosure = $builderClosure; + $this->setBuilderClosure($builderClosure); } /** @@ -58,10 +58,10 @@ public function passes($attribute, $value): bool { $this->attribute = $attribute; $this->value = $value; - /** @var Eloquent $builder */ + /** @var Model $builder */ $builder = new $this->model(); if (null === $this->key) { - $builder = $builder->where($builder->getKeyName(), $value); + $builder = $builder->where((new $this->model())->getKeyName(), $value); } else { $builder = $builder->where($this->key, $value); } @@ -80,10 +80,27 @@ public function passes($attribute, $value): bool */ public function message(): string { - return trans('modelValidationRules::validation.exist_model', [ + return trans('modelValidationRules::validation.exists_model', [ 'attribute' => $this->attribute, 'model' => class_basename($this->model), 'value' => $this->value, ]); } + + /** + * @param Closure|null $builderClosure + */ + public function setBuilderClosure(?Closure $builderClosure) { + $this->builderClosure = $builderClosure; + } + + /** + * @param Closure $builderClosure + * @return $this + */ + public function query(Closure $builderClosure): ExistsEloquent + { + $this->setBuilderClosure($builderClosure); + return $this; + } } diff --git a/src/Rules/UniqueEloquent.php b/src/Rules/UniqueEloquent.php new file mode 100644 index 0000000..9be24c7 --- /dev/null +++ b/src/Rules/UniqueEloquent.php @@ -0,0 +1,136 @@ +model = $model; + $this->key = $key; + $this->setBuilderClosure($builderClosure); + } + + /** + * Determine if the validation rule passes. + * + * @param string $attribute + * @param mixed $value + * @return bool + */ + public function passes($attribute, $value): bool { + $this->attribute = $attribute; + $this->value = $value; + /** @var Model $builder */ + $builder = new $this->model(); + $builder = $builder->where($this->key === null ? (new $this->model())->getKeyName() : $this->key, $value); + if (null !== $this->builderClosure) { + $builderClosure = $this->builderClosure; + $builder = $builderClosure($builder); + } + if($this->ignoreId !== null) { + $builder = $builder->whereNot( + $this->ignoreColumn === null ? (new $this->model())->getKeyName() : $this->ignoreColumn, + $this->ignoreId + ); + } + + return $builder->count() === 0; + } + + /** + * Get the validation error message. + * + * @return string|array + */ + public function message(): string { + return trans('modelValidationRules::validation.unique_model', [ + 'attribute' => $this->attribute, + 'model' => class_basename($this->model), + 'value' => $this->value, + ]); + } + + /** + * @param Closure|null $builderClosure + */ + public function setBuilderClosure(?Closure $builderClosure): void { + $this->builderClosure = $builderClosure; + } + + /** + * @param Closure $builderClosure + * @return $this + */ + public function query(Closure $builderClosure): UniqueEloquent + { + $this->setBuilderClosure($builderClosure); + return $this; + } + + /** + * @param mixed $id + * @param string|null $column + */ + public function setIgnore($id, ?string $column = null): void + { + $this->ignoreId = $id; + $this->ignoreColumn = $column; + } + + /** + * @param $id + * @param string|null $column + * @return UniqueEloquent + */ + public function ignore($id, ?string $column = null): UniqueEloquent + { + $this->setIgnore($id, $column); + + return $this; + } +} diff --git a/tests/Feature/ExistEloquentTest.php b/tests/Feature/ExistsEloquentTest.php similarity index 69% rename from tests/Feature/ExistEloquentTest.php rename to tests/Feature/ExistsEloquentTest.php index 83e9b56..a26b7d8 100644 --- a/tests/Feature/ExistEloquentTest.php +++ b/tests/Feature/ExistsEloquentTest.php @@ -4,14 +4,14 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Foundation\Testing\RefreshDatabase; -use Korridor\LaravelModelValidationRules\Rules\ExistEloquent; +use Illuminate\Support\Facades\Lang; +use Illuminate\Support\Str; +use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent; use Korridor\LaravelModelValidationRules\Tests\TestCase; use Korridor\LaravelModelValidationRules\Tests\TestEnvironment\Models\Fact; use Korridor\LaravelModelValidationRules\Tests\TestEnvironment\Models\User; -use Lang; -use Str; -class ExistEloquentTest extends TestCase +class ExistsEloquentTest extends TestCase { use RefreshDatabase; @@ -21,13 +21,13 @@ class ExistEloquentTest extends TestCase public function testThatValidationFailsIfEntryDoesNotExistInDatabase() { - $rule = new ExistEloquent(User::class); + $rule = new ExistsEloquent(User::class); $this->assertFalse($rule->passes('id', 1)); } public function testThatValidationFailsIfEntryIsSoftdeleted() { - $rule = new ExistEloquent(User::class); + $rule = new ExistsEloquent(User::class); $user = User::create([ 'id' => 1, 'name' => 'Testname', @@ -41,9 +41,9 @@ public function testThatValidationFailsIfEntryIsSoftdeleted() $this->assertCount(0, User::all()); } - public function testThatValidationFailsIfEntryWithCorrectAttributeExists() + public function testThatValidationPassesIfEntryWithCorrectAttributeExists() { - $rule = new ExistEloquent(User::class); + $rule = new ExistsEloquent(User::class); User::create([ 'id' => 2, 'name' => 'Testname', @@ -61,13 +61,13 @@ public function testThatValidationFailsIfEntryWithCorrectAttributeExists() public function testThatValidationFailsIfEntryDoesNotExistInDatabaseUsingOtherAttribute() { - $rule = new ExistEloquent(User::class, 'other_id'); + $rule = new ExistsEloquent(User::class, 'other_id'); $this->assertFalse($rule->passes('id', 1)); } public function testThatValidationFailsIfEntryIsSoftdeletedUsingOtherAttribute() { - $rule = new ExistEloquent(User::class, 'other_id'); + $rule = new ExistsEloquent(User::class, 'other_id'); $user = User::create([ 'id' => 1, 'other_id' => 3, @@ -82,9 +82,9 @@ public function testThatValidationFailsIfEntryIsSoftdeletedUsingOtherAttribute() $this->assertCount(0, User::all()); } - public function testThatValidationFailsIfEntryWithCorrectAttributeExistsUsingOtherAttribute() + public function testThatValidationPassesIfEntryWithCorrectAttributeExistsUsingOtherAttribute() { - $rule = new ExistEloquent(User::class, 'other_id'); + $rule = new ExistsEloquent(User::class, 'other_id'); User::create([ 'id' => 2, 'other_id' => 4, @@ -102,9 +102,9 @@ public function testThatValidationFailsIfEntryWithCorrectAttributeExistsUsingOth * Tests with builder closure */ - public function testThatValidationPassesIfRuleChecksThatFactExistsAndBelongsToUser() + public function testThatValidationPassesIfRuleChecksThatFactExistsAndBelongsToUserUsingConstructor() { - $rule = new ExistEloquent(Fact::class, null, function (Builder $builder) { + $rule = new ExistsEloquent(Fact::class, null, function (Builder $builder) { return $builder->where('user_id', 6); }); User::create([ @@ -128,6 +128,32 @@ public function testThatValidationPassesIfRuleChecksThatFactExistsAndBelongsToUs $this->assertCount(1, Fact::all()); } + public function testThatValidationPassesIfRuleChecksThatFactExistsAndBelongsToUserUsingFunction() + { + $rule = (new ExistsEloquent(Fact::class))->query(function (Builder $builder) { + return $builder->where('user_id', 6); + }); + User::create([ + 'id' => 6, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + Fact::create([ + 'id' => 1, + 'user_id' => 6, + 'type' => 'type1', + 'description' => 'Long desc', + ]); + $this->assertTrue($rule->passes('id', 1)); + $this->assertCount(1, User::withTrashed()->get()); + $this->assertCount(1, User::all()); + $this->assertCount(1, Fact::withTrashed()->get()); + $this->assertCount(1, Fact::all()); + } + /* * Test language support */ @@ -135,9 +161,9 @@ public function testThatValidationPassesIfRuleChecksThatFactExistsAndBelongsToUs public function testThatValidationParametersAreWorkingCorrectly() { Lang::addLines([ - 'validation.exist_model' => ':attribute :model :value', - ], Lang::getLocale()); - $rule = new ExistEloquent(User::class); + 'validation.exists_model' => ':attribute :model :value', + ], Lang::getLocale(), 'modelValidationRules'); + $rule = new ExistsEloquent(User::class); User::create([ 'id' => 2, 'name' => 'Testname', diff --git a/tests/Feature/UniqueEloquentTest.php b/tests/Feature/UniqueEloquentTest.php new file mode 100644 index 0000000..3f80783 --- /dev/null +++ b/tests/Feature/UniqueEloquentTest.php @@ -0,0 +1,225 @@ +assertTrue($rule->passes('id', 1)); + } + + public function testThatValidationPassesIfEntryIsSoftdeleted() + { + $rule = new UniqueEloquent(User::class); + $user = User::create([ + 'id' => 1, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $user->delete(); + $this->assertTrue($rule->passes('id', 1)); + $this->assertCount(1, User::withTrashed()->get()); + $this->assertCount(0, User::all()); + } + + public function testThatValidationFailsIfEntryWithCorrectAttributeExists() + { + $rule = new UniqueEloquent(User::class); + User::create([ + 'id' => 2, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $this->assertFalse($rule->passes('id', 2)); + $this->assertCount(1, User::all()); + } + + /* + * Tests with other attribute + */ + + public function testThatValidationPassesIfEntryDoesNotExistInDatabaseUsingOtherAttribute() + { + $rule = new UniqueEloquent(User::class, 'other_id'); + $this->assertTrue($rule->passes('id', 1)); + } + + public function testThatValidationPassesIfEntryIsSoftdeletedUsingOtherAttribute() + { + $rule = new UniqueEloquent(User::class, 'other_id'); + $user = User::create([ + 'id' => 1, + 'other_id' => 3, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $user->delete(); + $this->assertTrue($rule->passes('id', 3)); + $this->assertCount(1, User::withTrashed()->get()); + $this->assertCount(0, User::all()); + } + + public function testThatValidationFailsIfEntryWithCorrectAttributeExistsUsingOtherAttribute() + { + $rule = new UniqueEloquent(User::class, 'other_id'); + User::create([ + 'id' => 2, + 'other_id' => 4, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $this->assertFalse($rule->passes('id', 4)); + $this->assertCount(1, User::withTrashed()->get()); + $this->assertCount(1, User::all()); + } + + /* + * Tests with builder closure + */ + + public function testThatValidationFailsIfRuleChecksThatFactExistsAndBelongsToUserUsingConstructor() + { + $rule = new UniqueEloquent(Fact::class, null, function (Builder $builder) { + return $builder->where('user_id', 6); + }); + User::create([ + 'id' => 6, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + Fact::create([ + 'id' => 1, + 'user_id' => 6, + 'type' => 'type1', + 'description' => 'Long desc', + ]); + $this->assertFalse($rule->passes('id', 1)); + $this->assertCount(1, User::withTrashed()->get()); + $this->assertCount(1, User::all()); + $this->assertCount(1, Fact::withTrashed()->get()); + $this->assertCount(1, Fact::all()); + } + + public function testThatValidationFailsIfRuleChecksThatFactExistsAndBelongsToUserUsingFunction() + { + $rule = (new UniqueEloquent(Fact::class))->query(function (Builder $builder) { + return $builder->where('user_id', 6); + }); + User::create([ + 'id' => 6, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + Fact::create([ + 'id' => 1, + 'user_id' => 6, + 'type' => 'type1', + 'description' => 'Long desc', + ]); + $this->assertFalse($rule->passes('id', 1)); + $this->assertCount(1, User::withTrashed()->get()); + $this->assertCount(1, User::all()); + $this->assertCount(1, Fact::withTrashed()->get()); + $this->assertCount(1, Fact::all()); + } + + /* + * Test language support + */ + + public function testThatValidationParametersAreWorkingCorrectly() + { + Lang::addLines([ + 'validation.unique_model' => ':attribute :model :value', + ], Lang::getLocale(), 'modelValidationRules'); + $rule = new UniqueEloquent(User::class); + User::create([ + 'id' => 2, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $rule->passes('id', 2); + $this->assertEquals('id User 2', $rule->message()); + } + + /* + * Test ignore + */ + + public function testIgnoringEntryWithDefaultIdColumn() + { + $rule = (new UniqueEloquent(User::class))->ignore(1); + User::create([ + 'id' => 1, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name1@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + User::create([ + 'id' => 2, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name2@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $this->assertTrue($rule->passes('id', 1)); + } + + public function testIgnoringEntryWithGivenIdColum() + { + $rule = (new UniqueEloquent(User::class))->ignore('name1@test.com', 'email'); + User::create([ + 'id' => 1, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name1@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + User::create([ + 'id' => 2, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name2@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $this->assertTrue($rule->passes('id', 'name1@test.com')); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index f0de29d..79efb04 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -12,6 +12,7 @@ abstract class TestCase extends Orchestra { + public function setUp(): void { parent::setUp(); @@ -21,6 +22,10 @@ public function setUp(): void $this->app->make(EloquentFactory::class)->load(__DIR__.'/TestClasses/Factories'); } + /** + * @param \Illuminate\Foundation\Application $app + * @return array + */ protected function getPackageProviders($app) { return [ From b3b0f7c4f7d2c18bd5dfc45f0829863a06e5ca8a Mon Sep 17 00:00:00 2001 From: korridor <26689068+korridor@users.noreply.github.com> Date: Wed, 18 Sep 2019 22:21:55 +0200 Subject: [PATCH 02/11] Added travis ci config file --- .travis.yml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..44894d1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,38 @@ +cache: + directories: + - $HOME/.composer/cache + +language: php + +matrix: + include: + - php: 7.2 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.2 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.3 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.3 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.2 + env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.2 + env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.3 + env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.3 + env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable' + fast_finish: true + +before_script: + - composer config discard-changes true + +before_install: + - travis_retry composer self-update + - travis_retry composer require "laravel/framework:${LARAVEL}" "orchestra/testbench:${TESTBENCH}" --no-interaction --no-update + +install: + - travis_retry composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction --no-suggest + +script: + - vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover From 3dea241ccbcb366f82e764c16d2b9fca6d14e757 Mon Sep 17 00:00:00 2001 From: korridor <26689068+korridor@users.noreply.github.com> Date: Wed, 18 Sep 2019 22:26:27 +0200 Subject: [PATCH 03/11] Removed paltform config from composer.json --- composer.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 90214ed..4ceca09 100644 --- a/composer.json +++ b/composer.json @@ -44,9 +44,6 @@ } }, "config": { - "sort-packages": true, - "platform": { - "php": "7.1" - } + "sort-packages": true } } From 0646ef6323ce3250a86b6e8f16ab2a9c250144c9 Mon Sep 17 00:00:00 2001 From: korridor <26689068+korridor@users.noreply.github.com> Date: Wed, 18 Sep 2019 22:52:17 +0200 Subject: [PATCH 04/11] Formatted code; Added style ci config file and editorconfig --- .editorconfig | 15 + .styleci.yml | 1 + src/ModelValidationServiceProvider.php | 8 +- src/Rules/ExistsEloquent.php | 46 +-- src/Rules/UniqueEloquent.php | 259 ++++++++-------- tests/Feature/ExistsEloquentTest.php | 50 +-- tests/Feature/UniqueEloquentTest.php | 402 ++++++++++++------------- tests/TestCase.php | 9 +- 8 files changed, 406 insertions(+), 384 deletions(-) create mode 100644 .editorconfig create mode 100644 .styleci.yml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..cd8eb86 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +; This file is for unifying the coding style for different editors and IDEs. +; More information at http://editorconfig.org + +root = true + +[*] +charset = utf-8 +indent_size = 4 +indent_style = space +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 0000000..0285f17 --- /dev/null +++ b/.styleci.yml @@ -0,0 +1 @@ +preset: laravel diff --git a/src/ModelValidationServiceProvider.php b/src/ModelValidationServiceProvider.php index 92a2367..afb1c05 100644 --- a/src/ModelValidationServiceProvider.php +++ b/src/ModelValidationServiceProvider.php @@ -21,9 +21,9 @@ public function register() */ public function boot() { - $this->publishes([ - __DIR__.'/../resources/lang' => resource_path('lang/vendor/modelValidationRules'), - ]); - $this->loadTranslationsFrom(__DIR__.'/../resources/lang/', 'modelValidationRules'); + $this->publishes([ + __DIR__.'/../resources/lang' => resource_path('lang/vendor/modelValidationRules'), + ]); + $this->loadTranslationsFrom(__DIR__.'/../resources/lang/', 'modelValidationRules'); } } diff --git a/src/Rules/ExistsEloquent.php b/src/Rules/ExistsEloquent.php index 5090d0a..781b313 100644 --- a/src/Rules/ExistsEloquent.php +++ b/src/Rules/ExistsEloquent.php @@ -3,8 +3,8 @@ namespace Korridor\LaravelModelValidationRules\Rules; use Closure; -use Illuminate\Database\Eloquent\Model; use Illuminate\Contracts\Validation\Rule; +use Illuminate\Database\Eloquent\Model; class ExistsEloquent implements Rule { @@ -44,7 +44,7 @@ public function __construct(string $model, ?string $key = null, ?Closure $builde { $this->model = $model; $this->key = $key; - $this->setBuilderClosure($builderClosure); + $this->setBuilderClosure($builderClosure); } /** @@ -80,27 +80,29 @@ public function passes($attribute, $value): bool */ public function message(): string { - return trans('modelValidationRules::validation.exists_model', [ - 'attribute' => $this->attribute, - 'model' => class_basename($this->model), - 'value' => $this->value, - ]); + return trans('modelValidationRules::validation.exists_model', [ + 'attribute' => $this->attribute, + 'model' => class_basename($this->model), + 'value' => $this->value, + ]); + } + + /** + * @param Closure|null $builderClosure + */ + public function setBuilderClosure(?Closure $builderClosure) + { + $this->builderClosure = $builderClosure; } - /** - * @param Closure|null $builderClosure - */ - public function setBuilderClosure(?Closure $builderClosure) { - $this->builderClosure = $builderClosure; - } + /** + * @param Closure $builderClosure + * @return $this + */ + public function query(Closure $builderClosure): ExistsEloquent + { + $this->setBuilderClosure($builderClosure); - /** - * @param Closure $builderClosure - * @return $this - */ - public function query(Closure $builderClosure): ExistsEloquent - { - $this->setBuilderClosure($builderClosure); - return $this; - } + return $this; + } } diff --git a/src/Rules/UniqueEloquent.php b/src/Rules/UniqueEloquent.php index 9be24c7..af88b8d 100644 --- a/src/Rules/UniqueEloquent.php +++ b/src/Rules/UniqueEloquent.php @@ -6,131 +6,136 @@ use Illuminate\Contracts\Validation\Rule; use Illuminate\Database\Eloquent\Model; -class UniqueEloquent implements Rule { - - /** - * @var string - */ - private $model; - - /** - * @var string|null - */ - private $key; - - /** - * @var Closure|null - */ - private $builderClosure; - - /** - * @var string - */ - private $attribute; - - /** - * @var mixed - */ - private $value; - - /** - * @var mixed - */ - private $ignoreId; - - /** - * @var string - */ - private $ignoreColumn; - - /** - * UniqueEloquent constructor. - * @param string $model - * @param string|null $key - * @param Closure|null $builderClosure - */ - public function __construct(string $model, ?string $key = null, ?Closure $builderClosure = null) { - $this->model = $model; - $this->key = $key; - $this->setBuilderClosure($builderClosure); - } - - /** - * Determine if the validation rule passes. - * - * @param string $attribute - * @param mixed $value - * @return bool - */ - public function passes($attribute, $value): bool { - $this->attribute = $attribute; - $this->value = $value; - /** @var Model $builder */ - $builder = new $this->model(); - $builder = $builder->where($this->key === null ? (new $this->model())->getKeyName() : $this->key, $value); - if (null !== $this->builderClosure) { - $builderClosure = $this->builderClosure; - $builder = $builderClosure($builder); - } - if($this->ignoreId !== null) { - $builder = $builder->whereNot( - $this->ignoreColumn === null ? (new $this->model())->getKeyName() : $this->ignoreColumn, - $this->ignoreId - ); - } - - return $builder->count() === 0; - } - - /** - * Get the validation error message. - * - * @return string|array - */ - public function message(): string { - return trans('modelValidationRules::validation.unique_model', [ - 'attribute' => $this->attribute, - 'model' => class_basename($this->model), - 'value' => $this->value, - ]); - } - - /** - * @param Closure|null $builderClosure - */ - public function setBuilderClosure(?Closure $builderClosure): void { - $this->builderClosure = $builderClosure; - } - - /** - * @param Closure $builderClosure - * @return $this - */ - public function query(Closure $builderClosure): UniqueEloquent - { - $this->setBuilderClosure($builderClosure); - return $this; - } - - /** - * @param mixed $id - * @param string|null $column - */ - public function setIgnore($id, ?string $column = null): void - { - $this->ignoreId = $id; - $this->ignoreColumn = $column; - } - - /** - * @param $id - * @param string|null $column - * @return UniqueEloquent - */ - public function ignore($id, ?string $column = null): UniqueEloquent - { - $this->setIgnore($id, $column); - - return $this; - } +class UniqueEloquent implements Rule +{ + /** + * @var string + */ + private $model; + + /** + * @var string|null + */ + private $key; + + /** + * @var Closure|null + */ + private $builderClosure; + + /** + * @var string + */ + private $attribute; + + /** + * @var mixed + */ + private $value; + + /** + * @var mixed + */ + private $ignoreId; + + /** + * @var string + */ + private $ignoreColumn; + + /** + * UniqueEloquent constructor. + * @param string $model + * @param string|null $key + * @param Closure|null $builderClosure + */ + public function __construct(string $model, ?string $key = null, ?Closure $builderClosure = null) + { + $this->model = $model; + $this->key = $key; + $this->setBuilderClosure($builderClosure); + } + + /** + * Determine if the validation rule passes. + * + * @param string $attribute + * @param mixed $value + * @return bool + */ + public function passes($attribute, $value): bool + { + $this->attribute = $attribute; + $this->value = $value; + /** @var Model $builder */ + $builder = new $this->model(); + $builder = $builder->where(null === $this->key ? (new $this->model())->getKeyName() : $this->key, $value); + if (null !== $this->builderClosure) { + $builderClosure = $this->builderClosure; + $builder = $builderClosure($builder); + } + if (null !== $this->ignoreId) { + $builder = $builder->whereNot( + null === $this->ignoreColumn ? (new $this->model())->getKeyName() : $this->ignoreColumn, + $this->ignoreId + ); + } + + return 0 === $builder->count(); + } + + /** + * Get the validation error message. + * + * @return string|array + */ + public function message(): string + { + return trans('modelValidationRules::validation.unique_model', [ + 'attribute' => $this->attribute, + 'model' => class_basename($this->model), + 'value' => $this->value, + ]); + } + + /** + * @param Closure|null $builderClosure + */ + public function setBuilderClosure(?Closure $builderClosure): void + { + $this->builderClosure = $builderClosure; + } + + /** + * @param Closure $builderClosure + * @return $this + */ + public function query(Closure $builderClosure): UniqueEloquent + { + $this->setBuilderClosure($builderClosure); + + return $this; + } + + /** + * @param mixed $id + * @param string|null $column + */ + public function setIgnore($id, ?string $column = null): void + { + $this->ignoreId = $id; + $this->ignoreColumn = $column; + } + + /** + * @param $id + * @param string|null $column + * @return UniqueEloquent + */ + public function ignore($id, ?string $column = null): UniqueEloquent + { + $this->setIgnore($id, $column); + + return $this; + } } diff --git a/tests/Feature/ExistsEloquentTest.php b/tests/Feature/ExistsEloquentTest.php index a26b7d8..00bdbf9 100644 --- a/tests/Feature/ExistsEloquentTest.php +++ b/tests/Feature/ExistsEloquentTest.php @@ -128,31 +128,31 @@ public function testThatValidationPassesIfRuleChecksThatFactExistsAndBelongsToUs $this->assertCount(1, Fact::all()); } - public function testThatValidationPassesIfRuleChecksThatFactExistsAndBelongsToUserUsingFunction() - { - $rule = (new ExistsEloquent(Fact::class))->query(function (Builder $builder) { - return $builder->where('user_id', 6); - }); - User::create([ - 'id' => 6, - 'other_id' => null, - 'name' => 'Testname', - 'email' => 'name@test.com', - 'password' => bcrypt('secret'), - 'remember_token' => Str::random(10), - ]); - Fact::create([ - 'id' => 1, - 'user_id' => 6, - 'type' => 'type1', - 'description' => 'Long desc', - ]); - $this->assertTrue($rule->passes('id', 1)); - $this->assertCount(1, User::withTrashed()->get()); - $this->assertCount(1, User::all()); - $this->assertCount(1, Fact::withTrashed()->get()); - $this->assertCount(1, Fact::all()); - } + public function testThatValidationPassesIfRuleChecksThatFactExistsAndBelongsToUserUsingFunction() + { + $rule = (new ExistsEloquent(Fact::class))->query(function (Builder $builder) { + return $builder->where('user_id', 6); + }); + User::create([ + 'id' => 6, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + Fact::create([ + 'id' => 1, + 'user_id' => 6, + 'type' => 'type1', + 'description' => 'Long desc', + ]); + $this->assertTrue($rule->passes('id', 1)); + $this->assertCount(1, User::withTrashed()->get()); + $this->assertCount(1, User::all()); + $this->assertCount(1, Fact::withTrashed()->get()); + $this->assertCount(1, Fact::all()); + } /* * Test language support diff --git a/tests/Feature/UniqueEloquentTest.php b/tests/Feature/UniqueEloquentTest.php index 3f80783..7dd2628 100644 --- a/tests/Feature/UniqueEloquentTest.php +++ b/tests/Feature/UniqueEloquentTest.php @@ -11,215 +11,215 @@ use Korridor\LaravelModelValidationRules\Tests\TestEnvironment\Models\Fact; use Korridor\LaravelModelValidationRules\Tests\TestEnvironment\Models\User; -class UniqueEloquentTest extends TestCase { +class UniqueEloquentTest extends TestCase +{ + use RefreshDatabase; - use RefreshDatabase; - - /* + /* * Tests with primary key */ - public function testThatValidationPassesWhenIfEntryDoesNotExistInDatabase() - { - $rule = new UniqueEloquent(User::class); - $this->assertTrue($rule->passes('id', 1)); - } - - public function testThatValidationPassesIfEntryIsSoftdeleted() - { - $rule = new UniqueEloquent(User::class); - $user = User::create([ - 'id' => 1, - 'name' => 'Testname', - 'email' => 'name@test.com', - 'password' => bcrypt('secret'), - 'remember_token' => Str::random(10), - ]); - $user->delete(); - $this->assertTrue($rule->passes('id', 1)); - $this->assertCount(1, User::withTrashed()->get()); - $this->assertCount(0, User::all()); - } - - public function testThatValidationFailsIfEntryWithCorrectAttributeExists() - { - $rule = new UniqueEloquent(User::class); - User::create([ - 'id' => 2, - 'name' => 'Testname', - 'email' => 'name@test.com', - 'password' => bcrypt('secret'), - 'remember_token' => Str::random(10), - ]); - $this->assertFalse($rule->passes('id', 2)); - $this->assertCount(1, User::all()); - } - - /* + public function testThatValidationPassesWhenIfEntryDoesNotExistInDatabase() + { + $rule = new UniqueEloquent(User::class); + $this->assertTrue($rule->passes('id', 1)); + } + + public function testThatValidationPassesIfEntryIsSoftdeleted() + { + $rule = new UniqueEloquent(User::class); + $user = User::create([ + 'id' => 1, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $user->delete(); + $this->assertTrue($rule->passes('id', 1)); + $this->assertCount(1, User::withTrashed()->get()); + $this->assertCount(0, User::all()); + } + + public function testThatValidationFailsIfEntryWithCorrectAttributeExists() + { + $rule = new UniqueEloquent(User::class); + User::create([ + 'id' => 2, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $this->assertFalse($rule->passes('id', 2)); + $this->assertCount(1, User::all()); + } + + /* * Tests with other attribute */ - public function testThatValidationPassesIfEntryDoesNotExistInDatabaseUsingOtherAttribute() - { - $rule = new UniqueEloquent(User::class, 'other_id'); - $this->assertTrue($rule->passes('id', 1)); - } - - public function testThatValidationPassesIfEntryIsSoftdeletedUsingOtherAttribute() - { - $rule = new UniqueEloquent(User::class, 'other_id'); - $user = User::create([ - 'id' => 1, - 'other_id' => 3, - 'name' => 'Testname', - 'email' => 'name@test.com', - 'password' => bcrypt('secret'), - 'remember_token' => Str::random(10), - ]); - $user->delete(); - $this->assertTrue($rule->passes('id', 3)); - $this->assertCount(1, User::withTrashed()->get()); - $this->assertCount(0, User::all()); - } - - public function testThatValidationFailsIfEntryWithCorrectAttributeExistsUsingOtherAttribute() - { - $rule = new UniqueEloquent(User::class, 'other_id'); - User::create([ - 'id' => 2, - 'other_id' => 4, - 'name' => 'Testname', - 'email' => 'name@test.com', - 'password' => bcrypt('secret'), - 'remember_token' => Str::random(10), - ]); - $this->assertFalse($rule->passes('id', 4)); - $this->assertCount(1, User::withTrashed()->get()); - $this->assertCount(1, User::all()); - } - - /* + public function testThatValidationPassesIfEntryDoesNotExistInDatabaseUsingOtherAttribute() + { + $rule = new UniqueEloquent(User::class, 'other_id'); + $this->assertTrue($rule->passes('id', 1)); + } + + public function testThatValidationPassesIfEntryIsSoftdeletedUsingOtherAttribute() + { + $rule = new UniqueEloquent(User::class, 'other_id'); + $user = User::create([ + 'id' => 1, + 'other_id' => 3, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $user->delete(); + $this->assertTrue($rule->passes('id', 3)); + $this->assertCount(1, User::withTrashed()->get()); + $this->assertCount(0, User::all()); + } + + public function testThatValidationFailsIfEntryWithCorrectAttributeExistsUsingOtherAttribute() + { + $rule = new UniqueEloquent(User::class, 'other_id'); + User::create([ + 'id' => 2, + 'other_id' => 4, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $this->assertFalse($rule->passes('id', 4)); + $this->assertCount(1, User::withTrashed()->get()); + $this->assertCount(1, User::all()); + } + + /* * Tests with builder closure */ - public function testThatValidationFailsIfRuleChecksThatFactExistsAndBelongsToUserUsingConstructor() - { - $rule = new UniqueEloquent(Fact::class, null, function (Builder $builder) { - return $builder->where('user_id', 6); - }); - User::create([ - 'id' => 6, - 'other_id' => null, - 'name' => 'Testname', - 'email' => 'name@test.com', - 'password' => bcrypt('secret'), - 'remember_token' => Str::random(10), - ]); - Fact::create([ - 'id' => 1, - 'user_id' => 6, - 'type' => 'type1', - 'description' => 'Long desc', - ]); - $this->assertFalse($rule->passes('id', 1)); - $this->assertCount(1, User::withTrashed()->get()); - $this->assertCount(1, User::all()); - $this->assertCount(1, Fact::withTrashed()->get()); - $this->assertCount(1, Fact::all()); - } - - public function testThatValidationFailsIfRuleChecksThatFactExistsAndBelongsToUserUsingFunction() - { - $rule = (new UniqueEloquent(Fact::class))->query(function (Builder $builder) { - return $builder->where('user_id', 6); - }); - User::create([ - 'id' => 6, - 'other_id' => null, - 'name' => 'Testname', - 'email' => 'name@test.com', - 'password' => bcrypt('secret'), - 'remember_token' => Str::random(10), - ]); - Fact::create([ - 'id' => 1, - 'user_id' => 6, - 'type' => 'type1', - 'description' => 'Long desc', - ]); - $this->assertFalse($rule->passes('id', 1)); - $this->assertCount(1, User::withTrashed()->get()); - $this->assertCount(1, User::all()); - $this->assertCount(1, Fact::withTrashed()->get()); - $this->assertCount(1, Fact::all()); - } - - /* - * Test language support - */ - - public function testThatValidationParametersAreWorkingCorrectly() - { - Lang::addLines([ - 'validation.unique_model' => ':attribute :model :value', - ], Lang::getLocale(), 'modelValidationRules'); - $rule = new UniqueEloquent(User::class); - User::create([ - 'id' => 2, - 'name' => 'Testname', - 'email' => 'name@test.com', - 'password' => bcrypt('secret'), - 'remember_token' => Str::random(10), - ]); - $rule->passes('id', 2); - $this->assertEquals('id User 2', $rule->message()); - } - - /* - * Test ignore - */ - - public function testIgnoringEntryWithDefaultIdColumn() - { - $rule = (new UniqueEloquent(User::class))->ignore(1); - User::create([ - 'id' => 1, - 'other_id' => null, - 'name' => 'Testname', - 'email' => 'name1@test.com', - 'password' => bcrypt('secret'), - 'remember_token' => Str::random(10), - ]); - User::create([ - 'id' => 2, - 'other_id' => null, - 'name' => 'Testname', - 'email' => 'name2@test.com', - 'password' => bcrypt('secret'), - 'remember_token' => Str::random(10), - ]); - $this->assertTrue($rule->passes('id', 1)); - } - - public function testIgnoringEntryWithGivenIdColum() - { - $rule = (new UniqueEloquent(User::class))->ignore('name1@test.com', 'email'); - User::create([ - 'id' => 1, - 'other_id' => null, - 'name' => 'Testname', - 'email' => 'name1@test.com', - 'password' => bcrypt('secret'), - 'remember_token' => Str::random(10), - ]); - User::create([ - 'id' => 2, - 'other_id' => null, - 'name' => 'Testname', - 'email' => 'name2@test.com', - 'password' => bcrypt('secret'), - 'remember_token' => Str::random(10), - ]); - $this->assertTrue($rule->passes('id', 'name1@test.com')); - } + public function testThatValidationFailsIfRuleChecksThatFactExistsAndBelongsToUserUsingConstructor() + { + $rule = new UniqueEloquent(Fact::class, null, function (Builder $builder) { + return $builder->where('user_id', 6); + }); + User::create([ + 'id' => 6, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + Fact::create([ + 'id' => 1, + 'user_id' => 6, + 'type' => 'type1', + 'description' => 'Long desc', + ]); + $this->assertFalse($rule->passes('id', 1)); + $this->assertCount(1, User::withTrashed()->get()); + $this->assertCount(1, User::all()); + $this->assertCount(1, Fact::withTrashed()->get()); + $this->assertCount(1, Fact::all()); + } + + public function testThatValidationFailsIfRuleChecksThatFactExistsAndBelongsToUserUsingFunction() + { + $rule = (new UniqueEloquent(Fact::class))->query(function (Builder $builder) { + return $builder->where('user_id', 6); + }); + User::create([ + 'id' => 6, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + Fact::create([ + 'id' => 1, + 'user_id' => 6, + 'type' => 'type1', + 'description' => 'Long desc', + ]); + $this->assertFalse($rule->passes('id', 1)); + $this->assertCount(1, User::withTrashed()->get()); + $this->assertCount(1, User::all()); + $this->assertCount(1, Fact::withTrashed()->get()); + $this->assertCount(1, Fact::all()); + } + + /* + * Test language support + */ + + public function testThatValidationParametersAreWorkingCorrectly() + { + Lang::addLines([ + 'validation.unique_model' => ':attribute :model :value', + ], Lang::getLocale(), 'modelValidationRules'); + $rule = new UniqueEloquent(User::class); + User::create([ + 'id' => 2, + 'name' => 'Testname', + 'email' => 'name@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $rule->passes('id', 2); + $this->assertEquals('id User 2', $rule->message()); + } + + /* + * Test ignore + */ + + public function testIgnoringEntryWithDefaultIdColumn() + { + $rule = (new UniqueEloquent(User::class))->ignore(1); + User::create([ + 'id' => 1, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name1@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + User::create([ + 'id' => 2, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name2@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $this->assertTrue($rule->passes('id', 1)); + } + + public function testIgnoringEntryWithGivenIdColum() + { + $rule = (new UniqueEloquent(User::class))->ignore('name1@test.com', 'email'); + User::create([ + 'id' => 1, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name1@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + User::create([ + 'id' => 2, + 'other_id' => null, + 'name' => 'Testname', + 'email' => 'name2@test.com', + 'password' => bcrypt('secret'), + 'remember_token' => Str::random(10), + ]); + $this->assertTrue($rule->passes('id', 'name1@test.com')); + } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 79efb04..2e94eba 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -12,7 +12,6 @@ abstract class TestCase extends Orchestra { - public function setUp(): void { parent::setUp(); @@ -22,10 +21,10 @@ public function setUp(): void $this->app->make(EloquentFactory::class)->load(__DIR__.'/TestClasses/Factories'); } - /** - * @param \Illuminate\Foundation\Application $app - * @return array - */ + /** + * @param \Illuminate\Foundation\Application $app + * @return array + */ protected function getPackageProviders($app) { return [ From d837fe4b2ef11b234c8e3869968cde855de81b19 Mon Sep 17 00:00:00 2001 From: korridor <26689068+korridor@users.noreply.github.com> Date: Wed, 18 Sep 2019 22:52:40 +0200 Subject: [PATCH 05/11] Added testing for laravel 5.7 to travis ci config file --- .travis.yml | 70 +++++++++++++++++++++++++++++++-------------------- composer.json | 4 +-- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index 44894d1..02e19f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,38 +1,54 @@ cache: - directories: - - $HOME/.composer/cache + directories: + - $HOME/.composer/cache language: php matrix: - include: - - php: 7.2 - env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-lowest' - - php: 7.2 - env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-stable' - - php: 7.3 - env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-lowest' - - php: 7.3 - env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-stable' - - php: 7.2 - env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest' - - php: 7.2 - env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable' - - php: 7.3 - env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest' - - php: 7.3 - env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable' - fast_finish: true - -before_script: - - composer config discard-changes true + include: + - php: 7.1 + env: LARAVEL='5.7.*' TESTBENCH='3.7.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.1 + env: LARAVEL='5.7.*' TESTBENCH='3.7.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.2 + env: LARAVEL='5.7.*' TESTBENCH='3.7.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.2 + env: LARAVEL='5.7.*' TESTBENCH='3.7.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.3 + env: LARAVEL='5.7.*' TESTBENCH='3.7.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.3 + env: LARAVEL='5.7.*' TESTBENCH='3.7.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.1 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.1 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.2 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.2 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.3 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.3 + env: LARAVEL='5.8.*' TESTBENCH='3.8.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.2 + env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.2 + env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.3 + env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-lowest' + - php: 7.3 + env: LARAVEL='6.*' TESTBENCH='4.*' COMPOSER_FLAGS='--prefer-stable' + fast_finish: true before_install: - - travis_retry composer self-update - - travis_retry composer require "laravel/framework:${LARAVEL}" "orchestra/testbench:${TESTBENCH}" --no-interaction --no-update + - travis_retry composer self-update + - travis_retry composer require "laravel/framework:${LARAVEL}" "orchestra/testbench:${TESTBENCH}" --no-interaction --no-update install: - - travis_retry composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction --no-suggest + - travis_retry composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction --no-suggest + +before_script: + - composer config discard-changes true script: - - vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover + - vendor/bin/phpunit --coverage-text diff --git a/composer.json b/composer.json index 4ceca09..a47d028 100644 --- a/composer.json +++ b/composer.json @@ -12,10 +12,10 @@ "license": "MIT", "require": { "php": "^7.1|^7.2|^7.3", - "illuminate/support": "^5.8|^6.0" + "illuminate/support": "^5.7|^5.8|^6.0" }, "require-dev": { - "orchestra/testbench": "^3.5|^4.0", + "orchestra/testbench": "^3.7|^3.8|^4.0", "phpunit/phpunit": "^7.0|^8.0", "friendsofphp/php-cs-fixer": "^2.15", "squizlabs/php_codesniffer": "^3.4" From c225eef933c195941f65985b7364a27f119aa7d0 Mon Sep 17 00:00:00 2001 From: korridor <26689068+korridor@users.noreply.github.com> Date: Wed, 18 Sep 2019 23:06:23 +0200 Subject: [PATCH 06/11] Added code formatting diff from style ci --- resources/lang/de/validation.php | 2 +- resources/lang/en/validation.php | 2 +- src/Rules/ExistsEloquent.php | 4 ++-- src/Rules/UniqueEloquent.php | 6 +++--- tests/Feature/ExistsEloquentTest.php | 6 +++--- tests/Feature/UniqueEloquentTest.php | 6 +++--- tests/TestCase.php | 6 +++--- tests/TestEnvironment/Models/Fact.php | 2 +- tests/TestEnvironment/Models/User.php | 2 +- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/resources/lang/de/validation.php b/resources/lang/de/validation.php index 51da175..51581e0 100644 --- a/resources/lang/de/validation.php +++ b/resources/lang/de/validation.php @@ -2,5 +2,5 @@ return [ 'exists_model' => 'Die Ressource existiert nicht.', - 'unique_model' => 'Die Ressource existiert bereits.', + 'unique_model' => 'Die Ressource existiert bereits.', ]; diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index 9781d41..58b0526 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -2,5 +2,5 @@ return [ 'exists_model' => 'The resource does not exist.', - 'unique_model' => 'The resource already exists.', + 'unique_model' => 'The resource already exists.', ]; diff --git a/src/Rules/ExistsEloquent.php b/src/Rules/ExistsEloquent.php index 781b313..72f1832 100644 --- a/src/Rules/ExistsEloquent.php +++ b/src/Rules/ExistsEloquent.php @@ -3,8 +3,8 @@ namespace Korridor\LaravelModelValidationRules\Rules; use Closure; -use Illuminate\Contracts\Validation\Rule; use Illuminate\Database\Eloquent\Model; +use Illuminate\Contracts\Validation\Rule; class ExistsEloquent implements Rule { @@ -99,7 +99,7 @@ public function setBuilderClosure(?Closure $builderClosure) * @param Closure $builderClosure * @return $this */ - public function query(Closure $builderClosure): ExistsEloquent + public function query(Closure $builderClosure): self { $this->setBuilderClosure($builderClosure); diff --git a/src/Rules/UniqueEloquent.php b/src/Rules/UniqueEloquent.php index af88b8d..a1a466d 100644 --- a/src/Rules/UniqueEloquent.php +++ b/src/Rules/UniqueEloquent.php @@ -3,8 +3,8 @@ namespace Korridor\LaravelModelValidationRules\Rules; use Closure; -use Illuminate\Contracts\Validation\Rule; use Illuminate\Database\Eloquent\Model; +use Illuminate\Contracts\Validation\Rule; class UniqueEloquent implements Rule { @@ -110,7 +110,7 @@ public function setBuilderClosure(?Closure $builderClosure): void * @param Closure $builderClosure * @return $this */ - public function query(Closure $builderClosure): UniqueEloquent + public function query(Closure $builderClosure): self { $this->setBuilderClosure($builderClosure); @@ -132,7 +132,7 @@ public function setIgnore($id, ?string $column = null): void * @param string|null $column * @return UniqueEloquent */ - public function ignore($id, ?string $column = null): UniqueEloquent + public function ignore($id, ?string $column = null): self { $this->setIgnore($id, $column); diff --git a/tests/Feature/ExistsEloquentTest.php b/tests/Feature/ExistsEloquentTest.php index 00bdbf9..131343c 100644 --- a/tests/Feature/ExistsEloquentTest.php +++ b/tests/Feature/ExistsEloquentTest.php @@ -2,12 +2,12 @@ namespace Korridor\LaravelModelValidationRules\Tests\Feature; +use Illuminate\Support\Str; +use Illuminate\Support\Facades\Lang; use Illuminate\Database\Eloquent\Builder; use Illuminate\Foundation\Testing\RefreshDatabase; -use Illuminate\Support\Facades\Lang; -use Illuminate\Support\Str; -use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent; use Korridor\LaravelModelValidationRules\Tests\TestCase; +use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent; use Korridor\LaravelModelValidationRules\Tests\TestEnvironment\Models\Fact; use Korridor\LaravelModelValidationRules\Tests\TestEnvironment\Models\User; diff --git a/tests/Feature/UniqueEloquentTest.php b/tests/Feature/UniqueEloquentTest.php index 7dd2628..880704f 100644 --- a/tests/Feature/UniqueEloquentTest.php +++ b/tests/Feature/UniqueEloquentTest.php @@ -2,12 +2,12 @@ namespace Korridor\LaravelModelValidationRules\Tests\Feature; +use Illuminate\Support\Str; +use Illuminate\Support\Facades\Lang; use Illuminate\Database\Eloquent\Builder; use Illuminate\Foundation\Testing\RefreshDatabase; -use Illuminate\Support\Facades\Lang; -use Illuminate\Support\Str; -use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent; use Korridor\LaravelModelValidationRules\Tests\TestCase; +use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent; use Korridor\LaravelModelValidationRules\Tests\TestEnvironment\Models\Fact; use Korridor\LaravelModelValidationRules\Tests\TestEnvironment\Models\User; diff --git a/tests/TestCase.php b/tests/TestCase.php index 2e94eba..70dd940 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,13 +2,13 @@ namespace Korridor\LaravelModelValidationRules\Tests; +use Illuminate\Events\Dispatcher; use Illuminate\Container\Container; use Illuminate\Database\Capsule\Manager; -use Illuminate\Database\Eloquent\Factory as EloquentFactory; use Illuminate\Database\Schema\Blueprint; -use Illuminate\Events\Dispatcher; -use Korridor\LaravelModelValidationRules\ModelValidationServiceProvider; use Orchestra\Testbench\TestCase as Orchestra; +use Illuminate\Database\Eloquent\Factory as EloquentFactory; +use Korridor\LaravelModelValidationRules\ModelValidationServiceProvider; abstract class TestCase extends Orchestra { diff --git a/tests/TestEnvironment/Models/Fact.php b/tests/TestEnvironment/Models/Fact.php index 6c0776f..5e3158e 100644 --- a/tests/TestEnvironment/Models/Fact.php +++ b/tests/TestEnvironment/Models/Fact.php @@ -3,8 +3,8 @@ namespace Korridor\LaravelModelValidationRules\Tests\TestEnvironment\Models; use Illuminate\Database\Eloquent\Model; -use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Database\Eloquent\Relations\BelongsTo; class Fact extends Model { diff --git a/tests/TestEnvironment/Models/User.php b/tests/TestEnvironment/Models/User.php index 684fc08..85da702 100644 --- a/tests/TestEnvironment/Models/User.php +++ b/tests/TestEnvironment/Models/User.php @@ -3,8 +3,8 @@ namespace Korridor\LaravelModelValidationRules\Tests\TestEnvironment\Models; use Illuminate\Database\Eloquent\Model; -use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Database\Eloquent\Relations\HasMany; class User extends Model { From 8a023bb88a34f109a3518905dc93f2937862550e Mon Sep 17 00:00:00 2001 From: korridor <26689068+korridor@users.noreply.github.com> Date: Wed, 18 Sep 2019 23:06:49 +0200 Subject: [PATCH 07/11] Changed php_cs config file --- .php_cs | 12 +----------- phpcs.xml | 1 + 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/.php_cs b/.php_cs index 0eb7ffb..398a1a5 100644 --- a/.php_cs +++ b/.php_cs @@ -3,17 +3,7 @@ return PhpCsFixer\Config::create() ->setRiskyAllowed(false) ->setRules([ - '@Symfony' => true, - 'array_syntax' => ['syntax' => 'short'], - 'ordered_imports' => true, - 'protected_to_private' => false, - // Part of future @Symfony ruleset in PHP-CS-Fixer To be removed from the config file once upgrading - 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], - // custom - 'phpdoc_separation' => false, - 'phpdoc_align' => false, - 'phpdoc_no_alias_tag' => false, - 'array_indentation' => true, + '@PSR2' => true, ]) ->setUsingCache(true) ->setFinder( diff --git a/phpcs.xml b/phpcs.xml index 4f5006d..be378d7 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -5,5 +5,6 @@ src/ + resources/ tests/ From 0db569d9f7bd8abd0c71d1a3a3b16e8e195d3301 Mon Sep 17 00:00:00 2001 From: korridor <26689068+korridor@users.noreply.github.com> Date: Wed, 18 Sep 2019 23:24:10 +0200 Subject: [PATCH 08/11] Added shields to readme --- readme.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/readme.md b/readme.md index b9cc6f7..702abd9 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,10 @@ # Laravel model validation rules +[![Latest Version on Packagist](https://img.shields.io/packagist/v/korridor/laravel-model-validation-rules?style=flat-square)](https://packagist.org/packages/korridor/laravel-model-validation-rules) +[![License](https://img.shields.io/packagist/l/korridor/laravel-model-validation-rules?style=flat-square)](license.md) +[![TravisCI](https://img.shields.io/travis/korridor/laravel-model-validation-rules?style=flat-square)](https://travis-ci.org/korridor/laravel-model-validation-rules) +[![StyleCI](https://styleci.io/repos/208495858/shield)](https://styleci.io/repos/208495858) + This package is an alternative to the Laravel built-in validation rules `exist` and `unique`. This has the following advantages: From 05756fa2dbb0375cb5e3282b7560d20185eb4e75 Mon Sep 17 00:00:00 2001 From: korridor <26689068+korridor@users.noreply.github.com> Date: Wed, 18 Sep 2019 23:26:36 +0200 Subject: [PATCH 09/11] Added laravel 5.6 to travis build --- .travis.yml | 10 +++++----- composer.json | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 02e19f4..cc11811 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,15 +7,15 @@ language: php matrix: include: - php: 7.1 - env: LARAVEL='5.7.*' TESTBENCH='3.7.*' COMPOSER_FLAGS='--prefer-lowest' + env: LARAVEL='5.6.*' TESTBENCH='3.6.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.2 + env: LARAVEL='5.6.*' TESTBENCH='3.6.*' COMPOSER_FLAGS='--prefer-stable' + - php: 7.3 + env: LARAVEL='5.6.*' TESTBENCH='3.6.*' COMPOSER_FLAGS='--prefer-stable' - php: 7.1 env: LARAVEL='5.7.*' TESTBENCH='3.7.*' COMPOSER_FLAGS='--prefer-stable' - - php: 7.2 - env: LARAVEL='5.7.*' TESTBENCH='3.7.*' COMPOSER_FLAGS='--prefer-lowest' - php: 7.2 env: LARAVEL='5.7.*' TESTBENCH='3.7.*' COMPOSER_FLAGS='--prefer-stable' - - php: 7.3 - env: LARAVEL='5.7.*' TESTBENCH='3.7.*' COMPOSER_FLAGS='--prefer-lowest' - php: 7.3 env: LARAVEL='5.7.*' TESTBENCH='3.7.*' COMPOSER_FLAGS='--prefer-stable' - php: 7.1 diff --git a/composer.json b/composer.json index a47d028..072ac4e 100644 --- a/composer.json +++ b/composer.json @@ -12,10 +12,10 @@ "license": "MIT", "require": { "php": "^7.1|^7.2|^7.3", - "illuminate/support": "^5.7|^5.8|^6.0" + "illuminate/support": "^5.6|^5.7|^5.8|^6.0" }, "require-dev": { - "orchestra/testbench": "^3.7|^3.8|^4.0", + "orchestra/testbench": "^3.6|^3.7|^3.8|^4.0", "phpunit/phpunit": "^7.0|^8.0", "friendsofphp/php-cs-fixer": "^2.15", "squizlabs/php_codesniffer": "^3.4" From bd1795a29324569c8d1ddb55bdeab0b20c092fa8 Mon Sep 17 00:00:00 2001 From: korridor <26689068+korridor@users.noreply.github.com> Date: Wed, 18 Sep 2019 23:57:30 +0200 Subject: [PATCH 10/11] Updated composer --- composer.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.lock b/composer.lock index 922d894..0821d3b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "78eefea9de8cabbc02fd08e0eb83f42b", + "content-hash": "d5e92e288aa6a630e724dfabecef493a", "packages": [ { "name": "doctrine/inflector", @@ -3744,16 +3744,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a" + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e899757bb3df5ff6e95089132f32cd59aac2220a", - "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { @@ -3789,7 +3789,7 @@ "keywords": [ "tokenizer" ], - "time": "2019-07-25T05:29:42+00:00" + "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", @@ -4802,7 +4802,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "7.*" + "php": "^7.1|^7.2|^7.3" }, "platform-dev": [] } From 5a29192cb79e923795212773b5c0b379ee56de2c Mon Sep 17 00:00:00 2001 From: korridor <26689068+korridor@users.noreply.github.com> Date: Wed, 18 Sep 2019 23:57:49 +0200 Subject: [PATCH 11/11] Updated readme --- readme.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/readme.md b/readme.md index 702abd9..e90a22c 100644 --- a/readme.md +++ b/readme.md @@ -5,12 +5,13 @@ [![TravisCI](https://img.shields.io/travis/korridor/laravel-model-validation-rules?style=flat-square)](https://travis-ci.org/korridor/laravel-model-validation-rules) [![StyleCI](https://styleci.io/repos/208495858/shield)](https://styleci.io/repos/208495858) -This package is an alternative to the Laravel built-in validation rules `exist` and `unique`. -This has the following advantages: +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. - - It uses existing models instead of directly querying the database. - - The rule can be easily extended with the Eloquent builder. - - Softdeletes are working +**Advantages** + - The rule can be easily extended with the Eloquent builder. (scopes etc.) + - Softdeletes are working out of the box. + - Logic implemented into the models work in the validation as well. (multi tenancy system, etc.) ## Installation @@ -29,11 +30,14 @@ of the package to the `resources/lang/vendor/modelValidationRules` folder. php artisan vendor:publish --provider="Korridor\LaravelModelValidationRules\ModelValidationServiceProvider" ``` -## Rules +### Requirements -### ExistEloquent +This package is tested for the following Laravel versions: -### UniqueEloquent + - 6.0 + - 5.8 + - 5.7 (stable only) + - 5.6 (stable only) ## Usage examples @@ -107,4 +111,4 @@ project [laravel-validation-rules](https://github.com/spatie/laravel-validation- ## License -The MIT License (MIT). Please see [license file](license.md) for more information. +This package is licensed under the MIT License (MIT). Please see [license file](license.md) for more information.