Integrate symfony/validator with Doctrine entitites
[MAILPOET-2437]
This commit is contained in:
committed by
Jack Kitterhing
parent
bed49f97ef
commit
730f640cc3
@@ -117,6 +117,7 @@ class ContainerConfigurator implements IContainerConfigurator {
|
||||
->setFactory([new Reference(\MailPoet\Doctrine\EntityManagerFactory::class), 'createEntityManager'])
|
||||
->setPublic(true);
|
||||
$container->autowire(\MailPoet\Doctrine\EventListeners\TimestampListener::class);
|
||||
$container->autowire(\MailPoet\Doctrine\EventListeners\ValidationListener::class);
|
||||
// Dynamic segments
|
||||
$container->autowire(\MailPoet\DynamicSegments\DynamicSegmentHooks::class);
|
||||
// Cron
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace MailPoet\Doctrine;
|
||||
|
||||
use MailPoetVendor\Doctrine\Common\Annotations\AnnotationRegistry;
|
||||
use MailPoetVendor\Doctrine\Common\Annotations\SimpleAnnotationReader;
|
||||
use MailPoetVendor\Doctrine\Common\Cache\ArrayCache;
|
||||
use MailPoetVendor\Doctrine\Common\Proxy\AbstractProxyFactory;
|
||||
@@ -39,6 +40,10 @@ class ConfigurationFactory {
|
||||
$metadata_storage = new MetadataCache(self::METADATA_DIR);
|
||||
$configuration->setMetadataCacheImpl($metadata_storage);
|
||||
|
||||
// autoload all annotation classes using registered loaders (Composer)
|
||||
// (needed for Symfony\Validator constraint annotations to be loaded)
|
||||
AnnotationRegistry::registerLoader('class_exists');
|
||||
|
||||
// register annotation reader if doctrine/annotations package is installed
|
||||
// (i.e. in dev environment, on production metadata is dumped in the build)
|
||||
if (class_exists(SimpleAnnotationReader::class)) {
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace MailPoet\Doctrine;
|
||||
|
||||
use MailPoet\Doctrine\EventListeners\TimestampListener;
|
||||
use MailPoet\Doctrine\EventListeners\ValidationListener;
|
||||
use MailPoet\Tracy\DoctrinePanel\DoctrinePanel;
|
||||
use MailPoetVendor\Doctrine\DBAL\Connection;
|
||||
use MailPoetVendor\Doctrine\ORM\Configuration;
|
||||
@@ -18,27 +19,42 @@ class EntityManagerFactory {
|
||||
/** @var Configuration */
|
||||
private $configuration;
|
||||
|
||||
/** @var TimestampListener */
|
||||
private $timestamp_listener;
|
||||
|
||||
function __construct(Connection $connection, Configuration $configuration, TimestampListener $timestamp_listener) {
|
||||
/** @var ValidationListener */
|
||||
private $validation_listener;
|
||||
|
||||
function __construct(
|
||||
Connection $connection,
|
||||
Configuration $configuration,
|
||||
TimestampListener $timestamp_listener,
|
||||
ValidationListener $validation_listener
|
||||
) {
|
||||
$this->connection = $connection;
|
||||
$this->configuration = $configuration;
|
||||
$this->timestamp_listener = $timestamp_listener;
|
||||
$this->validation_listener = $validation_listener;
|
||||
}
|
||||
|
||||
function createEntityManager() {
|
||||
$entity_manager = EntityManager::create($this->connection, $this->configuration);
|
||||
$this->setupTimestampListener($entity_manager);
|
||||
$this->setupListeners($entity_manager);
|
||||
if (class_exists(Debugger::class)) {
|
||||
DoctrinePanel::init($entity_manager);
|
||||
}
|
||||
return $entity_manager;
|
||||
}
|
||||
|
||||
private function setupTimestampListener(EntityManager $entity_manager) {
|
||||
private function setupListeners(EntityManager $entity_manager) {
|
||||
$entity_manager->getEventManager()->addEventListener(
|
||||
[Events::prePersist, Events::preUpdate],
|
||||
$this->timestamp_listener
|
||||
);
|
||||
|
||||
$entity_manager->getEventManager()->addEventListener(
|
||||
[Events::onFlush],
|
||||
$this->validation_listener
|
||||
);
|
||||
}
|
||||
}
|
||||
|
38
lib/Doctrine/EventListeners/ValidationListener.php
Normal file
38
lib/Doctrine/EventListeners/ValidationListener.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Doctrine\EventListeners;
|
||||
|
||||
use MailPoet\Doctrine\ValidationException;
|
||||
use MailPoetVendor\Doctrine\ORM\Event\OnFlushEventArgs;
|
||||
use MailPoetVendor\Symfony\Component\Validator\Validation;
|
||||
use MailPoetVendor\Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
class ValidationListener {
|
||||
/** @var ValidatorInterface */
|
||||
private $validator;
|
||||
|
||||
function __construct() {
|
||||
$this->validator = Validation::createValidatorBuilder()
|
||||
->enableAnnotationMapping()
|
||||
->getValidator();
|
||||
}
|
||||
|
||||
function onFlush(OnFlushEventArgs $event_args) {
|
||||
$unit_of_work = $event_args->getEntityManager()->getUnitOfWork();
|
||||
|
||||
foreach ($unit_of_work->getScheduledEntityInsertions() as $entity) {
|
||||
$this->validate($entity);
|
||||
}
|
||||
|
||||
foreach ($unit_of_work->getScheduledEntityUpdates() as $entity) {
|
||||
$this->validate($entity);
|
||||
}
|
||||
}
|
||||
|
||||
private function validate($entity) {
|
||||
$violations = $this->validator->validate($entity);
|
||||
if ($violations->count() > 0) {
|
||||
throw new ValidationException(get_class($entity), $violations);
|
||||
}
|
||||
}
|
||||
}
|
48
lib/Doctrine/ValidationException.php
Normal file
48
lib/Doctrine/ValidationException.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Doctrine;
|
||||
|
||||
use MailPoetVendor\Symfony\Component\Validator\ConstraintViolationInterface;
|
||||
use MailPoetVendor\Symfony\Component\Validator\ConstraintViolationListInterface;
|
||||
|
||||
class ValidationException extends \RuntimeException {
|
||||
/** @var string */
|
||||
private $resource_name;
|
||||
|
||||
/** @var ConstraintViolationListInterface|ConstraintViolationInterface[] */
|
||||
private $violations;
|
||||
|
||||
function __construct($resource_name, ConstraintViolationListInterface $violations) {
|
||||
$this->resource_name = $resource_name;
|
||||
$this->violations = $violations;
|
||||
|
||||
$line_prefix = ' ';
|
||||
$message = "Validation failed for '$resource_name'.\nDetails:\n";
|
||||
$message .= $line_prefix . implode("\n$line_prefix", $this->getErrors());
|
||||
parent::__construct($message);
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
function getResourceName() {
|
||||
return $this->resource_name;
|
||||
}
|
||||
|
||||
/** @return ConstraintViolationListInterface|ConstraintViolationInterface[] */
|
||||
function getViolations() {
|
||||
return $this->violations;
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
function getErrors() {
|
||||
$messages = [];
|
||||
foreach ($this->violations as $violation) {
|
||||
$messages[] = $this->formatError($violation);
|
||||
}
|
||||
sort($messages);
|
||||
return $messages;
|
||||
}
|
||||
|
||||
private function formatError(ConstraintViolationInterface $violation) {
|
||||
return '[' . $violation->getPropertyPath() . '] ' . $violation->getMessage();
|
||||
}
|
||||
}
|
@@ -6,6 +6,7 @@ use Carbon\Carbon;
|
||||
use MailPoet\Doctrine\ConfigurationFactory;
|
||||
use MailPoet\Doctrine\EntityManagerFactory;
|
||||
use MailPoet\Doctrine\EventListeners\TimestampListener;
|
||||
use MailPoet\Doctrine\EventListeners\ValidationListener;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoetVendor\Doctrine\Common\Cache\ArrayCache;
|
||||
|
||||
@@ -84,7 +85,8 @@ class TimestampListenerTest extends \MailPoetTest {
|
||||
$configuration->setMetadataCacheImpl(new ArrayCache());
|
||||
|
||||
$timestamp_listener = new TimestampListener($this->wp);
|
||||
$entity_manager_factory = new EntityManagerFactory($this->connection, $configuration, $timestamp_listener);
|
||||
$validation_listener = new ValidationListener();
|
||||
$entity_manager_factory = new EntityManagerFactory($this->connection, $configuration, $timestamp_listener, $validation_listener);
|
||||
return $entity_manager_factory->createEntityManager();
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ use Exception;
|
||||
use MailPoet\Doctrine\ConfigurationFactory;
|
||||
use MailPoet\Doctrine\EntityManagerFactory;
|
||||
use MailPoet\Doctrine\EventListeners\TimestampListener;
|
||||
use MailPoet\Doctrine\EventListeners\ValidationListener;
|
||||
use MailPoet\Test\Doctrine\Types\JsonEntity;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoetVendor\Doctrine\Common\Cache\ArrayCache;
|
||||
@@ -158,7 +159,8 @@ class JsonTypesTest extends \MailPoetTest {
|
||||
$configuration->setMetadataCacheImpl(new ArrayCache());
|
||||
|
||||
$timestamp_listener = new TimestampListener($this->wp);
|
||||
$entity_manager_factory = new EntityManagerFactory($this->connection, $configuration, $timestamp_listener);
|
||||
$validation_listener = new ValidationListener();
|
||||
$entity_manager_factory = new EntityManagerFactory($this->connection, $configuration, $timestamp_listener, $validation_listener);
|
||||
return $entity_manager_factory->createEntityManager();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user