modeling associated models (DRY, KISS, SKINNY CONTROLLER AND FAT MODELS) - php

I have two Models:
Server (belongs to a Slave)
Slave (hasMany Servers)
In a Controller I need to get an array with information about a Server/Slave (and some additional informations, like business logic that can't be in Controller).. I thought to create a function in Server Model to build the array, and every field that I need from Slave I would just to call a function like this:
Model Server:
// I created this function for code easier to maintain
function getSlaveId($server_id){
$this->id = $server_id;
return $this->field('slave_id');
}
// Return the array that I need, with informations from Server and Slave
function getArrayByServerId($server_id){
$slave_id = $this->getSlaveId($server_id);
return array(
'slave_name' => $this->Slave->getName($slave_id)
// some other information that some did not even pull from some table..
);
}
as you can see, I created a function to pull a field from Server, because if one day that changes, I'll have to change only in one place .. the same goes for the Slave whose I'm thinking of using a function to pull each field too ..
So, the question is: should I to get Slave's info with a function for each field or there is another better way to do? (I need almost whole Slave's table info, except some fields..)

You could use the Containable behaviour which will pull the necessary information without complex logic like this. Using the behaviour you could make the request like:
$this->Server->find('first', array('conditions'=>array(...), 'contain'=>array('Slave')));
This way you don't make your models unnecessary fat (healthy are they :)) and you will take what is required. With containable you can get specific fields too.

Related

Is it ever right to call a PHP MVC model from a different model?

I am currently adding a notification feature to a website and need it to update it's data whenever a user is added to a table. The way I think is correct is to go through each of my controllers and whenever a call to the model is made that will change that table, I will follow that up with a second function call updateNotificationTable() or something like that.
The site is quite large however, and while I can make sure to follow all of these controller calls with an update function, I can easily see this being missed for any future changes that interact with the table.
It seems the most fool proof way to do this would be to include a function inside the model itself so that once it inserts or deletes a row from the table it would update the notifications there. The problem is that the notification process pulls data from a separate second model I would have to load up inside the starting model.
I don't believe it's supposed to work that way but the alternative would present problems too. In this instance would it be right to load another model inside my model to process the notification update?
edit: sample code
function addToTable(){
//There's probably a dozen or more functions like this scattered throughout various controllers, they all need to be followed by updateNotifications()
$this->other_model->Insert_stuff();
$this->updateNotifications();
}
function updateNotifications(){
$var1 = $this->model1->get_important_info();
$var2 = $this->model2->get_more();
$this->Notifications_Model->doTheUpdate($var1,$var2);
}
If I could instead take doTheUpdate() and have it directly call model1 and model2 to get it's required data then any future function that need to call $this->other_model->Insert_stuff(); will not need a follow up updateNotifications() call. If another programmer is working on it chances are good it won't happen.
There's probably a dozen or so controllers that I add this function to and call after various functions are executed. If Notifications_Model could directly call model1 and model2 then doTheUpdate

What does $model->save() do in PHP Yii?

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.

use dynamic entities in controller zf2 doctrine2

How can I use dynamic entity names in a controller action, in Zend framework 2 using Doctrine 2?
For eg.
public function indexAction()
{
return new ViewModel(array(
'albums' => $this->getEntityManager()->getRepository('Album\Entity\[dynamic_entity_name]')->findAll()
));
}
Also, in first place, can I even USE multiple entities in a single controller, like my case here?
The root of doing something like this is, I basically have two modes in my application, live and test, where the users can save data in either mode (something like sandbox and live modes of a payment gateway back-end).
I need to have two different tables, one for each mode; say for e.g., payment_test and payment_live tables for the payments that user makes.
So in my controller, based on the current mode (test or live) that user is using, the data should be retrieved from / saved to the respective entities (PAYMENT_LIVE or PAYMENT_TEST).
I believe checking conditions for the current mode at all the places is a bad bad idea, hence I will just set it in some CURRENT_MODE CONSTANT once, and then use it for using the entity name dynamically, something like:
public function indexAction()
{
return new ViewModel(array(
'payments' => $this->getEntityManager()->getRepository('Payment\Entity\Payment_'.CURRENT_MODE.')->findAll()
));
}
which will use Payment_live entity for live mode and Payment_test entity for test mode, based on value of CURRENT_MODE = "live" or "test".
Any thoughts how should I go about implementing this?
My first thought was: Why having two tables and not just an identifier to query the mode for. A field insire you table payments called payment_modus (could be a boolean for live true/false) or something.
Other than that, of course you can have multiple repositories in one controller.
$repo = 'Payment\Entity\Payment_'.$this->getCurrentMode();
$em->getRepository($repo);
Kinda difficult to answer since i don't really understand where your problem actually lies.

Zend_Db_Table joined queries vs database view

I was wondering what would be the best practices and the best way to achieve consistency while accessing your database data :
Current structure goes as follow
Data Access --> Business Logic --> Controller --> View
My data access layer is composed of a Zend_Db_Table, Zend_Db_TableRowset and a Zend_Db_TableRow for each table.
My business logic is stored in the model named based on a the table
Example of problematic query :
I want to get a specific user based on his username. To do so I have a user table and a role table (role.id is referred as role_id in the user table).
I don't want to have to use the findDependentRowset that will run additionnal queries for each row that get returned. (will get problematic in data grid that display the data as many rows can be returned).
The choices I have (getName() is used in this example to simplify, but it can be any processing) :
Make a custom join on the role table in the user table which will return an index array composed of associative array. In that case I can't call my getName() function defined in my Model_DbTable_User to build the name (first name + middle + last name). Even if I "cast" my array to a Zend_Db_Table_Rowset (or my custom table_rowset) I can't access my custom class method since I get a generic Zend_Db_Table_Row object.
Make a custom join but build the name using CONCAT() in my query at runtime, I still get an array but the name is build so I don't need the getName() method. But if I have specific logic to apply i'm stuck.
Make a view joining user and role tables in my database and create a new set of Zend_DbTable, Zend_DbTableRowset and Zend_DbTableRow. This way I can have specific logic in my database stack.
An ORM (propel or doctrine (1 or 2)), I have no experience with these, I might need more informations to make the right choice.
My alternate goal is to be sure I get consistency in my data structures
ie:
array all the way :
array(
array(row1),
array(row2)
);
object all the way
$row = $rowset->current();
$row->field;
Creating a view should be done regardless because it complements the other ideas more than it competes with them. The view will:
Abstract the database to something that you can more easily work with.
Be faster because there's no parsing.
Be accessible outside of your application.
Once you've created the views, you can choose a strategy that best solves the problem. If you're creating a form that represents a single entity, then an ORM is probably a good fit. But if you're displaying large lists of data or generating reports that contain many entities then using a declarative language like SQL is probably easier and would perform better.

MVC PHP: Data manipulation in View loop or Controller loop (ie. 1 loop or 2 loops)

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.

Categories