1

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 Answers1

1

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.

AlexP
  • 9,906
  • 1
  • 24
  • 43
Marcel
  • 4,854
  • 1
  • 14
  • 24
  • I keep getting this error: Plugin of type Rentals\Validator\ExistentialQuantificationFactory is invalid; must implement Zend\Validator\ValidatorInterface –  Jan 23 '18 at 20:02
  • How do you call your validator class? The validator class you have shown in your post is not a plugin. I guess you 're calling the class wrong. Can you show the part of code, where you call the validator? – Marcel Jan 24 '18 at 09:19
  • @GeoffreyStekelenburg I've fixed the issue in this answer. Marcel had a typo, the call to `get(ExistentialQuantificationFactory::class)` (in the last code example) should be `get(ExistentialQuantification::class)` (look at the answer history). Otherwise +1 – AlexP Jan 26 '18 at 19:04