I have started a new laravel website project and I have hit a road block in my understanding of MVC. I need to refactor to continue but I don't know the best way.
Currently I have web pages that display the results of a single bit of logic. I.e. A page listing all users, a page listing the details of just one user etc etc - all handled by a userController. This applies to other pages being handled by other controllers.
I have created models directly relating to the tables in my database, and controllers in relation on the models. I moved the business logic from the controllers to services. The controllers use the services to perform the business logic and with the data returned, pass that data to the views.
This nicely groups similar functionality together and works fine.
userTable -> userModel -> userController -> userService
clientTable -> clientModel -> clientController -> clientService
...
In my routes, I have pages which do related functionality use the same respective controller, but individual methods depending on what the page does
/listallusers -> userController#list -> userList.blade.php
/listallclients -> clientContoller#list -> clientList.blade.php
/listdetailofoneclient -> clientContoller#details -> clientDetails.blade.php
This is ok when dealing with pages that do that functionality and (apart from using services) seems to be what is hinted at in the laravel docs.
However, I'm starting to get confused about controllers when dealing with pages that either don't really use functionality from any of the services or pages that heavily require functionality from multiple services (and the data needs complex manipulation like formatting or such).
A basic index page.
What controller would handle this? The index might link to routes that are handled by existing controllers but it probably won't need to display much functionality apart from that. That means the controller won't need to pass much complex -if any- data to the view. You could stick the logic to return the view in the route file but that is pretty tightly coupled.
A page that shows complex client and user data
You need to pass client data and user data to the view from the controller. But from what controller? This is the part that is really holding me back.
Because I have a limited number of pages but lots of logic displaying on each page, I was thinking of making a page controller (or something) which would handle the routing. Although I have looked, I have not seen any real mention of this idea anywhere which makes me think I am either reinventing the wheel or have failed to grasp some basic concept in laravel / MVC.
Would the page controller in this case handle all the routing? Would it handle only the pages with 'overlapping' existing controller functionality and the pages that don't fall into the existing controllers? Is a page controller even a good idea?
Some more points that have made me question MVC from this issue
Do controllers need an equivalent model?
Can controllers 'control' other controllers in order to separate logic?
I'll take a shot at a couple of these questions.
Having a PageController or HomeController is very acceptable. Controllers don't have to be linked to a specific model, for instance an AuthController would handle logic for logging in and out but isn't tied to a model, or PasswordController which handles setting/resetting passwords, or a PaymentController that handles billing routes. A controller is just a way to organize logic for related routes in one file. Static basic pages are related routes so a PageController makes sense to me.
Are users tied to a specific client? If so you can arrange your controllers in a nested way so you have a ClientController and a UserController and your routes look something like this:
/clients/{client}/users //list all users for this client
For heavy data formatting it's probably best to use a service provider and use dependency injection to inject it into controllers where you need to use it. This allows you to detach your data manipulation from your controller so you could change it out if needed. Say you are using a software to make charts, and you want to change it out later - you want that formatting logic to be removed from your controller.
I hope I helped in some way... sort of a train of thought here!
Related
I'm using CakePHP 2.2.3 and I need to build an admin/dashboard area for my site.
I have many models and controllers related to this models and in the dashboard I need to have the ability to CRUD all posts/users/news etc.
Obviously I need to build a Dashboard controller with some index action which will be show dashboard "home" page.
My question is: where to put all other actions – for posts/users/other things adding/editing ?
Should I put all this actions in this new dashboard controller or it's better to put this actions to related controllers(Posts/Users..)?
Keep your specific actions in each of their own controllers. A DashbaordsController is fine for whatever pages need to display a lot of different model information, but CRUD actions should be kept in their own Controller.
If you want/need a single page to be able to actually do the CRUD actions ON that page, you can use ajax and STILL call the actions of that specific Controller.
Bottom line, if you try to put all your CRUD into a single Controller, it's just going to get messy, and will be very confusing for future programmers (which includes yourself 6 mo from now).
It's so easy to include data from other Models $this->loadModel('MyModel');, that doing CRUD actions in their own respective Controller is not much of a hindrance. Again - the DashboardsController is still fine for those few pages that really are like dashboards, and have no alliance toward a specific model. But not for each model's CRUD.
Generally the ideal way is to do skinny controllers and keep logic as far down the stack as possible that is near to the models. Ideally you'd want to introduce libraries for code reuse and testing. Robert Martin aka Uncle Bob says that the web delivery and databases should be as much of a plugin as possible. This lets you unit test much better. As far as your particular case i'd want to keep it close to REST as i can so separate controllers ideally delegating to some lower level stuff.
Cake's documentation says "Most commonly, controllers are used to manage the logic for a single model." I'm finding this is uncommon for most of my code, and I don't want to break convention unless it is proper to do so.
For example, my application sends a user to their account dashboard after they log in - this uses data from probably half a dozen tables, not all of which are even related. Do I create a "dashboard" controller for this (even though there is no dashboard model or table)? Or do I create a dashboard method in an existing controller?
Thanks, Brian
I have a similar situation and how I handle it is keeping the actions that connect a lot of models in the controller that is the most centric. For instance, my user can create voicenotes, comments, has settings, has twitter and facebook information. All this information I can get from my user model $this->User->Voicenotes->find('all'), for example.
I believe creating additional controllers might just confuse you, use what cake gives you, you can specify that models are to be used in a controller either by setting the $uses variable or using loadModel in the controller action, if you have your relations set up you can just do it the way i described before, no need to create additional controllers.
I guess it depends on how you want your own app to work and what comes easier in your situation.
I use php and usually structure my application into model-view-controller so its always accessed via index.php with class and method attributes. Class attribute passed as part of URL specifies controller class and method simply method to be called. This seems to be pretty common, but then I'm always having trouble in figuring out what controllers shall I create. What is the best, easiest and most applicable way to decide on what controllers should be created? I understand it depends on web application itself but must be some general way of thinking to get this process started.
I've found that building controllers based on your application's objects works well, and can take care of most actions you'll want for your app.
Take a look at SO -- there's URLs starting with /questions, /tags, /users, etc. I'd suggest a design which starts by creating a different controller for each object. /questions (or /questions/list) returns a list of all the questions. /questions/[0-9]+ returns the details of a particular question with that id number. /questions/ask returns the Ask Question interface.
As you continue building your app, you might find that the controller-based-on-objects method doesn't meet all your needs. For example, on my site (http://www.wysiap.com), I eventually made a /list controller to simplify my Grails URL mapping. But in most cases I did use this method and it's easy to figure out which controller should be doing different actions.
I recommend to think about the pages you'll need in your applications to accomplish all the requested tasks. You'll group similar tasks on the same page and create as many pages as you need. A page can be sliced in different views for specific actions.
With this in mind you could have one controller per page. Each view of the page can have its own method (action) in the controller. And inside the method of each view you can have a switch() that will enable you to have several tasks for the view. Example:
index.php (Dashboard controller)
/question-list (QuestionList controller, action index, display the whole page)
/question-list/add (QuestionList controller, action add, manage the "add" view with tasks like show-form, validate-form, insert-question)
/profile (Profile controller, action index)
/profile/edit (Profile controller, action edit, manage all the tasks requested for your profile)
...
I design most of my web applications this way and using Zend-Framework
I'm thinking of re-working my MVC before I get to far along with it. At the moment it uses a sinle controller which takes the user input and determines the model. The model has maby differ methods which I call actions, because one is called automatically. The model loads its view file, which again holds many different methods. The model can set properties which can be used in the view. Then the controller calls th template classwhich parses the output for display.
Is this the bst way to do it?
Or should each different part (news, contact, about) have its own controller, which loads a specific model and view. Essentially, instead of grouping methods into a single file, it uses multipe files.
I'm kind of lost as to how I should do it.
Cheers
Start using a MVC that works and is well-known like in Symfony or Cake. From that you will decide:
what do to in your own, knowing the best practices;
to drop your own if you feel like you can save time by using theses.
If you are thinking of advancing your own MVC model, like #e-satis have said, you will need to experience what is happening in already developed systems. However, as based on my experience in designing MVC model and determining what is there in opensource community, I stick back to my own MVC for two good reasons. One reason is the flexibility of customization and the other is own MVC privacy.
I used the following approach for MVC design pattern.
A Router.php file identifying user-request urls. This router will be able to fetch controllers and include the file and call the controller default method.
The loaded controller is also able to load other controllers if required to function. This is done using a global method, where all controller Class will extend to a MainController Class which is able to call to other controllers.
I do use a global registry to set and get variables from one controller to the other.
The Models are used to get the Data from Table, and most of my Models will represent Database functions which includes CRUD (Create Read Update Delete). So that a controller can easily manipulate database table data using a model.
Naming conventions in all controller, models, and views is also important, if you want to system to be more intelligent to identify the required action knowing the file name.
I use the Views separately for each type of controller. And these views will be sent to a Master Template View file.
Same as models, the controller will be able to set Views to Master View.
There are other customizations which you can do, like applying security methods before calling a class, or after calling a class/controller/model/view etc.
This is done by the MainController, which it will always look into a folder with autoload class which states what files should be loaded before and after of different actions during the process of building the content and delivering the output.
MVC is not a small scale idea, but it is a design idea which can always be developed. There are so many PHP MVC open source frameworks to be found if you know how to search the major search engines like google.com
But I do advice you that, MVC is not a good solution if you are simply developing a small dynamic website, as it will consume more time in developing compared to developing small websites. MVC is ideal, if you have business logic and needs system automation in order to avoid most routine tasks of developing, and like that I would say MVC is most ideal for larger applications.
The model loads its view file
The Controller should act as a Mediator between the Model and the View.
The Model shouldn't be aware of the way the view renders it, and also the View shouldn't be aware of any kind of logic of the Model.
In theory, if your MVC is well structured, you should be able to represent the same Model with different types of Views (HTML, XML, JSON for example).
Build FrontController which parses request uri and decides which controller to load and which method to run. With .htaccess rewrite all request to index.php
//index.php
class FrontController{
function run(){
//parse request uri here /comment/new
//load controller comment
//run controllers method new and pass some request attributes
}
}
// ../controllers/comment.php
class Controller_Comment extends Controller{
function new($request){
//do stuff here
}
}
1) Where does the homepage of your website fit into "controllers"? I've seen some people use a "page" controller to handle static pages like, about, home, contact, etc., but to me this doesn't seem like a good idea. Would creating a distinct controller just for your homepage be a better option? After all, it may need to access multiple models and doesn't really flow well with the whole, one controller per model theory that some people use.
2) If you need a dashboard for multiple types of users, would that be one dashboard controller that would have toggle code dependent upon which user, or would you have say a dashboard action within each controller per user? For example, admin/dashboard, account/dashboard, etc.
3) It seems to me that using the whole simple CRUD example works like a charm when trying to explain controllers, but that once you get past those simple functions, it breaks down and can cause your controllers to get unwieldy. Why do some people choose to create a login controller, when others make a login function in a user controller? One reason I think is that a lot of us come from a page approach background and it's hard to think of controllers as "objects" or "nouns" because pages don't always work that way. Case in point why on earth would you want to create a "pages" controller that would handle pages that really have nothing to do with each other just to have a "container" to fit actions into. Just doesn't seem right to me.
4) Should controllers have more to do with a use case than an "object" that actions can be performed on? For all intensive purposes, you could create a user controller that does every action in your whole app. Or you could create a controller per "area of concern" as some like to say. Or you could create one controller per view if you wanted. There is so much leeway that it makes it tough to figure out a consistent method to use.
Controllers shouldn't be this confusing probably, but for some reason they baffle the hell out of me. Any helpful comments would be greatly appreciated.
1) I use a simple homebrew set of classes for some of my MVC stuff, and it relates controller names to action and view names (it's a Front Controller style, similar to Zend). For a generic web site, let's assume it has a home page, privacy policy, contact page and an about page. I don't really want to make separate controllers for all these things, so I'll stick them inside my IndexController, with function names like actionIndex(), actionPrivacy(), actionContact(), and actionAbout().
To go along with that, inside my Views directory I have a directory of templates associated with each action. By default, any action automatically looks for an associated template, although you can specify one if you wish. So actionPrivacy() would look for a template file at index/privacy.php, actionContact() would look for index/contact.php, etc.
Of course, this relates to the URLs as well. So a url hit to http://www.example.com/index/about would run actionAbout(), which would load the About page template. Since the about page is completely static content, my actionAbout() does absolutely nothing, other than provide a public action for the Front Controller to see and run.
So to answer the core of your question, I do put multiple "pages" into a single controller, and it works fine for my purposes. One model per controller is a theory I don't think I'd try to follow when working with Web MVC, as it seems to fit an application with state much better.
2) For this, I would have multiple controllers. Following the same methods I use above, I would have /admin/dashboard and /account/dashboard as you suggest, although there's no reason they couldn't use the same (or portions of the same) templates.
I suppose if I had a gazillion different kinds of users, I'd make things more generic and only use one controller, and have a mod_rewrite rule to handle the loading. It would probably depend on how functionally complex the dashboard is, and what the account set up is like.
3) I find CRUD functionality difficult to implement directly into any layer of MVC and still have it be clean, flexible and efficient. I like to abstract CRUD functionality out into a service layer that any object may call upon, and have a base object class from which I can extend any objects needing CRUD.
I would suggest utilizing some of the PHP ORM frameworks out there for CRUD. They can do away with a lot of the hassle of getting a nice implementation.
In terms of login controller versus user controller, I suppose it depends on your application domain. With my style of programming, I would tend to think of "logging in" as a simple operation within the domain of a User model, and thusly have a single operation for it inside a user controller. To be more precise, I would have the UserController instantiate a user model and call a login routine on the model. I can't tell you that this is the proper way, because I couldn't say for sure what the proper way is supposed to be. It's a matter of context.
4) You're right about the leeway. You could easily create a controller that handled everything your app/site wanted to do. However, I think you'd agree that this would become a maintenance nightmare. I still get the jibbly-jibblies thinking about my last job at a market research company, where the internal PHP app was done by an overseas team with what I can only assume was little-to-no training. We're talking 10,000 line scripts that handled the whole site. It was impossible to maintain.
So, I'd suggest you break your app/site down into business domain areas, and create controllers based on that. Figure out the core concepts of your app and go from there.
Example
Let's say I had a web site about manatees, because obviously manatees rock. I'd want some normal site pages (about, contact, etc.), user account management, a forum, a picture gallery, and maybe a research document material area (with the latest science about manatees). Pretty simple, and a lot of it would be static, but you can start to see the breakdown.
IndexController - handles about page, privacy policy, generic static content.
UserController - handles account creation, logging in/out, preferences
PictureController - display pictures, handle uploads
ForumController - probably not much, I'd try to integrate an external forum, which would mean I wouldn't need much functionality here.
LibraryController - show lists of recent news and research
HugAManateeController - virtual manatee hugging in real-time over HTTP
That probably gives you at least a basic separation. If you find a controller becoming extremely large, it's probably time to break down the business domain into separate controllers.
It will be different for every project, so a little planning goes a long way towards what kind of architectural structure you'll have.
Web MVC can get very subjective, as it is quite different from a MVC model where your application has state. I try to keep major functionality out of Controllers when dealing with web apps. I like them to instantiate a few objects or models, run a couple of methods based on the action being taken, and collect some View data to pass off to the View once it's done. The simpler the better, and I put the core business logic into the models, which are supposed to be representative of the state of the application.
Hope that helps.