webdevilopers / php-ddd

PHP Symfony Doctrine Domain-driven Design
201 stars 10 forks source link

Directory Structure and Namespaces using Symfony Bundles #6

Open webdevilopers opened 8 years ago

webdevilopers commented 8 years ago

My structure is inspired by this highly recommended book written by @carlosbuenosvinos, @theUniC and @keyvanakbary:

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!

webdevilopers commented 8 years ago

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.

Ma27 commented 8 years ago

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

webdevilopers commented 8 years ago

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

webdevilopers commented 8 years ago

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 commented 8 years ago

Some examples for changing namespaces from the @dumplie framework suggested by @norzechowicz:

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.

norberttech commented 8 years ago

hi @webdevilopers So I just want to clarify SharedKernel. As you might notice, in dumplie we have 3 standalone and independent bounded contexts.

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.

webdevilopers commented 8 years ago

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?

sstok commented 8 years ago

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.

webdevilopers commented 8 years ago

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:

I just don't know if Bundles belong into the Infrastructure Layer at all. Maybe there should be extra layers:

norberttech commented 8 years ago

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

elnur commented 8 years ago

Start doing microservices, guys. 😉

webdevilopers commented 8 years ago

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.

yvoyer commented 7 years ago

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

webdevilopers commented 7 years ago

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 commented 7 years ago

Another post on this by Stefan Koopmanschap @skoop: