Welcome Guest, Not a member yet? Register   Sign In
Preferred model approach - instantiated or not?
#1

[eluser]tunesmith[/eluser]
Hi, I've been going back and forth between whether to do one of two different approaches with my models, and I'm a little stuck recognizing which is best given CI's structure.

Approach #1: Models have attributes refelecting database columns, and get instantiated in the control layer. Control layer sets attributes and has the model object call routines on itself. Some pseudo-code.

Controller:
Code:
$this->load->model('UserModel');
$user = new UserModel;
$user->FirstName = "Flibberty";
$user->LastName = "Bidget";
$user->insert();   // can return boolean for success/failure
echo $user->ID;

Model:
Code:
<?
class User extends Model {

var $ID;
var $FirstName;
var $LastName;

function insert ()
{
  // calls active record stuff, referring to $this->FirstName, etc.  
  // Set $this->ID to last_insert_id afterwards.
}

What I like about this approach is that it's the first approach I learned in other languages and frameworks. It's also a little more self-documenting in that you can see the database columns in the class's attributes. And it feels concise, I like writing $user->isLoggedIn() and $user->hasPermission($perm). What I don't like is that it feels a little more awkward to have static "list" methods in it like getUsersByFirstName($fname). One approach I maintained had a convention of having a sister *List class for any kind of method that wasn't appropriately called by an instantiated object. Like, UserList::getUsersByFirstName.

The other problem is that since User extends Model, each instantiated object contains a whole lot of extra stuff besides the database column information. It would be common to have a large array of User objects in other frameworks, but here it feels wasteful.

When I started learning CI I didn't instantiate and tried to use the object loaded from $this->load, but my models still had attributes reflecting db columns. I quickly ran into problems trying to loop multiple Users, because you couldn't unset a model easily.


The other approach seems to be more along the lines of:

controller:
Code:
$this->load->model('UserModel');

$array['FirstName'] = "Goofus";
$array['LastName'] = "Gallant";

$id = $this->UserModel->insert($array);

Accompanying it is a much sparser model that doesn't bother itself with database column attributes. Advantages are less typing in the model, you just sling arrays around. Disadvantages are that it's less self-documenting, and there's less flexibility in extending models, like extending a type of user. None of the methods really operate on "themselves", in that the object is just the instantiation of the CI model class with some table-specific routines, rather than an instantiation of a database table representation (meaning, the object doesn't have attributes reflecting database columns).

What is really the best approach here? Is the "CI way" the latter approach, or are there ways to code the former approach without running into some of the pitfalls? I've been considering switching from the former to the latter, but I'm not sure if I'll regret it.
#2

[eluser]clip[/eluser]
I started off my experience with ci using the second approach you listed. I have since switched to the first approach and I don't think I could ever go back. Using this approach makes my models feel more streamlined and consistent I do agree with your statement that coding each model was tedious(yes, was). I eliminated the tedious coding of the models by creating this handy little tool that generates my models for me.(shameless plug)
#3

[eluser]tunesmith[/eluser]
Yeah, that is generally a good approach when dealing with verbose models, using something that autogenerates them. But there are still some downsides compared with the static approach. For instance, in the static approach you can just pass in an array of only the values you want to update, and guarantee that the rest of the db columns will be left alone. In the approach of a verbose model, it dynamically creates its own sql query using every attribute, so it updates every column, which can cause problems if you set an attribute you didn't want to. Although, I don't personally mind that downside very much.

I do quite like the Active Record stuff. But you can't pass $this to the active record methods. Some good workarounds have been posted here, like having each model have a $this->fields array, and then just passing that to the active record methods. It's still not exactly OO though. I'm starting to look into DataMapper DMZ, that might be the best solution here - I haven't looked yet to see if the models are small or kitchen sink, though.

What might be best is to just create some models that don't extend Model, but can still access $db as something other than an object attribute. But, I'm still inexperienced with CodeIgniter. So I'm all ears if anyone knows of something that solves all this.
#4

[eluser]BrianDHall[/eluser]
You might check out Datamapper Overzealous Extention over in Ignited Code forum - it works just this way but handles your least-enjoyed cases like getUsersByFirstName($fname):

Code:
$user = new User();
$user->get_where('first_name', $fname);

foreach ($user->all as $u)
{
$u->first_name = $u->first_name . 'jacobjingleheimerschmidt';
$u->save();
}

It allows you to avoid trying to differentiate between insert() or update() needs (just use save()), it has lots of cool magic functions to help you get the data you want cleanly and concisely in one line of code (usually), and to top it off it also handles relationships (being ORM, after all). It is built on CI's use of ActiveRecord so you can always call SQL directly when needed.

DMZ also has an array extention that is just friggin' cool, it allows you to do things like:

Code:
if ($_POST)
{
$user = new User();
$user->from_array($_POST, '', true);
// 'true' allows auto-save, saving you a call to ->save(); Or if you prefer:
$user->from_array($_POST)->save();
}

All of which you could just program yourself...but why bother?

Free, open source, easily extendable, it allows all the positives of your first noted way of handling things but allows even shorter syntax than the second mentioned way of doing things.

I heart DMZ.
#5

[eluser]tunesmith[/eluser]
Sweet, thanks for the extra detail Brian, I think that'll be the direction I go for future development. As a plus it looks like I won't have to rewrite existing code that uses the old models.




Theme © iAndrew 2016 - Forum software by © MyBB