[ Index ]

PHP Cross Reference of Akelos Framework

title

Body

[close]

/AkActiveRecord/AkAssociations/ -> AkBelongsTo.php (source)

   1  <?php
   2  /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
   3  
   4  // +----------------------------------------------------------------------+
   5  // | Akelos Framework - http://www.akelos.org                             |
   6  // +----------------------------------------------------------------------+
   7  // | Copyright (c) 2002-2006, Akelos Media, S.L.  & Bermi Ferrer Martinez |
   8  // | Released under the GNU Lesser General Public License, see LICENSE.txt|
   9  // +----------------------------------------------------------------------+
  10  
  11  /**
  12   * @package ActiveRecord
  13   * @subpackage Associations
  14   * @author Bermi Ferrer <bermi a.t akelos c.om>
  15   * @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org
  16   * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html>
  17   */
  18  
  19  require_once (AK_LIB_DIR.DS.'AkActiveRecord'.DS.'AkAssociation.php');
  20  
  21  /**
  22  * Adds the following methods for retrieval and query for a single associated object that this object holds an id to.
  23  * * <tt>belongsTo->assign($association_id, $Associate);</tt> - assigns the associate object, extracts the primary key, and sets it as the foreign key.
  24  * * <tt>belongsTo->build($association_id, $attributes = array())</tt> - returns a new object of the associated type that has been instantiated
  25  *   with +attributes+ and linked to this object through a foreign key but has not yet been saved.
  26  * * <tt>belongsTo->create($association_id, $attributes = array())</tt> - returns a new object of the associated type that has been instantiated
  27  *   with +attributes+ and linked to this object through a foreign key and that has already been saved (if it passed the validation).
  28  *
  29  * Example: A Post class declares <tt>belongsTo('author')</tt>, which will add:
  30  * * <tt>$Post->author->load()</tt> (similar to <tt>$Author->find($author_id)</tt>)
  31  * * <tt>$Post->author->assign($Author)</tt> (similar to <tt>$Post->author_id = $Author->getId();</tt>)
  32  * * <tt>$Post->author->build($Author);</tt> (similar to <tt>$Post->author = new Author();</tt>)
  33  * * <tt>$Post->author->create($Author);</tt> (similar to <tt>$Post->author = new Author(); $Post->author->save();</tt>)
  34  *  The declaration can also include an options hash to specialize the behavior of the association.
  35  *  
  36  *  Options are:
  37  *  * <tt>class_name</tt>  - specify the class name of the association. Use it only if that name can't be inferred
  38  *    from the association name. So <tt>belongsTo('author')</tt> will by default be linked to the 'Author' class, but
  39  *    if the real class name is 'Person', you'll have to specify it with this option.
  40  *  * <tt>conditions</tt>  - specify the conditions that the associated object must meet in order to be included as a "WHERE"
  41  *    sql fragment, such as "authorized = 1".
  42  *  * <tt>order</tt>       - specify the order from which the associated object will be picked at the top. Specified as
  43  *    an "ORDER BY" sql fragment, such as "last_name, first_name DESC"
  44  *  * <tt>primary_key_name</tt> - specify the foreign key used for the association. By default this is guessed to be the name
  45  *    of the associated class in lower-case and "_id" suffixed. So a 'Person' class that makes a belongsTo association to a
  46  *    'Boss' class will use "boss_id" as the default primary_key_name.
  47  *  * <tt>counter_cache</tt> - caches the number of belonging objects on the associate class through use of increment_counter 
  48  *    and decrement_counter. The counter cache is incremented when an object of this class is created and decremented when it's
  49  *    destroyed. This requires that a column named "#{table_name}_count" (such as comments_count for a belonging Comment class)
  50  *    is used on the associate class (such as a Post class).
  51  * 
  52  *  Option examples:
  53  *    belongsTo('firm', array('primary_key_name' => 'client_of'));
  54  *    belongsTo('author', array('class_name' => 'Person', 'primary_key_name' => 'author_id'));
  55  *    belongsTo('valid_coupon', array('class_name' => 'Coupon', 'primary_key_name' => 'coupon_id', 'conditions' => "'discounts' > 'payments_count'"));
  56  */
  57  class AkBelongsTo extends AkAssociation
  58  {
  59      var $associated_ids = array();
  60  
  61      function &addAssociated($association_id, $options = array())
  62      {
  63  
  64          $default_options = array(
  65          'class_name' => empty($options['class_name']) ? AkInflector::camelize($association_id) : $options['class_name'],
  66          'primary_key_name',
  67          'remote',
  68          'conditions',
  69          'order',
  70          //'dependent',
  71          'instantiate'=>false,
  72          'counter_cache' => false
  73          );
  74  
  75          $options = array_merge($default_options, $options);
  76  
  77          //$options['table_name'] = empty($options['table_name']) ? AkInflector::tableize($options['class_name']) : $options['table_name'];
  78          $options['primary_key_name'] = empty($options['primary_key_name']) ? AkInflector::underscore($options['class_name']).'_id' : $options['primary_key_name'];
  79          if($options['counter_cache']){
  80              $options['counter_cache_column'] = !isset($options['counter_cache_column']) ? AkInflector::underscore($options['class_name']).'_counter' : $options['counter_cache_column'];
  81          }
  82  
  83          $this->setOptions($association_id, $options);
  84  
  85          $associated = $this->addModel($association_id,  new AkAssociatedActiveRecord());
  86  
  87          $this->setAssociatedId($association_id, $associated->getId());
  88  
  89          $this->_build($association_id, $associated);
  90  
  91          $this->_saveLoadedHandler($association_id, $associated);
  92  
  93          if($options['instantiate']){
  94              $associated =& $this->assign($association_id,  new $options['class_name']($this->Owner->get($options['primary_key_name'])));
  95          }
  96  
  97          return $associated;
  98      }
  99  
 100  
 101      function getType()
 102      {
 103          return 'belongsTo';
 104      }
 105  
 106  
 107      function &findAssociated($association_id)
 108      {
 109          $result = false;
 110          $primary_key_name = $this->Owner->$association_id->getAssociationOption('primary_key_name');
 111          $primary_key_name_value = $this->Owner->get($primary_key_name);
 112          if(!$primary_key_name_value){
 113              return $result;
 114          }
 115          if(empty($this->Owner->$association_id->__activeRecordObject)){
 116              $this->build($association_id, array(), false);
 117          }
 118  
 119          $result =& $this->Owner->$association_id->find($primary_key_name_value);
 120          
 121          return $result;
 122      }
 123  
 124      function &assign($association_id, &$Associated)
 125      {
 126          $primary_key_name = $this->Owner->$association_id->getAssociationOption('primary_key_name');
 127          if($Associated->save()){
 128              $this->Owner->set($primary_key_name, $Associated->getId());
 129          }
 130          $Associated =& $this->_build($association_id, &$Associated);
 131          return $Associated;
 132      }
 133  
 134      function &build($association_id, $attributes = array(), $replace = true)
 135      {
 136          $class_name = $this->Owner->$association_id->getAssociationOption('class_name');
 137          Ak::import($class_name);
 138          $record =& new $class_name($attributes);
 139          $record =& $this->Owner->$association_id->replace($record);
 140          return $record;
 141      }
 142  
 143      /**
 144      * Returns a new object of the associated type that has been instantiated with attributes 
 145      * and linked to this object through a foreign key and that has already been saved (if it passed the validation)
 146      */
 147      function &create($association_id, $attributes = array())
 148      {
 149          $class_name = $this->Owner->$association_id->getAssociationOption('class_name');
 150          $record =& new $class_name($attributes);
 151          $record->save();
 152          $this->replace($association_id, $record, true);
 153          return $this->Owner->$association_id;
 154      }
 155      
 156      
 157      function &load($association_id)
 158      {
 159          if (!$this->Owner->isNewRecord()){
 160              if(empty($this->Owner->$association_id->_loaded)){
 161                  if($Associated =& $this->findAssociated($association_id)){
 162                      $Associated->_loaded = true;
 163                      $this->_build($association_id, $Associated, false);
 164                  }
 165              }
 166          }
 167          return $this->Owner->$association_id;
 168      }
 169  
 170      function &replace($association_id, &$NewAssociated)
 171      {
 172          $counter_cache_name = $this->Owner->belongsTo->getOption($association_id, 'counter_cache_column');
 173          if(empty($NewAssociated)){
 174              $primary_key = $this->Owner->belongsTo->getOption($association_id, 'primary_key_name');
 175              if($counter_cache_name && isset($this->Owner->$association_id->$counter_cache_name) && !$this->Owner->isNewRecord()){
 176                  $this->Owner->$association_id->decrementCounter($counter_cache_name, $this->Owner->get($primary_key));
 177              }
 178              $this->Owner->$association_id =& $this->_getLoadedHandler($association_id);
 179              $this->Owner->set($primary_key, null);
 180          }else{
 181              $primary_key = $this->Owner->belongsTo->getOption($association_id, 'primary_key_name');
 182              if($counter_cache_name && !$this->Owner->isNewRecord()){
 183                  $this->Owner->$association_id->incrementCounter($counter_cache_name, $NewAssociated->getId());
 184                  $previous_id = $this->Owner->get($primary_key);
 185                  if($previous_id){
 186                      $this->Owner->$association_id->decrementCounter($counter_cache_name, $previous_id);
 187                  }
 188              }
 189              if(!$NewAssociated->isNewRecord()){
 190                  $this->Owner->set($primary_key, $NewAssociated->getId());
 191              }
 192              $this->updated[$association_id] = true;
 193  
 194              $this->updated[$association_id] = true;
 195              $this->loaded[$association_id] = true;
 196          }
 197          $this->_build($association_id, $NewAssociated);
 198          return $NewAssociated;
 199      }
 200      
 201      
 202      function getAssociatedFinderSqlOptions($association_id, $options = array())
 203      {
 204          $default_options = array(
 205          'conditions' => $this->Owner->$association_id->getAssociationOption('include_conditions_when_included'),
 206          'order' => $this->Owner->$association_id->getAssociationOption('include_order_when_included')
 207          );
 208  
 209          if(empty($this->Owner->$association_id->__activeRecordObject)){
 210              $this->build($association_id, array(), false);
 211          }
 212  
 213          $table_name = $this->Owner->$association_id->getTableName();
 214          $options = array_merge($default_options, $options);
 215  
 216          $finder_options = array();
 217  
 218          foreach ($options as $option=>$available) {
 219              if($available){
 220                  $value = $this->Owner->$association_id->getAssociationOption($option);
 221                  empty($value) ? null : ($finder_options[$option] = trim($this->Owner->$association_id->_addTableAliasesToAssociatedSql('_'.$association_id, $value)));
 222              }
 223          }
 224  
 225          $finder_options['joins'] = $this->Owner->$association_id->constructSqlForInclusion();
 226  
 227          $finder_options['selection'] = '';
 228          foreach (array_keys($this->Owner->$association_id->getColumns()) as $column_name){
 229              $finder_options['selection'] .= '_'.$association_id.'.'.$column_name.' AS _'.$association_id.'_'.$column_name.', ';
 230          }
 231          $finder_options['selection'] = trim($finder_options['selection'], ', ');
 232  
 233          return $finder_options;
 234      }
 235      
 236      function constructSqlForInclusion($association_id)
 237      {
 238          return ' LEFT OUTER JOIN '.
 239          $this->Owner->$association_id->getTableName().' AS _'.$association_id.
 240          ' ON '.
 241          '__owner.'.$this->Owner->$association_id->getAssociationOption('primary_key_name').
 242          ' = '.
 243          '_'.$association_id.'.'.$this->Owner->$association_id->getPrimaryKey().' ';
 244      }
 245  
 246  
 247      /**
 248       * Triggers
 249       */
 250  
 251      function beforeSave(&$object)
 252      {
 253          $association_ids = $object->getAssociatedIds();
 254          foreach ($association_ids as $association_id){
 255              if( !empty($object->$association_id->__activeRecordObject) &&
 256              strtolower($object->belongsTo->getOption($association_id, 'class_name')) == strtolower($object->$association_id->getType())){
 257                  $primary_key_name = $this->Owner->belongsTo->getOption($association_id, 'primary_key_name');
 258                  if($object->$association_id->isNewRecord() && !$object->$association_id->hasAttributesDefined()){
 259                      $object->$association_id->save(true);
 260                  }
 261                  $primary_key_name_value = $object->$association_id->getId();
 262                  if(!empty($primary_key_name_value)){
 263                      $object->set($primary_key_name, $primary_key_name_value);
 264                  }
 265              }
 266          }
 267          return true;
 268      }
 269  
 270      function beforeDestroy(&$object)
 271      {
 272          $association_ids = $object->getAssociatedIds();
 273          foreach ($association_ids as $association_id){
 274              if(!empty($object->$association_id) && is_object($object->$association_id) && method_exists($object->$association_id,'getType') && 
 275              strtolower($object->belongsTo->getOption($association_id, 'class_name')) == strtolower($object->$association_id->getType())){
 276                  $primary_key_name = $this->Owner->$association_id->getAssociationOption('primary_key_name');
 277                  if($this->Owner->$association_id->getAssociationOption('counter_cache')){
 278                      $object->$association_id->decrementCounter(AkInflector::pluralize($association_id).'_count', $object->get($primary_key_name));
 279                  }
 280              }
 281          }
 282          return true;
 283      }
 284  }
 285  
 286  
 287  ?>


Generated: Mon Oct 27 12:43:49 2008 Cross-referenced by PHPXref 0.6