I recently went through some tutorials on how to program your own PHP MVC framework. To avoid some questions and comments: I don't want to use it in a productive environment, I just like to fiddle and get the idea of whats going on in MVC.
So far I am able to have single pages eg. http://domain/news/show/3 shows me the news-record from the database with id 3 and http://domain/news/all lists them all on one page.
Now I have multiple entities and thus multiple lists and want them all to appear on one page. Preferably the page you see when you open http://domain/
Do I have to write a new model and controller that makes calls to the other models? I'm kinda unsure how to achieve this.
There is no strict definition or convention on this that I'm aware of.
What I would do is this:
Class Overview
Controller_Homepage
Controller_News
Model_NewsArticle
Behavior
Controller_Homepage
Action_Index fetches multiple Model_NewsArticle entities, has them rendered, and passes the output to view. Also fetches any other entities you may need and gives their rendered output to view.
Controller_News
Action_List fetches multiple Model_NewsArticle entities, has them rendered, and passes the output to view.
Action_View calls Model_NewsArticle::factory($id), has it rendered, and passes the output to view.
Model_NewsArticle
Contains a static factory method that accepts an $id. Returns an instance of Model_NewsArticle.
Contains methods used to find multiple articles. A query builder would be nice here.
That's by no means comprehensive and I've left out lots of little details, but it's fairly simple and is pretty dry.
This is a matter of preference really. Having another controller and model makes code separation easier in larger projects. Personally, I would only make a new controller since it is a different page with potentially different actions, and I would use the existing models to get the data to keep your code DRY (Don't Repeat Yourself).
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 need help clarifying the correct structure and process flow for an MVC application in PHP.
I think I've got the concept round the wrong way because currently most of my processing is done (or at least initiated by) the Views. -- I kind of inherited this way of thinking from the company I'm working for, but now I'm not sure that they are understanding the MVC model correctly!
Having looked at it again I think that the proccess should be as follows (very basicly):
The users actions are sent to the Controller
The Controller process those actions using any Models required
The Controller then instantiates the relevent View and passes the required data to it
The View renders the page to the user
I'm also having some difficulty deciding wether the view should even have any real functionality in it or not.
i.e. Is it just a wrapper to hold the page data and load the required template files (header, page, footer etc.), OR should any functions to do with rendering data (i.e. preparing HTML and outputting HTML) be in the View?
Another question is does the controller 'hand over' to the model and have nothing to do with the actual DBconn (so that the Model acts like a Bouncer on the doors of the DB nightclub, and we're not on the list) OR does the controller 'own' the DBconn and simply lends it to a model when it needs it?
I'd really appreciate any help and advice anyone can offer.
Thanks
edit -- I found this helpful!
I'll answyer to your two last questions:
1) The Views should have basic output capabilities, for example escaping values to avoid security issues or display a html table starting from a list of objects. Another responsibility could be the translation of labels and other constant values (for example you could have $this->_('Your label') where function _($val) is a function included in all your view classes that translates the strings starting from a csv file).
2) Depending on the complexity application, you could have two sub-layers in the model layer. The upper layer is the classic model with the functionality of your entities. The lower level is the resource model class associated that performs the db operations. You could also have a single layer with your models that implements the DAO pattern. Anyway, the controller shouldn't have nothing to do with db connection.
Your bulleted assumptions are correct :). The main idea behind MVC is loose-coupling and interchangeability between components.
To answer your questions:
The view should be presentational only, so iterating through a list of models in the view and outputting them there is fine, but processing data in the view is not.
The model should not assume anything about the controller and the view. It should be easy for you to switch between a model that draws data from a database to one that draws data from another type of data source and this should not determine changes in the Controller. Fabrizio is right, you should check out the DAO pattern for an example on how to do this.
I really recommend taking a look at frameworks that implement MVC to see how they do it. Especially Spring - even if you're not a Java person, the implementation is very clean -, Rails, Symfony. For something more exotic take a look at Django.
I am a beginner with CodeIgniter still struggling to get a complete grasp on how to use the MVC ideology most cleanly.
I am writing a basic CMS system with the ability to vote on entries and follow people etc, consequently, I have found myself using the same or similar pieces of code across multiple views here and there consisting of various pieces of html and logic such as:
Voting panel
Follow/Unfollow panel
Login/Logout panel
Code to check if a user is logged in etc...
I am wondering where to put this code so it can be unified? I am thinking a helper is the way to go? If I declare the helper in the controller, it can be called from the corresponding view right?
Some of the elements are dynamic - such as a follow/unfollow button - It would need to check if you are already following the user or not and display the appropriate button, which would require a model to check. What I have now is that all the logic is in the controller and it returns an appropriate button, but it seems weird to be returning formed html code in a controller return as well. Should it be more like:
controller checks if you are following someone
the controller passes a boolean to the view
the view calls the helper with this value to draw the appropriate button
Also, as a secondary question, I have been doing a fair bit of looping through mysql arrays in foreach loops to process mysql results returned from the view. It seems like my views are getting somewhat complicated, but I can't think of another way to do it, although perhaps this should be done in another helper as well?
Apologies if this is a naive or repetitive question, there is indeed a lot of discussion surrounding this subject but it is not always easily relatable to another project.
Helpers are certainly one way to modularize anything that isn't DRY. Another is to use Partial Views. CodeIgniter looks like it supports partial views. Here's a good breakdown - not PHP specific but the discussion should be agnostic.
As far as handling user logins is concerned, you will probably want to use a static class and the singleton design pattern, which will allow you to check to see if a particular user is logged in or not anywhere in your application. There is a good tutorial here
http://www.phpandstuff.com/articles/codeigniter-doctrine-scratch-day-4-user-login
Loading the helper, I don't believe loading it in your controller will automatically load it in your view. I think you have to re load the helper in your view file, or you have to autoload the helper. (cant remember off top of head but Im pretty sure).
Regarding looping through the mysql results, you should be using a model for this, always. Any functions which are grabbing or sorting information from your applicaiton, should be done within the model. Then, in your view file you loop through the results and format the data how you choose to.
When developing http://newspapair.com which has the vote functionality you mentioned I used helpers and custom classes to spread the functionality across multiple views.
Helper - has functions without a class. So a standalone function or group of functions can be placed in a file and saved as a helper.
For instance I used a helper with generic form processing functions for NewsPapair, instead of a static class. But this is not the "best practices" thing to do. I did it this way because I already had the functions from a previous project.
As far a looping through MySQL results, try to write a query that allows the DB Server to do the heavy lifting. This will make your code more efficient. Perhaps ask a question about a specific query with example code. Plus do all of the data gathering in your Model.
Currently, I am working on restructuring an existing code base. I'm new to php frameworks, but I do know in general how MVC works.
Right now, there is one controller file, one model file, and thirty view files.
Should every model correspond to a table?
Should every view correspond to an html page?
What about the controller? How can I break this thousand line monster into more organized code.
Thanks.
Should every model correspond to a table?
No. A model is often constructed from data from multiple sources. Don't think in terms of tying it to your physical database structure even though there will probably end up being lots of similarity.
Should every view correspond to an html page?
Not to sound trite, but every view should correspond to a view. I'm not sure exactly what you mean by a "page".
Perhaps an example would be useful. Imagine a user registration page. The model is User and might contain fields such as:
Title
Given names
Surname
Date of Birth
Username
Address(es)
Email address
Phone number(s)
etc
Now, that data may be in multiple tables. For example: Party, Person, Contact and Address.
There will probably be several views:
About page
Form page (used for new registration and possibly editing details as well as errors);
Success page;
Failure page.
Typically all of this will be handled by a single controller as all the processes are inter-related.
Every model should correspond to a logical data object - which should generally predominantly be stored in one table (often with foreign keys into other tables, since models generally need to reference other models).
Every view should correspond to a logical way of viewing your data (e.g. on stackoverflow, there is hopefully a view for the list of badges pages, a view for the list of tags pages etc).
Every controller should correspond to a logical grouping of views, which should not be too big (where too big is the line where the file is becoming unmanageable - if you've got 30 views, you can hopefully find a logical way to group them into say 3 controllers).
What about the controller? How can I
break this thousand line monster into
more organized code.
Have a look at CakePHP framework and how it solves the problem of large models, controllers, and numerous views. I find it quite elegant. Complex models can have behaviours. Large controllers can be broken into components. And numerous views are grouped with layouts, while having common bits separated into elements. It might sound complicated and scary at first, but once you try to use it, it really falls into place.
Should every model correspond to a
table?
It doesn't have to but it often will depending on the complexity of your business logic.
Since you're refactoring an existing application, think about how the model is used by the other layers. In MVC, the model is at the bottom of the dependency stack.
How will the view access the model? How will the controller modify it? How will the model be populated?
Should every view correspond to an
html page?
Again, it doesn't have to but it often will.
What about the controller? How can I
break this thousand line monster into
more organized code.
A common strategy is using the front controller pattern. The front controller deals with HTTP requests, application initialisation and site-wide logic (just as your thousand line monster is currently doing) - but then it delegates to more specialised controllers.
These specialised controllers could be grouped by the models it uses, site page structure, or anything else that seems logical. They then interact with the model and select a view to display.
Finally, +1 to frameworks as Leonid suggested. Even if you don't end up using one, there are some great implementations of controller patterns out there.
Hope that helps.