Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error when injecting object_repository and object_manager to UniqueObject validator annotation #585

Closed
vvaswani opened this issue Dec 5, 2016 · 12 comments
Assignees

Comments

@vvaswani
Copy link
Contributor

vvaswani commented Dec 5, 2016

I am trying to use the UniqueObject validator annotation in an entity but am unable to do so. This is in a ZF3 app. I see the error below

Error:
Catchable fatal error: Argument 1 passed to DoctrineModule\Validator\UniqueObject::__construct() must be of the type array, none given, called in /var/www/jade/vendor/zendframework/zend-servicemanager/src/Factory/InvokableFactory.php on line 32 and defined in /var/www/jade/vendor/doctrine/doctrine-module/src/DoctrineModule/Validator/UniqueObject.php on line 66

Not sure why it says "none given" as the array is present in the service config, see below.

Annotation:

     * @Annotation\Validator({"name":"DoctrineModule\Validator\UniqueObject"})

Module.php:

    public function getServiceConfig()
    {
        return [
            'factories' => [
                'Zend\Authentication\AuthenticationService' => function ($serviceManager) {
                    return $serviceManager->get('doctrine.authenticationservice.orm_default');
                },
                'DoctrineModule\Validator\UniqueObject' => function ($serviceManager) {
                    $uniqueObject = new DoctrineModule\Validator\UniqueObject(array(
                        'fields' => 'username',
                        'object_repository' => $serviceManager->get('Doctrine\ORM\EntityManager')->getRepository('Application\Entity\User'),
                        'object_manager' => $serviceManager->get('Doctrine\ORM\EntityManager'),
                    ));
                    return $uniqueObject;
                },
            ],
        ];
    }

I also tried placing this in getValidatorConfig and getFormElementsConfig as suggested in #289 , no luck. Please let me know how to make this work. I'll also add this info to the docs via a PR once it's working.

@vvaswani vvaswani changed the title Injecting object_repository and object_manager to UniqueObject validator annotation Error when injecting object_repository and object_manager to UniqueObject validator annotation Dec 5, 2016
@Ocramius
Copy link
Member

Ocramius commented Dec 5, 2016

