Warning: This post started as a self rant. One of those rants that shouldn’t be directed outwards, only inwards. You know, one finger pointing forwards, three point back and all that? Well hopefully this should be someone tamer than it’s purer form.
A class should be written to describe an object. An object, one single entity. A class is a form waiting to be filled in. A class is not a half filled form, as an object is not a tray full of forms. A class may have methods that manipulate or persist these values, it may even store meta data, but it only knows about itself.
class Model_Todo_Item extends Model {
public $text = NULL;
public function save()
{
// Do SQL
return $this;
}
}
$todo_item = Model::factory('Todo_Item');
$todo_item->text = 'I must do the dishes';
$todo_item->save();
Above $todo_item represents one item, it does not describe a full todo list, we just want to describe an individual object, in this case, a list item. We can save this object. We can set $text. That is all. If you want to protect the modification of $text, you can do this with encapsulation:
class Model_Todo_Item extends Model {
protected $_text = NULL;
public function get_text()
{
return $this->_text;
}
public function set_text($text)
{
$this->_text = $text;
return $this;
}
// ...
}
My model can get text, it can set text and it can save.
Model::factory('Todo_Item')
->set_text('Must conquer the world')
->save();
I didn’t even need to create a variable above, with chaining (returning $this) you can do things quickly and neatly.
Let’s try something else:
class Model_Todo_Item extends Model {
protected $_text = NULL;
public function __construct($id)
{
// Load from ID
}
// ...
}
My model can be constructed with an $id which loads from database using this as the primary key. Have a looksie:
Model::factory('Todo_Item', $id);
// Or
new Model_Todo_Item($id);
We can create helper methods too, these will likely be static because they just do some verbose stuff, they do not require initialisation of another object. Most importantly though, they do what they say on the tin:
class Model_Todo_Item extends Model {
public static function create($text)
{
return Model::factory('Todo_Item')
->set_text($text)
->save();
}
// ...
}
My model has a handy method to create a new todo item:
Model_Todo_Item::create('Run home tonight');
That’s a handy shortcut!! How about some more shortcuts:
class Model_Todo_Item extends Model {
public static function find_all()
{
// Do SQL and load into individual Model_Todo_Item's
return array(/** Model_Todo_Item **/);
}
// ...
}
My Model can find all items and return an array of objects.
foreach (Model_Todo_Item::find_all() as $_item)
{
echo $_item->get_text().'<br />';
}
So my Model can do a few things now. This is how Models should be conceived and perceived (in my opinion), at least domain models. Everything should just make sense. A model should not require something likes this:
$m = new My_Class_For_Something;
$m->find_by('field', 'value');
$m->do_my_find();
foreach ($m->get_list() as $_something)
{
echo $_something['access_like_an_array'];
}
That could (and should) be like this:
foreach (My_Class_For_Something::find_by('field', 'value') as $_item)
{
echo $_item->property;
}
Code should be written in small manageable chunks. Heavy work should be categorised and split up into logic domains, then placed in their appropriate models. Any logic to do with your Model, should be found in your Model.
To create an element you should not require a million methods especially non-chaining ones:
$m = new Something('Random string to describe something');
$user = new User;
$m->assign($user->id);
$m->more_info(array('key' => 'value'));
$m->save();
That could so easily be this:
$something = Something::create(array(
'random' => 'value',
'key' => 'value',
'more' => 'value',
))
->assign(new User);
Have a bit of care for your work, put in a bit more logical though. It feels good to create quality, I tend to feel pretty shitty doing any less.