Symfony 4: How to organize folder structure (namely, your business logic)

23,926

Solution 1

As stated in comments, Symfony can work well with all these structures, so indeed we cannot have an accepted anwser here, but here is my two cents.

To be honest, the best practices would be to organize architecture independently of the framework (it is mainly for this reason that Symfony 4 no longer imposes a bundle).

But in fact, except for really specific or complex projects, it will be more practical to have a "symfony-oriented" organization.

What follows is my personal preferences, and are also strongly influenced by the typology of my projects (CRUD oriented, Rest API, without strong business logic)

In general, I'm moving towards a structure like this:

-src
   - Controller
       - Core
       - Todos
       - ...
   - Entity
       - Core
       - Todos
       - ...
   - Repository
       - Core
       - Todos
   - Validator (or other Symfony oriented components)
       - Core
       - Todos
   - Others (depend on project)
       - Core
       - Todos
   - ...

The reasons are:

  • Less service definition with autowire - yeah, I'm lazy ;-)

    If you need to register your repositories or controllers as services, you can do it with one declaration.

  • In Symfony Flex recipes, it is usually this structure that is used.

    DoctrineBundle for example initialize src/Entity and src/Repository folders and recipes that contains entities also use this structure.

But keep in minde that Symfony Flex is not mandatory. Its purpose is mainly to ease the project's init and make the framework more accessible to beginer

Solution 2

Conway's law:

organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations.

You should design your directory structure around how you organize work.

If you or your colleagues work full-stack on per feature basis you should group your code per feature. It will make navigation and code discovery easier.

If you or your colleagues are well specialized on back-end, front-end, translations etc. you should organize your code around that. Directory structure on per function basis will support clear split of responsibilities.

Also, the depth should depend on how big do you foresee a project to be. If it will be a 5+ years effort of 5+ people, you should probably go with splitting both on per feature and per function with nesting, as mentioned, depending on work organization. If it will be a 3 month project for one person i.e. some simple internal tool you should probably go with more flat structure. I would also recommend sticking to defaults.

Additionally, I found this article informative: https://blog.nikolaposa.in.rs/2017/01/16/on-structuring-php-projects/

Solution 3

2nd structure is quite suitable for complex app, business areas splitted.
It is easy with Symfony 4 to configure its application in this way.

├─ assets/
├─ bin/
│  └─ console
├─ config/
│  ├─ doctrine/ 
│  │    ├─ core/
│  │    └─ sample/
│  ├─ packages/
│  ├─ routes/
│  └─ validator/
│  │    ├─ core/
│  │    └─ sample/
├─ public/
│  └─ index.php
├─ src/
│  ├─ Core/         
│  │  ├─ Controller/
│  │  ├─ Entity/
│  │  ├─ Repository/
│  │  └─ ...
│  ├─ Sample/      
│  └─ ...
├─ templates/
│  ├─ core/
│  └─ sample/
├─ tests/
├─ translations/
├─ var/
│  ├─ cache/
│  ├─ log/
│  └─ ...
└─ vendor/

With a little bit of configuration : service auto-wiring, auto-configuration etc... work like a charm.

# config/packages/doctrine.yaml
doctrine:
    # ...
    orm:
        # ...
        auto_mapping: true
        mappings:
            App\Core:
                is_bundle: false
                type: yml
                dir: '%kernel.project_dir%/config/doctrine/core'
                prefix: 'App\Core\Entity'
                alias: 'AppCore'


#config/routes/annotations.yaml
core_controllers:
    resource: ../../src/Core/Controller/
    type: annotation


# config/services.yaml
# But I prefer to put this on a separate config/services/_auto.yaml
services:
    App\:
        resource: '../../src/*/*'
        exclude: '../../src/*/{Entity,Migrations,Tests,Kernel.php}'

    app_controller:
        namespace: App\
        resource: '../../src/*/Controller'
        tags: ['controller.service_arguments']
Share:
23,926
Aerendir
Author by

Aerendir

Pensiero Classico, formazione giuridica, anima innovaTTiva. Sono un blogger, amo Internet e l'#ecommerce è la mia perfetta sintesi tra piacere e lavoro (futuro)

Updated on March 27, 2020

Comments

  • Aerendir
    Aerendir about 4 years

    In the Symfony Best Practices is advised to not use bundles to organize business logic.

    The bundles should be used only when the code in them is meant to be reused as-is in other applications:

    But a bundle is meant to be something that can be reused as a stand-alone piece of software. If UserBundle cannot be used "as is" in other Symfony apps, then it shouldn't be its own bundle.

    So, as I'm upgrading my app from Symfony 3.3 to Symfony 4, I think this is the right time to reorganize my code.

    At the moment I have followed the "bundled-structure":

    - src
       - AppBundle
          - Controller
          - Entity
          - Repository
          - Resources
          - ...
       - MyNamespace
          - Bundle
              - BundleTodo
                  - Controller
                  - Entity
                  - Repository
                  - Resources
                  - ...
              - BundleCatalog
                  - Controller
                  - Entity
                  - Repository
                  - Resources
                  - ...
              - BundleCart
                  - Controller
                  - Entity
                  - Repository
                  - Resources
                  - ...
              - ...
    

    Now, with the new directory structure, how should have I to organize my code?

    I'd like to organize it this way:

    -src
       - Core
          - Controller
          - Entity
          - Repository
          - ..
       - Todos
          - Controller
          - Entity
          - Repository
          - ..
       - Catalog
          - Controller
          - Entity
          - Repository
          - ..
       - Cart
          - Controller
          - Entity
          - Repository
          - ...
    

    But, is this correct? Is there any problem with the expected folder structure of Symfony 4 and Flex?

    Or is better something like this:

    -src
       - Controller
           - Core
           - Todos
           - Catalog
           - Cart
           - ...
       - Entity
           - Core
           - Todos
           - Catalog
           - Cart
           - ...
       - Repository
           - Core
           - Todos
           - Catalog
           - Cart
           - ...
       - ...
    

    The same applies also to other root folders as described in the project directory structure (about how to override it).

    Are there any rules or constraints that I have to take into account deciding my new folder structure?

    TRYING TO SOLVE THE PROBLEM

    So, trying to solve the problem, I'm going deeper in the documentation and I will write here what I will find.