How to include EntityManager in ZendFramework 2 AbstractValidator

105 Views Asked by At

I have a custom validator, extending Zend AbstractValidator. The thing is, i want to include Doctrine EntityManager, but i keep failing! I tried to make a Factory for my Validator, but it doesn't seem to work. Help!! What am I doing wrong?

Validator:

$this->objectRepository stays empty, while i expect content.

namespace Rentals\Validator;

use Rentals\Response;
use Zend\Validator\AbstractValidator;
use Zend\Stdlib\ArrayUtils;

class ExistentialQuantification extends AbstractValidator
{
    const NO_ENTITY_ID = 'noEntityId';
    const ENTITY_NOT_FOUND = 'entityNotFound';
    const INVALID_ID = 'invalidId';

    protected $messageTemplates = [
        self::NO_ENTITY_ID => 'The input does not contain an entity id.',
        self::ENTITY_NOT_FOUND => 'The entity could not be found.',
        self::INVALID_ID => 'The input does not contain an entity id.',
    ];

    protected $objectRepository;

    public function __construct(array $options)
    {
        $this->objectRepository = $options['object_repository'];

        parent::__construct($options);
    }

    public function isValid($value)
    {
        if ($value === null) {
            return true;
        }
        if (! isset($value->id)) {
            $this->error(self::NO_ENTITY_ID);

            return false;
        }

        $entityClass = $this->getOption('entity_class');
        $controller = new Controller();
        $entity = (new FactoryInterface)(EntityManager::class)->find($entityClass, $entity->id);
        if (! $entity instanceof $entityClass) {
            $this->error(self::ENTITY_NOT_FOUND);

            return false;
        }
        if (! $entity->getId()) {
            $this->error(self::NO_ENTITY_ID);

            return false;
        }

        return true;
    }
}

Factory:

namespace Rentals\Validator;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\MutableCreationOptionsInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Stdlib\ArrayUtils;

class ExistentialQuantificationFactory implements FactoryInterface, MutableCreationOptionsInterface
{
    protected $options = [];

    public function setCreationOptions(array $options)
    {
        $this->options = $options;
    }

    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        if (! isset($this->options['object_manager'])) {
            $this->options['object_manager'] = 'doctrine.entitymanager.orm_default';
        }

        $objectManager = $serviceLocator->get($this->options['object_manager']);
        $objectRepository = $objectManager->getRepository($this->options['entity_class']);

        return new ExistentialQuantification(ArrayUtils::merge(
            $this->options, [
                'objectManager' => $objectManager,
                'objectRepository' => $objectRepository
            ]
        ));
    }
}

Module config:

<?php
return [
    'service_manager' => [
        'factories' => [
            'Rentals\\Validator\\ExistentialQuantification' => 'Rentals\\Validator\\ExistentialQuantificationFactory'
        ]
    ]
];
?>
1

There are 1 best solutions below

3
Marcel On

What if you change your config entry like the following example?

return [
    'validators' => [
        'factories' => [
            ExistentialQuantification::class => ExistentialQuantificationFactory::class,
        ],
    ],
];

This change will result in further changes for your factory, because the service locator for the entity manager differs from the one you injected.

namespace Application\Validator\Factory;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\MutableCreationOptionsInterface;
use Zend\ServiceManager\MutableCreationOptionsTrait;
use Zend\ServiceManager\ServiceLocatorInterface;

class ExistentialQuantificationFactory implements FactoryInterface, MutableCreationOptionsInterface
{
    use MutableCreatinOptionsTrait;

    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $parentLocator = $serviceLocator->getServiceLocator();

        if (! isset($this->creationOptions['object_manager'])) {
            $this->creationOptions['object_manager'] = 'doctrine.entitymanager.orm_default';
        }

        $objectManager = $parentLocator->get($this->creationOptions['object_manager']);
        $objectRepository = $objectManager->getRepository($this->creationOptions['entity_class']);

        return new ExistentialQuantification(ArrayUtils::merge(
            $this->options, [
                'objectManager' => $objectManager,
                'objectRepository' => $objectRepository
            ]
        ));
    }
}

What I 've done here? First I implemented the MutableCreationOptionsTrait class. This trait implements the needed functions for working with creation options. But this is just a little hint for avoiding unnecessary work.

Because of setting the validator class as validator in the config, we have to use the parent service locator for getting the entity manager. The inherited service locator just provides access to validators.

Now you can try to access your validator in your controller like in the following examaple.

$validator = $this->getServiceLocator()
    ->get('ValidatorManager')
    ->get(ExistentialQuantification::class, [
        'entity_class' => YourEntityClass::class,
    ]);

\Zend\Debug\Debug::dump($validator, __METHOD__);

The validator manager should return your validator so that you can test it.