Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Laravel 11 support + include soft deletes #18

Merged
merged 2 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
with:
command: install
only_args: -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist --ignore-platform-reqs
php_version: 8.1
php_version: 8.3

- name: Run PHP-CS-Fixer
run: vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php --diff --dry-run
Expand All @@ -30,7 +30,7 @@ jobs:
with:
command: install
only_args: -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist --ignore-platform-reqs
php_version: 8.1
php_version: 8.3

- name: Run PHP CodeSniffer
run: vendor/bin/phpcs --extensions=php
9 changes: 8 additions & 1 deletion .github/workflows/unittests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ jobs:
laravel: 10.*
testbench: 8.*
composer-flag: '--prefer-stable'
- php: 8.3
laravel: 10.*
testbench: 8.*
composer-flag: '--prefer-stable'
- php: 8.1
laravel: 10.*
testbench: 8.*
Expand All @@ -24,7 +28,10 @@ jobs:
laravel: 10.*
testbench: 8.*
composer-flag: '--prefer-lowest'

- php: 8.3
laravel: 10.*
testbench: 8.*
composer-flag: '--prefer-lowest'
runs-on: ubuntu-latest

steps:
Expand Down
15 changes: 11 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
{
"name": "korridor/laravel-model-validation-rules",
"description": "A laravel validation rule that uses eloquent to validate if a model exists",
"keywords": ["validation", "laravel", "rule", "model", "exist", "eloquent"],
"keywords": [
"validation",
"laravel",
"rule",
"model",
"exist",
"eloquent"
],
"homepage": "https://github.com/korridor/laravel-model-validation-rules",
"authors": [
{
Expand All @@ -12,11 +19,11 @@
"license": "MIT",
"require": {
"php": ">=8.1",
"illuminate/support": "^10",
"illuminate/database": "^10"
"illuminate/support": "^10|^11",
"illuminate/database": "^10|^11"
},
"require-dev": {
"orchestra/testbench": "^8.0",
"orchestra/testbench": "^8.0|^9.0",
"phpunit/phpunit": "^10",
"friendsofphp/php-cs-fixer": "^3.6",
"squizlabs/php_codesniffer": "^3.5"
Expand Down
2 changes: 1 addition & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM php:8.1-cli
FROM php:8.3-cli

ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/

Expand Down
3 changes: 2 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ composer require korridor/laravel-model-validation-rules "^2.1"

This package is tested for the following Laravel and PHP versions:

- 10.* (PHP 8.1, 8.2)
- 10.* (PHP 8.1, 8.2, 8.3)
- 11.* (PHP 8.2, 8.3)

## Usage examples

Expand Down
33 changes: 33 additions & 0 deletions src/Rules/ExistsEloquent.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ class ExistsEloquent implements ValidationRule
*/
private ?string $customMessageTranslationKey = null;

/**
* Include soft deleted models in the query.
*
* @var bool
*/
private bool $includeSoftDeleted = false;

/**
* Create a new rule instance.
*
Expand Down Expand Up @@ -110,6 +117,10 @@ public function validate(string $attribute, mixed $value, Closure $fail): void
$builder = $builderClosure($builder);
}

if ($this->includeSoftDeleted) {
$builder = $builder->withTrashed();
}

if ($builder->doesntExist()) {
if ($this->customMessage !== null) {
$fail($this->customMessage);
Expand Down Expand Up @@ -141,4 +152,26 @@ public function query(Closure $builderClosure): self

return $this;
}

/**
* Activate or deactivate including soft deleted models in the query.
*
* @param bool $includeSoftDeleted
* @return void
*/
public function setIncludeSoftDeleted(bool $includeSoftDeleted): void
{
$this->includeSoftDeleted = $includeSoftDeleted;
}

/**
* Activate including soft deleted models in the query.
* @return $this
*/
public function includeSoftDeleted(): self
{
$this->setIncludeSoftDeleted(true);

return $this;
}
}
34 changes: 34 additions & 0 deletions src/Rules/UniqueEloquent.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ class UniqueEloquent implements ValidationRule
*/
private ?string $customMessageTranslationKey = null;

/**
* Include soft deleted models in the query.
*
* @var bool
*/
private bool $includeSoftDeleted = false;

/**
* UniqueEloquent constructor.
*
Expand Down Expand Up @@ -97,6 +104,10 @@ public function validate(string $attribute, mixed $value, Closure $fail): void
);
}

if ($this->includeSoftDeleted) {
$builder = $builder->withTrashed();
}

if ($builder->exists()) {
if ($this->customMessage !== null) {
$fail($this->customMessage);
Expand Down Expand Up @@ -178,4 +189,27 @@ public function ignore(mixed $id, ?string $column = null): self

return $this;
}

/**
* Activate or deactivate including soft deleted models in the query.
*
* @param bool $includeSoftDeleted
* @return void
*/
public function setIncludeSoftDeleted(bool $includeSoftDeleted): void
{
$this->includeSoftDeleted = $includeSoftDeleted;
}

/**
* Activate including soft deleted models in the query.
*
* @return $this
*/
public function includeSoftDeleted(): self
{
$this->setIncludeSoftDeleted(true);

return $this;
}
}
73 changes: 73 additions & 0 deletions tests/Feature/ExistsEloquentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,79 @@ public function testValidationPassesIfRuleChecksThatFactExistsAndBelongsToUserUs
$this->assertCount(1, Fact::all());
}

/*
* Tests for includeSoftDeleted
*/

public function testValidationSucceedsIfSoftDeletedEntryExistInDatabaseAndIncludeSoftDeletedFlagIsActive(): void
{
// Arrange
User::create([
'id' => 6,
'other_id' => null,
'name' => 'Testname',
'email' => 'name@test.com',
'password' => bcrypt('secret'),
'remember_token' => Str::random(10),
]);
$fact = Fact::create([
'id' => 1,
'user_id' => 6,
'type' => 'type1',
'description' => 'Long desc',
]);
$fact->delete();

$validator = Validator::make([
'id' => 1,
], [
'id' => [(new ExistsEloquent(Fact::class))->includeSoftDeleted()]
]);

// Act
$isValid = $validator->passes();
$messages = $validator->messages()->toArray();

// Assert
$this->assertTrue($isValid);
$this->assertArrayNotHasKey('id', $messages);
$this->assertCount(1, User::withTrashed()->get());
$this->assertCount(1, User::all());
$this->assertCount(1, Fact::withTrashed()->get());
$this->assertCount(0, Fact::all());
}

public function testValidationFailsIfSoftDeletedEntryDoesNotExistInDatabaseAndIncludeSoftDeletedFlagIsActive(): void
{
// Arrange
User::create([
'id' => 6,
'other_id' => null,
'name' => 'Testname',
'email' => 'name@test.com',
'password' => bcrypt('secret'),
'remember_token' => Str::random(10),
]);

$validator = Validator::make([
'id' => 1,
], [
'id' => [(new ExistsEloquent(Fact::class))->includeSoftDeleted()]
]);

// Act
$isValid = $validator->passes();
$messages = $validator->messages()->toArray();

// Assert
$this->assertFalse($isValid);
$this->assertEquals('The resource does not exist.', $messages['id'][0]);
$this->assertCount(1, User::withTrashed()->get());
$this->assertCount(1, User::all());
$this->assertCount(0, Fact::withTrashed()->get());
$this->assertCount(0, Fact::all());
}

/*
* Test language support
*/
Expand Down
73 changes: 73 additions & 0 deletions tests/Feature/UniqueEloquentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,79 @@ public function testValidationFailsIfRuleChecksThatFactExistsAndBelongsToUserUsi
$this->assertCount(1, Fact::all());
}

