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.
Related
Hey Guys
I know Stackoverflow is may not the right place to ask, if there's another Stackexchange group where
this question fits better, then please tell me.
So, I'm trying to learn OOP. I think I understand it quite good, but there's one thing I really can't figure
out what the right way is, and thats the handling of database.
So, I'm confused a bit of what should go in which class.
Lets say I've a db class. Inside of this class I'm connecting to the database in a constructor. And now lets say
I've got a user class.
So now the question:
Where should I put in the query for example creating a new user? Should i create a method in the user class,
or should I create a method in the DB class? If in DB class, should it really be a method like create_user()
or should it more be something globally like query where I can pass in whatever query I want.
Here, for example a project from Github:
https://github.com/christran/PHP-OOP-Login-Register-System/blob/master/classes/user.php
As you can see, all query methods are in db.php and from user.php he's just calling this methods. So is this the right way to go?
Or doesn't it matter at all? May, any of those approches is "more" OOP than the other?
It's actually just really confusing me and I don't understand whats the better way. I've searched a lot, but never
found an article to this specific question.
So what I did, I looked for projects on Github and looked at their code, how they've solved the problem...
But with this method I just got confused even more, because you see both.
Is it just a preference of the coder?
I am really thankful for all your help. Have a nice day! :)
Here a little example of what I mean:
Query inside user class:
class user {
private function createUser() {
//SQL Query here (prepared statements etc...)
}
}
OR:
class user {
private function createUser() {
// Call to db.class to insert_method() ...
}
}
Basically, you are looking into ORM.
To answer your question specifically,
Should i create a method in the user class
This is possible, and is called Active record pattern, where an entity contains not only methods related to itself (like $user->getBirthday()) but also methods that related to database interaction (like $user->save()).
or should I create a method in the DB class?
This is impossible, as this class will become enormously big.
However, you can create a sister class for the every entity, that will be responsible for the database interaction. This approach is called Data Mapper pattern. For example, there is a User class that contains methods related to the user, and also a UserMapper class, that is inherited from abstract mapper class with generic methods $userMapper->save(), $userMapper->find() and such.
The createUser method that contains the query shouldn't be part of the User object, but neither of the database object. The first one is for business logic. The latter one is for managing the database method and providing generic functionality for executing statements. A different object inbetween those objects should be the one that takes the data from the user object and generate the queries for storing it in the database.
The term I think you're looking for here is ORM (Object-relational mapping).
This concept is about mapping objects to a different, incompatible structure, like a database.
There are ORM libraries/frameworks available for PHP which can do much of the work for you, and some of them are part of, or can be used with, popular MVC frameworks like Eloquent ORM in Laravel. For example, they will often provide the basic CRUD operations by implementing the SQL statements needed after you just configure the right database table.
In terms of OOP, you will often have an extra layer on top of it. So you got a business object User, which contains the rules for users, for instance rules it has to follow for a user name. The business object will enforce those rules and contain the general behaviour of a User object. For saving you make use of an ORM to save a user object to a specific database. The database logic is not in the User object itself. It shouldn't have to know about the specific queries to save itself, and maybe it shouldn't even be aware of concepts like loading and saving. It just contains logic and data, and other parts of the implementation are responsible for persisting that data (optionally using an ORM framework to make things easier).
I was starting a project today and after designing the database structure and how the data would be stored etc, I started the implementation. I am doing this on php, but the language isn't really relevant here, since my doubts are more architectured related or I guess, since I'm struggling more than I thought by implenting stuff in OOP on PHP. (Recently jumped on php, I've been coding in c++ and java before).
So, I started by creating my "User" class, simple as that, few attributes, and __construct, insert, update and delete methods. Those last 3, queries to the db.
Then this doubt came to my head, and I probably know the answer myself but I just don't find out.
I can now create instances and create new Users: $user = new User("John", 34) but, what if I want to edit the user "Dave"? Or I want to show all users. That method, for example, getAllUsers() which would return all users where would be implemented? Because it doesn't really belong to the class User does it? If it did, then how I would instance that method if I don't have any User instance?
I guess, I would need a class Users, or UserCollection which would be a collection of all the users, with the methods ´getCertainUser(id)´ and ´getAllUsers()´ which would return certain User or All of them, now then I would have a User I would be able to edit, right?
That being said, my questions is, how this problem should be addressed as the way to go, Am I complicating things too much? How this should be solved 'the correct way' in OOP. The times I've handled similar problems I've never used a database, so having a collection of users was the only way to store them, but having the database which stores the users feels redundant to have that collection of users.
Thanks in advance.
First, you are doing the right thing, by challenging yourself.
Obviously, there are many ways of doing things.
I highly believe that trying to keep concerns separated as much as possible and keeping classes small and simple are always two good guidelines when you want to write code that is easy to maintain and to test.
This would be one way of doing it :
To handle Models & Structures
Entity/User (Define the properties of a user)
Collection/User (implements ArrayIterator, just a structure)
To handle communication with your repository (db).
Repository/Mysql/User (implements getAllUsers, saveUser, deleteUser, etc.)
Those classes should implements common interfaces or inherit common abstract classes (if they share common logic).
For the basic persistency operation (update, delete, create), I have a little preference of moving them in the repository class instead of the entity. I prefer to avoid using "smart" entity objects. In my mind, it makes more sense. But, there are plenty of people who would disagree (and there is really no right or wrong here).
I have a Data Model structure similar to yours, where classes represent their table counterparts. In the case of retrieving multiple of a "User" or "Categories", etc, I have a static method inside the class, that returns instances of the class. In example:
class User{
public static function fetchUsersForBusiness(Business $business){
//fetch code here into variable $users from database...
$userObjs = [];
foreach($users as $userData){
$userObjs[] = new User($userData);
}
return $userObjs;
}
}
class Business{
}
The following code would return all the users that fit a certain criteria (in this case, a business they're associated with). I then return them as the objects themselves.
I've found this model to be fairly successful, and have used it in a multitude of languages including Java, PHP, and Swift. Hope it helps you.
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.
I am a 4 days old yii fan and I like it so much.
I have a special database table that can't be used by CActiveRecord directly. My solution is to subclass CModel to have my own logic for listing, creating, saving and deleting records. My new CModel subclass cant not instantiated; it seems that CModel requires more methods to be defined to allow creating an instance from it.
My question is: Is this the right approach to go or there are better ways? If yes, what are the missing methods to define to make my new class complete; not abstract
Thanks
I usually create my own classes to handle the so called 'logic' of the webapp that I'm building.
I place it in another folder (usually the logics folder) and auto import the directory from the config. The logic classes doesn't subclass from any Model
public class ProfitLogic { ... }
where inside the class(es) I implement functions that instantiates and use any ActiveRecord(s) that I need.
The reasoning for this is that when prototyping I often refine my database design, and I need to regenerate the ActiveRecords again :p
Your approach is fine generally speaking, and would be fine even if you were not "forced" to adopt it. I use a CActiveRecord subclass as the base for my models to provide additional custom functionality.
As for your other question, you only need to implement attributeNames() to be able to instantiate objects of your class.
However, why do you not subclass CActiveRecord directly instead of CModel? You can still override any and all methods you choose to. Is your database so dramatically different from the usual schemas that you won't be able to reuse any of the logic?
I'm fairly new to Yii as well, but have found that extending CForm, as in the default ContactForm model can be useful.
Not the best for having lots of heavy business logic, but it touches on your point of breaking out of the typical workflow.
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.