You need to make sure that your form factory comes from the right service manager. If you inspect it via debugger (sorry, that's the only sensible way to do it), you will probably see that none of your factories are in it.

@vvaswani
Copy link
Contributor Author

vvaswani commented Dec 6, 2016

I tried to do this using Xdebug but not sure I succeeded. Here's the output:

[Catchable fatal error] Argument 1 passed to DoctrineModule\Validator\UniqueObject::__construct() must be of the type array, none given, called in /var/www/jade/vendor/zendframework/zend-servicemanager/src/Factory/InvokableFactory.php on line 32 and defined
[0] file:///var/www/jade/vendor/doctrine/doctrine-module/src/DoctrineModule/Validator/UniqueObject.php.DoctrineModule\Validator\UniqueObject->__construct:66
[1] file:///var/www/jade/vendor/zendframework/zend-servicemanager/src/Factory/InvokableFactory.php.Zend\ServiceManager\Factory\InvokableFactory->__invoke:32
[2] file:///var/www/jade/vendor/zendframework/zend-servicemanager/src/ServiceManager.php.Zend\ServiceManager\ServiceManager->doCreate:747
[3] file:///var/www/jade/vendor/zendframework/zend-servicemanager/src/ServiceManager.php.Zend\ServiceManager\ServiceManager->get:195
[4] file:///var/www/jade/vendor/zendframework/zend-servicemanager/src/AbstractPluginManager.php.Zend\ServiceManager\AbstractPluginManager->get:143
[5] file:///var/www/jade/vendor/zendframework/zend-validator/src/ValidatorChain.php.Zend\Validator\ValidatorChain->plugin:97
[6] file:///var/www/jade/vendor/zendframework/zend-validator/src/ValidatorChain.php.Zend\Validator\ValidatorChain->attachByName:194
[7] file:///var/www/jade/vendor/zendframework/zend-inputfilter/src/Factory.php.Zend\InputFilter\Factory->populateValidators:428
[8] file:///var/www/jade/vendor/zendframework/zend-inputfilter/src/Factory.php.Zend\InputFilter\Factory->createInput:267
[9] file:///var/www/jade/vendor/zendframework/zend-inputfilter/src/Factory.php.Zend\InputFilter\Factory->createInputFilter:357
[10] file:///var/www/jade/vendor/zendframework/zend-form/src/Factory.php.Zend\Form\Factory->prepareAndInjectInputFilter:545
[11] file:///var/www/jade/vendor/zendframework/zend-form/src/Factory.php.Zend\Form\Factory->configureForm:284
[12] file:///var/www/jade/vendor/zendframework/zend-form/src/Factory.php.Zend\Form\Factory->create:114
[13] file:///var/www/jade/vendor/zendframework/zend-form/src/Factory.php.Zend\Form\Factory->createForm:177
[14] file:///var/www/jade/vendor/zendframework/zend-form/src/Annotation/AnnotationBuilder.php.Zend\Form\Annotation\AnnotationBuilder->createForm:246
[15] file:///var/www/jade/module/Application/src/Controller/UserController.php.Application\Controller\UserController->saveAction:132
[16] file:///var/www/jade/vendor/zendframework/zend-mvc/src/Controller/AbstractActionController.php.Zend\Mvc\Controller\AbstractActionController->onDispatch:78
[17] file:///var/www/jade/vendor/zendframework/zend-eventmanager/src/EventManager.php.Zend\EventManager\EventManager->triggerListeners:271
[18] file:///var/www/jade/vendor/zendframework/zend-eventmanager/src/EventManager.php.Zend\EventManager\EventManager->triggerEventUntil:151
[19] file:///var/www/jade/vendor/zendframework/zend-mvc/src/Controller/AbstractController.php.Zend\Mvc\Controller\AbstractController->dispatch:105
[20] file:///var/www/jade/vendor/zendframework/zend-mvc/src/DispatchListener.php.Zend\Mvc\DispatchListener->onDispatch:119
[21] file:///var/www/jade/vendor/zendframework/zend-eventmanager/src/EventManager.php.Zend\EventManager\EventManager->triggerListeners:271
[22] file:///var/www/jade/vendor/zendframework/zend-eventmanager/src/EventManager.php.Zend\EventManager\EventManager->triggerEventUntil:151
[23] file:///var/www/jade/vendor/zendframework/zend-mvc/src/Application.php.Zend\Mvc\Application->run:332
[24] file:///var/www/jade/public/index.php.include:40
[25] file:///var/www/jade/index.php.{main}:2

@Ocramius does this provide any clue as to which service manager is being used or the change needed to the factory config?

@Ocramius
Copy link
Member

Ocramius commented Dec 6, 2016

[1] file:///var/www/jade/vendor/zendframework/zend-servicemanager/src/Factory/InvokableFactory.php.Zend\ServiceManager\Factory\InvokableFactory->__invoke:32

It's not using your factories.

@vvaswani
Copy link
Contributor Author

vvaswani commented Dec 6, 2016

It's not using your factories.

Yes, I see. I tried to create a custom factory as below:

<?php
namespace Application\Factory\Validator;

use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
use Doctrine\ORM\EntityManager;

class UniqueObjectFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $uniqueObject = new \DoctrineModule\Validator\UniqueObject(array(
            'fields' => 'username',
            'object_repository' => $container->get(EntityManager::class)->getRepository('Application\Entity\User'),
            'object_manager' => $container->get(EntityManager::class),
        ));
        return $uniqueObject;
    }
}

Then mapped this in Module.php:

    'service_manager' => [
        'factories' => [
            'DoctrineModule\Validator\UniqueObject' => 'Application\Factory\Validator\UniqueObjectFactory'
        ]
    ],

However it still does not seem to use it (error and stack trace same as before). Am I on the right track? Is there some further configuration needed?

@Ocramius
Copy link
Member

Ocramius commented Dec 6, 2016

