Skip to content

Commit 49370c7

Browse files
committed
Add option to include soft deleted models
1 parent 32fab9d commit 49370c7

File tree

4 files changed

+213
-0
lines changed

4 files changed

+213
-0
lines changed

src/Rules/ExistsEloquent.php

+33
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ class ExistsEloquent implements ValidationRule
4646
*/
4747
private ?string $customMessageTranslationKey = null;
4848

49+
/**
50+
* Include soft deleted models in the query.
51+
*
52+
* @var bool
53+
*/
54+
private bool $includeSoftDeleted = false;
55+
4956
/**
5057
* Create a new rule instance.
5158
*
@@ -110,6 +117,10 @@ public function validate(string $attribute, mixed $value, Closure $fail): void
110117
$builder = $builderClosure($builder);
111118
}
112119

120+
if ($this->includeSoftDeleted) {
121+
$builder = $builder->withTrashed();
122+
}
123+
113124
if ($builder->doesntExist()) {
114125
if ($this->customMessage !== null) {
115126
$fail($this->customMessage);
@@ -141,4 +152,26 @@ public function query(Closure $builderClosure): self
141152

142153
return $this;
143154
}
155+
156+
/**
157+
* Activate or deactivate including soft deleted models in the query.
158+
*
159+
* @param bool $includeSoftDeleted
160+
* @return void
161+
*/
162+
public function setIncludeSoftDeleted(bool $includeSoftDeleted): void
163+
{
164+
$this->includeSoftDeleted = $includeSoftDeleted;
165+
}
166+
167+
/**
168+
* Activate including soft deleted models in the query.
169+
* @return $this
170+
*/
171+
public function includeSoftDeleted(): self
172+
{
173+
$this->setIncludeSoftDeleted(true);
174+
175+
return $this;
176+
}
144177
}

src/Rules/UniqueEloquent.php

+34
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ class UniqueEloquent implements ValidationRule
5656
*/
5757
private ?string $customMessageTranslationKey = null;
5858

59+
/**
60+
* Include soft deleted models in the query.
61+
*
62+
* @var bool
63+
*/
64+
private bool $includeSoftDeleted = false;
65+
5966
/**
6067
* UniqueEloquent constructor.
6168
*
@@ -97,6 +104,10 @@ public function validate(string $attribute, mixed $value, Closure $fail): void
97104
);
98105
}
99106

107+
if ($this->includeSoftDeleted) {
108+
$builder = $builder->withTrashed();
109+
}
110+
100111
if ($builder->exists()) {
101112
if ($this->customMessage !== null) {
102113
$fail($this->customMessage);
@@ -178,4 +189,27 @@ public function ignore(mixed $id, ?string $column = null): self
178189

179190
return $this;
180191
}
192+
193+
/**
194+
* Activate or deactivate including soft deleted models in the query.
195+
*
196+
* @param bool $includeSoftDeleted
197+
* @return void
198+
*/
199+
public function setIncludeSoftDeleted(bool $includeSoftDeleted): void
200+
{
201+
$this->includeSoftDeleted = $includeSoftDeleted;
202+
}
203+
204+
/**
205+
* Activate including soft deleted models in the query.
206+
*
207+
* @return $this
208+
*/
209+
public function includeSoftDeleted(): self
210+
{
211+
$this->setIncludeSoftDeleted(true);
212+
213+
return $this;
214+
}
181215
}

tests/Feature/ExistsEloquentTest.php

+73
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,79 @@ public function testValidationPassesIfRuleChecksThatFactExistsAndBelongsToUserUs
255255
$this->assertCount(1, Fact::all());
256256
}
257257

