When building applications, whats the best way to decide what goes where. How do you know what functions to put in what controllers and models. For example, I'm building an application that is based highly on location. Users can post different things, that will in turn be shown to other users within a certain distance. Also, each user will have their own profile page that will show everything posted by that user regardless of location.
So I have models like this
class UserModel extends BaseM{
get_user($uid);
get_all_users();
edit_user($new_data);
delete_user($uid);
add_user($new_user);
get_user_articles($uid);
get_user_reviews($uid);
get_user_foo($uid);
}
class ArticleModel extends BaseM{
get_article($aid);
get_all_articles();
add_article($new_article);
delete_article($aid);
}// similar to ReviewModel, and other models
class LocalModel extends BaseM{
get_local_articles($zip_code, $range);
get_local_reviews($zip_code, $range);
get_local_foo($zip_code, $range);
}// holds all location related functions
As you can see, I lumped everything dealing with a user (needs a userID) in the userModel, everything dealing with location (needs a zip-code) in the localModel, and then everything else has its own model.
I was wondering whats the best way to figure out what goes where, is there like a rule of thumb for this kind of stuff?
Well you're 80% there already. You've got your models broken out and that is a big battle. Next design the app that you want. If you end up with a lots of repetitive "elements" on multiple pages, then each element should be a view. Otherwise each page should be a view. Or some combination of the two.
Once you have you pages defined and you know the data flow of the app, all that remains is the controller.
It may be practical in a small app to have a single controller. Or for really complex apps, you may have multiple controllers - no more than one per "page" though.
Just keep in mind - the Model should be view agnostic (you can retool the UI without impacting the model). The views should be blind to where the data comes from or where it's going - everything gets filtered through the controller.
See my previous answer to a similar question here:
I normally use this approach: try to put it somewhere. if after a while you use it, it feels awkward, then it's not in the right place.
In general every model class should have methods that make sense for itself, and eventually return other models. Refrain from putting too much computational intelligence in your models. If there's something that feels strange in either classes, there's probably a third class in between to be discovered.
Related
I'm trying to understand the MVC pattern in Phalcon.
In my current application I only need ONE template file for each table. The template contains the datagrid, the SQL statement for the SELECT, the form, add/edit/delete-buttons, a search box and all things necessary to interact with the database, like connection information (of course using includes as much as possible to prevent duplicate code). (I wrote my own complex framework, which converts xml-templates into a complete HTML-page, including all generated Javascript-code and CSS, without any PHP needed for the business logic. Instead of having specific PHP classes for each table in the database, I only use standard operation-scripts and database-classes that can do everything). I'm trying to comply more with web standards though, so I'm investigating alternatives.
I tried the INVO example of Phalcon and noticed that the Companies-page needs a Companies model, a CompaniesController, a CompaniesForm and 4 different views. To me, compared to my single file template now, having so many different files is too confusing.
I agree that separating the presentation from the business logic makes sense, but I can't really understand why the model and controller need to be in separate classes. This only seems to make things more complicated. And it seems many people already are having trouble deciding what should be in the model and what should be in the controller anyway. For example validation sometimes is put in the model if it requires business logic, but otherwise in the controller, which seems quite complex.
I work in a small team only, so 'separation of concerns' (apart from the presentation and business logic) is not really the most important thing for us.
If I decide not to use separate model and controller classes,
what problems could I expect?
Phalcon's Phalcon\Mvc\Model class, which your models are supposed to extend, is designed to provide an object-oriented way of interacting with the database. For example, if your table is Shopping_Cart then you'd name your class ShoppingCart. If your table has a column "id" then you'd define a property in your class public $id;.
Phalcon also gives you methods like initialize() and beforeValidationOnCreate(). I will admit these methods can be very confusing regarding how they work and when they're ran and why you'd ever want to call it in the first place.
The initialize() is quite self-explanatory and is called whenever your class is initiated. Here you can do things like setSource if your table is named differently than your class or call methods like belongsTo and hasMany to define its relationship with other tables.
Relationship are useful since it makes it easy to do something like search for a product in a user's cart, then using the id, you'd get a reference to the Accounts table and finally grab the username of the seller of the item in the buyer's cart.
I mean, sure, you could do separate queries for this kind of stuff, but if you define the table relationships in the very beginning, why not?
In terms of what's the point of defining a dedicated model for each table in the database, you can define your own custom methods for managing the model. For example you might want to define a public function updateItemsInCart($productId,$quantity) method in your ShoppingCart class. Then the idea is whenever you need to interact with the ShoppingCart, you simply call this method and let the Model worry about the business logic. This is instead of writing some complex update query which would also work.
Yes, you can put this kind of stuff in your controller. But there's also a DRY (Don't Repeat Yourself) principle. The purpose of MVC is separation of concerns. So why follow MVC in the first place if you don't want a dedicated Models section? Well, perhaps you don't need one. Not every application requires a model. For example this code doesn't use any: https://github.com/phalcon/blog
Personally, after using Phalcon's Model structure for a while, I've started disliking their 1-tier approach to Models. I prefer multi-tier models more in the direction of entities, services, and repositories. You can find such code over here:
https://github.com/phalcon/mvc/tree/master/multiple-service-layer-model/apps/models
But such can become overkill very quickly and hard to manage due to using too much abstraction. A solution somewhere between the two is usually feasible.
But honestly, there's nothing wrong with using Phalcon's built-in database adapter for your queries. If you come across a query very difficult to write, nobody said that every one of your models needs to extend Phalcon\Mvc\Model. It's still perfectly sound logic to write something like:
$pdo = \Phalcon\DI::getDefault()->getDb()->prepare($sql);
foreach($params as $key => &$val)
{
$pdo->bindParam($key,$val);
}
$pdo->setFetchMode(PDO::FETCH_OBJ);
$pdo->execute();
$results=$pdo->fetchAll();
The models are very flexible, there's no "best" way to arrange them. The "whatever works" approach is fine. As well as the "I want my models to have a method for each operation I could possibly ever want".
I will admit that the invo and vokuro half-functional examples (built for demo purposes only) aren't so great for picking up good model designing habits. I'd advise finding a piece of software which is actually used in a serious manner, like the code for the forums: https://github.com/phalcon/forum/tree/master/app/models
Phalcon is still rather new of a framework to find good role models out there.
As you mention, regarding having all the models in one file, this is perfectly fine. Do note, as mentioned before, using setSource within initialize, you can name your classes differently than the table they're working on. You can also take advantage of namespaces and have the classes match the table names. You can take this a step further and create a single class for creating all your tables dynamically using setSource. That's assuming you want to use Phalcon's database adapter. There's nothing wrong with writing your own code on top of PDO or using another framework's database adapter out there.
As you say, separation of concerns isn't so important to you on a small team, so you can get away without a models directory. If it's any help, you could use something like what I wrote for your database adapter: http://pastie.org/10631358
then you'd toss that in your app/library directory. Load the component in your config like so:
$di->set('easySQL', function(){
return new EasySQL();
});
Then in your Basemodel you'd put:
public function easyQuery($sql,$params=array())
{
return $this->di->getEasySQL()->prepare($sql,$params)->execute()->fetchAll();
}
Finally, from a model, you can do something as simple as:
$this->easyQuery($sqlString,array(':id'=>$id));
Or define the function globally so your controllers can also use it, etc.
There's other ways to do it. Hopefully my "EasySQL" component brings you closer to your goal. Depending on your needs, maybe my "EasySQL" component is just the long way of writing:
$query = new \Phalcon\Mvc\Model\Query($sql, $di);
$matches=$query->execute($params);
If not, perhaps you're looking for something more in the direction of
$matches=MyModel::query()->where(...)->orderBy(...)->limit(...)->execute();
Which is perfectly fine.
Model, View and Controller were designed to separate each process.
Not just Phalcon uses this kind of approach, almost PHP Frameworks today uses that approach.
The Model should be the place where you're saving or updating things, it should not rely on other components but the database table itself (ONLY!), and you're just passing some boolean(if CRUD is done) or a database record query.
You could do that using your Controller, however if you'll be creating multiple controllers and you're doing the same process, it is much better to use 1 function from your model to call and to pass-in your data.
Also, Controllers supposed to be the script in the middle, it should be the one to dispatch every request, when saving records, when you need to use Model, if you need things to queue, you need to call some events, and lastly to respond using json response or showing your template adapter (volt).
We've shorten the word M-V-C, but in reality, we're processing these:
HTTP Request -> Services Loaded (including error handlers) -> The Router -> (Route Parser) -> (Dispatch to specified Controller) -> The Controller -> (Respond using JSON or Template Adapter | Call a Model | Call ACL | Call Event | Queue | API Request | etc....) -> end.
I have been reading tutorials and questions about mvc on stackoverflow lately and I need to ask a couple of questions to see if I understand the basic concepts correctly.
To my understanding, having only one view object for rendering multiple views (html files) is enough most of the time. Is this correct?
Is putting the presentation logic in view files is better than putting it in view object to avoid adding extra complexity to the view layer?
It is known to be good practice to have one index page and autoloading controllers from there based on request urls and file names. But, doesn't that mean having controllers for every request url? Is it ok to group some of the request urls and map them to one controller. (Having multiple if-else statements on index page or putting the information in an array config file)
If I have one view object, than the relationship with this object and the controllers must be 1:1. Is this true?
Lastly, If I need to pass big amount of information from controller to the view, and some of that information is repeated in other controllers; than is it a good way to handle those repeated information in base controller, which is the parent of other controllers?
As you see, I'm still confused. Thanks in advance.
Well... this is a intresting question... As a general rule MVC was designed to decouple these 3 commonly intertwined components.
If your model cannot support multiple views at the same time, its not MVC
If your model speaks to your controller, or even knows about its existance (this applies to the view also) then its not MVC.
If you have a 1:1 ratio between view and controller its most likely not MVC.
You should be able to swap out any of those 3 components from the system with primarily only config changes.
Its a extremely misused term, and often 'attempts' at MVC end up with the extremely coupled code that the concept of MVC was designed to work around.
There's more than one way to do MVC with PHP.
One class supporting everything (global controller).
It load your classes, it process the URI to know which controller start, it check your data (GET, POST), it check the user session (is it expired?, is there someone logged in? Is he an admin?).
Many classes supporting the interactivity (controllers).
A class managing your News, a class managing your Users, etc...
With static methods doing every user to model action.
Basically "add a new item", "delete an item", "update an item".
Many classes telling how things are organized (model).
Your user have a login, an hashed password, an email adress, etc...
See DAO for more information. (basically, all SQL is in these classes). These classes check nothing except that data given are as expected.
Many classes telling how to show things (views).
Called by a Controller which give what is needed (object, array, output data)
The only place where you have HTML and where the more complicated is a loop in a loop creating a whole HTML .
You will have one showing "a message in a centered box", one showing "a list of element", one showing "a single element", one showing "a single element, with an author sidebar", etc.
HTML Templates/Elements are useful to build your view, but it's the view who call templates/Elements and place them how the view want.
I have 3 tables that contain user information, one for students, one for teachers and one for administrators.
They are not related in any way. I wan't to create a dashboard for the Administrators, where a list of students and teachers shows up.
The only way I found to achieve this was using the $uses variable in the Administrators controller. However, I have read in many places that this is bad practice.
Any solutions?
Another, perhaps better practice is the use of ClassRegistry::init('MyModel')->myMethod() (more reading # Cake API)
This only loads the object when it's used, as opposed to loadModel or uses, with ClassRegistry the models are treated as singletons.
--
that you are doing something wrong: you need access to a model that has nothing to do with your current controller.
There are plenty of conditions where you would need to access all of your models data, from one controller, but never a definitive answer on how to do it without breaking convention!
You can always use another Model which is not related by using
$this->loadModel('NewModelName');
Then you can access new loaded model by:
$this->NewModelName->add(); // whatever method model has defined
Why prefer loadModel() over uses?
To gain performance. How? uses calls the loadModel function itself to load all the models you specify in uses array. But the problem is if only one of your action needs a particular model, whats the good thing to include it in every action. e.g. only add() action requires an unrelated model, but if you have specified it in uses array, no matter what action gets called a completely unrelated model is going to load. To put simply it will be inefficient. Its like you have declared variables in a C programme but never used them. In case of C compiler will warn you that you are not using your variables, but unfortunately cake couldn't tell you.
Its alright to use uses if all your actions needs to load that model, use loadModel() otherwise.
You probably didn't read my answer in your other question :))
I have 3 tables that contain user information, one for students, one for teachers and one for administrators. They are not related in any way. I wan't to create a dashboard for the Administrators, where a list of students and teachers shows up.
The problem is you are separating similar data into 3 different tables, in this case, user information. So when you try to manage this data, you hit a brick wall: because you leave out the relationships when you separate them in 3 tables.
The only way I found to achieve this was using the $uses variable in the Administrators controller.
You got the wrong idea about the controller. Each controller manage the data flow of a particular model (and related models). It doesn't mean that you have to stay in Admin controller to do administrative things. What model you want to manipulate decides what controller you need to be in.
However, I have read in many places that this is bad practice.
Now for the main question: using $uses is a red flag that you are doing something wrong: you need access to a model that has nothing to do with your current controller. Now, there're always exceptions in programming, sometimes we need to have access to that model. That's where loadModel comes in. Because it should be rare. If you need the model a lot, then you'll need to call loadModel a lot, which is cumbersome, which is what $uses is for, but then that means something's wrong with your app design :))
So, you can say using $uses is a sign of bad decision (in DB design or application structure); and so is using loadModel a lot.
Edit: Any solutions?
I gave one solution in your other question. But if you want to have them all in one place, you can have 1 users table with user information. Each User can hasOne Student, Teacher, Administrator and a 'group' field to decide what group the User is. The third solution is using $uses. Its performance impact won't be a problem really. But it will be pretty convoluted when you develop your app further. That's what you need to worry about. For example, I can say that, if you use Auth, you'll need to tweak it a fair bit to get it working with 3 models. If you use the users table, it will be a lot easier.
I've been working on creating my own MVC app in PHP and I've seen a lot of differing opinions online about how exactly this should be set up. Sure, I understand there seems to be a general "It's MVC, it is what you make of it" approach, but I'm running into 2 seemingly conflicting viewpoints.
A little background on my app: I'm using smarty as my presenter and an object-oriented approach. Seems simple enough, but I'm trying to figure out the ubiquitous "what is a model" question.
If I take a look at some tutorials and frameworks, they seem to view the model as strictly a class that inherits DAL methods from an abstract class, with a little bit extra defined in the class itself as your data needs differ from object to object. For example, I might see something like $productModel->get(5) that returns an array of 5 products from the database. So what if I need to query multiple models? Do I store all of the data in the controller or an array and pass that to the view? Then if I'm dynamically calling my controller, how can I persist the data unique to the controller necessary to render the view? This seems bad, especially because I then have to pass in things like "controllerName", "controllerData", and my View::render() method gets hugely bloated with parameters, unless I pass in the controller itself. Maybe I'm missing something here.
Let's say I want to make a login that queries a users table. Login is a model or a controller, depending on certain implementations I've seen online. Some implementations (I'll call this method 1) make a LoginController with method login() that might do a comparison of $_POST and what's returned from the user model instance $user->get(1) to see if a user is validated. Or maybe login() might be a method in a default controller. On the flipside, an implementation (implementation method 2) that resembles more of a Joomla approach would make a Login model and declare all of the actions inside of that. Then any data that needs to get assigned to the view would get returned from those methods. So login->login() would actually check post, see if there's a match, etc. Also the User model would probably be instantiated inside that model method.
My feelings about 1: The controller is fat. Additionally the controller is storing data pulled from models or passing in ten thousand variables. It doesn't seem to jibe with the idea that the model should be passing data to the view that the controller should be blind to. Also, let's say I want to wrap everything that is in a specific model handled by a specific controller in an outer template. I'd have to copy this template-setting code all across my controller functions that interface with this model. It seems grossly inefficient.
My feelings about 2: It doesn't make for having actions that aren't model methods. If I want to go to my site root, I have to make an index model or something that seems like overkill in order to have a model that passes data to the view. Also, this doesn't seem to be a very popular approach. However, I do like it more because I can just do View::render(mymodel->func()) and ensure that the data is going to be passed back just the way I like it without having to crap up my controller with code merging a thousand query results together.
I've waded through far too many religious arguments about this and want to know what you guys think.
I've built my own framework in the past too so I know what you're going through. I've heard the saying "build fat models" and I agree with that -- as long as the main goal is to return data. I considered the controller to be "The Overlord" as it manipulated data and directed where it should go.
For a login controller i might create something it like...
Post URI: http://example.com/login/authenticate
LoginController extends ParentController {
public function authenticate() {
$credential_model = $this->getModel('credentials');
// Obviously you should sanitize the $_POST values.
$is_valid = $credential_model->isValid($_POST['user'], $_POST['email']);
$view = $is_valid ? 'login_fail.php' : 'login_success.php';
$data = array();
$data['a'] = $a;
// .. more vars
$this->view->render($view, $data);
}
}
In my opinion data should always flow from the model -> controller -> view as it makes the most sense (data, manipulation, output). The View should only have access to what it has been given by the controller.
As for this...
Then if I'm dynamically calling my controller, how can I persist the data unique to the controller necessary to render the view?
Well I would imagine you're building a 'base' or 'parent' controller that gets extended off of by your dynamically called controllers. Those child controllers can have properties that are needed for for the view to render -- honestly I'd need an example to go further.
Hopefully this helps a bit. If you ask more specific questions I might be able to give a better thought out opinion.
If you're writing your own app, I think the best solution is to do it yourself and find out.
Ultimately, whatever makes the most sense to you, and whatever makes it easier for you to conceptualize your app and quickly add to or change it, is going to be your best option.
If one way is "wrong", then you'll find out through experience, rather than someone else telling you. And you'll know the entire situation that much better, and know EXACTLY why one way is better.
What helped me when I was writing my own framework in PHP was, strangely enough, CherryPy. It made the concept of an object-oriented web app so simple and obvious, and I enjoyed using it so much, that I modeled the basic structure of my PHP framework to imitate CherryPy.
I don't mean to imply you should learn CherryPy. I mean that simplicity, clarity, and enjoying developing with your own web app go a LONG way.
If I were to give one piece of specific advice, I'd say try to avoid retyping code; write your code to be reusable in as many situations as possible. This will not only be good for your app, but for future apps you may write or work on.
You might check out Eric S. Raymond's Rules for Unix Programming. I think they're definitely applicable 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.