Bruce
Bruce

Reputation: 155

Using Doctrine module hydrator and form annotations in ZF2

I need some advices here. I am in a ZF2 project using Doctrine 2 with the Doctrine Orm module. I handle the authentication with the services provided by the doctrine module. The result is that after authentication, I have in my authentication service the identity (returned by the getIdentity() method) that is an instance of my User entity.

I have two entities : User and Group. There is a Many to One relation defined in the User entity with the Group (one user belong to a group an one group has many users). Basic stuff.

My problem comes when a connected user needs to go to edit it's own group in the CRUD.

The way I handle the CRUD is simple : I have my form defined in the annotations of my entities and I specified the Doctrine Hydrator and use the Doctrine Object Select. Every thing works perfectly except in the case of editing one's own group.

What I understood is : as my many to one relation is in the lazy loading fetch mode, after authentication, the identity map of doctrine contains the user group as an instance of the proxy. When the user arrive on the edit action, here is what happens :

/*
Code that get the goup id to edit from request
*/
if (!empty($id)) {
    $entity = $groupRepository->find($id);
}

$builder = new AnnotationBuilder();
$this->form = $builder->createForm($entity);

The result is that when editing any group that is not in the doctrine identity map as a proxy instance, every thing is ok. But if the entity I need to edit is already in the identity map as a proxy instance then the form factory cannot find the annotations defined in my entities and it breaks. Maybe my way is a bad practice ? I wanted to use the annotations to build my form.

The only fix I could find (that is a terrible way I guess) is to change my code like this :

/*
Code that get the goup id to edit from request
*/
if (!empty($id)) {
    $em->clear(); <== NEW LINE HERE
    $entity = $groupRepository->find($id);
}

$builder = new AnnotationBuilder();
$this->form = $builder->createForm($entity);

In theory, the call to clear() to detach all entities should not be a problem in my use case cause I know that I just want to edit the group entity but I guess this might not be the right thing to do.

Another solution (but not tried yet) : create a custom FormFactory that I pass to my AnnotationBuilder. This custom FormFactory would then detect the type of entity before launching the form creation from annotations. If it is a proxy then it should get the annotations of the "real" class instead ?

Or maybe I missed something simpler ?

Upvotes: 1

Views: 210

Answers (1)

Wilt
Wilt

Reputation: 44336

I am a bit surprised that this doesn't work correctly when you pass a proxy, but I agree that your current solution is terrible :). You could solve it differently like this:

// collect the class from the entity or proxy
$className = \Doctrine\Common\Util\ClassUtils::getClass($entity);

$builder = new AnnotationBuilder();
$this->form = $builder->createForm($className);

The annotation builder works well when passing the class name. The above code collects the real class name from both proxy objects as well as entities, so this works for both cases.

But I would still suggest to check your configuration because I am almost sure it should also work correctly with proxies.

Upvotes: 2

Related Questions