I have a couple quick conceptual questions about saving models in PHP's Yii framework. I've run into this code a couple of times $model->save() (for example if($model->save())....
but I've never quite understood what it means.
Also, I read in the MVC Tips/Handbook that we should try to save our models in the model and not the controller - could someone explain why that is? I have a friend who has told me that it doesn't matter - but, I'd like to understand the rule behind it.
Thank you for you help!
What does $model->save() do?
Just check the source, it's on github. Apply logic, and the answer is pretty predictable.
As the docs clearly state: the BaseActiveRecord represents a data object. It could be a row returned from a MySQL query, or a processed form being sent by a client, or a MongoDB document, or whatever.
Calling save on that object either inserts the data into the DB you chose, or attempts to update that record. Depending on the insert/update call being successful, it returns a boolean (true if save succeeded, false if it failed).
It's pretty intuitive, really. If you want to learn more about the tools/frameworks you are using, common sense dictates you check out their online documentation. Yii's docs seem to me to be pretty comprehensive and easy to navigate: check them here.
Why save models in the Model?
Well that's easy, but it requires some disambiguation. The term "model" is often used to refer to the data containers. The objects on which you call save in this case. They are data models, true enough, and they are used to carry data back and forth throughout your application. In Yii, what some call models are called "ActiveRecords".
In the acronym MVC (as you know Model View Controller), the Model part actually covers a lot more than mere data containers. That "Model" (with a capital M) refers to the Model layer, also known as the logic or business layer. It's the part of your application that actually will contain the bulk of the code. It's there where the more complex computation is handled, it's the layer where you'll connect and query the DB. And it's this layer that has methods that the controller will call. These methods will then return data models (lower-case m) containing the data or the result of the computation that the controller will then pass on to the view.
If you want to know what logic/jobs/classes make up the Model layer, simply ask yourself this simple question: "What doesn't this bit of do?" If it doesn't handle the raw request, and it doesn't present the data to the user (those are the jobs of the controller and the view respectively), it's part of the Model layer, with the exception of a router component, dispatcher and all that that ties an MVC framework together, of course.
Controller actions (the methods in a controller, obviously) should, therefore be quite small. All they really do, 9/10 times, is pour the request data (form submissions and the like) into a model, and call one or more methods on a service (which is part of the Model layer). These methods will receive the models created in the controller as arguments, and set to work with them.
The controller can perform some basic validation, but the Model layer will dot the i's and cross the t's.
Once the Model layer has done its job, it's back to the controller which has only two things left to do: Did the Model layer return data that it expects or not? If so, pass it on to the view. If not (an exception was thrown or nothing was returned) -> handle the error/exception and, if required, redirect the user.
So in short: The Model layer is the bulk of your code, and it communicates with the controller (and internally) through data models. The Model layer never communicates with the view directly, nor does it redirect the user or handles raw input like $_POST data.
Here's a couple of links to posts of mine where I explain this even further, complete with graphs and what not. They are code-review answers, so ignore the bits that deal with the code itself, but the background information may be relevant to you:
CodeReview: How to put XML results in the MVC pattern?
CodeReview: PHP MVC: how to do $_POST the right way
As I understand in your case $model variable it's instance of BaseActiveRecord class.
So when you call:
$model->save();
Yii run mechanism to insert/update data in data storage.
The save() method return true or false, which does mean model saved or not.
So when you write:
if ($model->save()) {
//some code will be here
}
you check saved model or not.
This tutorial describe how Yii implements MVC practices.
It will insert a new row into the table that the model represents.
i.e. If I have a model called $user that represents a table called users, then calling $user->save(); will insert a new row into the users table.
if($model->save())
Would be the same as:
//Attempt to insert row
$inserted = $model->save();
//If insert is successful.
if($inserted){
//Do this
}
Note that many frameworks will also allow you to update a table row via the save function. In those cases, a where condition is attached or the primary key of the row is passed in.
$model->save() are using for insert and update data in database.
Related
In a MVC application it is easy to understand how the Controller extracts data from the request and updates the Model layer but I am a bit confused as to how a View is supposed to retrieve data from the Model layer when the View does not know about the request?
For example if I go to
http://www.site.com/product/view/428
I route the URL and I dispatch the request and I end up in the Controller. Nothing needs to be done in the Controller(I think?) and when it gets to my View I need the product ID but the View should not be extracting data from the Request so what do I do?
Thanks.
There are two approaches for handling this and both actually would indicate that controller in this case a significant role to play.
The fabled ways of ancients ..
The first option for resolving this issue would be adhering to classical MVC as close as possible. This kinda relates to what people mean, when they say 'you cannot do classical MVC for web'. In classical MVC the view observes model layer. And that part can actually be implemented.
If that's the approach you want to take, then you will have to learn about Observer (1), (2) pattern and how to use it in PHP (1), (2). Though there has been some push for moving away from Observer pattern.
Since I have not explored this approach in any meaningful way, I will not give any examples.
The puny trail from this decade ..
If you read Fowler's "GUI Architectures" article, you might notice the part which state that views and controllers form pairs. When applying the ideas of MVC to context of web, there are ways to benefit from it in the bootstrapping stage of application.
FYI : I'm not anymore so sure, that you can call this way "Model2 MVC". There are some significant inconsistencies. I'm gonna poke more at this nagging suspicion some more, when I'm bored.
Consider this fragment:
$router->route( $request );
$resource = $request->getParameter('controller');
$view = new {'Views\\'.$resource}($serviceFactory);
$controller = new {'Controller\\'$resource}($serviceFactory, $view);
$method = $request->getMethod(); //post, get & etc.
$command = $request->getParameter('action');
$controller->{$command.$method}($request);
$view->{$command}();
echo $view->render();
The controller fragment in your example URL would be "product" and action would contain "list". I left those names instead of resource/command pair to make it less confusing.
If you start out with a premise that views and controllers are paired to some extent (whether the pairing is cohesive or not is debatable), then you can express it by using same names. This also lets you move the initialization of view out of controller.
Another aspect which is encapsulated in the fragment above is the fact that, due to the request-response nature of web, every operation in controller will require an accompanying one in the view. And similarly to how you have actions in controllers, you can also opt to call specific, route-related methods in the view. That would remove some boilerplate conditionals from views and let you better organize the whole thing (this is kinda the "highly subjective bit").
So .. how do you turn /product/view/428 request in something visible on site?
As you probably know, the responsibility of controller is to alter the state of model layer, which in this case might code something like this:
public function getView( $request )
{
$warehouse = $this->serviceFactory->provide('warehouse');
$warehouse->chooseItem( $request->getParameter('id') );
}
The your view instance uses the primed service from model layer to acquire data:
public function view()
{
$warehouse = $this->serviceFactory->provide('warehouse');
..
..
// retrieve data about sales for product with ID: 428
$something = $warehouse->getSalesFigures();
..
}
The exact implementation of view will depend on how far off deepend you are willing to go. Two most reasonable options would be:
fetch data, inspect it and if necessary choose templates and dump data into them
use a set of presentation objects to work with model layer and based on the result bind those presentation objects to ant number of templates
my 2 cents
In MVC, A controller "controls" the flow of information between the model, where the information is "stored," and the view, where it is displayed. Therefore, the controller handles all the changes of information and interaction with the models and then sends the necessary information to a view that then displays whatever information was requested/changed/etc.
MVC is all about the separation of responsibilities.
Models are responsible for storing and modeling the application's data.
Views are responsible for displaying information to the user.
Controllers actually have multiple responsibilities:
Deciding when to Create new instances of a Model.
Deciding which instances of Models to Read and passing them to the appropriate View.
Deciding which data in a Model instance needs to be Updated based on data passed back from a View.
Deciding when to Delete no longer needed instances of a Model.
In other words, Controllers sit between the Models and Views and do all the business logic for an application, including figuring out which CRUD operations need to happen... although the actual CRUD operations are usually part of the Model itself.
A better name for MVC would probably be MCV to stress how the Controller sits between the Model and View.
Sticking to MVC basics in Yii, I am trying to embed my business rules in the model class but facing problem in implementing it. The problem at hand is to stop the user from making duplicate entries and code the function in model class that checks if the entry already exists in table. I want to write a method in my model class which would query the sames model's underlying table and if the new business entity exists, it simply returns false. If I code this in controller, I can achieve the desired functionality but I want to keep this in model so that where ever the model is used, I can access the method and also stick to MVC basics which dictates Thin Controllers and Thick Models. Thanks in advance.
The best way would be to avoid the use of active record instances (at least) directly in the controller.
Instead you should create service-like structures, which contains the interaction between your CActiveRecord and CFormModel instances. This would let you better isolate the presentation layer (views, controllers and templates) from model layer.
Such services also would be able to hold (and sometimes, react upon) errors/exceptions thrown by CActiveRecord and CFormModel instances, that it utilizes.
Cross-site Request Forgery Prevention may be what you are looking for? unless your idea of 'duplicate entries' is directly related to your business model, in which case you can override the CActiveRecord.beforeSave() and put your logic in there, if this method returns false, the record won't be saved to the database.
If you use the later method, and you want to pass the error to the view and display to the user, you can always use the CModel.addError() method, in this case in your beforeSave method.
There is another option though, which is using custom validators.
which is more appropriate? depends on your business logic.
I'm just starting to convert some basic applications to CodeIgniter and I'm trying to make sure that I start off on the right footing.
Most actions in my controller require at least 1 query and as I see it there are 2 ways to go about this...
Combine the queries into a single method in the model, therefore making only a single call to the model from the controller.
Have each query be its own method in the model, then call each method in turn from the controller.
So far I've adopted my own policy but I'm not sure if it's advised or breaking the MVC pattern.
If the queries are directly related to one another and only ever run together in sequence (the 2nd query is dependent on the 1st running successful), or data from the 1st query is passed to a 2nd query and it's the 2nd query that returns the actual display result set, then I go with #1
If each of the queries is returning its own individual result set for display, then I go with #2
Is there a recommended way to structure and separate the logic in this scenario?
The last thing I want to do is cause myself a nightmare later down the line. My gut instinct is telling me that as much of the logic should be in the controller as possible.
Your thinking is right in that if a certain set of queries will only ever be run together, they should belong to the same method in the model. Free-standing queries should be in methods of their own, this way you can call them from the controller when required.
To combine multiple queries, you can either make multiple calls from the controller like this:
$this->your_model->doQuery1();
$this->your_model->doQuery2();
$this->your_model->doQuery3();
Or (and this is what I would do), create a wrapper method in the model that runs those three queries.
So you can do
$this->your_model->runQueries();
where
function runQueries() {
$this->doQuery1();
$this->doQuery2();
$this->doQuery3();
}
This makes it more malleable to later change.
Finally, as for your statement 'as much of the logic should be in the controller as possible', this actually goes against the school of though of skinny controller, fat model that some people subscribe to. As any other school of thought, it is not set in stone.
First of all: slapping on a framework on exiting application - always a bad choice. Frameworks do not make you application better. They are there to make development faster.
Also, you have to understand that CodeIgniter is not really implementing proper MVC. Instead it is mimicking Rails architecture and naming conventions. It's actually closer to MVP pattern.
In any case, controllers must be as light as possible.
If implementing proper MVC or MVC-inspired pattern, all of the domain business logic would be in thee model layer and all of presentation logic in the views. Controller would be only passing relevant data to model layer and current view.
When writing code for CodeIgniter, you should keep as much domain logic as possible in the "models" and most of the presentation logic in the view helpers.
What in CodeIgniter are called "models" are mostly domain objects, which sometimes are merged with storage logic (violating SRP) to implement active record pattern.
The best option for you would be to create higher level "models" which would act as services and would separate the controllers from direct interaction with CodeIgniter's "models".
In your described situation, where you have to make two requests to different "models", this operation would be done is the such services. And the service aggregate the data from both "models" and pass it to the controller.
For example: if you are registering new user, you would have to perform two operations - create an entry for the account in storage (usually - database) and sent user notification to email. Those both operations can be contained in the service, that is responsible for user management.
Controller would only ask the service to crate new account. Fact that service would perform multiple operations( initialize a User "model", assign data to it, store it and then on success, initiate Mailer and send an email) is completely irrelevant to the controller. Controller would only want to know the list of errors (if the list was empty, everything was ok).
.. my two cents.
I'm using ZF for an MVC application and am massively confused about how my code should be structured.
I've got a procedural application which is basically 1 huge long file with functions for everything I want my app to do.... like: getUsername($id) etc. So now I'm remaking the entire thing in ZF because my current codebase is unworkable, crap and hard to debug.
I'm new to MVC and massively confused about how it should all be laid out, what should talk to what etc. So I know about Views about being templates and Controllers needing to be skinny and that you should have fat models but I'm confused where the logic needs to be.
I'm making a game and there usual objects like.... Users, Villages, Armies, MapSquares, Resources etc.
If I was thinking about it completely by theory I would just say:
1 User Object contains many villages, each village belongs to one square and contains an army (which contains many units).
So what I thought was that my Models should contain no logic, just a list of get and set functions for retrieving the data and that the logic for processing, asking questions should be done inside the Mapper... like:
$villageMapper = new VillageMapper();
// Get village from database using mapper
$village = $villageMapper->getVillage($id, new Village());
When I want to determine say the outcome of two villages attacking one another, where would this be done? Would I do something like:
$outcome = $villageMapper->determineAttackOutcome($village1, $village2);
Or would I have say... a battle object with a bit of logic inside it?
$battle = new Battle();
// Add participants
$battle->addAttacker($village1)->addDefender($village2);
$outcome = $battle->performAttack();
// Save village changes cause of battle
$villageMapper->save($battle->getAttacker());
$villageMapper->save($battle->getDefender());
I have a bunch of DbTable php files, which I guess all the Database code lives in... so my question is: Should my Mapper objects ONLY really be used for things like, getting and saving to the database?
Thanks, Dom
There are many different interpretations of MVC, but this is how I understand it:
Model: Contains virtually all the logic pertaining to a specific item. Each thing that must be modeled (in your case users, villiages, etc) has a model to go with it. The model has functions to get data out and put data in (i.e. getters and setters). The model also does error checking and such and makes sure that nothing conflicting is entered in.
View: Has no logic whatsoever. In a web application, this is literally just the thing that says where to put stuff on the page. In some frameworks you feed a view a model (i.e. ASP.NET MVC3), in other frameworks (like Savant3 for php) it can be fed anything. The controller generally feeds the view, but the if the view is given a model it just reads from the model and doesn't write to it.
Controller: Controls the interaction between the user and the model. When the user does something, the controller translates that into things that the model must do. For example, if you say to the program "Please move my character 6 spaces north", the controller will say "Is there anything to run in to 6 spaces north of here?" and if it sees the spot is clear it tells the character model "Move yourself 6 spaces north". After doing that, it will send data to the view about whatever should be displayed as a result of that. Most of the actual logic implemented in a controller should be user-model instead of model-model. The interactions between models can be either taken care of by methods in individual models or other models that encapsulate some sort of behavior or interaction.
So, on to your implementation:
I would make a battle object (which is a model) whose constructor takes two villages or whatever is fighting. It would have a method called execute or doBattle or something that the controller would call and then the battle object would perform its logic to decide the outcome and update the status of the combatants (i.e. lowering hp, giving experience, etc). It would return to the controller the result so that the controller knows what to do (i.e. if the controller needs to forget about a model because it died, it would tell it that). This return value could also be the thing sent to the view to tell the outcome of the battle.
Some of your models (such as user, village, etc) would be kept in the database and so the model would know how to map itself to that database (or it would talk to another layer that knows how to map it) and also take care the exact implementation of updating the database and stuff (the controller would call the actual method to "save", but the model would be the only thing knowing what goes on behind the scenes). Other models (such as battle) don't need to exist in the database since they are just logic encapsulating some interaction.
Having a fat model means then nearly all of the logic exists within the model.
Some sugesstions...
If you are doing Domain Driven Design (http://en.wikipedia.org/wiki/Domain-driven_design) your village object could be an aggregate root that manages the business logic of that village.
A battle could also be an aggregate root that consists of two (or more) village objects, or a service that takes in two village objects and returns an "outcome" object. You could also do something along the lines of $village->attack($anotherVillage) that could return a battle object that you may then persist.
I would suggest following Domain Driven Design and the Repository pattern when it comes to creating and persisting these business objects http://msdn.microsoft.com/en-us/library/ff649690.aspx
Datamapper should only be used for storing and retrieving data from your database and mapping that data to your domain objects (Users, Villages, Armies, MapSquares).
You could put your logic inside your domain objects, but I like to use a service layer instead.
In your controller your would do something like:
function attackAction() {
$gameService->doVillageBattle($villageId1,$villageId2);
}
GameService would look like:
doVillageBattle($villageId1,$villageId2) {
$village1 = villageService->getById( $villageId1);
$village2 = villageService->getById( $villageId2);
if ($village1->getStrength() > $village2->getStrength()) {
$village1->winBattle();
$village2->looseBattle();
$villageService->save($village1);
$villageService->save($village2);
}
}
And finally VillageService would have:
function save( $village ) {
villageMapper->save( $village );
}
So controllers talk to services only, and services talk to each other or to datamappers logically associated with them. Services host most of the "business logic" and are database independent. Datamappers are independent of services & controllers ofcourse.
I'm testing CodeIgniter, and trying to create a simple blog. The video tutorial on the CodeIgniter site is nice, but very incomplete. I'm not too familiar with the MVC structure, and I am wondering exactly how a model is used. For instance, I'm currently doing the "admin" portion of my blog, which allows you to create, delete, and modify entries. The view only contains xhtml, and the controller takes care of the rest. What should be in the model? Does everything database related occur in the model (i.e. inserts, updates, selects, etc.)?
Depends who you ask.
Some people like to put as much as possible in the model (validation, data retrieval, etc), and have the controller just poke it to get the data it needs, which it then hands over to the view.
Think about it like this: if you have more than one controller accessing a single model, then shouldn't common things between them be in a common place (as long as that common thing actually has something to do with the model)?
The Model should contain everything database related, and perform all of the basic CRUD operations (Create, Get, Update, Delete).
The Controller should handle all communication between the model and the view. So for example, if you have a form for adding a new post, you should have a view for that form, which is called from a controller. The Controller would check to see if anything has been submitted, and if something has, call the create/insert method from the Post Model.
For me, model is a where I do all 'dirty' work for my data. I fetch, insert, update data to database, all in a model. I create 1 model for 1 table in the db.
Controller will be logic central for a page that I build. It need as slim as possible. If a function go beyond 1 screen, then it's too long (except if it do form validation which is must be done in controller). This is where Model come to play. Controller just pass the data into model. I do checking, processing, and formatting the data in model. My controller then fetch processed data from model, pass it to view, finish.
model = is object that "talking with your database"
view = is object that building user interface
controller = is the commander .. he got command from user and then he pass it on the model and serve to the user through view.
to create a simple blog, try to read Codeigniter getting started. it will help you a lot after you watch the video. the codeigniter references are good documented and well explained. try that first.