Accessing CodeIgniter Models in Other Models - php

It used to be that within a CodeIgniter model you couldn't access another model.
$this->load->model('bar');
$this->bar->something();
Is this still valid, or have they changed it?

Those are some VERY long answers for a simple question.
Short answer: This is now fully supported. Cross-load away if you feel like it!

I strongly disagree with the notion that a "model" should only encapsulate a database table with simple CRUD operations. As noted in the Wikipedia article:
http://en.wikipedia.org/wiki/Model-view-controller#As_a_design_pattern
...that application layer is intended to do more than simply act as a single database table abstraction. Think about the meaning of the word "controller" -- it should act more as a director rather than being the entire application in and of itself. A "model" is a place for business logic. Most large scale applications in fact hold much of their business logic in the database itself (in the form of triggers, stored procedures, foreign keys, etc.).
I think the misunderstanding of what a "model" is is partly caused by the same (over-)hype of "MVC", without carrying with it much understanding of the concepts themselves. Kinda like how empty "AJAX" is, or even more easy, "Web 2.0". For better or worse, plenty of script kiddies have jumped on the MVC wagon, and since the simple howtos and example scenarios don't do much more than tell you to put your database code in the "model", the misuse of that layer as only a database abstraction has become commonplace. Now you read posts all over the Internet calling it "unpure", "dirty", "hackish" to put any business logic in a model. That's WRONG. Misinformed.
The easy example is to think about foreign keys: even if you only want your "model" to be a database model, if you want to be "pure", "correct" or what have you, you really should be enforcing referential integrity therein. Thanks to the lack of real foreign key support in MySQL for many years, web applications grew up without anyone worrying about referential integrity at all. Fits the script kiddie lifestyle I guess. Anyhow, for even this simplified view of a model to be able to maintain foreign key validity, a model then has to work with others (or, especially if a framework like CodeIgniter does not let you do so, you have to write queries to other tables, sometimes duplicating queries elsewhere - THAT is bad style).
Therefore, I believe this to be a shortcoming of CodeIgniter. I understand that it might not be an easy fix, but it's certainly a disappointing oversight.
So what I did was take the example code above and abstract it into a helper so that I now have a function that works almost identically to the normal $this->load->model() functionality. Here it is (put it into a helper that is auto-loaded and you can use it in any model):
/**
*
* Allow models to use other models
*
* This is a substitute for the inability to load models
* inside of other models in CodeIgniter. Call it like
* this:
*
* $salaries = model_load_model('salary');
* ...
* $salary = $salaries->get_salary($employee_id);
*
* #param string $model_name The name of the model that is to be loaded
*
* #return object The requested model object
*
*/
function model_load_model($model_name)
{
$CI =& get_instance();
$CI->load->model($model_name);
return $CI->$model_name;
}

It's possible, but not ideal and considered bad and more for "quick fix" than ideal or pure implementation.
class Location extends Model{
public function get($ID){
// Get main CI object handle and load model
$CI =& get_instance();
$CI->load->model('LocationType');
// Call new model functions using handle to main CI object
$CI->LocationType->setID($result->LocationTypeID);
$CI->LocationType->setTitle($result->TypeTitle);
$this->_locationType = $CI->LocationType;
//Other Stuff
}
}
Anytime you're using the main CI object like this is probably a bad idea. Try to re-think your layout and just pass data to/from your controller to the models.
http://codeigniter.com/forums/viewthread/69833/

You can load models from models as Phil Sturgeon says, but you have to be careful of dependencies if you load the models in the model constructor: if model A uses model B and model B uses model A, when you try to load one or the other, you'll go into an infinite loop.

In situations like this in Code Igniter I prefer one of two posiibilities:
1) Have model's attribute and setter like this:
class X extends Model {
var $Y_model;
public function setY($Y) {
$this->Y_model = $Y;
}
public function doItRightNow($a,$b) {
$list = $this->Y_model->getSomeList($a,$b);
// ...
}
// ...
}
And then use this setter before other methods to give an instance of other model so it can be used by methods.
$this->load->model('X');
$this->load->model('Y');
$this->X->setY($this->Y);
$this->X->doItRightNow($something,$somethingElse);
2) To have a parameter in method by which I will give an other model instance from controller.
class X extends Model {
public function doItRightNow($a,$b,$Y_model) {
$list = $Y_model->getSomeList($a,$b);
// ...
}
// ...
}
And use it like this:
$this->load->model('X');
$this->load->model('Y');
$this->X->doItRightNow($something,$somethingElse,$this->Y);
I think that these are more clean possibilities.
Which way to use depends on how many methods need to access other model. If there are one or two it might be better to give it as a method parameter. If more - I think it's better to have a class attribute and setter.
And in elegant way you can give one model or another depending on some condition - if they both partially implement same interface with the same kind of data returned (it's rarely useful, but it can be sometimes).

I think it's generally better the write libraries that access the models and then include the libraries in your model if need be.
For instance, if you needed to check if someone is authorized to go through with a certain CRUD action, you might want to include whatever authentication library you are using (its probably auto-included in most cases). You wouldn't necessarily want to access the model directly--it just seems dirty and improper.
I think the preferred way is to do what you need to do in your controller and pass the results from one model's method(s), if need be, to your other model's method(s).
Regardless, I can't see why it wouldn't be possible to include one model into another, per se. I don't think you can do it with the syntax you are showing, though. You would have to do it some other convoluted way. In any case, IMO, it's bad practice to include a model directly into another model.

In CI 2.0 you can just call one model directly from another.

Better to create a helper function instead of calling the function from another model so that it can be used in 2 models at a time and code can be reused.

Related

Monolithic Model

Background
This is a long and complicated question. I'm using php/MySQL as an example (since it's an actual example) but this could theoretically apply to other languages. Bear with me.
MVC Framework with no ORM
I'm creating an application that uses its own framework. For a variety of reasons, the following answers to this question will not be accepted:
Why don't you just use X framework?
Why don't you just use X ORM?
This application does its own queries (written by me) and that's how I'd like it to stay for now.
Business Logic?
"Business Logic" seems to be a meaningless buzzword, but I take it to essentially mean
The queries and the logic that builds the result set based on those queries
I've also read that the Model in an MVC should do all the business logic.
User.php is 884 lines
Now that I've gotten my app working fairly well, I'd like to refactor it so as not to have such abominations. User.php is essentially the model for Users (obviously). There are some responsibilities I see in it that I could easily pluck out, but a major hurdle I'm running into is:
How can I reconcile SOLID with MVC?
The reason that User.php has grown so large is because I do any query that requires a User member in that file. User is used for a ton of operations (it needs to do so much more than just CRUD), so any query that needs userid, username, etc. is run by a function in this file. Apparently the queries should be in the model (and not the controller), but I feel that this should definitely be split up somehow. I need to accomplish the following:
Create an API that covers all of these necessary queries in a compartmentalized way
Avoid giving access to the DB connection class when it's not necessary
Add User data to the view (User.php is doing that right now -- the view object is injected by a setter, which I think is also bad).
...so what I could do is create other objects like UserBranchManager, UserSiteManager, UserTagManager, etc. and each of those could have the relevant queries and the DB object injected to run those queries, but then how do they get the coveted User::$userid that they need to run these queries? Not only that, but how could I pass Branch::$branchid? Shouldn't those members be private? Adding a getter for them also makes that pointless.
I'm also not sure where to draw the line of how much an object should do. A lot of the operations similar but still different. A class for each one would be huge overkill.
Possible Answer
If I can't get any help, what I'll do (or at least try to do) is have a dependency injection container of some kind build dependencies for the objects above (e.g. UserBranchManager) and inject them into the relevant controller. These would have a DB and Query object. The Query object could be passed to low level models (like User) to bind parameters as needed, and the higher level models or whatever they are called would give the results back to the controller which would add the data to the template as needed as well. Some possible hurdles I see are creating proper contracts (e.g. the UserController should preferably depend on some abstraction of the user models) but some specifics are inevitably required, especially when it comes to the view.
Can anyone offer some wisdom in response to my rambling question?
Response to #tereško
He has provided a great answer not only here, but also at How should a model be structured in MVC?
Code
As requested, here is some extremely pared down code (basically services one request). Some important notes:
Right now, controllers are not classes, just files
The controller also handles a lot of the routing
There are no "view" objects, just the templates
This will probably look really bad
These are also things to improve, but I'm mostly worried about the model (User in particular since it's getting out of control):
#usr.php -- controller
$route = route();
$user = '';
$branch = '<TRUNK>';
if (count($route) > 0) {
if (count($route) > 1) {
list($user, $branch) = $route;
}
else {
list($user) = $route;
}
}
$dec = new Decorator('user');
$dec->css('user');
if (isset($_SESSION['user']) && $_SESSION['user']->is($user)) {
$usr = $_SESSION['user'];
}
else {
$usr = new User(new DB, $user);
}
$usr->setUpTemplate($dec, $branch);
return $dec->execute();
# User.php -- model
class User {
private $userid;
private $username;
private $db;
public function __construct(DB $db, $username = null) {
$this->username = $username;
$this->db = $DB;
}
public function is($user) {
return strtolower($this->username) === strtolower($user);
}
public function setUpTemplate(Decorator $dec, $branch) {
$dec->_title = "$this->username $branch";
// This function runs a moderately complicated query
// joining the branch name and this user id/name
$dec->branch = $this->getBranchDisplay($branch);
}
}
Questions about answers
Answer here:
You talk about leaving off caching/authentication/authorization. Are these important? Why aren't they covered? How do they relate to the model/controller/router?
The Data Mapper example has the Person class with methods like getExemption, isFlaggedForAudit .. what are those? It seems like those calculations would require DB data, so how does it get them? Person Mapper leaves off select. Isn't that important?
What is "domain logic?"
Answer 5863870 (specifically the code example):
Shouldn't these factory objects be abstractions (and not rely on creation via new) or are these special?
How would your API include the necessary definition files?
I've read a lot about how it's best for dependencies to be injected in the constructor (if they're mandatory). I assume you set the factories in this way, but why not the objects/mappers/services themselves? What about abstractions?
Are you worried about code duplication (e.g. most models requiring an _object_factory member in their class definition)? If so, how could you avoid this?
You're using protected. Why?
If you can provide any specific code examples that would be best since it's easier for me to pick stuff up that way.
I understand the theory of what your answers are saying and it's helped a lot. What I'm still interested in (and not totally sure of) is making sure that dependencies of objects in this API are handled in the best way (the worst would be new everywhere).
Dont confuse SOLID (You can get a good explanation of what it is on my blog at: http://crazycoders.net/2012/03/confoo-2012-make-your-project-solid/
SOLID is great when considering the framework that goes around the application you are trying to build. The management of the data itself is another thing. You can't really apply the Single Responsibility of the S of SOLID to a business model that RELIES on other business models such as User, Groups and Permissions.
Thus, you have to let some of the SOLID go when you build an application. What SOLID is good for, is to make sure your framework behind your application is strong.
For example, if you build your own framework and business model, you will probably have a base class MODEL another for DATABASEACCESS, just remember that your MODEL shouldn't be aware of how to get the data, just know that it must get data.
For example:
Good:
- MyApp_Models_User extends MyApp_Framework_Model
- MyApp_Models_Group extends MyApp_Framework_Model
- MyApp_Models_Permission extends MyApp_Framework_Model
- MyApp_Framework_Model
- MyApp_Framework_Provider
- MyApp_Framework_MysqliProvider extends MyApp_Framework_Provider
In this good part, you create a model like this:
$user = new MyApp_Models_User(new MyApp_Framework_MysqliProvider(...));
$user->load(1234);
This way, you will prevent a fail in the single responsibility, your provider is used to load the data from one of the many providers that exist and your model represents the data that you extracted, it doesn't know how to read or write the data, thats the providers job...
Bad way:
- MyApp_Model_User
- MyApp_Model_Group
- MyApp_Model_Permission
define('MyDB', 'localhost');
define('MyUser', 'user');
define('MyPass', 'pass');
$user = new MyApp_Models_User(1234);
Using this bad method you first of all break the single responsibility, your model represents something and also manages the input/ouput of the data. Also, you create a dependency by stating that you need to define constants for the model to connect to the database and you completly abstract the database methods, if you need to change them and have 37 models, you'll have TONS of work to do...
Now, you can, if you want work the bad way... i still do it, i'm aware of it, but sometimes, when you have crappy structure and want to refactor, you can and should work against a principle just to refactor correctly and slowly, THEN, refactor a little more and end up with something SOLID and MVC looking.
Just remember that SOLID doesn't apply to everything, it's just a guideline, but it's very very good guideline.
Well .. it depends on what is actually inside your ./user.php file. If i had to guess, you would be a situation, where your user "model" has too many responsibilities. Basically, you are violating single responsibility principle and not sure how to go about fixing that.
You did no provide any code .. so , lets continue with guessing ...
It is possible that your user "model" is implementing active record pattern. This would be the main source of SRP problems. You could watch this part of lecture slides. It will explain some of it. The point would be, instead of using active record, to go with something similar to a data mapper pattern.
Also, you might notice that some of the domain logic, which works with User class instances, seems to happen outside your "model". It might be beneficial to separate that part in a different structure. Otherwise you will be forcing the domain logic inside the controller. Maybe this comment could shine some light on the whole subject.
Another thing you might have crammed inside your user "model" could be parts of the authorization (no to confuse with authentication) mechanism. It could be pragmatic to separate this responsibility.
Update
You talk about leaving off caching/authentication/authorization. Are these important? Why aren't they covered? How do they relate to the model/controller/router?
Caching is something that you would add later in the application. The domain objects do not care where the data comes from. For that reason you can wither add the caching with in the service-level objects or inside the existing data mappers. I would advise to choose former option, because changing existing mappers might have unforeseen side effects. And because it would just over-complicate the existing mappers.
namespace Application\Service;
class Community{
public function getUserDetails( $uid )
{
$user = $this->domainObjectFactory->build('User');
$cache = $this->cacheFactory->build('User');
$user->setId( $uid );
try
{
$cache->pull( $user );
}
cache( NotFoundException $e)
{
$mapper = $this->mapperFactory->build('User');
$mapper->pull( $user );
$cache->push( $user );
}
return $user->getDetails();
}
}
This would illustrate a very simplified acquisition of user information based on user's ID. The code creates domain object and provides it with ID, then this $user ovject is used as condition to search for cached details or, if it fails, fetching that pulling that information from DB via the data mapper. Also, if that is successful, the details are pushed into the cache, for next time.
You might notice, that this example did not handle situation, when mapper cannot find such user with such ID in storage (usually - SQL database). As I said , it's a simplified example.
Also, you might notice, that this sort of caching can be easily added on case-by-case basis and would not drastically change how your logic behaves.
Authorization is another part, which should not directly influence your business logic. I already linked my preferred way for providing authentication. The idea is that, instead of checking for credentials inside controller (like here, here, here or here), the access rights are checked before you execute a method on the controller. This way you have additional options for handling the denial of access, without being stuck within a specific controller.
The Data Mapper example has the Person class with methods like getExemption(), isFlaggedForAudit() .. what are those? It seems like those calculations would require DB data, so how does it get them? Person Mapper leaves off select. Isn't that important?
The Person class is a domain object. It would contain the part of domain logic, that is associated directly with that entity.
For those methods to be executed, the mapper should at first load the data. In PHP it would look something like this:
$person = new Person;
$mapper = new PersonMapper( $databaseConnection );
$person->setId( $id );
$mapper->fetch( $person );
if ( $person->isFlaggedForAudit() )
{
return $person->getTaxableEearnings();
}
The names of methods in the PersonMapper are there as an example, so that you would understand, how the class is supposed to be used. I usually name methods fetch(), store() and remove() (or push/pull/remove ... depends on how much GIT have I been using). IMHO, there is no point to have a separate update() and insert() methods. If object's data was initially retrieved by mapper, then it is an UPDATE. If not - it is an INSERT. You can also determine it whether the value, which corresponds to PRIMARY KEY has been set or not (in some cases, at least).
What is "domain logic?"
It is part of the code which knows how to create an invoice and apply discount price for specific products. It's also the code which makes sure, that you do not submit registration form, you do not state that you have been born in 1592.
The MVC is made from two layers: presentation (can contain: views, templates, controllers) and model layer (can contain: services, domain objects, mappers). The presentation layer deals with user interaction and responses. The model layer deals with business and validation rules. You could say that domain business logic is everything in model, that does not deal with storage.
I guess there is no easy way to explain.
Shouldn't these factory objects be abstractions (and not rely on creation via new) or are these special?
Which "factory objects", where? Are you talking about this fragment ?
$serviceFactory = new ServiceFactory(
new DataMapperFactory( $dbhProvider ),
new DomainObjectFactory
);
$serviceFactory->setDefaultNamespace('Application\\Service');
That whole code fragment is supposed to be in bootstrap.php file (or you might be using index.php or init.php for that). It's the entry point for the application. It is not part of any class, therefore you cannot have *tight coupling" there. There is nothing to "couple with".
How would your API include the necessary definition files?
That fragment is not entire bootstrap.php file. Above that code are includes and initialization for autoloader. I am currently using dynamic loader, which lets classes from same namespace to be located in different folders.
Also, such autoloader is a development-stage artifact. In production code you have to use loader, which works with predefined hashtable and does not need to actually walk the tree of namespaces and locations.
I've read a lot about how it's best for dependencies to be injected in the constructor (if they're mandatory). I assume you set the factories in this way, but why not the objects/mappers/services themselves? What about abstractions?
What are you talking about ?!?
Are you worried about code duplication (e.g. most models requiring an _object_factory member in their class definition)? If so, how could you avoid this?
Did you actually LOOK at how old that code fragment in comments was ?!?!?
You're using protected. Why?
Because, if values/methods are defined with protected visibility, you can access them when you extend the original class. Also, that code example was made for old version of answer. Check the dates.
And no. I will not provide any specific code examples. Because each situation is different. If you want to do copy-paste development, then use CakePHP or CodeIgniter.

Where do I put a database query in MVC?

The last few days, I have extensively read books and web pages about OOP and MVC in PHP, so that I can become a better programmer. I've come upon a little problem in my understanding of MVC:
Where do I put a mysql_query?
Should I put it in the controller and call a method on a model that returns data based on the provided query? Or should I put it in the model itself? Are both of the options I'm providing total garbage?
Materials on the subject of MVC
You could have listed the books you were reading, because most (if not all) php books, which touch on MVC, are wrong.
If you want to become a better developer, i would recommend for you to start with article by Marting Fowler - GUI Architectures. Followed by book from same author - "Patterns of Enterprise Application Architecture". Then the next step would be for you to research SOLID principles and understand how to write code which follows Law of Demeter. This should cover the basics =]
Can I use MVC with PHP ?
Not really. At least not the classical MVC as it was defined for Smalltalk.
Instead in PHP you have 4 other patterns which aim for the same goal: MVC Model2, MVP, MVVM and HMVC. Again, I am too lazy to write about differences one more time, so I'll just link to an old comment of mine.
What is Model ?
First thing you must understand is that Model in MVC is not a class or an object. It is a layer which contains multitude of classes. Basically model layer is all of the layers combined (though, the second layer there should be called "Domain Object Layer", because it contains "Domain Model Objects"). If you care to read quick summary on what is contained in each part of Model layer, you can try reading this old comment (skip to "side note" section).
                            
The image is taken from Service Layer article on Fowler's site.
What does the Controllers do ?
Controller has one major responsibilities in MVC (I'm gonna talk about Model2 implementation here):
Execute commands on structures from model layer (services or domain objects), which change the state of said structures.
It usually have a secondary responsibility: to bind (or otherwise pass) structures from Model layer to the View, but it becomes a questionable practice, if you follow SRP
Where do I put SQL related code ?
The storage and retrieval of information is handled at the Data Source Layer, and is usually implemented as DataMapper (do not confuse with ORMs, which abuse that name).
Here is how a simplified use of it would look like:
$mapper = $this->mapperFactory->build(Model\Mappers\User::class);
$user = $this->entityFactory->build(Model\Entities\User::class);
$user->setId(42);
$mapper->fetch($user);
if ($user->isBanned() && $user->hasBannExpired()){
$user->setStatus(Model\Mappers\User::STATUS_ACTIVE);
}
$mapper->store($user);
As you see, at no point the Domain Object is even aware, that the information from it was stored. And neither it cases about where you put the data. It could be stored in MySQL or PostgreSQL or some noSQL database. Or maybe pushed to remote REST API. Or maybe the mapper was a mock for testing. All you would need to do, to replace the mapper, is provide this method with different factory.
Also, please see these related posts:
understanding MVC Views in PHP
testable Controllers with dependencies
how should services communicate between each other?
MVC for advanced PHP developers
Model and Entity Classes represents the data and the logic of an application, what many calls business logic. Usually, it’s responsible for:
Storing, deleting, updating the application data. Generally it includes the database operations, but implementing the same operations invoking external web services or APIs is not an unusual at all.
encapsulating the application logic. This is the layer that
should implement all the logic of the application
Here is the MVC Sequence Diagram which shows the flow during a http request:
In this case Model is the best place to implement the code realted to access database.
The model contains the domain objects or data structures that represent the application's state. [wikipedia]. So the model would be the place to make the database call.
In the 'classic' (lack of a better word atm) MVC pattern the view would get the current state from the model.
Don't make the mistake by saying that the model is for accessing the database. It's more than just accessing the database.
For one, don't use mysql_query() and family; they're being deprecated, so consider also learning about PDO and/or mysqli.
The model takes care of data handling; it provides an interface to the controller by which it retrieves and/or stores information. So this would be a primary place where database actions take place.
Update
To answer a question asked by the OP in the comments: "one generic model for the whole db or a model for each table/action?"
Models are meant to abstract away individual tables (although there are models that exclusively handle a single table); for instance, instead of asking for all articles and then query the usernames for the authors you would have one function like this:
function getArticles()
{
// query article table and join with user table to get username
}
How many models you will create largely depends on how big the project is and how inter-related the data is. If you can identify independent groups of data, it's likely that you'd create a model for each group; but this is no hard & fast rule.
Data manipulation can be part of the same model, unless you want a clear separation between read-only and write-only models (I wouldn't know of a situation that warrants this, but who knows).
To go even further, your model should not contain the database access code. This belongs to another layer outside the Model/View/Controller: this is called the persistence layer, which can be implemented using an Object-Relational Mapper such as the popular Doctrine 2 for PHP.
This way, you never touch any (my)SQL code. The persistence layer takes care of this for you.
I really advise you to have a look at a Doctrine tutorial, this is a really professional way to create your applications.
Instead of working with raw data loaded from the database, you create objects that hold your data, and the behavior associated with it.
For example, you might have a User class, such as:
class User
{
protected $id;
protected $name;
protected $privileges;
public function setName($name) { ... }
public function getName() { ... }
public function addPrivilege(Privilege $privilege) { ... }
public function getPrivileges() { ... }
}
You controller will only interact with objects:
class UserController
{
public function testAction()
{
// ...
$user = $em->getRepository('User')->find(123); // load User with id 123
$user->setName('John'); // work with your objects,
echo $user->getName(); // and don't worry about the db!
$em->flush(); // persist your changes
}
}
Behind the scenes, the ORM takes care of all the low-level work of issuing a SELECT query, instantiating your object, detecting modifications to your object, and issuing the necessary UPDATE statement!

My models all tend to look the same

I've noticed that all my models look very similar. Most of them tend to follow a pattern where they are collections of methods containing active record code that are just slight variations on one another. Here is an example:
class Site extends CI_Model {
public function get_site_by_id($id)
{
// Active record code to get site by id
}
public function get_sites_by_user_id($user_id)
{
// ...
}
// ...
public function get_site_by_user_id_and_url_string($user_id, $url_string)
{
// ...
}
// Non active record methods and business logic
// ...
}
This approach has worked fine for me but I'm wondering if there is a more elegant solution. It just doesn't seem right to me that I should have to create a new method every time I need to look up data in a new way. Is this common practice or am I missing a way to refactor this?
Strictly following your request, you could add an intermediate class between the main model class (CI_Model) and your class (Site), something like
class MyCommonMethodsClass extends CI_Model {
}
and you would extend it in your classes (Site), while putting the common code on it. That would work and could be somehow'elegant'. In fact at the end you would end up adding your basic crud, site adapted actions, to it.
Now, if that's 'clean', that's another thing. Again, strictly speaking the model does that. It takes care of common and 'advanced' getters. And yes, they almost always have the tendency to have the same code all around your website. The problem is that, although that looks nice in your code (less code) you're technically sacrificing abstraction between your business logic and the db. Are you a model purist or practical one ?
I think this is matter of opinion but I think best practice is to create some sort of Create, Retrieve, Update, Delete (CRUD) model which does many basic SQL functions like GetID, UpdateByID, GetById and so on.
CRUD models can only go so far in helping you with more modular queries. But it makes sense to call a function called GetId and pass it some parameters than to have different functions for each table.
As I say though, CRUD's can only go so far. For example it would make sense to have a function that queries a database users table to check if a user has verified and username & password match. As this is a unique and not an abstract function, it should have it's own function defined.
Also as a best practice, Logic and Database access should never be mixed in the same file.
It is common practice to have different methods to handle getting your data like that. The Single Responsibility Principal states that every object should only do one thing, by making multiple methods that get very specific data you are creating very maintainable and easy to debug code.
If you have multiple classes that are providing essentially the same functionality, then this would suggest that there may be something wrong with your class hierarchy (a so-called "code smell"). If they have similar interactions then that suggests that they are related in some way. If that's the case then the chances are they should all be inheriting from a common superclass that implements the functionality common to all your subclasses, with each subclass simply specializing the generalized functionality of the superclass.
The advantages of this approach are:
You're not repeating work (SPOT, DRY)
Code that interacts with the classes can be written in a more general way and can handle any object that inherits from the superclass (substitution)
I do not think there is any thing wrong with creating an 'base' model class to extend you other models by. If it is solid and well tested, it can make you life easier. What is the point of creating the same CRUD functions over and over again?
Another benefit of doing it is that you can have a base development repository that you clone to start all new projects.
If you need an example of how to do this then look at a question I previously asked.
You can also do the same with your controllers.

Using ORM classes directly from the controller in MVC, bad practice?

I've recently delved into using an ORM in my CodeIgniter application and one i've gone for is Propel. Now this gives me the power to basically use Propels classes as the 'Model' but is this bad practive?
So my controller code would be as follows:
<?php
class Page extends Controller {
function __construct() {
parent::__construct();
}
function index() {
$foo = FooQuery::create()->limit(10)->find();
$data['content'] = array('foo'=>$foo);
$this->load->view('home', $foo);
}
}
?>
I want to solve this issue before I carry on developing my application. An example of how I should do this would be very helpful if you do consider this to be bad practice please.
Thanks in advance
Yes, it's bad practice.
The model should contain all of your data logic and abstract it all away from the rest of the program. To the rest of the application, the models should look like black boxes out of which it gets its data. If you use an ORM as your model, you're leaking the abstraction and tightly coupling your controller to your data layer.
Instead, create your models, and deal with the ORM in there. That way if you ever need to adjust your data model, you can just change it in one place (the model layer) and know that the abstraction will hold.
With the Query classes Propel now uses, I think the difference with a more "formal" Model becomes smaller and smaller. If this will become a library that you release into the world it would be an advantage to have an abstraction layer so you can have different backends, but if it is an in-house application I would just use the Query classes as your Model.
But remember that the Query classes are created to feel like an actual object, and that they hide the relational part as much as they can. You can use this to your advantage. Check out this article about rewriting your SQL queries with Query methods, especially the third answer: move more and more into your Query class, so your Controller doesn't feel like it uses a database.
// Instead of this code in your controller,
// tightly coupled to your database logic
$books = BookQuery::create()
->filterByTitle('%war%')
->filterByPrice(array('max' => 10)
->filterByPublishedAt(array('max' => time()))
->leftJoin('Book.Author')
->where('Author.Name > ?', $fameTreshold);
// You would use this code in your controller
// and create small methods with the business logic in the BookQuery class
$books = BookQuery::create()
->titleContainsWord('war')
->cheap()
->published()
->writtenByFamousAuthors();
I've found this to be an occasional necessary evil when your ORM is following the Active Row pattern.
The problem I always run into is that a model only represents a single instance of the data structure. It makes no sense to add collection retrieval methods into the model.
This is where I have historically used a service layer to handle pulling in collections of models. Although to be honest lately I've simply wrote a controller helper object that just abstracts my table object.
It depends a lot on what you are doing and why. in this example you are putting a limit clause in the query - is that business or display logic? From my perspective, it's hard to argue that it's business logic - that I get back 10 elements is irrelevant to the model - that's just how many I think makes sense to using in one page. If you want that rule to be consistent across controllers, you could set some config value to enforce consistency. But putting it in the model just makes the model needless large (there's a difference between fat models and obese models)
I would say that limits, orders and offsets are often not business logic. Even a simple where might or might not be depending on the case. If there's a join there, it's a sign that something is wrong.
The example from Jan Fabry is mostly pretty good. filterByTitle looks about the same to me as titleContainsWord. filterByPublishedAt(array('max' => time())) is much worse than ->published(). In general, the less you controllers need to know about the inner data structure, the better.

Models in the Zend Framework

What are some of the ways you have implemented models in the Zend Framework?
I have seen the basic class User extends Zend_Db_Table_Abstract and then putting calls to that in your controllers:
$foo = new User;
$foo->fetchAll()
but what about more sophisticated uses? The Quickstart section of the documentation offers such an example but I still feel like I'm not getting a "best use" example for models in Zend Framework. Any interesting implementations out there?
EDIT: I should clarify (in response to CMS's comment)... I know about doing more complicated selects. I was interested in overall approaches to the Model concept and concrete examples of how others have implemented them (basically, the stuff the manual leaves out and the stuff that basic how-to's gloss over)
I worked for Zend and did quite a bit of work on the Zend_Db_Table component.
Zend Framework doesn't give a lot of guidance on the concept of a "Model" with respect to the Domain Model pattern. There's no base class for a Model because the Model encapsulates some part of business logic specific to your application. I wrote a blog about this subject in more detail.
Persistence to a database should be an internal implementation detail of a Model. The Model typically uses one or more Table. It's a common but improper object-oriented design to consider a Model as an extension of a Table. In other words, we should say Model HAS-A Table -- not Model IS-A Table.
This is an example of IS-A:
class MyModel extends Zend_Db_Table_Abstract
{
}
This is an example of HAS-A:
class MyModel // extends nothing
{
protected $some_table;
}
In a real domain model, you would use $some_table in the methods of MyModel.
You can also read Martin Fowler's take on the Domain Model design pattern, and his description of the Anemic Domain Model antipattern, which is how many developers unfortunately approach OO programming.
I personally subclass both Zend_Db_Table_Abstract and Zend_Db_Table_Row_Abstract. The main difference between my code and yours is that explicitly treat the subclass of Zend_Db_Table_Abstract as a "table" and Zend_Db_Table_Row_Abstract as "row". Very rarely do I see direct calls to select objects, SQL, or the built in ZF database methods in my controllers. I try to hide the logic of requesting specific records to calls for behind Zend_Db_Table_Abstract like so:
class Users extends Zend_Db_Table_Abstract {
protected $_name = 'users';
protected $_rowClass = 'User'; // <== THIS IS REALLY HELPFUL
public function getById($id) {
// RETURNS ONE INSTANCE OF 'User'
}
public function getActiveUsers() {
// RETURNS MULTIPLE 'User' OBJECTS
}
}
class User extends Zend_Db_Table_Row_Abstract {
public function setPassword() {
// SET THE PASSWORD FOR A SINGLE ROW
}
}
/* CONTROLLER */
public function setPasswordAction() {
/* GET YOUR PARAMS */
$users = new Users();
$user = $users->getById($id);
$user->setPassword($password);
$user->save();
}
There are numerous ways to approach this. Don't think this is the only one, but I try to follow the intent of the ZF's design. (Here are more of my thoughts and links on the subject.) This approach does get a little class heavy, but I feel it keeps the controllers focused on handling input and coordinating with the view; leaving the model to do the application specific work.
Don't ever use Zend_Db_Table as your model. It just gets you into trouble. Either you write your own model classes which use Zend_Db_Table to talk to your database or you can read my blog post here for a hack that allows you to somewhat combine the "Model" class and Zend_Db_Table.
The main thing to not is that when you use Zend_Db_Table directly in your controllers you end up doing the same things in multiple places. If you have to make a change to some of that logic, you have to make a change in multiple places. Not good. My first professional project was done like this because I was the one in the company who had to learn how to use ZF and it's a total mess now.
I also tend to write helper functions into my classes for sophisticated fetches. Somthing like $table->doNameFetchAll() or $table->doOrderFetchAll().
I've been doing some research on Models for ZF and came across an interesting series of articles by Matthew Weier O'Phinney which are well worth checking out:
Using Zend_Form in your Models
Applying ACLs to Models
Model Infrastructure
It's not "production code" and a lot is left to the imagination, but it's a good read and has helped me quite a bit.
A model has nothing to do with the database. What if I am fetching data from an RSS feed or a SOAP service or reading files from the FS?
I put all these kinds of things in models. In that case, my model class might not extend anything. I'm about to write a model that uses methods of other models.
Skip ZF for the models part, there are much better solutions. The "M" in ZF's "MVC" is pretty much absent. Reading their docs they don't really mention models at all -- which is a good thing, it means you can use just about anything you want without writing lots of adapter code.
Take a look at Doctrine for models instead. It is quickly becoming the de-facto ORM for PHP.
You can do more complicated queries, check the Advanced usage section in the Zend_Db_Table manual page.
$select = $table->select();
$select->from($table,
array('COUNT(reported_by) as `count`', 'reported_by'))
->where('bug_status = ?', 'NEW')
->group('reported_by');
you can extend the Zend_Db_Table_Abstract class and add some useful methods to it. for example you can add a changePassword() method to your user class and manipulate it's data. or you can change the default __toString() method of your class, so you'll have a customized __toString() method that, let's say returns the whole contact information of the user (name, address, phone number) in a well formatted string. in your constructor you could populate your data into properties of your object. then use them like:
public function __toString() {
$data = $this->_name . ', ' . $this->_adderss . ', call: ' . $this->_phone;
return $data;
}
your model extends the Zend_Db_Table_Abstract just to ease the process of accessing its data, but the functionality you could have on that data is all up on your creativity and need.
I recommend you the book "php|architect's guide to programming with zend framework" by Cal Evans. the book is very informative and easy to read. chapters 4 and 6 are going to be useful for this matter.
A database entity is not the only kind of model component. As such, it doesn't really make sense to speak of models (in plural) - Your application has one model, which contains a multitude of components. Some of these components could be table gateways (And thus extend from Zend_Db), while others would not.
I recommend that you get hold of the book Domain Driven Design by Eric Evans, which does an excellent job of explaining how to construct an object model.
I use Propel 1.3 instead of Zend_Db_Table.
It's tricky to setup, but awesome.
It can examine your database and auto-generate all your models.
It actually generates 2 levels and 2 types of model.
Examples for 'user' table:
Level 1: BaseModel & BasePeer: these get overwritten every time you regenerate your ORM. i.e. BaseUser.php & BaseUserPeer.php
Level 2: StubModel & StubPeer: these don't get overwritten. They're the ones you customize. i.e. User.php & UserPeer.php
Type 1: Model - for basic CRUD operations, not queries i.e. User.php
Type 2: Peer -- for queries. These are static objects. i.e. UserPeer.php
So to create a user:
$derek = new User();
$derek->setFirstName('Derek');
$derek->save();
To find all dereks:
$c = new Criteria();
$c->add(UserPeer::FIRST_NAME, 'Derek');
$dereks = UserPeer::doSelect($c);
http://zfsite.andreinikolov.com/2008/08/zend_db_table-time-overhead-about-25-percents/
Bit of a catch 22, Zend_Table is nice in principle, but generates some performance overheads (without caching)...

Categories