Skip to content

Commit

Permalink
feat: allow to define validation groups
Browse files Browse the repository at this point in the history
  • Loading branch information
nikophil committed Feb 3, 2025
1 parent ea75772 commit c2b6e9a
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/Object/ValidationListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function __invoke(AfterInstantiate $event): void
return;
}

$violations = $this->validator->validate($event->object);
$violations = $this->validator->validate($event->object, groups: $event->factory->getValidationGroups());

if ($violations->count() > 0) {
throw new ValidationFailedException($event->object, $violations);
Expand Down
40 changes: 39 additions & 1 deletion src/ObjectFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Zenstruck\Foundry;

use Symfony\Component\Validator\Constraints\GroupSequence;
use Zenstruck\Foundry\Object\Event\AfterInstantiate;
use Zenstruck\Foundry\Object\Event\BeforeInstantiate;
use Zenstruck\Foundry\Object\Instantiator;
Expand All @@ -37,6 +38,9 @@ abstract class ObjectFactory extends Factory

private bool $validationEnabled;

/** @var string|GroupSequence|list<string>|null */
private string|GroupSequence|array|null $validationGroups = [];

// keep an empty constructor for BC
public function __construct()
{
Expand Down Expand Up @@ -116,10 +120,12 @@ public function afterInstantiate(callable $callback): static
}

/**
* @param string|GroupSequence|list<string>|null $groups
*
* @psalm-return static<T>
* @phpstan-return static
*/
public function withValidation(): static
public function withValidation(string|GroupSequence|array|null $groups = null): static
{
if (!Configuration::instance()->validationAvailable) {
throw new \LogicException('Validation is not available. Make sure the "symfony/validator" package is installed and validation enabled.');
Expand All @@ -128,6 +134,10 @@ public function withValidation(): static
$clone = clone $this;
$clone->validationEnabled = true;

if ($groups !== null) {
$clone->validationGroups = $groups;
}

return $clone;
}

Expand All @@ -143,6 +153,24 @@ public function withoutValidation(): static
return $clone;
}

/**
* @param string|GroupSequence|list<string>|null $groups
*
* @psalm-return static<T>
* @phpstan-return static
*/
public function withValidationGroups(string|GroupSequence|array|null $groups): static
{
if (!Configuration::instance()->validationAvailable) {
throw new \LogicException('Validation is not available. Make sure the "symfony/validator" package is installed and validation enabled.');
}

$clone = clone $this;
$clone->validationGroups = $groups;

return $clone;
}

/**
* @internal
*/
Expand All @@ -151,6 +179,16 @@ public function validationEnabled(): bool
return $this->validationEnabled;
}

/**
* @return string|GroupSequence|list<string>|null
*
* @internal
*/
public function getValidationGroups(): string|GroupSequence|array|null
{
return $this->validationGroups;
}

/**
* @internal
*/
Expand Down
4 changes: 4 additions & 0 deletions tests/Fixture/Entity/EntityForValidation.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ public function __construct(
#[ORM\Column()]
#[Assert\NotBlank()]
public string $name = '',

#[ORM\Column()]
#[Assert\GreaterThan(10, groups: ['validation_group'])]
public int $number = 0,
) {
}
}
31 changes: 31 additions & 0 deletions tests/Integration/ValidationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public function test_it_throws_if_validation_enabled_in_foundry_but_disabled_in_
public function test_it_validates_object_if_validation_forced(): void
{
self::expectException(ValidationFailedException::class);
self::expectExceptionMessageMatches('/This value should not be blank/');

self::bootKernel(['environment' => 'validation_available']);

Expand All @@ -67,4 +68,34 @@ public function test_validation_can_be_disabled(): void

factory(EntityForValidation::class)->withoutValidation()->create();
}

public function test_it_validates_object_with_validation_groups(): void
{
self::expectException(ValidationFailedException::class);
self::expectExceptionMessageMatches('/This value should be greater than 10/');

self::bootKernel(['environment' => 'validation_available']);

factory(EntityForValidation::class)->withValidation('validation_group')->create();
}

public function test_it_validates_object_with_validation_groups_when_validation_enabled_globally(): void
{
self::expectException(ValidationFailedException::class);
self::expectExceptionMessageMatches('/This value should be greater than 10/');

self::bootKernel(['environment' => 'validation_enabled']);

factory(EntityForValidation::class)->withValidationGroups('validation_group')->create();
}

public function test_it_can_erase_validation_groups(): void
{
self::expectException(ValidationFailedException::class);
self::expectExceptionMessageMatches('/This value should not be blank/');

self::bootKernel(['environment' => 'validation_available']);

factory(EntityForValidation::class)->withValidation('validation_group')->withValidationGroups(null)->create();
}
}

0 comments on commit c2b6e9a

Please sign in to comment.