php-ddd icon indicating copy to clipboard operation
php-ddd copied to clipboard

Directory Structure and Namespaces using Symfony Bundles

Open webdevilopers opened this issue 9 years ago • 15 comments

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/

webdevilopers avatar Apr 25 '16 09:04 webdevilopers

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.

webdevilopers avatar Apr 26 '16 08:04 webdevilopers

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 :)

Ma27 avatar Apr 26 '16 13:04 Ma27

Thanks @Ma27 ! As soon as we have a concept for structure I will keep you up to date.

webdevilopers avatar Apr 26 '16 13:04 webdevilopers

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

webdevilopers avatar May 08 '16 18:05 webdevilopers

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.

webdevilopers avatar Jul 27 '16 08:07 webdevilopers

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.

norberttech avatar Aug 02 '16 20:08 norberttech

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?

webdevilopers avatar Aug 05 '16 18:08 webdevilopers

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.

sstok avatar Aug 07 '16 14:08 sstok

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 CQRS and the @Doctrine NEW Operator for READ models, DTOs for Form Models and his own Specification project.

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

webdevilopers avatar Aug 09 '16 10:08 webdevilopers

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 : /

norberttech avatar Aug 09 '16 11:08 norberttech

Start doing microservices, guys. 😉

elnur avatar Aug 09 '16 12:08 elnur

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 avatar Aug 09 '16 16:08 webdevilopers

@webdevilopers fyi, I came across this repos that might help with structure using symfony: https://github.com/jorge07/ddd-playground

yvoyer avatar Sep 06 '16 16:09 yvoyer

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.

webdevilopers avatar Dec 06 '16 10:12 webdevilopers

Another post on this by Stefan Koopmanschap @skoop:

  • http://leftontheweb.com/blog/2016/12/29/best-practices-on-bundles-symfony/

webdevilopers avatar Dec 29 '16 16:12 webdevilopers