Adding Actions

Actions are methods which are defined inside a model. Because Agile Toolkit follows the principles of "Object Oriented" design, it properly implements encapsulation inside a single class. Basic methods such as save() and delete() are already implemented by the model parent class, but you are encouraged to add more methods:

class Model_Book extends Model_Table {
  public 
$table='book';
  function 
init(){
    
parent::init();
    
$this->addField('name');
    
$this->addField('isbn')->mandatory(true)->caption('ISBN');
    
$this->hasOne('Publisher');
    
$this->hasOne('Author');
  }
  function 
addMultipleBooks($data){
    
$this->unloadData();
    foreach(
$data as $row){
      
$this->set($row)->save();
    }
  }
}

It's highly suggested that your Business Logic would not rely on the existence of UI or any views.

You can call your actions like this:

$this->add('Model_Book')->addMultipleBooks($data);

Hooks

Agile Toolkit contains a system-wide implementation for "hooks". Models use hooks to allow you to perform actions before or after loading or save operations are taken place. The below example can show how normalization and validation can be implemented in Agile Toolkit.

class Model_Book extends Model_Table {
  function 
init(){
    
parent::init();

    
$this->addHook('beforeSave,afterLoad',$this);
  }

  function 
beforeSave(){
    
// manually update some fields before saving. This is to create a indexable field for full-text search
    
$this['book_search_field'] = $this['title'].' '.$this['descr'].' '.$this['author_name'];

    
// let's also perform some validation
    
if(strlen($this['book_name']<10))throw $this->exception('Name of the book is too short');

    
// normalization will modify field to match some internal rules
    
$this['book_url']=$this['book_url'] ?: preg_replace('/[^a-zA-Z0-9]/','-',trim($this['name']));
  }
  function 
afterLoad(){
    
$this['name'] = $this->api->_($this['name']); // wraps name through localization function
  
}
}

There are the following hooks available for the model (at least):

  • beforeLoad($model, $query) - called before loading SQL query is executed. You have a chance to modify that query. This is called for both model->load() and for iterating through model with foreach($model). This hook is great for applying extra options to your SQL query.
  • afterLoad($model) - called after data have been loaded from SQL. You can now access $model->get() and the model will appear to be loaded. Called for both model->load() and iterating. This hook is great for performing data manipulation and normalization.
  • beforeSave($model) - called when $model->save() is called. This is called inside SQL transaction, so database changes you perform here will be rolled back if save would be unsuccessful. This hook is great for performing data modification before it's been saved. You can check $model->loaded() to see if a new record is being stored or updated
  • beforeInsert($model, $query) - called when inserting new data and after the insert query is being formed. That query is passed as 2nd argument. This hook is great for changing insert query options.
  • afterInsert($model,$id) - called after insertion method is performed successfully, but before model is re-loaded. You can break out of this hook and return a substitute model. Great for overriding how model is reloaded after insert.
  • beforeModify($model,$query) - called before update SQL query is executed. This hook is great for changing update query options.
  • afterModify($model) - called after SQL query is executed but before reloading has taken place. Note that if you access set() / get() here it will be reloaded by a subsequental reload.
  • afterSave($model) - called after model have been successfully reloaded. This is the last hook to be executed before SQL transaction is finished with commit. Please note taht beforeLoad / afterLoad will also be called during the reloading of a model. This hook is great for hiding some fields from a model after they are being saved such as wiping your password field.
Few more recommendation on query use.
  • to perform additional validation use beforeSave().
  • to measure speed of your query use beforeInsert / afterInsert and beforeModify and afterModify respectively.
  • beforeLoad will be called once per query, but afterLoad may be called several times when iterating through results.
  • apply SQL options in beforeLoad, beforeInsert and beforeModify
  • if you want to divert the query to a different database connection beforeLoad, beforeInsert and beforeModify are good place, but you must enhance DSQL to support switching before databsae handles. If this is what you need, please discuss on Agile Toolkit Development Forum.

Non-relational models

Above hooks also are used for non-relational models, however instead of $query they will receive $id of the record which is about to be loaded or modified.