Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

symfony domain event

I'm trying to implement Domain Driven Design in my Symfony2 project and experience some problems. After reading some articles on Domain Models I found, that

  • I should put all the business logic into my domain models(entities).
  • Application level stuff, that needs to be done and doesn't belong to domain logic is fired with Domain Events(sending emails, putting some messages to the queue, etc.)

Luckily, Symfony provides Events, but here is a problem - I can't raise event from my entity. Symfony documentation suggects to use DI to inject the dispatcher into the class, that raises Event

http://symfony.com/doc/current/book/internals.html#passing-along-the-event-dispatcher-object

But Symfony Entities are newable, not injectable. Right now I can see two ways:

1) Provide Event Dispather to Entity like this

class FooEntity
{
    protected $dispatcher = null;

    public function setEventDispatcher(EventDispatcher $dispatcher)
    {
        $this->dispatcher = $dispatcher;
    }
}

2) Raise Events from the service(not from the Entity).

None of this options look pretty, because it seems to me that they break Domain Model ideology. Can you point me in the right direction, please.

like image 634
mik Avatar asked Nov 07 '11 18:11

mik


2 Answers

The idea of this here is to give paths to attain the DDD paradygm.

I do not want to shadow over @magnusnordlander answer, I will apply what he says.

Here is some of observations on the matter:

I think that the Entity itself should not have everything. It is sure not what the DDD people would say anyway. The [Doctrine2] Entity should only take care of the relationships (an entity with different variation too <= This is actually a thing that I was stuck for a while) and the aggregate root.

The Doctrine entity should only know about how to work with itself.

But, to Get Data or work with it, there is other stuff that you can use:

Repository

Is the thing that provides helpers to get your more sophisticated finders than what a quick findBy(array('id'=>$idvalue)) would do (and that the Entity/Assocation/Annotation cannot cover) and is indeed a great thing to have handy.

I personally tried to build all queries, and realized the EntityManager is already very good, out of the box. In most case, to my opinion: If you can /not/ use query or query builder, the better.

Business logic in all that...

Last thing on note, what you would be searching for must be to basically thin the Controller.

FooManager (for example) is where (if I am not mistaken) the business logic go.

I found a goldmine of information on that matter on this blog that covers:

  • Controllers and application logic revisited
  • Putting controllers in a diet, and mix it with some custom Event with
  • Leveraging the Symfony2 Event dispatcher

If you have any ideas, to augument, I set this answer as a Community Wiki

like image 66
renoirb Avatar answered Oct 22 '22 12:10

renoirb


By Symfony entities, do you mean Doctrine 2 entities? If so, you can set services on both new objects and old objects that are loaded from the database in the following manner:

Prototype scoped service

Services in the prototype scope are always recreated when you get them. Instead of doing new FooEntity you would do $container->get('foo_entity').

In the YAML syntax you would define the service as follows:

foo_entity:
  class: FooEntity
  calls: 
    - [setEventDispatcher, [@event_dispatcher]]
  scope: prototype

This will take care of new entities. For existing entities you need a...

Post load event listener

Create an event listener, in the manner described here:

http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.html

Have the listener listen for the postLoad-event. Inject the event dispatcher into the listener service, and use the listener service to set the event dispatcher on the entity.

Bear in mind that the listener service will fire after loading any entity, not just the FooEntity, so you'll need to do a type check.

like image 29
Magnus Nordlander Avatar answered Oct 22 '22 14:10

Magnus Nordlander