Question

I am struggling with a proper injection of Doctrine's ObjectManager to my Fieldsets. I do not want to pass it over all constructors to them. The case is as follows:

Controllers:

  • Controllers have no ObjectManager.
  • Controllers use Services.

Services:

  • Services implement the ObjectManagerAwareInterface.
  • Services get the ObjectManager by an Initializer class.
  • Services provide Forms.

Forms:

  • Forms should not have an ObjectManager - at least they do not need one so far.
  • Forms create the respective Fieldsets.

Fieldsets:

  • Fieldsets implement the ObjectManagerAwareInterface.

As it is now I pass the ObjectManager from the Service over the Form to the Fieldset. This approach is very ugly.

I know that there is a solution using the FormElementManager. But in order to do that I would have to give the Form access to the ServiceLocator by injecting it. This approach seems not to be more proper than my current one.

The question is how to inject Doctrine's ObjectManager into my Fieldsets without injecting the global ServiceLocator (or something else) into my Forms. I would like to leave the Forms simple as they are if possible.

The following shows roughly how my application is built up right now:

abstract class AbstractService implements ObjectManagerAwareInterface
{

    private $objectManager;

    public function getObjectManager()
    {
        return $this->objectManager;
    }

    public function setObjectManager(ObjectManager $objectManager)
    {
        $this->objectManager = $objectManager;

        return $this;
    }

}

class MyService extends AbstractService
{

    public function doSomething()
    {
        $count = $this->someCalculation();
        $myForm = new MyForm($count, $this->getObjectManager());

        // ...
    }

}

class MyForm extends Form
{

    private $objectManager;

    public function __construct($count, ObjectManager $objectManager) // TODO: Remove $objectManager
    {
        parent::__construct('myForm');

        $this->objectManager = $objectManager;

        $myCollection = new Collection('myCollection');
        $myCollection->setCount($count);
        $myCollection->setTargetElement(new MyFieldset($objectManager)); // TODO: ???
        $myCollection->setUseAsBaseFieldset(true);
        $this->add($myCollection);

        $submit = new Submit('submit');
        $this->add($submit);
    }
}

abstract class AbstractFieldset extends Fieldset
                                implements ObjectManagerAwareInterface
{

    private $objectManager;

    public function getObjectManager()
    {
        return $this->objectManager;
    }

    public function setObjectManager(ObjectManager $objectManager)
    {
        $this->objectManager = $objectManager;

        return $this;
    }

}

class MyFieldset extends AbstractFieldset
{

    public function __construct(ObjectManager $objectManager) // TODO: Remove $objectManager
    {
        parent::__construct('myFieldset');

        $this->setObjectManager($objectManager); // TODO: Use initializer

        $this->setHydrator(new DoctrineObject($this->getObjectManager(), true));
        $this->setObject(new MyModel());

        // ...
    }
}
Was it helpful?

Solution

Basically you'd wanna be using the FormElementManager.

// Config array
'form_elements' => [
    'factories' => [
        'My\Cool\Fieldset' => 'My\Cool\FieldsetFactory'
    ]
]

And then you have anormal factory-class

class FieldsetFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $sl)
    {
        $realServiceLocator = $sl->getServiceLocator();
        $entityManager      = realServiceLocator->get('Doctrine\ORM\EntityManager');

        return new \My\Cool\Fieldset($entityManager);
    }
}

That would be the most proper way to do it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top