I've recently started to rewrite a project I did a few years ago using CakePHP. I'm trying to do everything 'right' this time, so maybe someone get give me a a pointer on doing to the following:
I'm showing a simple table from a table using Model->find('all') in the View. There are two boolean fields in this table, that together make up something I need to show to a user. So: 0x0 = 'A', 1x0 = 'B', 0x1 = 'C', 1x1 = 'D'. Where should I put this logic? I've been thinking about the following methods:
The view
A View helper
The controller
Something in the Model so that Model->find('all') outputs this value (is that even possible?)
This task might seem trivial, but I think it might learn me getting this project organized and maintainable from the start.
Thanks!
Well, it depends on the type of logic for making up final table (is it presentation or business?).
Imagine you add new type of UI, for example command line interface. How would you show your table there? The data passed to View has to be same for both HTML and console presentations. So the logic which is responsible for preparing that data - is business logic and it should be placed in Model. The logic responsible for displaying the data should be placed in View (maybe in view helper if it's used more than once).
And never place this kind of logic in Controller.
If it's something you're going to use all over the place I would put it in the model. You can either put a method on the model that gives that value back or loop over all the rows you've retrieved in an afterFind callback and set it as a proper field.
I put this kind of logic in the view if it is something that is going to determine rendering style. In that way, the designer has maximum access and can style accordingly.
On the other hand, if the two columns only exist for convenience in datamodelling, put it in the model. The designer shouldn't even be aware of other possibilities!
In the controller! The methods from the model comes in the controller. The view is just for output( like HTML UI programming.)
Related
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).
I've done up a bit of code in which I attempt to integrate data tables (http://datatables.net/) with cakePHP.
It's up and running with my own app, but I want to make it more generic, so it can be used by anyone across any cakePhp application, and most importantly I want it to fit in with cakePHP conventions.
So at the moment this is what I have...
A cakePHP helper called dataTables, which takes the following arguments: $modelName, $fields, $headers.
$modelName is the name of the model whose data will be populating the table.
$fields is an array of fields we want to show in the table (all fields must be prepended with "ModelName." which means we can show associated model values in the table)
$headers is a list of headers we want to be displayed at the top of the table.
The helper produces an empty html table (with the $headers as headers). The table is then populated by datables' javascript (you might have to read up on this if you're not familiar with dataTables server-side processing).
The Javascript retrieves the table data from the dataTable() action of the controller whose model we want to get at. The javascript will also send the model name (which we sent to the helper), and the fields. The controller then prints out the JSON data (through a blank view)
My two main questions are:
It doesn't seem right to place the dataTable action in a controller. A) because it doesn't actually need the controller because it knows what model and fields it needs to load and B) because it's not really a user action, its really just a JSON response. So where should it be put?
To print the JSON repsonse for my dataTable() action, I use a "blank.ctp" view and the use echo jsonencode($output). It doesn't seem right to use a view to output JSON data. Usually views are just for the user right?
One way of answering both of these questions is to have a standalone dataTable.php file, which will print the relevant JSON data based on the model name and fields it receives.
But this ^^ doesn't seem logical considering the MVC pattern.
The code is a bit messy at the moment (answers to the above should help me tidy it up!) but let me know if need to see.
Hope this makes sense to someone other then myself..
I thought about this for a second and a plugin seems to be the best idea.
You can use a Component to load the helper automatically and give you a controller visible hook to set the data for the helper/element that provides the output.
Use a behavior to expose the model function for your json, and then use the component to set the data.
As far as whether or not you should use a view or not - here is the section from the book on json views.
The _serialize key is a special view variable that indicates which
other view variable(s) should be serialized when using a data view.
This lets you skip defining view files for your controller actions if
you don’t need to do any custom formatting before your data is
converted into json/xml.
If you need to do any formatting or manipulation of your view
variables before generating the response, you should use view files.
The value of _serialize can be either a string or an array of view
variables to serialize:
http://book.cakephp.org/2.0/en/views/json-and-xml-views.html#using-data-views-with-the-serialize-key
I wrote a CakePHP Componenent that handles this https://github.com/cnizzdotcom/cakephp-datatable
Something that has always bothered me is doing more than one loop to manipulate an array.
What I mean is, in the controller the data is fetched from the DB via a model. Lets say we are showing a list of users, and each user has a status (1,2,3 equates to verified, unverified, banned respectively). Within each iteration of the loop the status would be checked and displayed via another Db query (forget mysql joins in this example).
Now, would you do that in the controller within a loop, and then perform another loop in the view with all the data already fetched and pre-formed ready for display (therefore resulting in 2 loops).
--OR--
Would you just do it in the view therefore resulting in the one loop but with model calls from the view. I understand that this is ok in the strict MVC pattern but its frowned upon generally.
It seems silly to loop twice but then its tidier as all the data manipulation is kept within the controller.
I would do that nor in the view or the controller but on the model.
I explain :
Your controller's job is to retrieve the expected user list, check ACL, etc...
Your view's job is to present this data in an elegant form
Your Model job's in to fetch/store data from Database and ensure integrity. Userstatus is a model too for me.
My configuration make this pretty easy, I use mustache (Php port) for view, which allow me to call methods from my models directly in view. I wrote my own ORM for my models, that way I have wrappers.
Such code would look like that for me :
// Controller
$template = new Template('pages/users.html');
$template->users = mUser::find(); // return array of mUsers instances
echo $template->render();
// View
{{#users}} <!-- For each user -->
{{getName}} has status {{#getStatus}}{{getStatusName}}{{/getStatus}}<br />
<!-- getStatus is a method from mUser model, that return a mUserStatus instance -->
{{/users}}
/* More explain on the view syntax
{{name}} = $user->getName() (return string)
{{getStatus}} = $user->getStatus() (return instance of mUserStatus);
{{statusName}} = $user->getStatus()->getStatusName();
*/
You may want to have request caching for each model instances in request level so that you never runs a request twice times if not needed.
That seems more natural to me than to delegate it to controller. I try to put business intelligence on controllers, there is no need for intelligence nor programmer intervention to retrieve a status name for each user.
I Hope it help.
In my opinion logic that manipulates the data you're returning, should be located in the controller. Logic that manipulates the representation of your data can be located in the view.
So I would go for the second option.
But, as you pointed out yourself this is a choice of implementation.
Also note that multiple round trips to your DB are bad for performance. Your example is a typical n+1 problem, meaning that you have 1 'top' select query and then N more queries for each row in your first result set. If you encounter such a problem always try to solve them on the DB level.
Another note I would like to add is that in your example you're storing status explanations in the DB. If you want to provide your applications in other languages, this might prove to be a problem. But this is beyond the scope of your question :)
Doing two loops is the clean way. That is what I would do for most cases, but I think there is no gerneral answer to this. Like if you have a lot a data and performance gets an issue it would be better to forgett about MVC and just use one loop.
A third way would be to use a helper function you can call from the view. Now that I think about it... that would probably be the best way.
I don't know if I'm wrong. But all I know is that in MVC, is that the Controllers is always responsible for calculating the data, and the View to print them.
The problem
I have a poll that I need use a model to get your data and I use a view to print. Currently I can access this poll by use the url "poll/last". This works fine.
My problem is that I need print this info on some pages (like in "site" controller).
The Dilemma
If I simple load the poll view on page, nothing data is get from model. Onetime that it is work of Controller.
If I move all controller part to view, this works fine. The low point is that turn the application in a "non-MVC compatible".
The Solution
So how can I solve this dilemma?
Actually the CodeIgniter not is a HMVC, and the HMVC module don't works fine -- only locally.
There are some viable solution to solve this problem?
Controllers are not always responsible of all calculations. When those calculations are part o fthe 'business or data model' they should go into the model. My english is not good sometimes but i'll try to explain with an example: Let's say we have a table with persons data, and a column birth_date. Age() function should be in Model, because is another way of seen birth_date.
In your case, I would try to move calc into the model, and write a partial who shows the result, and pass the resulting partial view to the main one. Something like
$data['poll_view'] = $this->load->view('poll_partial',$this->poll_model->getPollData(),true);
$this->load->view('current_view', $data ); //that includes poll subview
I may be misunderstanding your question, forgive me if I'm wrong. I can't comment yet on posts, so consider that this may be an answer.
You're wanting to use the data that is in the poll/last controller in another one?
Why not have the same code that you're doing on the controller, in a method/function in the model?
That way, when you call your model just like in the poll controller, the same code and data is available to the site controller.
That's the main function of models.
In my opinion it goes like this:
View - Displays the data, formats the data, and puts the data where you want it.
Controller - Takes the data and determines what exactly to show and on what URL / location to show it, and in which view.
Model - Gets the data from the database, does any calculations that you need to, and returns it.
Hope this helps!
It sounds like you are trying to load the poll view into other views? If so, take a look here: http://codeigniter.com/forums/viewthread/189935/
The same question has been asked/answered
Forgive me if that wasn't your question... can't comment on posts...
I am writing this web project in which one of the views will be having two types of boxes. There is an array and based on type of the values of each item in the array i have to display one or the other box.
Qn is: Should i write the html code for boxes in the controller as two methods or should i write it as two functions and call on it from inside the view itself? Both methods sounds not so good. Your thoughts,suggestions or any ideas for a method outside of two i mentioned above?
Here is a link i saw which closely resembles my thought on writing html code in controller. PHP coding standards
MVC is a guideline. It's there to help you, if it's hindering you getting the job done then something is wrong.
I'm not sure I understand your question properly, but if you mean that you have to display different HTML depending on the data passed to you during run time, then I'd suggest you package that code in a helper function and call it from your view.
On the other hand, if you mean that you're views are well defined and unchanging, I'd just do the checking in the controller and display the appropriate view.
You should follow the common way of dealing with view using MVC guidelines, meaning you should populate a variable with your two functions inside the controller with the values - then inside your view, you should fetch the raw data and display it as you choose.
I'm not sure I understood you completely, but :
No HTML code in your controller.
If you have 2 different HTML code,
and one controller action, then you
need 2 views. In your controller, you
can then choose which view to use.