Skip to content
Permalink
Browse files

Moved doctrine knowledge into a manager class

The controller didn't need to know about the implementation
details of doctrine, it only needs to know that our application
can provide some blog posts objects. Therefore we introduce
a "Manager" class whose job it is to do that.
  • Loading branch information
peterjmit committed Sep 4, 2013
1 parent 55c0bf8 commit 4a87e1d447c106e479b335a0a95c81d4feddfefa
@@ -5,25 +5,18 @@
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\Persistence\ObjectRepository;
use Peterjmit\BlogBundle\Model\BlogManagerInterface;

use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\HttpFoundation\Response;

class BlogControllerSpec extends ObjectBehavior
{
function let(
ManagerRegistry $registry,
ObjectManager $manager,
ObjectRepository $repository,
BlogManagerInterface $manager,
EngineInterface $templating
) {
$registry->getManager()->willReturn($manager);
$manager->getRepository('PeterjmitBlogBundle:Blog')->willReturn($repository);

$this->beConstructedWith($registry, $templating);
$this->beConstructedWith($manager, $templating);
}

function it_is_initializable()
@@ -32,11 +25,11 @@ function it_is_initializable()
}

function it_should_respond_to_index_action(
ObjectRepository $repository,
BlogManagerInterface $manager,
EngineInterface $templating,
Response $mockResponse
) {
$repository->findAll()->willReturn(array());
$manager->findAll()->willReturn(array());

$templating
->renderResponse(
@@ -2,24 +2,23 @@

namespace Peterjmit\BlogBundle\Controller;

use Doctrine\Common\Persistence\ManagerRegistry;
use Peterjmit\BlogBundle\Model\BlogManagerInterface;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;

class BlogController
{
private $doctrine;
private $manager;
private $templating;

public function __construct(ManagerRegistry $doctrine, EngineInterface $templating)
public function __construct(BlogManagerInterface $manager, EngineInterface $templating)
{
$this->doctrine = $doctrine;
$this->manager = $manager;
$this->templating = $templating;
}

public function indexAction()
{
$entityManager = $this->doctrine->getManager();
$posts = $entityManager->getRepository('PeterjmitBlogBundle:Blog')->findAll();
$posts = $this->manager->findAll();

return $this->templating->renderResponse('PeterjmitBlogBundle:Blog:index.html.twig', array(
'posts' => $posts
@@ -28,8 +27,7 @@ public function indexAction()

public function showAction($id)
{
$entityManager = $this->doctrine->getManager();
$post = $entityManager->getRepository('PeterjmitBlogBundle:Blog')->find($id);
$post = $this->manager->find($id);

if (!$post) {
throw $this->createNotFoundException(sprintf('Blog post %s was not found', $id));
@@ -0,0 +1,9 @@
<?php

namespace Peterjmit\BlogBundle\Model;

interface BlogManagerInterface
{
function findAll();
function find($id);
}

12 comments on commit 4a87e1d

@docteurklein

This comment has been minimized.

Copy link

@docteurklein docteurklein replied Sep 5, 2013

That's very good stuff! Great that you put that into words, in a clear and concrete example!

However, I would have implemented the interface in this commit, so that you can have a working controller at the end :)

I know that following DDD would make you create a semantic interface, but https://github.com/doctrine/common/blob/master/lib/Doctrine/Common/Persistence/ObjectRepository.php is already a good fit.

What about making the repository a service ?

@everzet

This comment has been minimized.

Copy link

@everzet everzet replied Sep 5, 2013

Even more specifically - use concrete BlogRepository.

@docteurklein

This comment has been minimized.

Copy link

@docteurklein docteurklein replied Sep 5, 2013

right.

@peterjmit

This comment has been minimized.

Copy link
Owner Author

@peterjmit peterjmit replied Sep 5, 2013

I think you chaps are right, the example would be simpler/would benefit from just injecting the repository rather than BlogManagerInterface.

Its more habit rather than anything because I've always found the way FOSUserBundle had managers for the entities with the repository injected useful.

@everzet

This comment has been minimized.

Copy link

@everzet everzet replied Sep 5, 2013

@peterjmit just don't forget that interfaces though are cleanest, are not the only way to define public communication protocol. Classes public API forms communication protocols as well. And yes, interfaces are the purest form of protocol. Question actually is do you need this purest protocol in that particular case ;)

@silviuvoicu

This comment has been minimized.

Copy link

@silviuvoicu silviuvoicu replied Sep 5, 2013

@peterjmit how to inject BlogManagerInterface in the constructor of BlogController, for the templating is easy, because is already a service with an id.

@peterjmit

This comment has been minimized.

Copy link
Owner Author

@peterjmit peterjmit replied Sep 5, 2013

@silviuvoicu I'll do a follow up with some concrete code, but you would need to both write a concrete implementation of BlogManager define it as a service, define your controller as a service then pass the manager service as an argument

@silviuvoicu

This comment has been minimized.

Copy link

@silviuvoicu silviuvoicu replied Sep 5, 2013

@peterjmit Thanks.

@cordoval

This comment has been minimized.

Copy link

@cordoval cordoval replied Sep 5, 2013

I guess when you say "Classes public API " you talking about adjusting rather the uniquitous language (DDD related) so changing the method names on our models, that is defining a domain language I guess ...? or what exactly if i am totally lost 👶 ?

@docteurklein

This comment has been minimized.

Copy link

@docteurklein docteurklein replied Sep 5, 2013

No, he means the public methods defined for a class. They are, by definition, accessible, and "open to receive messages". Otherwise, they would be protected.

@cordoval

This comment has been minimized.

Copy link

@cordoval cordoval replied Sep 5, 2013

thanks for the prescription Dr. 👶

Please sign in to comment.
You can’t perform that action at this time.