我正在尝试在我的 Symfony2 项目中实现领域驱动设计并遇到一些问题。
在阅读了一些有关领域模型的文章后,我发现
- 我应该将所有业务逻辑放入我的领域模型(实体)中。
- 应用程序级别的东西,需要完成并且不属于域逻辑,是通过域事件触发的(发送电子邮件,将一些消息放入队列等)
幸运的是,Symfony 提供了事件,但这里有一个问题 - 我可以不要从我的实体引发事件。
Symfony 文档建议使用 DI 将调度程序注入到类中,从而引发事件
http://symfony.com/doc/current/book/internals.html#passing-along-the-event-dispatcher-object
但是Symfony 实体是可更新的,不可注入。
现在我可以看到两种方法:
1)像这样向实体提供事件调度程序
class FooEntity
{
protected $dispatcher = null;
public function setEventDispatcher(EventDispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
}
2)从服务(而不是从实体)引发事件。
这些选项看起来都不漂亮,因为在我看来它们打破了领域模型意识形态。
请您给我指出正确的方向。
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.
发布评论
评论(2)
这里的想法是提供实现 DDD 范式的路径。
我不想掩盖@magnusnordlander 的答案,我会应用他所说的。
以下是对此事的一些观察:
我认为实体本身不应该拥有一切。无论如何,DDD 的人肯定不会这么说。 [Doctrine2] 实体应该只处理 关系(也有不同变体的实体 <=这实际上是我被困了一段时间的事情)和聚合根。
教义实体应该只知道如何与自己合作。
但是,要获取数据或使用它,您还可以使用其他东西:
Repository
是提供帮助程序的东西,可以让您获得比快速
findBy(array( 'id'=>$idvalue))
会做(并且 实体/协会/注释不能覆盖)并且是确实是一个方便的好东西。我个人尝试构建所有查询,并意识到 EntityManager 已经非常好,开箱即用。 在大多数情况下,我认为:如果您可以/不/使用查询或查询生成器,那就更好了。
所有这些中的业务逻辑...
最后要注意的是,您要寻找的必须是从根本上精简控制器。
FooManager (例如)是业务逻辑所在的位置(如果我没有记错的话)。
我在此博客上发现了有关此事的信息金矿涵盖:
事件
与如果您有任何想法,为了增强,我设置了这个以社区 Wiki 的形式回答
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:
Event
withIf you have any ideas, to augument, I set this answer as a Community Wiki
Symfony 实体是指 Doctrine 2 实体吗?如果是这样,您可以通过以下方式在从数据库加载的新对象和旧对象上设置服务:
原型范围服务
原型范围内的服务在您获取它们时始终会重新创建。您可以执行
$container->get('foo_entity')
,而不是执行new FooEntity
。在 YAML 语法中,您将按如下方式定义服务:
这将处理新实体。对于现有实体,您需要...
加载后事件侦听器
按照此处描述的方式创建事件侦听器:
http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.html
让侦听器侦听
postLoad
事件。将事件调度程序注入到侦听器服务中,并使用侦听器服务在实体上设置事件调度程序。请记住,侦听器服务将在加载任何实体(而不仅仅是 FooEntity)后触发,因此您需要进行类型检查。
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:
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.