Advanced Models

  1. A Model class should extend BaseModel, and the corresponding table in the database should match the name of the class, in lowercase. Note that if you have a Task class, the table in the database should be named task as well, not tasks.
  2. BaseModel has an id and a created attribute, both of which should exist in the table. id should be the auto-incrementing primary key. created should be a datetime file, and automatically gets set to the current time when the object is first created. If you don't required this filed, you can leave it out of your table, and it will be ignored.
  3. Below is a sample class for a "task" item that we would save if we were building an online task list.
    class Task extends BaseModel { public $description; public $completed = '0'; public $dateCompleted; public function Item($values) { parent::__construct($values); } }
    This example has a simple field for a description, a 0/1 indicator for being completed, and a date for when the task was marked as completed. The table in your database that represents this model would have a ddl as follows:
    CREATE TABLE `task` ( `id` int(11) NOT NULL auto_increment, `completed` int(1) NOT NULL default '0', `description` varchar(255) NOT NULL default '', `created` datetime default NULL, `dateCompleted` datetime default NULL, PRIMARY KEY (`id`) )
  4. BaseModel provides basic methods for persisting models to your database:
    • save(), update(), delete()
  5. There are also several methods for retrieval from the database:
    • get(), getAll(), getByField(), getByQuery()
    These are static methods that are accessed through the Model you are trying to retrieve. For example, if you wanted to retrieve a "task" from the database by an id, 23, it would be as follows:
    $myTask = Task::get(23);
    There is a caveat to calling these "get" methods in php. Due to the fact that they are static methods, when you call them on a subclass of BaseModel, like your "Task" class, during execution of the method in BaseModel, there is no reference to the fact that you called it through your sublcass, "Task" (Task::get(23)). This is just the way PHP handles static method inheritance. The way around this is to override the "get" method in the subclass, "Task", and call the superclass method, but passing in the current classes name, using the __CLASS__ accessor in php. This can be a bit confusing, so to help alleviate the issue, it is recommended to implement a "Retrievable" interface on your model, which enforces the overriding of the "get" and "getAll" methods, which are the most commonly used. With these additions, your class would now look as follows:
    class Task extends BaseModel implements Retrievable { public $description; public $completed = '0'; public $dateCompleted; public function Item($values) { parent::__construct($values); } public static function get($id) { return parent::get($id, __CLASS__); } public static function getAll($searchArray=array(), $sortArray=array()) { return parent::getAll($searchArray, $sortArray, __CLASS__); } }
  6. Validation is often very important when dealing with Models. This is handled by creating a validate method in your model, and checking whatever is required. If there are no errors, return true, otherwise, return an array of error messages. This validate method would typically be called from your Controller performing a save or update, and if errors are returned, they can be handled/displayed appropriately. AdroitAlertsHandler is a class that can help with handling alert and error messages, and will be covered at a later point. Below is an example of how a validate method might look for our "Task" class:
    public function validate() { $errors = Array(); if($this->description == '') $errors[] = 'An Item must have a description.'; return count($errors) == 0 ? true : $errors; }
  7. The great thing about Models, is that they are the perfect place to encapsulate logic pertenant to that object. Martin Fowler has a great article on the anti-pattern of this practice, AnemicDomainModel. Striving to be a good OO programmer, we would place a method on our "Task" object that would change its state from completed, to incomplete:
    public function toggle() { if($this->completed === 1) { $this->dateCompleted = null; $this->completed = 0; }else { $this->dateCompleted = date('Y:m:d H:i:s'); $this->completed = 1; } }