in my Symfony 5 application I have an architecture like this:
src/
├─ Website/
│ ├─ Entity/
│ ├─ Repository/
│ ├─ Controller/
├─ Application/
│ ├─ Entity/
│ ├─ Repository/
│ ├─ Controller/
When I create an entity with the command php bin/console make:entity, I would like to be able to specify on which folder to create the entity, and that it also creates the repository on the correct folder automatically.
Here is my configuration of the doctrine.yaml file
orm:
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
App\Application:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Application/Entity'
prefix: 'App\Application\Entity'
alias: Application
App\Website:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Website/Entity'
prefix: 'App\Website\Entity'
alias: Website
For the moment, the only solution I have found is the following:
php bin/console make:entity
I wait for it to ask me for the path, and I enter this if I want to create the entity Totoo in the src/Application/Entity folder : \App\Application\Entity\Totoo
It does create the entity on src/Application/Entity/Totoo.php
But it will create the repository on src/Repository/Application\Entity\TotooRepository.php
How could we optimize this way of creating entities with the command, in order to automatically create the entity and the repository in the right place, and if possible without having to type the full path each time? (Maybe thanks to the aliases in my doctrine setup? But I don't see how)
To perform this do you need to add a maker.yaml file
with the following lines (e.g)
# config/package/dev
maker:
root_namespace: 'App\Application\'
When you will type : bin/console make:entity the new entity or modifying an existing Entity will check it out into this folder.
P:S watch out in which env do you configure it, dev in my case
That's it ;)
Related
I have a FastAPI application that is going to production soon, however i am facing some problems with hydra integration.
First i could not run the #hydra.main() decorator on fastAPI endpoints. This was overcome with using the Hydra Compose API. Here is my implementation for it:
def load_config(config_path, config_name):
"""Loads specified hydra config.
This method is used because, fastapi and hydra did not
wanna work together.
"""
core.global_hydra.GlobalHydra.instance().clear()
initialize(version_base=None, config_path=config_path)
cfg = compose(config_name=config_name)
return cfg
This was fine until now, while I only used one config, but now I need to separate test and production configurations.
My configuration dircetory structure looks like this:
├── config
│ ├── config.yaml
│ ├── env
│ │ ├── prod.yaml
│ │ └── test.yaml
│ ├── prod
│ │ └── prod1.yaml
│ └── test
│ └── test1.yaml
The directory structure and file contents are based on this post:
Python Hydra configuration for different environments. The default environment is set to test.
My application runs with this command:
uvicorn my.api:app and this successfully loads the test config.
However when I try to run it with:
uvicorn env=prod my.api:app the test config still loads instead of production. Here i want to load the prod configuration.
How can I achieve this?
I have found this related github issue, but the solution was not clear from it: https://github.com/facebookresearch/hydra/issues/204
To be clear, i am willing to make fundamental changes if the problem lies within not using #hydra.main()
The Compose API does not integrate with the command line. You need to pass the overrides yourself on the call site.
Check the example in the Compose API page again, in particular the overrides parameter.
from hydra import compose, initialize
from omegaconf import OmegaConf
if __name__ == "__main__":
# context initialization
with initialize(version_base=None, config_path="conf", job_name="test_app"):
cfg = compose(config_name="config", overrides=["db=mysql", "db.user=me"])
print(OmegaConf.to_yaml(cfg))
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.
Controllers: Use a fine grained configuration of controllers.
Twig:
Entity: Use orm.entity_managers.some_em.mappings.mapping_name
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/
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']
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
I use symfony3. Have the only bundle - AppBundle. I use yml for annotation. They live in AppBundle\Resources\config\doctrine. If I want a new entity - I create new .orm.yml file and then run php bin/console doctrine:generate:entities AppBundle. Everything works fine.
Once I needed another namespace for my entity. So I created a folder Filter in doctrine folder. And put a Category entity there. And then called a 'generate' command. I had an error No mapping file found named 'Category.orm.yml' for class 'AppBundle\Entity\Filter\Category'. Then removed Filter folder and recall the command. And everything worked fine. So the issue is in an additional folder. I tried to place Category just in doctrine folder but keep namespace in yml file (AppBundle\Entity\Filter\Category). That does not work.
So the question is: how to create an annotation for an antity with a parent namespace?
You can test it using the php bin/console doctrine:generate:entity command:
The Entity shortcut name: AppBundle:Filter/Category
This is how your project structure would be generated. No subdirectory in the doctrine directory, but instead the namespace in the YAML filename along:
src/
└── AppBundle/
├── Entity/
│ ├── Filter/
│ │ └── Category.php
│ └── SomeEntity.php
└── Resources/
└── config/
└── doctrine/
├── Filter.Category.orm.yml
└── SomeEntity.orm.yml
Is there someone who can explain in detail the standard used by Symfony* to name folders and files in the directory structure?
MyBundle
├─ Controller/ <-- 1) why singular?
├─ Model/ <-- 2) why singular?
├─ Resources/ <-- 3) why plural?
│ ├─ config/ <-- 4) why the "c" is lowercase?
│ ├─ translations/
│ ├─ views/ <-- 5) why the "v" is lowercase and views is plural?
│ │ └─ Default/ <-- 6) Why uppercase?
│ │ └─ my_view.html.twig <-- 7) Why lowercase and snake case?
│ └─ public/
├─ Service/ <-- 8) why singular?
└─ Tests/
This leads to another question: if I want to create a folder which contains ArchiveSection classes inside the Model folder, how should I name it?
Model/ArchiveSections/
Model/ArchiveSection/
Model/archive_sections/
* I am using Symfony 2.3.
See the docs talking about bundle directory structure.
I would say just keep in mind that the Resources directory structure must follow the standards to get some automatic registration of view paths and translations files in the kernel. The same applies to the Command directory.
For the rest it's how you want it to be, just know that the directory structure should repeat the symfony components structure to keep logic and readability (a Twig directory for creating twig extensions or functions, a Serializer directory to hold custom normalizers...).
This is relevant to have a good directory structure as it defines your classes namespace structure.
There is no strictly rules for structure and architecture directory in symfony framework. But exist best practices and standard convention.
In your case, there is nothing issue and you can do what do you want.
It seems that underscore in name directory is not very standard convention but not mandatory.
For question deal with singular or plurial it seems that is unanswered convention from symfony developers. Example : Me I name my service directory with plurial like this 'services' and all my code run perfectly with this name.
Before Symfony 2.8 and because I was in need of a multiApp system in Symfony,
I followed these two posts to achieve this :
-http://jolicode.com/blog/multiple-applications-with-symfony2
-http://mihai-stancu.ro/2015/10/03/multiple-apps-in-one-repo-with-symfony2/
It's not really supported by SensioLabs but it works well, with a attached console option (php app/console generate:bundle --app=app1 for example) to select on which app you need to use a command.
I see now since Symfony 2.8 that a new question is asked when generating a bundle :
Welcome to the Symfony bundle generator!
Are you planning on sharing this bundle across multiple applications? [no]:
But I don't find anything about this feature nowhere across the net.
Is it related to a MultiApp functionality ? Any information about that ?
Thanks anyway & Best Regards !
answer of #michael-sivolobov is very Good.
But, I want to add more clarity in answering the Question:
Are you planning on sharing this bundle across multiple applications?
[no]:
The Symfony Bundle generator needs to decide the useage of the generated bundle.
If this question is answered with yes : That means your generated Bundle will be Used "as is" with multiple projects, not Just for your current project, so you need to prefix a "vendor" name for your generated bundle, and also add the prefix to the namespace of the generated bundle.
Upon not following the convention, a message will print from the Console which reads:
Each bundle is hosted under a namespace (like Acme/BlogBundle). The
namespace should begin with a "vendor" name like your company name,
your project name, or your client name, followed by one or more
optional category sub-namespaces, and it should end with the bundle
name itself (which must have Bundle as a suffix).
See Best Practice for Bundle Name for more details on bundle
naming conventions.
Use / instead of \ for the namespace delimiter to avoid any problem.
File structure for the generated Bundle under src/ dirctory will Be:
├─ src/
│ └─ yourVendor/
│ └─ yourBundle/
│ └─ Controller/
│ └─ DependencyInjection/
│ └─ Resources/
│ └─ Tests/
│ └─ yourVendorYourBundle.php/
If you answer this question with a No : This means you intend to use your generated Bundle only for your Current Project, so you do not need the "vendor" name as the prefix as it is never going to be shared.
File structure for the generated Bundle under src/ dirctory will Be:
├─ src/
│ └─ yourBundle/
│ └─ Controller/
│ └─ Resources/
│ └─ Tests/
│ └─ yourBundle.php/
Here is some good documentation on Best Practices for creating projects .
If you don't know how to answer use the default value.
This question is here because you can create bundle for sharing and you must name it with vendor name (like everyone did before best practices had been posted).
But you also can create bundle for internal usage only as a main bundle of your application or some helpful bundle. And so you don't need vendor name in the name of your bundle. And answering no on this question generator will generate you not YourVendorName/AppBundle but simple AppBundle.
Also if answering yes configuration will be generated in xml format while answering no leads to annotation format.
So you don't need to worry about multiple apps if you generate them as separate bundles.