Skip to content

Commit 0df77be

Browse files
committed
Added UniqueEloquentTest; Renamed ExistEloquent to ExistsEloquent
1 parent 87a0f9e commit 0df77be

File tree

10 files changed

+491
-28
lines changed

10 files changed

+491
-28
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
],
1212
"license": "MIT",
1313
"require": {
14-
"php": "7.*",
14+
"php": "^7.1|^7.2|^7.3",
1515
"illuminate/support": "^5.8|^6.0"
1616
},
1717
"require-dev": {

phpunit.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
stopOnFailure="false">
1212
<testsuites>
1313
<testsuite name="Feature">
14-
<directory>tests</directory>
14+
<directory>tests/Feature</directory>
1515
</testsuite>
1616
</testsuites>
1717
<filter>

readme.md

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,60 @@
11
# Laravel model validation rules
22

3+
This package is an alternative to the Laravel built-in validation rules `exist` and `unique`.
4+
This has the following advantages:
5+
6+
- It uses existing models instead of directly querying the database.
7+
- The rule can be easily extended with the Eloquent builder.
8+
- Softdeletes are working
9+
310
## Installation
411

12+
You can install the package via composer with following command:
13+
514
```bash
615
composer require korridor/laravel-model-validation-rules
716
```
817

18+
### Translation
19+
20+
If you want to customize the translations of the validation errors you can publish the translations
21+
of the package to the `resources/lang/vendor/modelValidationRules` folder.
22+
923
```bash
1024
php artisan vendor:publish --provider="Korridor\LaravelModelValidationRules\ModelValidationServiceProvider"
1125
```
1226

13-
## Usage
27+
## Rules
28+
29+
### ExistEloquent
30+
31+
### UniqueEloquent
32+
33+
## Usage examples
34+
35+
**PostStoreRequest**
36+
37+
```php
38+
public function rules()
39+
{
40+
$postId = $this->post->id;
41+
42+
return [
43+
'username' => [new UniqueEloquent(User::class, 'username')],
44+
'title' => ['string'],
45+
'content' => ['string'],
46+
'comments.*.id' => [
47+
'nullable',
48+
new ExistEloquent(Comment::class, null, function (Builder $builder) use ($postId) {
49+
return $builder->where('post_id', $postId);
50+
}),
51+
],
52+
'comments.*.content' => ['string']
53+
];
54+
}
55+
```
56+
57+
**PostUpdateRequest**
1458

1559
```php
1660
public function rules()
@@ -19,6 +63,7 @@ public function rules()
1963

2064
return [
2165
'id' => [new ExistEloquent(Post::class)],
66+
'username' => [new UniqueEloquent(User::class, 'username')->ignore($postId)],
2267
'title' => ['string'],
2368
'content' => ['string'],
2469
'comments.*.id' => [
@@ -34,6 +79,8 @@ public function rules()
3479

3580
## Contributing
3681

82+
I am open for suggestions and contributions. Just create an issue or a pull request.
83+
3784
### Testing
3885

3986
```bash
@@ -48,6 +95,11 @@ composer fix
4895
composer lint
4996
```
5097

98+
## Credits
99+
100+
The structure of the repository and the TestClass is inspired by the
101+
project [laravel-validation-rules](https://github.com/spatie/laravel-validation-rules) by [spatie](https://github.com/spatie).
102+
51103
## License
52104

53105
The MIT License (MIT). Please see [license file](license.md) for more information.

resources/lang/de/validation.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php
22

33
return [
4-
'exist_model' => 'Die Ressource existiert nicht.'
4+
'exists_model' => 'Die Ressource existiert nicht.',
5+
'unique_model' => 'Die Ressource existiert bereits.',
56
];

resources/lang/en/validation.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php
22

33
return [
4-
'exist_model' => 'The resource does not exist.'
4+
'exists_model' => 'The resource does not exist.',
5+
'unique_model' => 'The resource already exists.',
56
];

src/Rules/ExistEloquent.php renamed to src/Rules/ExistsEloquent.php

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
namespace Korridor\LaravelModelValidationRules\Rules;
44

55
use Closure;
6-
use Eloquent;
6+
use Illuminate\Database\Eloquent\Model;
77
use Illuminate\Contracts\Validation\Rule;
88

9-
class ExistEloquent implements Rule
9+
class ExistsEloquent implements Rule
1010
{
1111
/**
1212
* @var string
@@ -44,7 +44,7 @@ public function __construct(string $model, ?string $key = null, ?Closure $builde
4444
{
4545
$this->model = $model;
4646
$this->key = $key;
47-
$this->builderClosure = $builderClosure;
47+
$this->setBuilderClosure($builderClosure);
4848
}
4949

5050
/**
@@ -58,10 +58,10 @@ public function passes($attribute, $value): bool
5858
{
5959
$this->attribute = $attribute;
6060
$this->value = $value;
61-
/** @var Eloquent $builder */
61+
/** @var Model $builder */
6262
$builder = new $this->model();
6363
if (null === $this->key) {
64-
$builder = $builder->where($builder->getKeyName(), $value);
64+
$builder = $builder->where((new $this->model())->getKeyName(), $value);
6565
} else {
6666
$builder = $builder->where($this->key, $value);
6767
}
@@ -80,10 +80,27 @@ public function passes($attribute, $value): bool
8080
*/
8181
public function message(): string
8282
{
83-
return trans('modelValidationRules::validation.exist_model', [
83+
return trans('modelValidationRules::validation.exists_model', [
8484
'attribute' => $this->attribute,
8585
'model' => class_basename($this->model),
8686
'value' => $this->value,
8787
]);
8888
}
89+
90+
/**
91+
* @param Closure|null $builderClosure
92+
*/
93+
public function setBuilderClosure(?Closure $builderClosure) {
94+
$this->builderClosure = $builderClosure;
95+
}
96+
97+
/**
98+
* @param Closure $builderClosure
99+
* @return $this
100+
*/
101+
public function query(Closure $builderClosure): ExistsEloquent
102+
{
103+
$this->setBuilderClosure($builderClosure);
104+
return $this;
105+
}
89106
}

src/Rules/UniqueEloquent.php

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
<?php
2+
3+
namespace Korridor\LaravelModelValidationRules\Rules;
4+
5+
use Closure;
6+
use Illuminate\Contracts\Validation\Rule;
7+
use Illuminate\Database\Eloquent\Model;
8+
9+
class UniqueEloquent implements Rule {
10+
11+
/**
12+
* @var string
13+
*/
14+
private $model;
15+
16+
/**
17+
* @var string|null
18+
*/
19+
private $key;
20+
21+
/**
22+
* @var Closure|null
23+
*/
24+
private $builderClosure;
25+
26+
/**
27+
* @var string
28+
*/
29+
private $attribute;
30+
31+
/**
32+
* @var mixed
33+
*/
34+
private $value;
35+
36+
/**
37+
* @var mixed
38+
*/
39+
private $ignoreId;
40+
41+
/**
42+
* @var string
43+
*/
44+
private $ignoreColumn;
45+
46+
/**
47+
* UniqueEloquent constructor.
48+
* @param string $model
49+
* @param string|null $key
50+
* @param Closure|null $builderClosure
51+
*/
52+
public function __construct(string $model, ?string $key = null, ?Closure $builderClosure = null) {
53+
$this->model = $model;
54+
$this->key = $key;
55+
$this->setBuilderClosure($builderClosure);
56+
}
57+
58+
/**
59+
* Determine if the validation rule passes.
60+
*
61+
* @param string $attribute
62+
* @param mixed $value
63+
* @return bool
64+
*/
65+
public function passes($attribute, $value): bool {
66+
$this->attribute = $attribute;
67+
$this->value = $value;
68+
/** @var Model $builder */
69+
$builder = new $this->model();
70+
$builder = $builder->where($this->key === null ? (new $this->model())->getKeyName() : $this->key, $value);
71+
if (null !== $this->builderClosure) {
72+
$builderClosure = $this->builderClosure;
73+
$builder = $builderClosure($builder);
74+
}
75+
if($this->ignoreId !== null) {
76+
$builder = $builder->whereNot(
77+
$this->ignoreColumn === null ? (new $this->model())->getKeyName() : $this->ignoreColumn,
78+
$this->ignoreId
79+
);
80+
}
81+
82+
return $builder->count() === 0;
83+
}
84+
85+
/**
86+
* Get the validation error message.
87+
*
88+
* @return string|array
89+
*/
90+
public function message(): string {
91+
return trans('modelValidationRules::validation.unique_model', [
92+
'attribute' => $this->attribute,
93+
'model' => class_basename($this->model),
94+
'value' => $this->value,
95+
]);
96+
}
97+
98+
/**
99+
* @param Closure|null $builderClosure
100+
*/
101+
public function setBuilderClosure(?Closure $builderClosure): void {
102+
$this->builderClosure = $builderClosure;
103+
}
104+
105+
/**
106+
* @param Closure $builderClosure
107+
* @return $this
108+
*/
109+
public function query(Closure $builderClosure): UniqueEloquent
110+
{
111+
$this->setBuilderClosure($builderClosure);
112+
return $this;
113+
}
114+
115+
/**
116+
* @param mixed $id
117+
* @param string|null $column
118+
*/
119+
public function setIgnore($id, ?string $column = null): void
120+
{
121+
$this->ignoreId = $id;
122+
$this->ignoreColumn = $column;
123+
}
124+
125+
/**
126+
* @param $id
127+
* @param string|null $column
128+
* @return UniqueEloquent
129+
*/
130+
public function ignore($id, ?string $column = null): UniqueEloquent
131+
{
132+
$this->setIgnore($id, $column);
133+
134+
return $this;
135+
}
136+
}

0 commit comments

Comments
 (0)