• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Not grokking models, please help

#1
[eluser]KingSkippus[/eluser]
Hey all, I've been using CodeIgniter for a while now, but I have to admit, most of the time in my Model classes, they are just shuffling around arrays. For example, if I have an employee "object," in CodeIgniter that object is almost always just an associative array of key-to-value pairs. My Model object just reads and writes those arrays to and from the back-end database.

I know in my heart that this is not really how an MVC model is supposed to work, but CodeIgniter doesn't really seem to adhere to what my concept of a model is. Take the example given in the User Guide. First, we have a class, Blogmodel, that extends the CodeIgniter model class:

Code:
class Blogmodel extends Model {

    var $title   = '';
    var $content = '';
    var $date    = '';

    function Blogmodel()
    {
        // Call the Model constructor
        parent::Model();
    }

So far, so good. In theory, I should be able to instantiate a Blogmodel class and reference its properties, such as $myblog->title, $myblog->content, and $myblog->date. However, right after that in the code, we have the following function defined:

Code:
function get_last_ten_entries()
{
    $query = $this->db->get('entries', 10);
    return $query->result();
}

Conceptually, I'm thinking that this makes a couple of pretty serious mistakes. First, if Blogmodel really is supposed to be a blog-class object such that we access properties and methods of it, this should really be a static function. After all, why would we call a function like get_last_ten_entries() on a specific instantiation of a Blogmodel object?

Second, this function doesn't return an array of Blogmodel objects, which I would intuitively think that a method named get_last_ten_entries() should. Instead, it returns an array of database query results. If we're lucky, the database column names match up with our model properties and all is good. But what if the database columns are named, I dunno, display_name, post_content, and timestamp instead? Now, if we're accessing an honest-to-god Blogmodel object, we have to use $myblog->title. But if we call $last_ten = $myblog->get_last_ten_entries(), each array element will have to be accessed as $last_ten->display_name. This is extremely confusing.

Still, I could work around that. I could define a static get_last_ten_entries() function that returns an array of Blogmodel objects, except that there's one more sticking point that's kind of gumming up the works. That is that when you call $this->load->model('Blogmodel'), it actually instantiates a Blogmodel object and assigns it to $this->Blogmodel. Even if I don't really need an actual Blogmodel object right now because I'm going to be calling a static function to create what I need for me, I've got an unitialized "throwaway" one anyway. If I call $this->Blogmodel->get_last_ten_entries(), I'm actually going to have eleven objects--the ten created by get_last_ten_entries(), plus the one created when I called $this->load->model('Blogmodel').

Is there any way of accessing static methods within a model without actually instantiating the model object itself?

Alternatively, one could look at Blogmodel merely as an interface of shuffling around objects of some other class, say, blogpost objects. Using this philosophy, you would have code such as this:

Code:
class blogpost {
    var $title;
    var $content;
    var $date;
    // ...
}

$this->Blogmodel->get($post_id); /* Returns a blogpost object */
$this->Blogmodel->get_last_ten_entries(); /* Returns an array of ten blogpost objects */
$this->Blogmodel->save($post); /* $post is a blogpost object */
// ...

Of course, doing this, the Blogmodel object wouldn't have properties such as $title, $content, or $date in it; those would be contained in the blogpost class definition and objects.

I am curious, how do the CodeIgniter gurus use Models? Do you use them just to shuffle around associative arrays like I do now? Do you just suck it up and let it instantiate an unneeded object so that you can use the class to generate other real objects? Do you use the model as an interface to some other class? Or is there some best practice that I just haven't seen yet that I really need to be adhering to instead? Is there something coming in CodeIgniter 2.0 that addresses this better?

Any thoughts would be appreciated!

#2
[eluser]titoneo[/eluser]
I understand you, why a Model class can by a model itself (value object) and a handler objects class of their own kind?

Well, Models in codeigniter are based in Active Record pattern (they say it is a modification), and this pattern does things like that you have mentioned. I think that Active Record can't be called ORM , really is a wrapper on the database with an object-oriented touch. That is why you think you have somewhat 'merged' or 'mixed'.

I've worked with JPA in Java and uses objects as a model and then to handle other classes (ex: User modeling and UserJPA as the handler). Maybe something like what you want.

There are other languages like Ruby on Rails that have made use of this pattern,I think it's a pattern that should not reside in very large applications, but it helps a lot in small and medium-sized applications.

http://en.wikipedia.org/wiki/Active_record_pattern
http://guides.rubyonrails.org/active_rec...rying.html

#3
[eluser]tunesmith[/eluser]
I am pounding my head against the same problem. Right now I have a scheme that looks like:

Code:
$this->load->model('UserModel');
$user = new UserModel;
$user->getByID($userid);
$user->firstname = "Blah";
$user->update();

This is proving not to be ideal for several reasons. First of all, the $user variable is huge, full of all the codeigniter internals, and when you have an array of user objects, that gets frightening. Second, there's the wasted object, like you mention. Third, the model itself is wordy, including a routine that populates itself (its vars) from the results of the sql queries.

For that I'm considering switching back to the more approved away of doing things, but I don't like the feeling that it is encouraging me to devolve. The fact is that my webapp requires database entities that then contain several other database entities, and I'm used to structuring those as objects that have arrays of other objects. I'm not sure where to define these objects, since I want to keep the controller layer free of business logic - it seems an alternative approach would be to have a library for each model that would do the assembly somehow, and then pass those objects into the model layer, but I haven't really experimented with that yet.

#4
[eluser]WanWizard[/eluser]
All CI internals are there by reference, so they wouldn't take up (much) space.

If you want a rough estimate of the object size, do a memory_get_usage() before and after you created the object (due to lack of a sizeof() function), and calculate the difference.

As to the loading, CI's models are not designed to be loaded this way. Instead of trying to design this by yourself, maybe you should look at Datamapper (DMZ), which does exactly this.

#5
[eluser]mddd[/eluser]
I think it helps to think of a CI Model as 'the thing that handles User stuff' (in this case). That's different from 'the object that IS a user'.

WanWizard's tip is a good one, there are extensions that do this a lot more 'object like'. Although I think that in total memory usage those solutions might quickly get large too. Because if you really want to keep it consistent, every object will need its own model. So getting a list of users with some related properties will instantiate a lot of objects!

I think in many cases, CI takes the 'middle road' between separated objects, efficient building and small memory use.


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2019 MyBB Group.