+1  A: 

Using an array to represent a set of records is a perfectly valid approach.

However the property image_url directly depends on the value of another property, so it doesn't make sense to store it as a separate field. Just calculate it on the fly, in your case you'd have to do that in the get_property method.

On the other hand should the model really be responsible for dealing with URLs? I don't think so. There should be a method outside the model that takes the Biography_model object and generates the URL of the image based on its image_file_name. If you already have some routing module responsible for mapping controllers to URLs, this code should probably land there.

Adam Byrtek
After a bit of thought, I have to agree that I don’t need an additional class property for the image_url, it is deterministic based on the image_file_name. I do have the routes defined elsewhere, but to keep the image_url handy with a biography_model object, I simply changed it to a method get_image_url() which returns the link. But it sounds like having a class method return an array of its own objects is considered acceptable? It’s what I’m really curious about, and have not found much to go on. - Wolf
Wolf
Yes, it's perfectly fine to have a class method that returns either a single model or a collection of models satisfying certain criteria. Such methods are often called *finder methods*. PS. Don't forget to accept some answer when you are satisfied with it in order to mark the question as answered.
Adam Byrtek
+1  A: 

Usually it's better for functions to have one job. Your get_biography() function has 2: get one biography and get all biographies. Consider splitting them up into 2 functions. Also there's no need for the multiple db access.

public function get_biography($id=null)
{
    $this->db->where('id', $this->get_property($id))
    $query = $this->db->get('biography_content');

    foreach($query->row() as $key => $value)
    {
        $this->set_property($key, $value);
    }
}

public function get_biographies()
{
    $biography_list = array();

    // don't limit this query to just id's - get everything
    $query = $this->db->get('biography_content');

    // For each record, return a new biography_model object
    foreach($query->result() as $row)
    {
        $model = new biography_model();
        // set the properties you already have straight onto the new model
        // instead of querying again with just the id
        foreach($row as $key => $value)
        {
            $model->set_property($key, $value);
        }
        $biography_list[] = $model;
    }
    return $biography_list;
}

Also you might want to take advantage of php's __get and __set magic methods:

public function __get($property)
{
    if(!isset($this->$property))
        return null;

    return $this->$property;
}

public function __set($property, $value)
{
    if(!property_exists($this, $property))
        return;

    if($property == 'image_file_name')
    {
        $this->image_url = $this->get_bio_img_url($value);
    }
    else
        $this->$property = $value;
}

This will let you get properties on your model like this: $bio->title instead of $bio->get_property('title') while at the same time provide a place you can introduce new logic later.

rojoca
I confess I was not aware of the __set and __get magic methods. I found notes suggesting that there is high overhead with using these methods, so I modified the pages served by this biography_model and profiled the performance before and after changing to __get and __set and I really cannot measure or detect a difference. Also, point taken on breaking out get_biography function into two methods. For some reason I was focused on having the object set its own properties on instantiation, so I overlooked simply setting them directly as suggested. Thanks, -Wolf
Wolf