258+
/*
259+
* Tests for includeSoftDeleted
260+
*/
261+
262+
public function testValidationSucceedsIfSoftDeletedEntryExistInDatabaseAndIncludeSoftDeletedFlagIsActive(): void
263+
{
264+
// Arrange
265+
User::create([
266+
'id' => 6,
267+
'other_id' => null,
268+
'name' => 'Testname',
269+
'email' => '[email protected]',
270+
'password' => bcrypt('secret'),
271+
'remember_token' => Str::random(10),
272+
]);
273+
$fact = Fact::create([
274+
'id' => 1,
275+
'user_id' => 6,
276+
'type' => 'type1',
277+
'description' => 'Long desc',
278+
]);
279+
$fact->delete();
280+
281+
$validator = Validator::make([
282+
'id' => 1,
283+
], [
284+
'id' => [(new ExistsEloquent(Fact::class))->includeSoftDeleted()]
285+
]);
286+
287+
// Act
288+
$isValid = $validator->passes();
289+
$messages = $validator->messages()->toArray();
290+
291+
// Assert
292+
$this->assertTrue($isValid);
293+
$this->assertArrayNotHasKey('id', $messages);
294+
$this->assertCount(1, User::withTrashed()->get());
295+
$this->assertCount(1, User::all());
296+
$this->assertCount(1, Fact::withTrashed()->get());
297+
$this->assertCount(0, Fact::all());
298+
}
299+
300+
public function testValidationFailsIfSoftDeletedEntryDoesNotExistInDatabaseAndIncludeSoftDeletedFlagIsActive(): void
301+
{
302+
// Arrange
303+
User::create([
304+
'id' => 6,
305+
'other_id' => null,
306+
'name' => 'Testname',
307+
'email' => '[email protected]',
308+
'password' => bcrypt('secret'),
309+
'remember_token' => Str::random(10),
310+
]);
311+
312+
$validator = Validator::make([
313+
'id' => 1,
314+
], [
315+
'id' => [(new ExistsEloquent(Fact::class))->includeSoftDeleted()]
316+
]);
317+
318+
// Act
319+
$isValid = $validator->passes();
320+
$messages = $validator->messages()->toArray();
321+
322+
// Assert
323+
$this->assertFalse($isValid);
324+
$this->assertEquals('The resource does not exist.', $messages['id'][0]);
325+
$this->assertCount(1, User::withTrashed()->get());
326+
$this->assertCount(1, User::all());
327+
$this->assertCount(0, Fact::withTrashed()->get());
328+
$this->assertCount(0, Fact::all());
329+
}
330+
258331
/*
259332
* Test language support
260333
*/

tests/Feature/UniqueEloquentTest.php

+73
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,79 @@ public function testValidationFailsIfRuleChecksThatFactExistsAndBelongsToUserUsi
257257
$this->assertCount(1, Fact::all());
258258
}
259259

260+
/*
261+
* Tests for includeSoftDeleted
262+
*/
263+
264+
public function testValidationSucceedsIfSoftDeletedEntryDoesNotExistInDatabaseAndIncludeSoftDeletedFlagIsActive(): void
265+
{
266+
// Arrange
267+
User::create([
268+
'id' => 6,
269+
'other_id' => null,
270+
'name' => 'Testname',
271+
'email' => '[email protected]',
272+
'password' => bcrypt('secret'),
273+
'remember_token' => Str::random(10),
274+
]);
275+
276+
$validator = Validator::make([
277+
'id' => 1,
278+
], [
279+
'id' => [(new UniqueEloquent(Fact::class))->includeSoftDeleted()]
280+
]);
281+
282+
// Act
283+
$isValid = $validator->passes();
284+
$messages = $validator->messages()->toArray();
285+
286+
// Assert
287+
$this->assertTrue($isValid);
288+
$this->assertArrayNotHasKey('id', $messages);
289+
$this->assertCount(1, User::withTrashed()->get());
290+
$this->assertCount(1, User::all());
291+
$this->assertCount(0, Fact::withTrashed()->get());
292+
$this->assertCount(0, Fact::all());
293+
}
294+
295+
public function testValidationFailsIfSoftDeletedEntryDoesExistInDatabaseAndIncludeSoftDeletedFlagIsActive(): void
296+
{
297+
// Arrange
298+
User::create([
299+
'id' => 6,
300+
'other_id' => null,
301+
'name' => 'Testname',
302+
'email' => '[email protected]',
303+
'password' => bcrypt('secret'),
304+
'remember_token' => Str::random(10),
305+
]);
306+
$fact = Fact::create([
307+
'id' => 1,
308+
'user_id' => 6,
309+
'type' => 'type1',
310+
'description' => 'Long desc',
311+
]);
312+
$fact->delete();
313+
314+
$validator = Validator::make([
315+
'id' => 1,
316+
], [
317+
'id' => [(new UniqueEloquent(Fact::class))->includeSoftDeleted()]
318+
]);
319+
320+
// Act
321+
$isValid = $validator->passes();
322+
$messages = $validator->messages()->toArray();
323+
324+
// Assert
325+
$this->assertFalse($isValid);
326+
$this->assertEquals('The resource already exists.', $messages['id'][0]);
327+
$this->assertCount(1, User::withTrashed()->get());
328+
$this->assertCount(1, User::all());
329+
$this->assertCount(1, Fact::withTrashed()->get());
330+
$this->assertCount(0, Fact::all());
331+
}
332+
260333
/*
261334
* Test language support
262335
*/

0 commit comments

Comments
 (0)