[14] file:///var/www/jade/vendor/zendframework/zend-form/src/Annotation/AnnotationBuilder.php.Zend\Form\Annotation\AnnotationBuilder->createForm:246

Who created that annotation builder?

@vvaswani
Copy link
Contributor Author

vvaswani commented Dec 6, 2016

Who created that annotation builder?

It's part of the Application\Controller\UserController::saveAction:

    public function saveAction()
    {   
        $id = (int) $this->params()->fromRoute('id', 0);
        $user = $this->em->getRepository(User::class)->find($id);        
        if (!$user) {
            $user = new User();
            $user->setCreated(new \DateTime("now"));
            $passwordRequired = true;  // new user creation
        } else {
            $passwordHash = $user->getPassword();
            $passwordRequired = false;  // existing user modification
        }
        $builder = new AnnotationBuilder();
        ...

@Ocramius
Copy link
Member

Ocramius commented Dec 6, 2016

@vvaswani that obviously breaks the entire dependency injection chain ;-)

@vvaswani
Copy link
Contributor Author

vvaswani commented Dec 6, 2016

@vvaswani that obviously breaks the entire dependency injection chain ;-)

Yes, I think I see the issue now. But is there a better approach you can suggest, or a sample you can point me to that uses this validator with the annotation builder? Or, what's the correct way to accomplish this?

@Ocramius
Copy link
Member

Ocramius commented Dec 6, 2016

If done manually, you'd have to call AnnotationBuilder#setFormFactory(), and grab the form factory from the DIC.

Something like this (if I remember correctly):

$builder = new AnnotationBuilder();
$builder->setFormFactory(new Factory($container->get(FormElementManager::class)));

Meanwhile, closing here: this is not a bug in DoctrineModule.

@Ocramius Ocramius closed this as completed Dec 6, 2016
@Ocramius Ocramius self-assigned this Dec 6, 2016
@vvaswani
Copy link
Contributor Author

vvaswani commented Dec 6, 2016

@Ocramius , thanks for the tip! An update that I tried this:

$builder->setFormFactory(new \Zend\Form\Factory($container->get(FormElementManager::class)));

Threw an immediate exception as $container doesn't exist within the controller, so I then injected the FormElementManager into the UserController via factory and tried the code below in the UserController:

    public function __construct(EntityManager $em, \Zend\Form\FormElementManager $fem)
    {
        $this->em = $em;
        $this->fem = $fem;
        ...
    }


    public function saveAction() {
        ...
        $builder->setFormFactory(new \Zend\Form\Factory($this->fem));
        ...
    }

However this simply ended up back at the original error/stack trace. When I dump $this->fem, I do see the UniqueObject validator in the dump output but it doesn't seem to be getting configured correctly. Not really sure how to proceed further here.

I did however manage to get it working through another approach, which I acknowledge is very hack-y. I removed the annotation in the entity and instantiated/attached the UniqueObject validator to the form validator chain in the controller. Including the code here in case it's useful to someone else:

        $builder = new AnnotationBuilder();
        $form = $builder->createForm();
        $form->getInputFilter()->get('username')->getValidatorChain()->attach(
             new \DoctrineModule\Validator\UniqueObject(array(
                        'use_context' => true,
                        'fields' => 'username',
                        'object_repository' => $this->em->getRepository('Application\Entity\User'),
                        'object_manager' => $this->em,
                    ))
        );
        $form->setInputFilter($form->getInputFilter());         
        $form->bind($user);

Wish there was a better way but it gets the job done! Look forward to any suggestions to improve.

@Ocramius
Copy link
Member

Ocramius commented Dec 6, 2016

@bartoszzajac
Copy link

bartoszzajac commented Dec 14, 2016

I think I have similar problem with Fieldset - configured factories in form_element key, but not seen by FormElementManagerV3Polyfill.

'form_elements' => [
    'factories' => [
        Form\TagFieldset::class => Form\Factory\TagFieldsetFactory::class,
    ],
    'aliases' => [
         'tagfieldset' => Form\TagFieldset::class,
    ],
],

I want to add this fieldset inside another fieldset
How can I inject my factory?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants