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

Made the Annotation builder automatically pass the EntityManager to Form Elements which need it. #180

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public function setEventManager(EventManagerInterface $events)
{
parent::setEventManager($events);

$this->getEventManager()->attach(new ElementAnnotationsListener);
$this->getEventManager()->attach(new ElementAnnotationsListener($this->em));

return $this;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace DoctrineORMModule\Form\Annotation;

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\GeneratedValue;
use Zend\EventManager\EventManagerInterface;
Expand All @@ -14,6 +15,21 @@ class ElementAnnotationsListener implements ListenerAggregateInterface
*/
protected $listeners = array();

/**
* @var \Doctrine\ORM\EntityManager
*/
protected $em;

/**
* Constructor. Ensures EntityManager is present.
*
* @param \Doctrine\ORM\EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}

/**
* Detach listeners
*
Expand Down Expand Up @@ -42,6 +58,7 @@ public function attach(EventManagerInterface $events)
$this->listeners[] = $events->attach('configureElement', array($this, 'handleRequiredAnnotation'));
$this->listeners[] = $events->attach('configureElement', array($this, 'handleTypeAnnotation'));
$this->listeners[] = $events->attach('configureElement', array($this, 'handleValidatorAnnotation'));
$this->listeners[] = $events->attach('configureElement', array($this, 'handleLinkedFormElements'));

$this->listeners[] = $events->attach('checkForExclude', array($this, 'handleExcludeAnnotation'));
}
Expand Down Expand Up @@ -234,4 +251,33 @@ public function handleValidatorAnnotation($e)
break;
}
}

/**
* Handle the form elements which require the doctrine entity manager to populate.
*
* @param \Zend\EventManager\EventInterface $e
* @return void
*/
public function handleLinkedFormElements($e)
{
$annotation = $e->getParam('annotation');
if (!$annotation instanceof \Zend\Form\Annotation\Type) {
return;
}

if (!in_array(
$annotation->getType(),
array(
'DoctrineORMModule\Form\Element\EntityMultiCheckbox',
'DoctrineORMModule\Form\Element\EntityRadio',
'DoctrineORMModule\Form\Element\EntitySelect',
)
)) {
return;
}

$elementSpec = $e->getParam('elementSpec');

$elementSpec['spec']['options']['object_manager'] = $this->em;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No side effects?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None that I'm aware of?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's exactly what I mean: what does this line do? :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the line which makes it all work. In order for EntityMultiCheckbox, EntityRadio & EntitySelect to work they required access to the EntityManager so they can fetch the options from the database, this is provided by an option called object_manager (see \DoctrineModule\Form\Element\Proxy). Here I am setting that option.

It saves having to call

$form->get('element_name')->setOptions(array('object_manager', $entityManager);

after the form has been created.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$elementSpec is not retrieved byref as far as I know

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably when not using Annotation you would do something like

$form->add(array(
    'name' => 'entity_name',
    'type' => 'DoctrineORMModule\Form\Element\EntitySelect',
    'options' => array(
            'object_manager' => $entityManager,
    )
));

However when using Annotations to build a form you cannot set object_manager to an instance in the annotation. So here I'm getting the AnnotationBuilder to do it for these types of Element.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ocramius I did wander about that but it seems to be working fine. Even though $elementSpec may not be retrieved by ref unless the value in object_manager is cloned it will still be a ref to the same object (since its an object and not a scalar) so it should be safe.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, $elementSpec is an object?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was talking about the EntityManager object however $elementSpec is indeed an instance of ArrayObject ;)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh by the way if you're worried about assigning to $elementSpec then take look at the other handler methods in this class you'll see that several of the assign to $elementSpec is the same way ;-)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,25 @@
*/
class ElementAnnotationsListenerTest extends PHPUnit_Framework_TestCase
{
protected $listener;

protected $entityManager;

protected function setUp()
{
$this->entityManager = $this->getMockBuilder('Doctrine\ORM\EntityManager')
->disableOriginalConstructor()
->getMock();

$this->listener = new ElementAnnotationsListener($this->entityManager);
}

/**
* @dataProvider eventProvider
*/
public function testHandleAnnotationType($type, $expectedType)
{
$listener = new ElementAnnotationsListener();
$listener = $this->listener;
$event = new Zend\EventManager\Event();
$checkboxAnnotation = new Doctrine\ORM\Mapping\Column();
$checkboxAnnotation->type = $type;
Expand All @@ -30,7 +42,7 @@ public function testHandleAnnotationType($type, $expectedType)

public function testHandleAnnotationAttributesShallAppent()
{
$listener = new ElementAnnotationsListener();
$listener = $this->listener;
$event = new Zend\EventManager\Event();
$annotation = new Doctrine\ORM\Mapping\Column();

Expand All @@ -56,4 +68,42 @@ public function eventProvider()
array('string', 'Zend\Form\Element'),
);
}

/**
* @covers DoctrineORMModule\Form\Annotation\ElemenetAnnotationsListener::handleLinkedFormElements
* @dataProvider linkedElementTypeProvider
*/
public function testHandleLinkedFormElements($type, $requiresEntityManager)
{
$listener = $this->listener;
$event = new \Zend\EventManager\Event();
$annotation = new \Zend\Form\Annotation\Type(array('value' => $type));

$event->setParam('annotation', $annotation);
$event->setParam('elementSpec', new ArrayObject(array(
'spec' => array('options' => array()),
)));

$listener->handleLinkedFormElements($event);
$spec = $event->getParam('elementSpec');

if ($requiresEntityManager) {
$this->assertArrayHasKey('object_manager', $spec['spec']['options']);
$this->assertEquals($this->entityManager, $spec['spec']['options']['object_manager']);
return;
}

$this->assertArrayNotHasKey('object_manager', $spec['spec']['options']);

}

public function linkedElementTypeProvider()
{
return array(
array('DoctrineORMModule\Form\Element\EntityMultiCheckbox', true),
array('DoctrineORMModule\Form\Element\EntityRadio', true),
array('DoctrineORMModule\Form\Element\EntitySelect', true),
array('Zend\Form\Element', false),
);
}
}