For the past two months, I've been developing a Symfony2 web application. Now I've been going back through and trying to fix some issues with it, because it's gotten a little out of control and I want to make it easy to maintain.
My application is structured into a series of bundles like this:
src/AppName/HelpBundle
src/Appname/InterfaceBundle
src/AppName/ProductBundle
src/AppName/UserBundle
InterfaceBundle just contains several twig templates for the main layout, and each of the other bundles just extend that, e.g.:
{% extends 'AppNameInterfaceBundle::layout.html.twig' %}
For controllers, each controller directory has two sub directories: User and Admin, for example:
src/AppName/ProductBundle/Controller/Admin/ProductCategoryController.php
src/AppName/ProductBundle/Controller/User/ProductCategoryController.php
Is this the appropriate way to structure a Symfony application, or should it be done differently?
The problem is not very detailed but for what I see I think that what you could do is organize things in a way that AdminBundle and a UserBundle contain a set of generic services that allow you to build controllers reusing them.
Then you could have a series of bundles like ProductBundle that reuse/interact with these services. Use dependency injection in your controllers rather than extending the Symfony's Controller class; this way you can leverage service inheritance and build abstract controllers in your AdminBundle and UserBundle and use them to derive your specific controllers.
More in general I like to structure Symfony applications in a way that for each concern that is cross-cutting the application's domain (e.g. indexing of entities in a search engine, logging, generation of URLs and so on) I like to create a bundle that provides some abstractions to handle it; for each area of the domain (e.g. product management, user management etc.) then I like having a bundle that implements interfaces provided in the abstraction ones and that registers specific services to be used in the provided abstractions. Interfacing can be done in this case through the container's configuration and tagging systems.
The question was pretty generic and so my answer is too, if you want more details feel free to provide more details to your question.
Related
I am developing an app with Symfony2 that has 3 main parts called frontoffice, backoffice, admin. I was thinking to create three separate bundles: FrontOfficeBundle, BackOfficeBundle, AdminBundle but Symfony's docs says, each bundle should not have any relation with each other. Entity is already a shared property and probably some models. I could create a SharedBundle but it does not make sense. I remember when I created an app 2 years go when I had like 15 bundles and all connected each other and I know from experience that it's a nightmare.
Should I have just one bundle AppBundle and logic split in the folders, eg. Controller/Admin; Controller/FrontOffice, Controller/BackOffice?
What's the best approach?
It's all about SRP and DRY
It doesn't hurt to create a bundle, so make a separate bundle for stuff you need in multiple bundles, e.g. I tend to create an EntityBundle which contains entities and their repositories (as service).
Of course you can just use a single AppBundle too but please don't put your logic into the controllers -> create reusable services! Inject the services you need into your controller (which should themselves be services too).
Alternatives to base Controller Methods
No such thing as best approach.
However, instead of grouping by class type (Controller,Command,Form,Templates) within a directory, I like to create a single "component" directory for each request action. So I would have
Action
FrontOffice
BackOffics
Admin
User
UserController.php
UserFormType.php
UserTemplate.html.twig
Grouping files in this fashion really cuts down on figuring out where the various files live. Is it the "best" approach? Nope. But it works for me.
I know a Symfony2 bundle should contain a common set of features. However, how granular do you define that set of features? For example, I have a ContentBundle which deals with creating and editing content. Then I have a TaxonomyBundle which handles tagging and categories etc. Finally I have a PollsBundle, which deals with polls.
The trouble I'm having is that the doctrine entities rely on entities in other bundles. For example I have an entity 'Type' in TaxonomyBundle, and a 'Poll' in PollBundle belongs to 'Type'. Finally 'Type' belongs to 'Content' in the ContentBundle.
Am I being too granular when trying to separate concerns? Should things like content and taxonomy be a part of the same bundle?
tl;dr how wide a scope, in terms of features should a Symfony2 bundle be?
According to Symfony best practices :
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. Moreover
InvoiceBundle depends on ProductBundle, then there's no advantage to
having two separate bundles.
So it looks that in your case this rule applies:
Best Practice
Create only one bundle called AppBundle for your application logic
I'm refactoring a not-so-complex website based on Symfony 2.2 / PHP 5.3, and the main issue here is repeated code.
There are two bundles, one for the main website, and another with the mobile version. Those differences are not only on templates and static files, as they comprise some differences in business rules and so on.
Currently those two bundles sport three controllers, one being the main guy, another being the exceptions controller, but a third is the "mother-controller", that holds several common methods and behaviours, and is inherited by the actual controllers.
This poses a small problem, since I can't simply make the action controllers of the mobile bundle inherit from the desktop bundle. All I could do is implement inheritance between the mobile's DefaultController and the desktop one... And thus I still have a bunch of actions almost equal, except for some custom lines.
Is there a way to extract those actions to a generic class and them import them into the controllers (like we have in Yii's Action classes)? I searched about using the decorator pattern to no avail, and was wondering if there's any sort of known method to implement this idea.
Since you have two bundles my first idea would be to create another (let's call it "CoreBundle") and create CommonController there and put common logic into it. Then, let other controllers extend this CommonController.
The more cleaner, but harder, solution would be to create service which would be parametrized by needed data/services.
I'm trying to understand how Models work in proper MVC.
As far as I know, Models in MVC is where the application logic happens, Models are meat, or back bone of MVC. Views are just presentation, and Controllers are "glue" that asks Models to do some actions, return some data, and pass that information to the View that is presented to the user.
Now, I'm exploring all kinds of different MVC frameworks and would like to understand how to use models in MVC. Symfony 2 is interesting framework as far as Models goes, since there are no Models :)
I have problems grasping some of the features of Symfony2, and where does Models fit in Symfony2 MVC.
By definition, Models are where domain logic, and database actions goes.
So my questions are:
In Symfony2 we have Entities, and Services, are those two Models in Symfony?
What is the difference in Symfony2 Services, and Web Services?
So my questions are where is the Model in Symfony2? Since Model is a layer, composed of Domain Objects, and Data Mappers, then I can assume that Entities are Domain Objects, and Doctrine is Data Mapper, is that correct?
And where do Symfony2 services fit in?
Symfony2 does not have the traditional "Model" part of MVC like other frameworks do. Even Entities/Documents from ORM/ODM Doctrine are not part of the framework itself nor does Symfony2 depend on it.
As Fabien (creator of Symfony framework) wrote on his blog,
"It's up to you to create your model by hand or use any other tool,
like an ORM" ... "I don't like MVC because that's not how the web works.
Symfony2 is an HTTP framework; it is a Request/Response framework."
It was hard for me to understand just reading, but I understood what he meant when I actually started programming in Symfony2.
A service in Symfony2 on the otherhand is just an object that performs a global task. Router, doctrine, logger, mailer are some of the many services that come preloaded with Symfony2. You can access services from any part of your code.
Symfony2 services are completely different from web services. Symfony2 services are meant to be used within your system while web services are meant to be used from machine to machine via REST api for example. Although, I guess you could create RESTful api as part of your service.
"I don't like MVC because that's not how the web works. Symfony2 is an HTTP framework; it is a Request/Response framework."
I disagree with this statement completely. MVC is definitely suited to the web if you look at it the right way.
1) The HTTP request is received by the Controller.
2) The Controller instantiates the Model (or Models) and activates the relevant method(s) on the Model(s) which each return a result which will usually be an array of data.
3) When the Model(s) have finished the Controller instantiates the View, inserts the data from the Model(s) then activates the method which transforms the data into HTML.
4) The Controller takes the result from the View and sends it back to the client as the HTTP response.
Just because MVC was invented for desktop applications years before the web existed and is therefore irrelevant for the web is a mistake made by people who cannot see the wood for the trees, who cannot see the big picture without fixating on irrelevant details. Each component in MVC has a distinct set of responsibilities, and provided that you create three components each of which fulfils one of these responsibilities - where the physical implementation is irrelevant - then you have MVC whether you like it or not.
I don't know Symfony but I already use other MVC frameworks (grails, codeigniter).
Models (Entities) represents the data and it is possible to define directly in the models some limits used later for the validation. For example, you can define for each attribute if it is required, its length, its pattern, ...
Services is maybe more symfony dependent. Comparing with Grails, Services are the components where you put your business code. In Java EE, it is the Beans. Note that a service can become a web service but it is not mandatory. A Service can also be called by the Controller in order to do some calculation before rendering the view.
I hope that my answer can help.
I want to create a blogging system in order to practice symfony2,
but currently I get a bit confused when creating entities such as user or blog.
The reason is the following :
User( or Blog) is commonly used in frontend and backend(admin)
(currently I have considered creating FrontendBundle and AdminBundle)
Entity must belong to one bundle.
Currently I have considered the following methods, but what is the best way
in this case, or please tell me if there is another way.
Create bundle named 'BlogCommonBundle' and define User entity as "BlogCommonBundle:User".
Define all controllers under 1 bundle, such as 'BlogBundle', so
frontend/backend(admin) controllers belong to same bundle.
I think creating a BlogBundle and having multiple controllers for frontend and admin functionality is a good way to handle this. Both controllers would make use of the same entities and repositories, and you can easily firewall your admin actions in the security settings of your application. By keeping everything blog related to one bundle, you maintain good code organization.
The same goes for a UserBundle. It's helpful to remind yourself that a bundle should represent a set of like functionality for an application. So if you have code that fetches blog posts, and allows you to create and manage them, they naturally group together in a single bundle.
I asked a similar question here:
How to share a Symfony2 model with several projects
I went with the 'ModelBundle' approach that contains all the entities, forms, repositories, etc. These are all shared with the FrontendBundle and BackendBundle.
So far I'm very happy with this solution.