2
votes

Being able to use Doctrine speeds up a lot of things however it feels somewhat clunky to me having to set / use the entity manager in all of my controllers. I would prefer to have all of the database logic in 1 specific module. Perhaps I'm just thinking about this the wrong way, and someone can point me in the right direction.

Currently I have my Entity which functions just fine and I can do insertions into the database fine with the following

namespace Manage\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;


class ViewController extends AbstractActionController {
    public function somethingAction(){
        $objectManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
        $user = new \Manage\Entity\User();
        $user->setname('foo');
        $user->settitle('bar');        
        $objectManager->persist($user);
        $objectManager->flush();
    }
}

However whenever I want to select something from the database I have to make sure to add

 use Doctrine\ORM\EntityManager;

And then the following list of Controller functions...

/**
 * @var EntityManager
 */
protected $entityManager;

/**
 * Sets the EntityManager
 *
 * @param EntityManager $em
 * @access protected
 * @return PostController
 */
protected function setEntityManager(EntityManager $em) {
    $this->entityManager = $em;
    return $this;
}

/**
 * Returns the EntityManager
 *
 * Fetches the EntityManager from ServiceLocator if it has not been initiated
 * and then returns it
 *
 * @access protected
 * @return EntityManager
 */
protected function getEntityManager() {
    if (null === $this->entityManager) {
        $this->setEntityManager($this->getServiceLocator()->get('Doctrine\ORM\EntityManager'));
    }
    return $this->entityManager;
}

Once I have added all of that I can now do a query in my getsomethingAction like so...

public function getsomethingAction() {
    $repository = $this->getEntityManager()->getRepository('Manage\Entity\User');
    $list = $repository->findAll();
    var_dump($list);
    return new ViewModel();
}

To me that feels very clunky... I can do an insert without needing all the extra functions but I cannot do a select? Is it possible to extend the Entity class in order to get the find / findAll etc functions that is provided by calling $repository = $this->getEntityManager()->getRepository('Manage\Entity\User'); directly inside the entity?

By that I mean I would prefer to be able to run the find directly on the entity as I would when I set the data... like below:

public function getsomethingAction(){
    $list = new \Manage\Entity\User();
    $l = $list->findAll();
    var_dump($l);
    return new ViewModel();
}
1
It is not the entity's responsibility to load itself or its siblings. Also, you are hereby assuming that the entity keeps some kind of reference to the object manager/database connection/etc (kind-of what we were doing with active record). We moved away from that pattern especially because it brought people to move business logic to entities, making the entity layer a big ball of mud. - Ocramius
That I 100% understand and agree with that it is fine. However what I'm failing to see how to do is to create an additional business logic module that will be able to both fetch / find from db and also insert into db. That way the entity stays as an entity. I have a sneaking suspicion that I've confused myself into not seeing the wood for the trees... - Will H
you have 3 elements into play: Entity | ObjectManager (entity manager) and ObjectRepository (entity repository), whose functionalities are respectively: being a data packet | saving changes to data | retrieving data. That's all - Ocramius
@Ocramius have you seen the answer I posted to my question? I'm curious to hear your thoughts on my implementation. It seems to work out well at this point. - Will H
will be able to check tomorrow. Right now, this looks like you're simply creating a service layer between your controller and the persistence layer, which is a GOOD thing. You may want to check stackoverflow.com/questions/15266862/… - Ocramius

1 Answers

3
votes

Ok so my main objective so far has been to move the complex logic out of the controllers into a re-usable model. So with this example answer I'm creating an interface where the complex logic would live however it also allows me to still use the model in a controller to get data from the database... here is the Model...

namespace Manage\Model;

use Doctrine\ORM\EntityManager;

class ApiInterface {

    /**
     * @var EntityManager
     */
    protected $entityManager;
    protected $sl;

    /**
     * Sets the EntityManager
     *
     * @param EntityManager $em
     * @access protected
     * @return PostController
     */
    protected function setEntityManager(EntityManager $em) {
        $this->entityManager = $em;
        return $this;
    }

    /**
     * Returns the EntityManager
     *
     * Fetches the EntityManager from ServiceLocator if it has not been initiated
     * and then returns it
     *
     * @access protected
     * @return EntityManager
     */
    protected function getEntityManager() {
        if (null === $this->entityManager) {
            $this->setEntityManager($this->sl->get('Doctrine\ORM\EntityManager'));
        }
        return $this->entityManager;
    }

    public function __construct($ServiceLocator) {
        $this->sl = $ServiceLocator;
    }

    public function get() {
        $repository = $this->getEntityManager()->getRepository('Manage\Entity\ApiList');
        return $repository;
    }

    public function set() {
        return new \Manage\Entity\ApiList();
    }

    public function save($data) {
        $objectManager = $this->sl->get('Doctrine\ORM\EntityManager');
        $objectManager->persist($data);
        $objectManager->flush();
    }

    public function doComplexLogic($foo,$bar){
        // Can now use both set() and get() to inspect/modify/add data
    }

}

So now inside my controller I can do something that gets some basic data from the table like:

public function getapiAction() {
    $api = new \Manage\Model\ApiInterface($this->getServiceLocator());
    var_dump($api->get()->findAll());
    return new ViewModel();
}

And to quickly set data from a controller I can do:

public function setapiAction() {
    $apiInterface = new \Manage\Model\ApiInterface($this->getServiceLocator());
    $api= $apiInterface->set();
    $user->setfoo('blah');
    $user->setbar('moo');
    $apiInterface->save($api);
    return new ViewModel();
}

And it also allows me to run complex logic from the controller by taking the complexity out of the controller like so...

public function complexAction(){
    $foo = $this->params()->fromQuery();
    $bar = $this->params()->fromPost();
    $apiInterface = new \Manage\Model\ApiInterface($this->getServiceLocator());
    $apiInterface->doComplexLogic($foo, $bar);
}

Please let me know in comments if this answer would be the proper way to do things, I realize it's very simple and generic but I wanted to keep it that way so others can understand what / why and if this is a good approach / not etc.