8
8
use Illuminate \Contracts \Validation \ValidationRule ;
9
9
use Illuminate \Database \Eloquent \Builder ;
10
10
use Illuminate \Database \Eloquent \Model ;
11
+ use Illuminate \Support \Str ;
11
12
12
13
class UniqueEloquent implements ValidationRule
13
14
{
@@ -63,12 +64,17 @@ class UniqueEloquent implements ValidationRule
63
64
*/
64
65
private bool $ includeSoftDeleted = false ;
65
66
67
+ /**
68
+ * @var bool Whether the ID is a UUID
69
+ */
70
+ private bool $ isFieldUuid = false ;
71
+
66
72
/**
67
73
* UniqueEloquent constructor.
68
74
*
69
- * @param class-string<Model> $model Class name of model.
70
- * @param string|null $key Relevant key in the model.
71
- * @param Closure|null $builderClosure Closure that can extend the eloquent builder
75
+ * @param class-string<Model> $model Class name of model.
76
+ * @param string|null $key Relevant key in the model.
77
+ * @param Closure|null $builderClosure Closure that can extend the eloquent builder
72
78
*/
73
79
public function __construct (string $ model , ?string $ key = null , ?Closure $ builderClosure = null )
74
80
{
@@ -77,17 +83,32 @@ public function __construct(string $model, ?string $key = null, ?Closure $builde
77
83
$ this ->setBuilderClosure ($ builderClosure );
78
84
}
79
85
86
+ /**
87
+ * @param class-string<Model> $model Class name of model.
88
+ * @param string|null $key Relevant key in the model.
89
+ * @param Closure|null $builderClosure Closure that can extend the eloquent builder
90
+ */
91
+ public static function make (string $ model , ?string $ key = null , ?Closure $ builderClosure = null ): self
92
+ {
93
+ return new self ($ model , $ key , $ builderClosure );
94
+ }
95
+
80
96
/**
81
97
* Determine if the validation rule passes.
82
98
*
83
- * @param string $attribute
84
- * @param mixed $value
85
- * @param Closure $fail
99
+ * @param string $attribute
100
+ * @param mixed $value
101
+ * @param Closure $fail
86
102
*
87
103
* @return void
88
104
*/
89
105
public function validate (string $ attribute , mixed $ value , Closure $ fail ): void
90
106
{
107
+ if ($ this ->isFieldUuid ) {
108
+ if (!is_string ($ value ) || !Str::isUuid ($ value )) {
109
+ return ;
110
+ }
111
+ }
91
112
/** @var Model|Builder $builder */
92
113
$ builder = new $ this ->model ();
93
114
$ modelKeyName = $ builder ->getKeyName ();
@@ -112,19 +133,20 @@ public function validate(string $attribute, mixed $value, Closure $fail): void
112
133
if ($ this ->customMessage !== null ) {
113
134
$ fail ($ this ->customMessage );
114
135
} else {
115
- $ fail ($ this ->customMessageTranslationKey ?? 'modelValidationRules::validation.unique_model ' )->translate ([
116
- 'attribute ' => $ attribute ,
117
- 'model ' => strtolower (class_basename ($ this ->model )),
118
- 'value ' => $ value ,
119
- ]);
136
+ $ fail ($ this ->customMessageTranslationKey ?? 'modelValidationRules::validation.unique_model ' )
137
+ ->translate ([
138
+ 'attribute ' => $ attribute ,
139
+ 'model ' => strtolower (class_basename ($ this ->model )),
140
+ 'value ' => $ value ,
141
+ ]);
120
142
}
121
143
}
122
144
}
123
145
124
146
/**
125
147
* Set a custom validation message.
126
148
*
127
- * @param string $message
149
+ * @param string $message
128
150
* @return $this
129
151
*/
130
152
public function withMessage (string $ message ): self
@@ -137,7 +159,7 @@ public function withMessage(string $message): self
137
159
/**
138
160
* Set a translated custom validation message.
139
161
*
140
- * @param string $translationKey
162
+ * @param string $translationKey
141
163
* @return $this
142
164
*/
143
165
public function withCustomTranslation (string $ translationKey ): self
@@ -150,15 +172,15 @@ public function withCustomTranslation(string $translationKey): self
150
172
/**
151
173
* Set a closure that can extend the eloquent builder.
152
174
*
153
- * @param Closure|null $builderClosure
175
+ * @param Closure|null $builderClosure
154
176
*/
155
177
public function setBuilderClosure (?Closure $ builderClosure ): void
156
178
{
157
179
$ this ->builderClosure = $ builderClosure ;
158
180
}
159
181
160
182
/**
161
- * @param Closure $builderClosure
183
+ * @param Closure $builderClosure
162
184
* @return $this
163
185
*/
164
186
public function query (Closure $ builderClosure ): self
@@ -169,8 +191,8 @@ public function query(Closure $builderClosure): self
169
191
}
170
192
171
193
/**
172
- * @param mixed $id
173
- * @param string|null $column
194
+ * @param mixed $id
195
+ * @param string|null $column
174
196
*/
175
197
public function setIgnore (mixed $ id , ?string $ column = null ): void
176
198
{
@@ -180,7 +202,7 @@ public function setIgnore(mixed $id, ?string $column = null): void
180
202
181
203
/**
182
204
* @param mixed $id
183
- * @param string|null $column
205
+ * @param string|null $column
184
206
* @return UniqueEloquent
185
207
*/
186
208
public function ignore (mixed $ id , ?string $ column = null ): self
@@ -201,6 +223,20 @@ public function setIncludeSoftDeleted(bool $includeSoftDeleted): void
201
223
$ this ->includeSoftDeleted = $ includeSoftDeleted ;
202
224
}
203
225
226
+ /**
227
+ * The field has the data type UUID.
228
+ * If a value is not a UUID, the validation will be skipped.
229
+ * This is useful for example for Postgres databases where queries fail if a field with UUID data type is queried with a non-UUID value.
230
+ *
231
+ * @return $this
232
+ */
233
+ public function uuid (): self
234
+ {
235
+ $ this ->isFieldUuid = true ;
236
+
237
+ return $ this ;
238
+ }
239
+
204
240
/**
205
241
* Activate including soft deleted models in the query.
206
242
*
0 commit comments