I'm developing several web sites in Kohana using its template system so that one code base is running several web sites using the same back end DB. I'm starting to see a lot of if statements in the views to say if this site do this, if that site do that. It starting to look very non-MVC or Object Oriented. Do other developers have any rules they follow when deciding to breakout view into separate partial views? I want to reuse as much of the code as possible but not swim in if statement in every view. Any reference would be great also.
If you are using Kohana, you should use modules for stuff you don't want to duplicate for every application. Then you can keep specifics in your application with extended classes or specific settings in config files.
http://kohanaframework.org/3.2/guide/kohana/modules
A lot of if statements are mostly an indication that you need to do refactoring. A large cascading if statement to allow for different sites to be loaded is bad practice in the sense that you make files tightly coupled causing to edit multiple files when you need to make a simple addition or change. Furthermore, it will eventually become ugly if every site needs to load different dependencies or settings or whatever in your if statement.
It's difficult to say what you need to change without seeing the code, but try looking at design patterns like the factory or abstract factory design patterns to create site objects.
A good book that deals with the subject of patterns and best practices with PHP is PHP 5: Objects, Patterns and Practice by Matt Zandstra: http://www.amazon.com/PHP-5-Objects-Patterns-Practice/dp/1590593804. A very good book.
I had a similar issue cropping up with this, to keep the views nice and neat I extended the view class into a theme class. I would give the factory method two (or more) views ie Theme::factory(array('site1/home','default/home'),$data)->bind(...); If a themed view existed it would use that, else just serve up the default. That way I, or someone else less competent could easily override to display structure and view behaviour.
The class looks like this
class Theme extends View {
public static function factory($pages = NULL, array $data = NULL){
if (is_string($pages)) {
$pages=array($pages);
}
if (!is_array($pages)) {
$pages=array(0=>null);
}
foreach ($pages as $page){
if ((Kohana::find_file('views', 'themes/'.$page)) !== FALSE){
return new View('themes/'.$page,$data);
}
}
throw new Kohana_View_Exception("None of the requested views ':file' could not be found.", array(
':file' => join($pages,"' or '"),
));
}
}
You really want ViewModels, only you don't know how to name them yet. Little birds have been tweeting that it'll be in Kohana 3.3 but unless you have a year or so to wait, I recommend trying either View-Model module by Zombor or moving away from Kohana's templating system whatsoever in favour of KOstache (it's Mustache for Kohana)
If for any reason you want to stick with your current codebase, I'd go with splitting the view into several smaller interchangable parts and loading them when necessary (echo View::Factory(($something == 'one' ? 'view_one' : 'view_two')) or a custom written helper would be a nice toy here)
Related
I'm developing a PHP MVC REST API which will have OAuth for authenticating if the call can be performed.
So my plan is to develop it for an Angular 2/4 app which will handle the API calls.
The idea was to create a structure where my domain for example test.com will have a subdomain api.test.com.And from it the API calls will be requested.
The thing that i would like to confirm before i start building this is my MVC backend structure.
Ref.Pic
Model will have all the logic
View will be the api.test.com/api/call presentation.Outputing the JSON in my case.
Controller will accept input exmp:the api.test.com/api/call call the logic in the Model if the call is correct.Than the call will react on the view where presenting the JSON.It would hold the OAuth also....
I'm trying to understand the whole concept of this, since i have tried several times to build it and every time i end up in a mess of code.I'd like to see if my understanding of the project above makes sense.
Thank you
There are multiple issues, that you will encounter as you try to apply SoC principle in your codebase.
And, what to do with communication between views and controllers, is one of the more visible ones. That's because, if you mess it up, there are no abstractions to hide it all behind.
The two major approaches are Supervising Controller and Autonomous View (which has no article, but you can deduce some of it from this and this).
Supervising controller
This approach is best suited for smaller applications (well .. for large values of "small", since really small projects don't really need the architectural bloat of MVC). It essentially looks like this:
/* in a controller */
public function verifyEmail(Request $request)
{
$identity = $this->search->findEmailIdentityByToken(
$request->get('token'),
Identity::ACTION_VERIFY
);
$this->registration->verifyEmailIdentity($identity);
$body = [
'status' => 'ok',
];
return new JsonResponse($body);
}
Essentially, what you have there is a controller, that interacts with the business model and (when necessary) populates the view with data. Then it causes the view to be rendered and returns the response.
In my own experience, I have found this to be the best approach to use, when writing backend applications, that are expected to only be manipulated via REST-like API.
As you see in the example, the "view" in this case is extremely trivial. It is basically array, that you render as JSON (which the provided code would actually do - it's copied from a real project).
Note:
If your intention is to fully implement REST as it was proposed (not just the REST-like resource endpoints) and/or
have functionality of resource expansion, then this approach might be wrong and even harmful.
Autonomous View
When your presentation logic becomes complicated or have to provide different UIs for the same application with the same functionality (like having single app with both website and REST API, with both xml an json interface), then using Supervising Controller becomes a ball and chain around your neck. Your controllers start to grow uncontrollably and your project can be described as "legacy codebase", before it even reaches production.
And that's where you use this approach.
You use views and controllers as completely separate classes and you interact of their instances at the same layer (for example: bootstrap stage). It ends up looking something like this:
/* in /src/application.bootstrap.php */
$command = $request->getMethod() . $parameters['action'];
$resource = $parameters['resource'];
$controller = $container->get("controllers.$resource");
if (method_exists($controller, $command)) {
$controller->{$command}($request);
}
$view = $container->get("views.$resource");
if (method_exists($view, $command)) {
$response = $view->{$command}($request);
$response->send();
}
Again, example from a different live project, which also uses a DI container. In this case there is only one UI (hence, no "type" prefix, when making a view instance), which mean that the code can take advantage of 1:1 relation between controllers views (it would be 1:n, if you need multiple UIs).
The controller in this case basically only "writes" to the model layer. And the view (which also has access to services from model layer) only performs "reads" and extracts only the information, that it requires for populating templates and rendering them.
And, if your presentation logic grows further, it is a good idea to start adding presentation objects, that will contain the repeating parts of the presentation logic (e.g. deciding, which menu item in the sidebar has to be expanded and which submenu item has to be highlighted), that are common for multiple views.
If your backend application only deals with API, then this approach might be too complex, unless you are doing one of the things mentioned in the "note" part.
... maybe this helps a bit
Yes, That makes sense. I suggest using the Laravel framework instead. Or the OctoberCMS even better.
As a mostly self-taught programmer I'm late to the game when it comes to design patterns and such. I'm writing a labor management webapp using CodeIgniter.
I did a bit of MVC ASP.NET/C# and Java at school, and the convention was that your model mainly consisted of classes that represented actual objects, but also abstracted all the database connection and such...which is pretty standard MVC stuff from what I've gathered.
I imagine I'm right in saying that CI abstracts the database connection completely out of sight (unless you go looking), which is par for the course, and the models you can create can abstract the 'generic' CRUD methods a bit more to create some methods that are more useful for the specific model.
The thing I have a problem with, because it's different to what I'm used to with MVC, is that whenever you say...return a row from a database, the convention is to just put it in an associative array or standard object with the properties representing the data from the row.
In ASP you'd have actual classes that you could construct to store this information. For example you'd have a House class and the data would be stored as properties (e.g. bedrooms, bathrooms, address) and the methods would represent useful things you could do with the data (e.g. printInfo() may print("$address has $bedrooms bedrooms and $bathrooms bathrooms!')).
I'm getting the impression — just from code I've seen around the Internet — that this isn't the standard way of doing things. Are you supposed to just use arrays or generic objects, and say...do $this->house_model->print_info($houseobject) instead of $houseobject->print_info();?
Thanks.
Despite its claims to the contrary, Codeigniter does not use MVC at all (In fact, very few web frameworks do!) it actually uses a PAC (Presentation-abstraction-control) architecture. Essentially, in PAC the presentation layer is fed data by a presenter (which CodeIgniter calls a controller) and in MVC the View gets its own data from the model. The confusion exists because of this mislabeling of MVC.
As such, CodeIgniter (and most of the other popular web frameworks) don't encourage a proper model but just use very rudimentary data access its place. This causes a large set of problems because of "fat controllers". None of the code which relates to the domain becomes reusable.
Further reading:
MVC vs. PAC
The M in MVC: Why Models are Misunderstood and Unappreciated
Model-View-Confusion part 1: The View gets its own data from the Model
The Fat Controller
This is a widespread point of confusion in the PHP Community (The MVC vs. PAC article identifies the problem as stemming from the PHP community. that was written in 2006 and nothing has changed, if anything it's got worse because there are more frameworks and tutorials teaching an erroneous definition of MVC.) and why people looking at "MVC" PHP code who have come from a background outside web development understandably become confused. Most "MVC" implementations in PHP are not MVC. You are correct in thinking models should be properly structured, it's CodeIgniter that's wrong to label itself as MVC.
CodeIgniter is very flexible when it comes to following the MVC pattern and it's really up to you how much you want to enforce it. Most of the CodeIgniter code you will find online is exactly like you describe, the Models are just a collection of methods really, and don't strive to strictly represent an object.
You can, however, code that way too if you so like within CI (and this is something I often do). It makes the code much more maintainable and readable, and just seems better all around.
PS - If you're just getting into MVC in PHP, you might want to look around a little. Frameworks like CodeIgniter and CakePHP are (somewhat) of a previous generation. CI was initially written for PHP4 where OOP support was kinda spotty in PHP. A fork of CI, called Fuel, was specifically created to address this issue (though I believe at some point, they just decided they would be better served by rewriting it from scratch). CI does have the advantage of having a lot of documentation and help online since it is more widely used than Fuel.
controller
// get the houses result from the model
// return it as an object
if( ! $houses = $this->house_model->findHouses($search) )
{ // if no results - call a no results view
$this->load->view( 'no_results', $data );
}
else
{
// pass the houses object to data so it automatically goes to view
data['houses'] = $houses ;
// Call your view
$this->load->view( 'house_results', $data );
}
view
// we already know we have at least one house,
// thats what the controller is for, so we dont need to do an isset() etc for $houses
foreach $houses as $house :
echo 'This fine house at ' . $house->address . 'has '. $house->bedrooms . ' bedrooms and ' $house->bathrooms . ' bathrooms' ;
endforeach ;
obviously there are different ways to create that final sentence in the view, but the idea is that by the time we get to the view - its as simple as possible.
so for complex queries like Show me all the houses next to the good schools, with 2 bedrooms and room for my pet Ocelot.
Thats what happens in the model. all of the messy conditions and business rules. views should be specific - if you dont have results - then just show a no results view. Versus -- doing a results check in the view, and then changing the display based on no results. the more specific you make the view, the easier it will be to build out, and it will encourage you to make the choices in the controller and model.
I started making a website, and quickly i found out that my code is a mess. It's been a while since I've been programming in PHP, and since then I learned OOP. Now while making an application in C# or java is pretty easy from this point of view, PHP is giving me trouble.
I used to program everything (in php) just from one line to another, with minimum amount of methods and no classes at all. So how much should be in methods, and where should this classes be?
Example:
I have account.php, and i want to update user information. So after checking that someone has sent some data if(isset($_POST[.. what next? I used to just make
all the checks like $email=CheckForRisksOrSomething($_POST["email]); and then just update mysql.
This brings me to the question, should I create a class User and what methods should it contain? Also WHERE should this class be saved, assuming that user.php would show you user's profile.
Back to how much should be in classes, should i just use in a file like:
$smth = new Someclass();
if($smth->checkIfSaved()){
$user = new User();
$user->updateUser(/* all the $_POST stuff here? */);
} else {
$smth->showUserDetailsForm();
}
Also where should Someclass be saved?
So if ayone would give me an example of how to structure the following functionalities (in files, classes and possibly methods).
users (registration, login, editing account..)
picture with comments of it
news (also with comments)
administration
This is just an example of course, but i don't want to keep on with my mess and then look at it three days later and just facepalm and wonder what did i write there. Well, i already did that today, that's why I'm asking.
EDIT 24.2.2016
While this is an old question, as suggested look into a framework. While it might take a bit to set it up it increases development speed, code is nice and clean and a lot safer. I personally use Laravel.
There's more than one way to skin this cat, but I'll recommend some helpful links and books for you.
Zend's Coding Standards: If you're looking at how to structure, name, etc. your files, then I would look at how Zend suggests to do these things. By following their guidelines, you can create a package that is compatible with somebody else's code using these same methods, as well.
What you will want to do is create a folder specifically for your classes. How do you know when you'll need to make a new class, and what to include? Good question!
If you find yourself running into groups of information that is related, needs to be handled together a lot, or solves a particular problem, chances are you should create a new class that can handle it.
For example, a User class to handle any sort of changes you want to make to a user of your site. Another example is a Role class that can perform tasks (or not) depending on if they're an admin or not. The wonderful thing about Objects and Classes is you can create a User::$role (variable named $role in the User class) that is a Role class. So for instance, you will have a Role object in your User object. From here, your user object can now call to the role object by doing something like:
class User {
private $username;
private $role;
function __construct($username){
$this->username = $username;
}
public function setRole($roleType){
switch($roleType){
case "admin":
$this->role = new Admin(); // contained in another class file
break;
case "staff":
$this->role = new Staff(); // contained in another class file
break;
default:
$this->role = new Visitor(); // contained in another class file
} // end case
} // end setRole
} // end Class User
$loggedInUser = new User("Bubba");
$loggedInUser->setRole("admin");
$loggedInUser->role->deleteMessage();
In general, you will want to keep your code structured and separate, so that each class only handles information that it should have, and not do anything more than it should. If you find a class doing too many things, this means you found a good time to create another class to handle this new responsibility. How you tie it all together is generally a problem answered with "design patterns". There is a very good book that covers both programming using objects and classes, as well as using design patterns.
Check out the book "PHP 5 Objects, Patterns, and Practice" by Matt Zandstra, and published by Apress. It's a wonderful book that dips your toes into OOP with PHP!
It is very hard to tell you how you should do that. There are many different preferences out there. Look at frameworks like Zend, Kohana, CodeIgniter, and so forth.
When I create smaller applications with OOP design, I usually try to follow the following hierarchy:
In the index.php include a bootstrap.php.
In the bootstrap.php include all classes and the config.
Make a classes directory where you can save core functionallity in a core folder.
Furthermore, in your classes directory create the two folders controllers and models.
In my projects I usually have another folder templates, where all my html files go in (and afterwards get rendered with the Smarty Template Engine).
This is a very simplified approach, but can lead you in the right direction. For your requirements like users, pictures, etc. create a model that contains all the data of one single user.
class UserModel() {
public $name;
public $email;
}
And then a controller that can modify this model:
class UserController() {
public function update($user) {
...
}
}
My answer might not be directly answering your questions but might do you lot of good.
Go with a real framework. Don't build websites with code from scratch. It will save you huge amount of time and will force you to use good practices of code separation, really good and clean project structure but again, it will save you time! For many things you decide to implement there there will be a ready solution and the common thing you do (as validate email address) would be done the right way.
I would go with a MVC PHP framework and after having used a lot CakePHP, Zend, Kohana and few others in the past, I would recommend you to go with Yii. Very small learning curve, nice docs, nice big active community and you will be able to port whatever you already have, to it in very small time.
I'm pretty sure for the project you've described that framework will cut your time at least 2 times and in the same time you will have all the things you ask above already solved. I know this from experience, having developed projects from scratch quite some time ago.
if you are developing for web, there are high chances that you will be developing a MVC application, simplest MVC framework known to me is CodeIgniter. And I will advice you to use it.
All the examples I've seen of what and how MVC SHOULD be have used classes as the models, classes as the controller, and HTML templates as the view. And all of them consisted of one index.php script and different requests in the url to run the entire site.
So they've all been something like...
MODEL
class User{
function getUser($userID){
$sql = mysql_query('SELECT name......');
// more code.....
return $array
}
}
VIEW
<h2><?php echo $user['name']; ?></h2>
CONTROLLER
class Controller{
$userModel = new User;
$userInfo = $userModel->getUser($id);
$template = new Template('usertemplate.tpl');
$template->setVariables($userInfo);
$template->display();
}
I understand why the model is made of classes that simply get and save data (even though I assume classes arent always necessary and functions could be used). I understand why the template consists of mainly HTML. But I dont understand why the controller is a class. I would assume the controller to be a procedural script (like userprofile.php which gets the users data from the model and sends it to the template for displaying).
Also, I was wondering why every tutorial I've read dealt with mod rewriting, and using a single page with requests in the url like "index.php?user=1", or index.php?news=3 to run the entire site. Whats wrong with having separate pages like user_profile.php?id=1, or news.php?id=3...
Can somebody please help me with a quick "tutorial" and an explanation along the way. Like...how would a registration form be implemented using MVC, what would go where and why? thankyou
PS. what other kind of design patterns are there
The big "win" of the controller in PHP's version of MVC is you get away from having a separate PHP page for each and every URL that your application responds to.
When you have a new single page being created for each URL, you're expecting your developers (or yourself) to pull in the needed libraries and initialize the template/layout engine in the same way. Even when you're a single developer, the temptation to break from the "standard" way of doing things usually ends up being too strong, which means each URL/PHP-page ends up being its own mini-application instead of each URL/PHP-page being part of the same application. When you have multiple developers this is guarantied to happen.
The end results is pages and components that don't play nice with each other and are hard to debug (with everything hanging out in the global namespace), giving an inconsistent experience for both the users and the developers who have to work on the project.
MVC frameworks also make it easier to give your site friendly URLs. There's usually enough going on in the routing system that you don't need to resort to a huge number of query string variables. Readable URLs are a plus, for SEO and for savvy users.
Finally, although this is pie in the sky with most shops, when you have a controller the methods on the controller become easily unit testable. While you can technically wrap a test harness around a non-MVC site, it's always a pain in the ass, and never works like you'd like it to.
using a single page with requests in
the url like "index.php?user=1", or
index.php?news=3 to run the entire
site. Whats wrong with having separate
pages like user_profile.php?id=1, or
news.php?id=3...
Using a single entry point makes some things easier, I suppose :
You don't have to duplicate any portion of code in user_profile.php and news.php
If you want to set up any kind of filter (like PHPIDS for security, or ACL, for instance), you only have one file to modify, and it's done for the whole application.
PS. what other kind of design patterns
are there
There are a lot of design patterns ; you can find a list on the Design pattern (computer science) article on wikipedia, for instance -- with links to the page of each one of them, for more details.
There's nothing wrong with having separate scripts for each action, and in fact you CAN create a MVC architecture this way, without using a class for the controller. I'm working on an MVC framework at the moment that supports both styles.
The important thing is really to keep separation of different concerns. Database logic goes in your models, Layout logic goes in templates, and everything else in the controller.
So for a really simple example you could have a script "register.php" with the following code
$signup_options = SignupOptions::getSignupOptions(); // Load some data
require("register_form.php"); // Pass it to the view
And this posts to register_process.php
$username = $_REQUEST['username'];
$password = $_REQUEST['password'];
$email = $_REQUEST['email'];
Users::Register( $username, $password, $email );
header( 'location: register_success.php' );
MVC is not suitable for all applications, so you should consider your architecture on a per project basis. For many sites, just having a bunch of independent scripts works fine. For larger more complex applications however, MVC has proven itself to be a reliable and scalable way of developing web applications.
Another common design pattern is "View-Helper", which is where you call a template directly, and the template calls a "Helper" object that performs business logic between the template and the models. Similar in concept, but you can skip having any extra code for templates that don't need it, while still maintaining separation of concerns like MVC. (The difference is essentially that you call the template directly, rather than calling a controller).
There are several ways to implement a good application, but I am just going to touch on a few concepts. These concepts are taken from Samstyle PHP Framework.
Firstly, you have these components: Model (Table Data Gateway), View, View Controller and Backend Controller.
This View Controller actually controls how the view is going to be like (e.g. display out the registration form). The Backend Controller processes user data on the backend and interacts with the Model (database).
So here we can easily integrate Post-Redirect-Get into it.
Say you have register.php for the View Controller which will display the form and parse the content into the template HTML file.
User uses the form, submit and will then be posted to the Backend Controller deck.php. The Backend Controller validates, check then passes the data to functions (Table Data Gateway) which will help you to interact with the database. After the interaction is done, the user is redirected either to a success page, or the registration page with an error.
In the Model (Table Data Gateway), you actually have functions which take in an array and then CRUD with the database.
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.