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/.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/.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/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..cc11811
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,54 @@
+cache:
+ directories:
+ - $HOME/.composer/cache
+
+language: php
+
+matrix:
+ include:
+ - php: 7.1
+ 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-stable'
+ - 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
+
+install:
+ - 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
diff --git a/composer.json b/composer.json
index 3b00991..072ac4e 100644
--- a/composer.json
+++ b/composer.json
@@ -11,11 +11,11 @@
],
"license": "MIT",
"require": {
- "php": "7.*",
- "illuminate/support": "^5.8|^6.0"
+ "php": "^7.1|^7.2|^7.3",
+ "illuminate/support": "^5.6|^5.7|^5.8|^6.0"
},
"require-dev": {
- "orchestra/testbench": "^3.5|^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"
@@ -44,9 +44,6 @@
}
},
"config": {
- "sort-packages": true,
- "platform": {
- "php": "7.1"
- }
+ "sort-packages": true
}
}
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": []
}
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/
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..e90a22c 100644
--- a/readme.md
+++ b/readme.md
@@ -1,16 +1,69 @@
# Laravel model validation rules
+[](https://packagist.org/packages/korridor/laravel-model-validation-rules)
+[](license.md)
+[](https://travis-ci.org/korridor/laravel-model-validation-rules)
+[](https://styleci.io/repos/208495858)
+
+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.)
+ - Softdeletes are working out of the box.
+ - Logic implemented into the models work in the validation as well. (multi tenancy system, etc.)
+
## 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
+### Requirements
+
+This package is tested for the following Laravel versions:
+
+ - 6.0
+ - 5.8
+ - 5.7 (stable only)
+ - 5.6 (stable only)
+
+## 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 +72,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 +88,8 @@ public function rules()
## Contributing
+I am open for suggestions and contributions. Just create an issue or a pull request.
+
### Testing
```bash
@@ -48,6 +104,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.
+This package is licensed under 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..51581e0 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..58b0526 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/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/ExistEloquent.php b/src/Rules/ExistsEloquent.php
similarity index 65%
rename from src/Rules/ExistEloquent.php
rename to src/Rules/ExistsEloquent.php
index 32e618d..72f1832 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,29 @@ public function passes($attribute, $value): bool
*/
public function message(): string
{
- return trans('modelValidationRules::validation.exist_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 $builderClosure
+ * @return $this
+ */
+ public function query(Closure $builderClosure): self
+ {
+ $this->setBuilderClosure($builderClosure);
+
+ return $this;
}
}
diff --git a/src/Rules/UniqueEloquent.php b/src/Rules/UniqueEloquent.php
new file mode 100644
index 0000000..a1a466d
--- /dev/null
+++ b/src/Rules/UniqueEloquent.php
@@ -0,0 +1,141 @@
+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): self
+ {
+ $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): self
+ {
+ $this->setIgnore($id, $column);
+
+ return $this;
+ }
+}
diff --git a/tests/Feature/ExistEloquentTest.php b/tests/Feature/ExistsEloquentTest.php
similarity index 67%
rename from tests/Feature/ExistEloquentTest.php
rename to tests/Feature/ExistsEloquentTest.php
index 83e9b56..131343c 100644
--- a/tests/Feature/ExistEloquentTest.php
+++ b/tests/Feature/ExistsEloquentTest.php
@@ -2,16 +2,16 @@
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 Korridor\LaravelModelValidationRules\Rules\ExistEloquent;
use Korridor\LaravelModelValidationRules\Tests\TestCase;
+use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
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,35 @@ 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([
+ '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([
@@ -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..880704f
--- /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..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
{
@@ -21,6 +21,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 [
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
{