Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

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

Closed
wants to merge 2 commits into from

3 participants

@tomphp

Currently the only way I have found to get my

\DoctrineORMModule\Form\Element\EntitySelect

elements to populate is, after creating the form using the AnnotationBuilder, calling

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

I find this pretty messy so this little mod does it automatically.

Hope you like it.

@Ocramius
Owner

@tomphp I do like the idea, but such stuff needs tests :\

Ping @bakura10

@Ocramius Ocramius commented on the diff
...Module/Form/Annotation/ElementAnnotationsListener.php
((16 lines not shown))
+ }
+
+ 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;
@Ocramius Owner

No side effects?

@tomphp
tomphp added a note

None that I'm aware of?

@Ocramius Owner

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

@tomphp
tomphp added a note

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.

@Ocramius Owner

$elementSpec is not retrieved byref as far as I know

@tomphp
tomphp added a note

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.

@tomphp
tomphp added a note

@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.

@Ocramius Owner

Ah, $elementSpec is an object?

@tomphp
tomphp added a note

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

@tomphp
tomphp added a note

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 ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@tomphp

as in you want me to write some unit tests or as in the idea/method needs testing?

@Ocramius
Owner

I stopped merging PRs without tests :P

@tomphp

No problem, I did look at the tests there and so much was uncovered so I wasn't sure if I should do it or not. Will get on to it now...back in 10mins or so ;)

@bakura10
Collaborator

Speaking about it, I suppose most of the AnnotationBuilder could be moved to DotrineModule.

@tomphp

Where are we at with this? Is it still the question of $elementSpec which is the sticking point or is there anything else I need to do?

@tomphp

Is there anything I need to do with this to get it accepted or is the concept still in question?

@Ocramius
Owner

@tomphp can you cross-check #193?

@tomphp

@Ocramius by the looks of it #193 does what this was supposed to do (and more) so this should probably be closed?

@Ocramius
Owner

@tomphp I can merge your test into #193, that one is OK IMO.

Consider that the feature (regardless if this one or the one in #193) lands in 0.8

@tomphp

@Ocramius are you talking about DoctrineORMModuleTest/Form/ElementAnnotationsListenerTest?

If so all I really added to that was a test for the extra method I created so I don't think it's relevant to #193

Unless I'm misunderstanding or missing something?

@Ocramius
Owner

@tomphp nvm, I saw what you mean. I think it's just going to be funny to handle the merge conflicts, but that's up to me :)

@Ocramius
Owner

Scheduled for 0.8

@tomphp

@Ocramius do you think this PR is needed? To me it looks like lines 88 and 112 of `src/DoctrineORMModule/Form/Annotation/ElementAnnotationsListener.php' in #193 handle the functionality that I was aiming to provide with this PR. I think this PR is probable redundant?

Unless I'm missing something I think this PR should be closed and just #193 merged?

@Ocramius
Owner

@tomphp I will keep the test

@Ocramius
Owner

Sorry about the awfully late response :( I'm going to close this since the entire annotation listener was re-written to use metadata in #233

@Ocramius Ocramius closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 19, 2013
  1. @tomphp

    Made the Annotation builder automatically pass the EntityManager to F…

    tomphp authored
    …orm Elements which need it.
  2. @tomphp
This page is out of date. Refresh to see the latest.
View
2  src/DoctrineORMModule/Form/Annotation/AnnotationBuilder.php
@@ -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;
}
View
46 src/DoctrineORMModule/Form/Annotation/ElementAnnotationsListener.php
@@ -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;
@@ -15,6 +16,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
*
* @param EventManagerInterface $events
@@ -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'));
}
@@ -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;
@Ocramius Owner

No side effects?

@tomphp
tomphp added a note

None that I'm aware of?

@Ocramius Owner

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

@tomphp
tomphp added a note

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.

@Ocramius Owner

$elementSpec is not retrieved byref as far as I know

@tomphp
tomphp added a note

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.

@tomphp
tomphp added a note

@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.

@Ocramius Owner

Ah, $elementSpec is an object?

@tomphp
tomphp added a note

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

@tomphp
tomphp added a note

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 ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ }
}
View
54 tests/DoctrineORMModuleTest/Form/ElementAnnotationsListenerTest.php
@@ -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;
@@ -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();
@@ -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),
+ );
+ }
}
Something went wrong with that request. Please try again.