I'm building an application in symfony2 just to better understand how it works. My problem is I'm undecided on where to put some classes, for example:
I have a category entity and a category repository, and a controller to manage categories where I query the repos (how explained in the cookbook) using
$category = $this->getDoctrine()->getRepository()
now I'm working on a blog controller, I want to display a form (for example in edit mode), so I have to query the blog repos, but I also need to query again the category repos to permit to choose a category.
I don't think it could be a good idea to query 2 different repos in the controller, can anyone suggest me how to organize this classes just to avoid to instantiate all the repository in all the actions I need them?
any other useful suggestion on how to organize the code?
thanks
There is nothing wrong with calling methods of 2 (or more) repositories in a single controller.
But in the scenario you describe the Form Component will take case of querying for categories to choose from. I suggest you dive a litter deeper in that documentation. Hint: the Entity Field Type .
Some advice
You probably know what "spaghetti code" is, but there's also something called "lasagna code" which is the opposite: you get pillars of classes that don't really work together.
You could have a pillar for users (UserEntity, UserRepository, UserService and UserController) and another for blog-posts (BlogPostEntity, BlogPostRepository, BlogPostService and BlogPostController), etc...
This is also something you rather not create, so a good mix between spaghetti and lasagna would be advisable ;)
Try to have services represent your business needs / the business world (or Domain). Controllers are nothing more than connectors between clients (browsers, etc) and your services. And repositories are just technical details (not your points of focus).
PS: Little correction
You should change this:
$category = $this->getDoctrine()->getRepository();
to this:
$categoryRepository = $this->getDoctrine()->getRepository('Category');
It will be less confusing for you in the long run. Example:
$categoryRepository = $this->getDoctrine()->getRepository('Category');
$category = $categoryRepository->find(123);
Related
I'm developing an application in Symfony and am yet to setup some data fixtures - I think it'd about time I got round to doing it so setting up a fresh dev copy is faster. :-)
Using my example below, how would I handle setting the 'category' property on my blog to a category? Assuming a ManyToOne relationship with a category entity.
$blog1 = new Blog();
$blog1->setTitle('A day with Symfony2');
$blog1->setImage('beach.jpg');
$blog1->setAuthor('dsyph3r');
$manager->persist($blog1);
I've gathered from the Symblog tutorial that I include AbstractFixture and the Category entity in my file, but surely the category needs to be created before the blog for this to work? How can I ensure that happens when running my fixtures command?
What is the best way to approach this?
You need to share objects between ordered fixtures — make the categories fixture run before the posts fixture.
I'm using Symfony2 with Doctrine2. I want to achieve the following:
$place = $this->getDoctrine()->getRepository('TETestBundle:Place')->find($id);
And on that place will be the info of the place (common data + texts) on the user language (in session). As I am going to do that hundreds of times, I want to pass it behind the scenes, not as a second parameter. So an English user will view the place info in English and a Spanish user in Spanish.
One possibility is to access the locale of the app from an EntityRepository. I know it's done with services and DI but I can't figure it out!
// PlaceRepository
class PlaceRepository extends EntityRepository
{
public function find($id)
{
// get locale somehow
$locale = $this->get('session')->getLocale();
// do a query with the locale in session
return $this->_em->createQuery(...);
}
}
How would you do it? Could you explain with a bit of detail the steps and new classes I have to create & extend? I plan on releasing this Translation Bundle once it's ready :)
Thanks!
I don't believe that Doctrine is a good approach for accessing session data. There's just too much overhead in the ORM to just pull session data.
Check out the Symfony 2 Cookbook for configuration of PDO-backed sessions.
Rather than setting up a service, I'd consider an approach that used a Doctrine event listener. Just before each lookup, the listener would pick out the correct locale from somewhere (session, config, or any other place you like in the future), inject it into the query, and like magic, your model doesn't have to know those details. Keeps your model's scope clean.
You don't want your model or Repository crossing over into the sessions directly. What if you decide in the future that you want a command-line tool with that Repository? With all that session cruft in there, you'll have a mess.
Doctrine event listeners are magically delicious. They take some experimentation, but they wind up being a very configurable, out-of-the-way solution to this kind of query manipulation.
UPDATE: It looks like what you'd benefit from most is the Doctrine Translatable Extension. It has done all the work for you in terms of registering listeners, providing hooks for how to pass in the appropriate locale (from wherever you're keeping it), and so on. I've used the Gedmo extensions myself (though not this particular one), and have found them all to be of high quality.
After "finish" studying Symfony2, I start to take a look to Sonata Admin and User bundles since, those bundles, could help me in some future works.
On the firsts, all seems to me terribly complicated and difficult to understd. But with few hours of architecture study, applied to real files,classes and so on, I suppose that I've understood perfectly what's the essence of that bundle and how this works.
My only "black hole" into whole thing understand is, where can I find the parameter used into sonata.user.admin.user, called sonata.user.admin.user.entity? As far I know, that parameter simply point to user class that is responsable for read/write operation from and to database.
I ask this because, after dozens of minutes spent looking, the only place where I found those information are
./app/cache/prod/appProdProjectContainer.php
./app/cache/dev/appDevDebugProjectContainer.xml
./app/cache/dev/appDevDebugProjectContainer.php
Is possible that this variable is defined only there?
If yes, because is placed into cache folder? Is loading time faster?
You should also look through Extensions in DependencyInjection folders - sometimes arguments are defined in yaml in one way, but after loading with concatenation they are transformed into another:
If in your parameters you have something like:
your_user: 'Somename'
And in DependencyInjection it is parsed as follows:
foreach($config as $key => $value) {
$container->setParameter('your.prepend.'.$key, $value);
}
Then in the end you'll have your parameter compiled with index your.prepend.your_user.
I guess, the same logic is used in mentioned bundles.
UPDATE:
Example of usage of described logic
I have been reading about "Fat Controllers" but most of the articles out there focus on pulling the service/repository layer logic out of the controller. However, I have run into a different situation and am wondering if anyone has any ideas for improvement.
I have a controller with too many actions and am wondering how I can break this down into many controllers with fewer actions. All these actions are responsible for inserting/updating/removing objects that all belong to the same aggregate. So I'm not quiet keen in having a seperate controller for each class that belongs to this aggregate...
To give you more details, this controller is used in a tabbed page. Each tab represents a portion of the data for editing and all the domain model objects used here belong to the same aggregate.
Any advice?
Cheers,
Mosh
For all your tabs you can use one action, that have an tab parameter, that indicate what data you need to return.
The controller job is to cast this string tab into enum type variable. Then the tab will be send to the repository, and the repository job is to return data in response to the tab value.
The controller should do its job through to services: Input Validator and Mapper.
The mapper service job is to map the user input (typically strings) into actual typed value (int, System.DateTime, enum types, etc).
The validator job is to check that the input is valid.
Following this principles should keep your controllers really tiny.
If you wanted something simple and easy I'd suggest just splitting up the controller into partial classes based on the tabs. Of course, it's still a fat controller there's just some obvious separation between the various tab functionalities.
How would you tackle this problem:
I have data in my data store. Each item has information about:
URL = an arbitrary number of first route segments that will be used with requests
some item type = display will be related to this type (read on)
title = used for example in navigation around my application
etc.
Since each item can have an arbitrary number of segments, I created a custom route, that allows me to handle these kind of requests without using the default route and having a single greedy route parameter.
Item type will actually define in what way should content of a particular item be displayed to the client. I was thinking of creating just as many controllers to not have too much code in a single controller action.
So how would you do this in ASP.NET MVC or what would you suggest would be the most feasible way of doing this?
Edit: A few more details
My items are stored in a database. Since they can have very different types (not inheritable) I thought of creating just as many controllers. But questions arise:
How should I create these controllers on each request since they are related to some dynamic data? I could create my own Controller factory or Route handler or possibly some other extension points as well, but which one would be best?
I want to use MVC basic functionality of using things like Html.ActionLink(action, controller, linkText) or make my own extension like Html.ActionLink(itemType, linkText) to make it even more flexible, so Action link should create correct routes based on Route data (because that's what's going on in the background - it goes through routes top down and see which one returns a resulting URL).
I was thinking of having a configuration of relation between itemType and route values (controller, action, defaults). Defaults setting may be tricky since defaults should be deserialized from a configuration string into an object (that may as well be complex). So I thought of maybe even having a configurable relation between itemType and class type that implements a certain interface like written in the example below.
My routes can be changed (or some new ones added) in the data store. But new types should not be added. Configuration would provide these scenarios, because they would link types with route defaults.
Example:
Interface definition:
public interface IRouteDefaults
{
object GetRouteDefaults();
}
Interface implementation example:
public class DefaultType : IRouteDefaults
{
public object GetRouteDefaults()
{
return new {
controller = "Default",
action = "Show",
itemComplex = new Person {
Name = "John Doe",
IsAdmin = true
}
}
}
Configuration example:
<customRoutes>
<route name="Cars" type="TypeEnum.Car" defaults="MyApp.Routing.Defaults.Car, MyApp.Routing" />
<route name="Fruits" type="TypeEnum.Fruit" defaults="MyApp.Routing.Defaults.Fruit, MyApp.Routing" />
<route name="Shoes" type="TypeEnum.Shoe" defaults="MyApp.Routing.Defaults.Shoe, MyApp.Routing" />
...
<route name="Others" type="TypeEnum.Other" defaults="MyApp.Routing.Defaults.DefaultType, MyApp.Routing" />
</customRoutes>
To address performance hit I can cache my items and work with in-memory data and avoid accessing the database on each request. These items tend to not change too often. I could cache them for like 60 minutes without degrading application experience.
There is no significant performance issue if you define a complex routing dictionary, or just have one generic routing entry and handle all the cases yourself. Code is code
Even if your data types are not inheritable, most likely you have common display patterns. e.g.
List of titles and summary text
item display, with title, image, description
etc
If you can breakdown your site into a finite number of display patterns, then you only need to make those finite controllers and views
You them provide a services layer which is selected by the routing parameter than uses a data transfer object (DTO) pattern to take the case data and move it into the standard data structure for the view
The general concept you mention is not at all uncommon and there are a few things to consider:
The moment I hear about URL routing taking a dependency on data coming from a database, the first thing I think about is performance. One way to alleviate potentialy performance concerns is to use the built in Route class and have a very generic pattern, such as "somethingStatic/{*everythingElse}". This way if the URL doesn't start with "somethingStatic" it will immediately fail to match and routing will continue to the next route. Then you'll get all the interesting data as the catch-all "everythingElse" parameter.
You can then associate this route with a custom route handler that derives from MvcRouteHandler and overrides GetHttpHandler to go to the database, make sense of the "everythingElse" value, and perhaps dynamically determine which controller and action should be used to handle this request. You can get/set the routing values by accessing requestContext.RouteData.Values.
Whether to use one controller and one action or many of one or many of each is a discussion unto itself. The question boils down to how many different types of data do you have? Are they mostly similar (they're all books, but some are hardcover and some are softcover)? Completely different (some are cars, some are books, and some are houses)? The answer to this should be the same answer you'd have if this were a computer programming class and you had to decide from an OOP perspective whether they all have a base class and their own derives types, or whether they could be easily represented by one common type. If they're all different types then I'd recommend different controllers - especially if each requires a distinct set of actions. For example, for a house you might want to see an inspection report. But for a book you might want to preview the first five pages and read a book review. These items have nothing in common: The actions for one would never be used for the other.
The problem described in #3 can also occur in reverse, though: What if you have 1,000 different object types? Do you want 1,000 different controllers? Without having any more information, I'd say for this scenario 1,000 controllers is a bit too much.
Hopefully these thoughts help guide you to the right solution. If you can provide more information about some of the specific scenarios you have (such as what kind of objects these are and what actions can apply to them) then the answer can be refined as well.