php-ddd
php-ddd copied to clipboard
Directory Structure and Namespaces using Symfony Bundles
My structure is inspired by this highly recommended book written by @carlosbuenosvinos, @theUniC and @keyvanakbary:
- https://leanpub.com/ddd-in-php
- https://github.com/dddinphp/book-issues/issues/50
src/Acme/QualityManagement\Application\Services\ (All my Commands, Queries and Handlers go here) src/Acme/QualityManagement\DomainModel\Order\Order.php (and OrderId, OrderRepository etc.) src/Acme/QualityManagement\Infrastructure\Persistence\Doctrine\OrderRepository.php (ORM and ODM Repositories implementing the DomainModel Interfaces)
The UserInterface aka PresentationLayer is currently missing. Maybe there won't be a UserInterface in this src folder after all when a frontend developer creates a separate AngularJS app for instance.
Currently I'm using a Symfony Bundle for this: src/Acme/QualityManagementBundle
It holds the Doctrine XML Mapping for ORM and ODM, Forms, Controllers and Tests.
Translations and templates were moved to the app/Resources/QualityManagementBundle folder.
I ask myself if this "Bundle" actually is some kinde of Presentation or even Application Layer.
Should I move it to:
src/Acme/QualityManagement\Application\QualityManagementBundle
Should I try to include the Bundle into the Application folder? src/Acme/QualityManagement\Application\Controller (formerly QualityManagementBundle\Controller) src/Acme/QualityManagement\Application\Form (formerly QualityManagementBundle\Form)
Or is the Bundle the Presentation Layer? Should I keep the QualityManagementBundle name and move it to the Domain:
src/Acme/QualityManagement\UserInterface\QualityManagementBundle
or
src/Acme/QualityManagement\Presentation\QualityManagementBundle
or try to override the Symfony internals to use the correct layer naming instead of the Domain name QualityManagement with the the Bundle suffix?
src/Acme/QualityManagement\UserInterface (formerly QualityManagementBundle)
or
src/Acme/QualityManagement\Presentation (formerly QualityManagementBundle)
Looking forward to thoughts from @leopro and @willdurand!
- https://github.com/leopro/trip-planner/tree/master/src/Leopro/TripPlanner
- http://williamdurand.fr/2013/08/07/ddd-with-symfony2-folder-structure-and-code-first/
Regarding renaming @symfony Bundles to UserInterface for instance and removing the Bundle suffix it seams to be possible.
Discussion on Twitter started here: https://twitter.com/webdevilopers/status/723201477016055808 @jaspernbrouwer @Ma27
Moving some parts of the bundle to the Domain Layer as suggested by @elnur has already been achieved. http://elnur.pro/symfony-without-bundles/
Entities or Models or DomainModels went to the Domain. Annotations were removed and replaced by XML mapping. Mappings live inside the QualityManagementBundle and Doctrine Repositories can be found in the Infrastructure Layer.
Twig Templates could stay in the domain if we put them into the UserInterface / Presentation Layer. Or they could live in a Symfony app/Resources/QualityManagementBundle folder.
I didn't try to remove the bundle suffix in one of my projects, but it should work according the source of the Bundle class (https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpKernel/Bundle/Bundle.php)
All the methods registering something (e.g. the bundle extension or the command or the bundle alias) do work with the suffix according to convention over configuration, but overriding those methods should do the job.
Unless you can ping me, so I may help to find another solution :)
Thanks @Ma27 ! As soon as we have a concept for structure I will keep you up to date.
Another approach I've seen by @qandidate-labs @ricbra @wjzijderveld is to add the FooBundle into a src/Bundle folder:
https://github.com/qandidate-labs/broadway/tree/master/src/Broadway
Some examples for changing namespaces from the @dumplie framework suggested by @norzechowicz:
- https://github.com/dumplie/dumplie/pull/23
Separating Application Services to Command and Query namespaces. No Domain\Model or DomainModel namespace as suggested by the @dddinphp book.
But the first time I see a SharedKernel namespace.
hi @webdevilopers
So I just want to clarify SharedKernel. As you might notice, in dumplie we have 3 standalone and independent bounded contexts.
- Customer
- CustomerService
- Inventory
Each of them can be represented by standalone application with separated database etc. The whole point of SharedKernel is to put reusable things like for example SKU, Price value objects or event interfaces for CommandBus into one place to not duplicate that code in each context. Shared Kernel is a dependency of all contexts but it does not depends on any of them by itself.
Thanks for clearing this up @norzechowicz ! If you were to design @dumplie as a Symfony bundle I guess each bounded context would become its own Symfony App(Kernel) and things like a CommandBus would be added to each vendor dir instead of using one directory across all App(Kernel)s?
When it comes to the presentation or delivery mechanism, what I have seen so far is one bundle for infrastructure, and then a separate bundle for each delivery mechanism (WebBundle, CliBunde, ApiBundle).
@norzechowicz Interesting naming choice on the SharedKernel, usually you see Common or Shared.
In most of my cases the Infrastructure layer only holds Doctrine related stuff.
Symfony is a combination of User Interface or Presentation Layer (using TWIG for instance).
I guess if the frontend was standalone with a REST API the Presentation Layer/ UI could go anywhere - independent of Symfony. But the User Interface would remain inside a Symfony Bundle talking to the Application Layer.
Another great proposal here by @maximecolin:
- http://slidedeck.io/maximecolin/talk-rex-ddd
Including
CQRSand the @Doctrine NEW Operator for READ models, DTOs for Form Models and his ownSpecificationproject.
I just don't know if Bundles belong into the Infrastructure Layer at all. Maybe there should be extra layers:
- Vendor\Application
- Vendor\Domain
- Vendor\Infrastructure
- Vendor\UserInterface
- Vendor\UserInterface\AppBundle
If you were to design @dumplie as a Symfony bundle I guess each bounded context would become its own Symfony App(Kernel) and things like a CommandBus would be added to each vendor dir instead of using one directory across all App(Kernel)s?
@webdevilopers thats the one way to deal with it. It depends how big project you need to create, in simple shop, single AppKernel with shared database would be enough. If you are thinking about something bigger you can even implement each BC as a standalone application.
@sstok I think I read about SharedKernel in one of the DDD books but I don't remember which one : /
Start doing microservices, guys. 😉
Well, a microservice can be related to a bounded context in #DDD using CQRS or CRUD for instance. In both cases you should think about the directory structure.
@webdevilopers fyi, I came across this repos that might help with structure using symfony: https://github.com/jorge07/ddd-playground
Interesting approach by @jorge07.
For anybody that is interested in putting the Bundle into their infrastructure folder this works includind the Suffix:
s generate:bundle --bundle-name=AcmeBoundedContextBundle --format=xml --namespace=Acme/BoundedContext/Infrastructure/Symfony/BoundedContextBundle --dir=src/
Maybe Acme/BoundedContext/Infrastructure/Framework/Symfony/BoundedContextBundle or something would make even more sense since Doctrine is also subfoldered with Persistence.
Another post on this by Stefan Koopmanschap @skoop:
- http://leftontheweb.com/blog/2016/12/29/best-practices-on-bundles-symfony/