From 15b0846f34f4f1611566e113362bddfc8c864ede Mon Sep 17 00:00:00 2001 From: alex-mpoet Date: Sun, 10 Mar 2024 19:09:59 +0300 Subject: [PATCH] Leave on-save email validation only in SubscriberSaveController [MAILPOET-5878] --- .../EntityTraits/ValidationGroupsTrait.php | 18 ++++++++++ .../EventListeners/ValidationListener.php | 10 +++++- mailpoet/lib/Entities/SubscriberEntity.php | 4 ++- .../Subscribers/SubscriberSaveController.php | 3 ++ .../tasks/phpstan/phpstan-7-baseline.neon | 2 +- .../tasks/phpstan/phpstan-8-baseline.neon | 2 +- .../EventListeners/ValidatedEntity.php | 20 +++++++++++ .../EventListeners/ValidationTest.php | 33 ++++++++++++++++++- 8 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 mailpoet/lib/Doctrine/EntityTraits/ValidationGroupsTrait.php diff --git a/mailpoet/lib/Doctrine/EntityTraits/ValidationGroupsTrait.php b/mailpoet/lib/Doctrine/EntityTraits/ValidationGroupsTrait.php new file mode 100644 index 0000000000..86eebce50d --- /dev/null +++ b/mailpoet/lib/Doctrine/EntityTraits/ValidationGroupsTrait.php @@ -0,0 +1,18 @@ +validationGroups; + } + + public function setValidationGroups(?array $validationGroups): void { + $this->validationGroups = $validationGroups; + } +} diff --git a/mailpoet/lib/Doctrine/EventListeners/ValidationListener.php b/mailpoet/lib/Doctrine/EventListeners/ValidationListener.php index fec99940d9..f7acc3f07c 100644 --- a/mailpoet/lib/Doctrine/EventListeners/ValidationListener.php +++ b/mailpoet/lib/Doctrine/EventListeners/ValidationListener.php @@ -29,9 +29,17 @@ class ValidationListener { } private function validate($entity) { - $violations = $this->validator->validate($entity); + $groups = $this->getValidationGroups($entity); + $violations = $this->validator->validate($entity, null, $groups); if ($violations->count() > 0) { throw new ValidationException(get_class($entity), $violations); } } + + private function getValidationGroups($entity) { + if (is_object($entity) && method_exists($entity, 'getValidationGroups')) { + return $entity->getValidationGroups(); + } + return null; + } } diff --git a/mailpoet/lib/Entities/SubscriberEntity.php b/mailpoet/lib/Entities/SubscriberEntity.php index 122c471f5d..8ebcbb443f 100644 --- a/mailpoet/lib/Entities/SubscriberEntity.php +++ b/mailpoet/lib/Entities/SubscriberEntity.php @@ -7,6 +7,7 @@ use MailPoet\Doctrine\EntityTraits\AutoincrementedIdTrait; use MailPoet\Doctrine\EntityTraits\CreatedAtTrait; use MailPoet\Doctrine\EntityTraits\DeletedAtTrait; use MailPoet\Doctrine\EntityTraits\UpdatedAtTrait; +use MailPoet\Doctrine\EntityTraits\ValidationGroupsTrait; use MailPoet\Util\Helpers; use MailPoetVendor\Doctrine\Common\Collections\ArrayCollection; use MailPoetVendor\Doctrine\Common\Collections\Collection; @@ -44,6 +45,7 @@ class SubscriberEntity { use CreatedAtTrait; use UpdatedAtTrait; use DeletedAtTrait; + use ValidationGroupsTrait; /** * @ORM\Column(type="bigint", nullable=true) @@ -71,7 +73,7 @@ class SubscriberEntity { /** * @ORM\Column(type="string") - * @Assert\Email() + * @Assert\Email(groups={"Saving"}) * @Assert\NotBlank() * @var string */ diff --git a/mailpoet/lib/Subscribers/SubscriberSaveController.php b/mailpoet/lib/Subscribers/SubscriberSaveController.php index 52bf2a554b..78ac8d68d2 100644 --- a/mailpoet/lib/Subscribers/SubscriberSaveController.php +++ b/mailpoet/lib/Subscribers/SubscriberSaveController.php @@ -229,6 +229,9 @@ class SubscriberSaveController { // wipe any unconfirmed data at this point $subscriber->setUnconfirmedData(null); + // Validate the email (Saving group) + everything else (Default group) + $subscriber->setValidationGroups(['Saving', 'Default']); + try { $this->subscribersRepository->persist($subscriber); $this->subscribersRepository->flush(); diff --git a/mailpoet/tasks/phpstan/phpstan-7-baseline.neon b/mailpoet/tasks/phpstan/phpstan-7-baseline.neon index ec9c3a25e2..4f1f008eda 100644 --- a/mailpoet/tasks/phpstan/phpstan-7-baseline.neon +++ b/mailpoet/tasks/phpstan/phpstan-7-baseline.neon @@ -772,7 +772,7 @@ parameters: - message: "#^Dead catch \\- MailPoet\\\\Doctrine\\\\Validator\\\\ValidationException is never thrown in the try block\\.$#" - count: 2 + count: 4 path: ../../tests/integration/Doctrine/EventListeners/ValidationTest.php - diff --git a/mailpoet/tasks/phpstan/phpstan-8-baseline.neon b/mailpoet/tasks/phpstan/phpstan-8-baseline.neon index 2381af1dc0..15e1d1fb45 100644 --- a/mailpoet/tasks/phpstan/phpstan-8-baseline.neon +++ b/mailpoet/tasks/phpstan/phpstan-8-baseline.neon @@ -767,7 +767,7 @@ parameters: - message: "#^Dead catch \\- MailPoet\\\\Doctrine\\\\Validator\\\\ValidationException is never thrown in the try block\\.$#" - count: 2 + count: 4 path: ../../tests/integration/Doctrine/EventListeners/ValidationTest.php - diff --git a/mailpoet/tests/integration/Doctrine/EventListeners/ValidatedEntity.php b/mailpoet/tests/integration/Doctrine/EventListeners/ValidatedEntity.php index 3e1262eb3a..4639599b04 100644 --- a/mailpoet/tests/integration/Doctrine/EventListeners/ValidatedEntity.php +++ b/mailpoet/tests/integration/Doctrine/EventListeners/ValidatedEntity.php @@ -2,6 +2,7 @@ namespace MailPoet\Test\Doctrine\EventListeners; +use MailPoet\Doctrine\EntityTraits\ValidationGroupsTrait; use MailPoetVendor\Doctrine\ORM\Mapping as ORM; use MailPoetVendor\Symfony\Component\Validator\Constraints as Assert; @@ -10,6 +11,8 @@ use MailPoetVendor\Symfony\Component\Validator\Constraints as Assert; * @ORM\Table(name="test_validated_entity") */ class ValidatedEntity { + use ValidationGroupsTrait; + /** * @ORM\Column(type="integer") * @ORM\Id @@ -26,6 +29,13 @@ class ValidatedEntity { */ private $name; + /** + * @ORM\Column(type="string") + * @Assert\Email(groups={"Saving"}) + * @var string + */ + private $email; + /** @return int|null */ public function getId() { return $this->id; @@ -40,4 +50,14 @@ class ValidatedEntity { public function setName($name) { $this->name = $name; } + + /** @return string */ + public function getEmail() { + return $this->email; + } + + /** @param string $email */ + public function setEmail($email) { + $this->email = $email; + } } diff --git a/mailpoet/tests/integration/Doctrine/EventListeners/ValidationTest.php b/mailpoet/tests/integration/Doctrine/EventListeners/ValidationTest.php index d35f24d684..45e28337be 100644 --- a/mailpoet/tests/integration/Doctrine/EventListeners/ValidationTest.php +++ b/mailpoet/tests/integration/Doctrine/EventListeners/ValidationTest.php @@ -35,7 +35,8 @@ class ValidationTest extends \MailPoetTest { $this->connection->executeStatement(" CREATE TABLE $this->tableName ( id int(11) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, - name varchar(255) NOT NULL + name varchar(255) NOT NULL, + email varchar(255) ) "); } @@ -69,6 +70,36 @@ class ValidationTest extends \MailPoetTest { } } + public function testItSupportsValidationGroups() { + $id = 1; + $name = 'Test name'; + $email = 'test@example.com'; + $this->connection->executeStatement("INSERT INTO $this->tableName (id, name, email) VALUES (?, ?, ?)", [$id, $name, $email]); + + /** @var ValidatedEntity $entity */ + $entity = $this->entityManager->find(ValidatedEntity::class, $id); + $entity->setEmail('example'); + + // Validation group is Default, no email validation + try { + $this->entityManager->flush(); + } catch (ValidationException $e) { + $this->fail('Validation exception was thrown.'); + } + + // Validation group is Default + Saving, with email validation + $entity->setValidationGroups(['Saving', 'Default']); + $entity->setEmail('example2'); + + try { + $this->entityManager->flush(); + $this->fail('Validation exception was not thrown.'); + } catch (ValidationException $e) { + $entityClass = get_class($entity); + verify($e->getMessage())->same("Validation failed for '$entityClass'.\nDetails:\n [email] This value is not a valid email address."); + } + } + private function createEntityManager() { $annotationReaderProvider = new AnnotationReaderProvider(); $configurationFactory = new ConfigurationFactory($annotationReaderProvider, false);