1 / 17

Behaviors in CakePHP 1.2

Behaviors in CakePHP 1.2. Making your models behave. CakeFest 08. Mariano Iglesias. Purpose of Models. Models encapsulate business logic The more models do, the less controllers have to They are not necessarily the PHP representation of a database table

totie
Télécharger la présentation

Behaviors in CakePHP 1.2

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Behaviors in CakePHP 1.2 Making your models behave CakeFest 08 Mariano Iglesias

  2. Purpose of Models • Models encapsulate business logic • The more models do, the less controllers have to • They are not necessarily the PHP representation of a database table • They keep our code more manageable and readable

  3. Purpose of Models • The skinny controllers / fat models approach • Taking it further: sexying up our application $comments = $this->Comment->find(‘all’, array( ‘conditions’ => array( ‘Comment.date’ => ‘<= ‘ . strtotime(‘-1 day’), ‘Comment.published’ => true ) )); foreach($records as $index => $record) { $records[$index][‘Comment’][‘by’] = $record[‘Author’][‘last’] . ‘, ‘ . $record[‘Author’][‘first’]; } versus: $comments = $this->Comment->last(‘1 day’);

  4. Keeping Models DRY • The fatter models get, the more DRY they need to be • DRYing models the 1.1 way: AppModel • Orginizing AppModel by hierarchy AppModel MyModel method() AppModel SluggableModel method() MyModel

  5. And then there was light: Behaviors • Behaviors are all about reusable model logic • They help us put models to diet: the skinny controllers / chubby models / athletic behaviors approach • They make our code even more readable, and help us solve the 1.1 AppModel multi-hierarchy problem

  6. And then there was light: Behaviors • There are already a lot of behaviors out there: • Acl • Bindable / Containable • Sluggable • SoftDeletable • Taggable • Translate • Tree • Upload

  7. Using Behaviors • Behaviors are attached to models through the actsAs model attribute: • A behavior can receive settings as an indexed array: class MyModel extends AppModel { var $name = ‘My’; var $actsAs = array(‘Bindable’); } class MyModel extends AppModel { var $name = ‘My’; var $actsAs = array(‘Bindable’ => array( ‘parameter’ => ‘value’, ‘parameter2’ => ‘value2’ )); }

  8. Using Behaviors MyModel OtherModel BindableBehavior • There’s only one behavior instance per CakePHP instance: • A model can use several behaviors • Behaviors can also be specified at the AppModel level • Fresh from the owen: attach(), and detach()

  9. Using Behaviors • Callbacks in behaviors: • beforeFind(&$Model, $query) • afterFind(&$Model, $results, $primary) • beforeValidate(&$Model) • beforeSave(&$Model) • afterSave(&$Model, $created) • beforeDelete(&$Model, $cascade) • afterDelete(&$Model) • onError(&$Model, $error) • Extending the model with methods in behaviors • Extending the new find syntax

  10. Getting inside behaviors • Naming your behavior classes and files • A simple behavior skeleton • The $settings behavior property class MyBehavior extends ModelBehavior { function setup(&$Model, $settings = array()) { } function cleanup(&$Model) { } } class MyBehavior extends ModelBehavior { var $settings; function setup(&$Model, $settings = array()) { } // ……… }

  11. Getting inside behaviors • Implementing callbacks in behaviors • Implementing model accesible methods in behaviors • Using other behaviors from a behavior: • App::import($behavior, ‘Behavior’) • Calling attach() and detach() class MyBehavior extends ModelBehavior { function beforeSave(&$Model) { $data = $Model->data[$Model->alias]; // ……… } }

  12. Getting inside behaviors • Modifying and extending the find syntax $Model->find(‘all’, array( ‘parameter’ => ‘setting’ )); class MyBehavior extends ModelBehavior { function beforeFind(&$Model, $query) { if (isset($query[‘parameter’])) { // ……… } } }

  13. Learning by example: SoftDeletable • Defining the purpose of the behavior • Identifying callbacks that need implementation: • beforeDelete: actual soft delete • beforeFind: get non soft-deleted records • beforeSave: disable soft deleted check before saving • afterSave: re-enable soft deleted check • Custom methods: • hardDelete • purge • undelete

  14. Learning by example: SoftDeletable • Taking care of initialization and cleaning class SoftDeletableBehavior extends ModelBehavior { var $__settings = array(); function setup(&$Model, $settings = array()) { $default = array('field' => 'deleted', 'field_date' => 'deleted_date', 'delete' => true, 'find' => true); if (!isset($this->__settings[$Model->alias])) { $this->__settings[$Model->alias] = $default; } $this->__settings[$Model->alias] = array_merge($this->__settings[$Model->alias], ife(is_array($settings), $settings, array())); } function cleanup(&$Model) { } }

  15. Learning by example: SoftDeletable function beforeDelete(&$Model, $cascade = true) { if ($this->__settings[$Model->alias]['delete'] && $Model->hasField($this->__settings[$Model->alias]['field'])) { $attributes = $this->__settings[$Model->alias]; $id = $Model->id; $data = array($Model->alias => array( $attributes['field'] => 1 )); if (isset($attributes['field_date']) && $Model->hasField($attributes['field_date'])) { $data[$Model->alias][$attributes['field_date']] = date('Y-m-d H:i:s'); } foreach(array_merge(array_keys($data[$Model->alias]), array('field', 'field_date', 'find', 'delete')) as $field) { unset($attributes[$field]); } if (!empty($attributes)) { $data[$Model->alias] = array_merge($data[$Model->alias], $attributes); } $Model->id = $id; $deleted = $Model->save($data, false, array_keys($data[$Model->alias])); if ($deleted && $cascade) { $Model->_deleteDependent($id, $cascade); $Model->_deleteLinks($id); } return false; } return true; }

  16. Learning by example: SoftDeletable function beforeFind(&$Model, $queryData) { // ……… if (!empty($queryData['conditions']) && is_string($queryData['conditions'])) { $fields = array( $Db->name($Model->alias) . '.' . $Db->name($this->__settings[$Model->alias]['field']), $Db->name($this->__settings[$Model->alias]['field']), $Model->alias . '.' . $this->__settings[$Model->alias]['field'], $this->__settings[$Model->alias]['field'] ); foreach($fields as $field) { if (preg_match('/^' . preg_quote($field) . '[\s=!]+/i', $queryData['conditions']) || preg_match('/\\x20+' . preg_quote($field) . '[\s=!]+/i', $queryData['conditions'])) { $include = false; break; } } if ($include) { if (empty($queryData['conditions'])) { $queryData['conditions'] = array(); } if (is_string($queryData['conditions'])) { $queryData['conditions'] = $Db->name($Model->alias) . '.' . $Db->name($this->__settings[$Model->alias]['field']) . '!= 1 AND ' . $queryData['conditions']; } else { $queryData['conditions'][$Model->alias . '.' . $this->__settings[$Model->alias]['field']] = '!= 1'; } } } return $queryData; }

  17. Conclusion • Questions? • Comments? • Standing round of applause? Mariano Iglesias mariano.iglesias@cricava.com

More Related