/*
* Tests for includeSoftDeleted
*/

public function testValidationSucceedsIfSoftDeletedEntryDoesNotExistInDatabaseAndIncludeSoftDeletedFlagIsActive(): void
{
// Arrange
User::create([
'id' => 6,
'other_id' => null,
'name' => 'Testname',
'email' => 'name@test.com',
'password' => bcrypt('secret'),
'remember_token' => Str::random(10),
]);

$validator = Validator::make([
'id' => 1,
], [
'id' => [(new UniqueEloquent(Fact::class))->includeSoftDeleted()]
]);

// Act
$isValid = $validator->passes();
$messages = $validator->messages()->toArray();

// Assert
$this->assertTrue($isValid);
$this->assertArrayNotHasKey('id', $messages);
$this->assertCount(1, User::withTrashed()->get());
$this->assertCount(1, User::all());
$this->assertCount(0, Fact::withTrashed()->get());
$this->assertCount(0, Fact::all());
}

public function testValidationFailsIfSoftDeletedEntryDoesExistInDatabaseAndIncludeSoftDeletedFlagIsActive(): void
{
// Arrange
User::create([
'id' => 6,
'other_id' => null,
'name' => 'Testname',
'email' => 'name@test.com',
'password' => bcrypt('secret'),
'remember_token' => Str::random(10),
]);
$fact = Fact::create([
'id' => 1,
'user_id' => 6,
'type' => 'type1',
'description' => 'Long desc',
]);
$fact->delete();

$validator = Validator::make([
'id' => 1,
], [
'id' => [(new UniqueEloquent(Fact::class))->includeSoftDeleted()]
]);

// Act
$isValid = $validator->passes();
$messages = $validator->messages()->toArray();

// Assert
$this->assertFalse($isValid);
$this->assertEquals('The resource already exists.', $messages['id'][0]);
$this->assertCount(1, User::withTrashed()->get());
$this->assertCount(1, User::all());
$this->assertCount(1, Fact::withTrashed()->get());
$this->assertCount(0, Fact::all());
}

/*
* Test language support
*/
Expand Down
Loading