[ Index ]

PHP Cross Reference of Akelos Framework

title

Body

[close]

/AkActiveRecord/AkAssociations/ -> AkHasOne.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 of a single associated object.
  23  * $association is replaced with the symbol passed as the first argument, so 
  24  * <tt>hasOne('manager')</tt> would add among others <tt>$this->manager->getAttributes()</tt>.
  25  *
  26  * Example: An Account class declares <tt>hasOne('beneficiary');</tt>, which will add:
  27  * * <tt>$Account->beneficiary->load()</tt> (similar to <tt>$Beneficiary->find('first', array('conditions' => "account_id = $id"))</tt>)
  28  * * <tt>$Account->beneficiary->assign($Beneficiary);</tt> (similar to <tt>$Beneficiary->account_id = $Account->id; $Beneficiary->save()</tt>)
  29  * * <tt>$Account->beneficiary->build();</tt> (similar to <tt>$Beneficiary = new Beneficiary("account_id->", $Account->id)</tt>)
  30  * * <tt>$Account->beneficiary->create();</tt> (similar to <tt>$b = new Beneficiary("account_id->", $Account->id); $b->save(); $b</tt>)
  31  *
  32  * The declaration can also include an options array to specialize the behavior of the association.
  33  *
  34  * Options are:
  35  * * <tt>class_name</tt>  - specify the class name of the association. Use it only if that name can't be inferred
  36  *   from the association name. So <tt>hasOne('manager')</tt> will by default be linked to the "Manager" class, but
  37  *   if the real class name is "Person", you'll have to specify it with this option.
  38  * * <tt>conditions</tt>  - specify the conditions that the associated object must meet in order to be included as a "WHERE"
  39  *   sql fragment, such as "rank = 5".
  40  * * <tt>order</tt>       - specify the order from which the associated object will be picked at the top. Specified as
  41  *    an "ORDER BY" sql fragment, such as "last_name, first_name DESC"
  42  * * <tt>dependent</tt>   - if set to true, the associated object is destroyed when this object is. It's also destroyed if another
  43  *   association is assigned.
  44  * * <tt>foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name
  45  *   of this class in lower-case and "_id" suffixed. So a "Person" class that makes a hasOne association will use "person_id"
  46  *   as the default foreign_key.
  47  *
  48  * Option examples:
  49  *   var $hasOne = array(
  50  *       'credit_card' => array('dependent' => true),
  51  *       'last_comment' => array('class_name' => "Comment", 'order' => "posted_on"),
  52  *       'project_manager' => array('class_name' => "Person", 'conditions' => "role = 'project_manager'")
  53  *       );
  54  */
  55  class AkHasOne extends AkAssociation
  56  {
  57      var $associated_ids = array();
  58  
  59      function &addAssociated($association_id, $options = array())
  60      {
  61          $default_options = array(
  62          'class_name' => empty($options['class_name']) ? AkInflector::camelize($association_id) : $options['class_name'],
  63          'foreign_key' => empty($options['foreign_key']) ? AkInflector::singularize($this->Owner->getTableName()).'_id' : $options['foreign_key'],
  64          'remote'=>false,
  65          'instantiate'=>false,
  66          'conditions'=>false,
  67          'include_conditions_when_included'=>true,
  68          'order'=>false,
  69          'include_order_when_included'=>true,
  70          'dependent'=>false,
  71          'counter_cache'=>false
  72          );
  73  
  74          $options = array_merge($default_options, $options);
  75  
  76          $options['table_name'] = empty($options['table_name']) ? AkInflector::tableize($options['class_name']) : $options['table_name'];
  77  
  78          $this->setOptions($association_id, $options);
  79  
  80          $this->addModel($association_id,  new AkAssociatedActiveRecord());
  81  
  82          $associated =& $this->getModel($association_id);
  83          $this->setAssociatedId($association_id, $associated->getId());
  84  
  85          $associated =& $this->_build($association_id, &$associated, false);
  86  
  87          $this->_saveLoadedHandler($association_id, $associated);
  88  
  89          if($options['instantiate']){
  90              $associated =& $this->addModel($association_id,  new $options['class_name']($options['foreign_key'].' = '.$this->Owner->quotedId()));
  91          }
  92  
  93          return $associated;
  94      }
  95  
  96  
  97      /**
  98       * Assigns the associate object, extracts the primary key, sets it as the foreign key, and saves the associate object.
  99       */
 100      function &assign($association_id, &$Associated)
 101      {
 102          if(!$this->Owner->isNewRecord()){
 103              $Associated->set($this->Owner->$association_id->getAssociationOption('foreign_key'), $this->Owner->getId());
 104              $Associated->save();
 105          }
 106  
 107          $this->_build($association_id, &$Associated);
 108          $this->Owner->$association_id->_loaded = true;
 109          return $Associated;
 110      }
 111  
 112      function getAssociatedId($association_id)
 113      {
 114          return isset($this->associated_ids[$association_id]) ? $this->associated_ids[$association_id] : false;
 115      }
 116  
 117  
 118      function getType()
 119      {
 120          return 'hasOne';
 121      }
 122  
 123  
 124      function getAssociatedFinderSqlOptions($association_id, $options = array())
 125      {
 126          $default_options = array(
 127          'conditions' => $this->Owner->$association_id->getAssociationOption('include_conditions_when_included'),
 128          'order' => $this->Owner->$association_id->getAssociationOption('include_order_when_included')
 129          );
 130  
 131          if(empty($this->Owner->$association_id->__activeRecordObject)){
 132              $this->build($association_id, array(), false);
 133          }
 134  
 135          $table_name = $this->Owner->$association_id->getTableName();
 136          $options = array_merge($default_options, $options);
 137  
 138          $finder_options = array();
 139  
 140          foreach ($options as $option=>$available) {
 141              if($available){
 142                  $value = $this->Owner->$association_id->getAssociationOption($option);
 143                  empty($value) ? null : ($finder_options[$option] = trim($this->Owner->$association_id->_addTableAliasesToAssociatedSql('_'.$association_id, $value)));
 144              }
 145          }
 146  
 147          $finder_options['joins'] = $this->Owner->$association_id->constructSqlForInclusion();
 148  
 149          $finder_options['selection'] = '';
 150          foreach (array_keys($this->Owner->$association_id->getColumns()) as $column_name){
 151              $finder_options['selection'] .= '_'.$association_id.'.'.$column_name.' AS _'.$association_id.'_'.$column_name.', ';
 152          }
 153          $finder_options['selection'] = trim($finder_options['selection'], ', ');
 154  
 155          return $finder_options;
 156      }
 157  
 158      function constructSqlForInclusion($association_id)
 159      {
 160          return ' LEFT OUTER JOIN '.
 161          $this->Owner->$association_id->getTableName().' AS _'.$association_id.
 162          ' ON '.
 163          '__owner.'.$this->Owner->getPrimaryKey().
 164          ' = '.
 165          '_'.$association_id.'.'.$this->Owner->$association_id->getAssociationOption('foreign_key').' ';
 166      }
 167  
 168      function &build($association_id, $attributes = array(), $replace_existing = true)
 169      {
 170          $class_name = $this->Owner->$association_id->getAssociationOption('class_name');
 171          $foreign_key = $this->Owner->$association_id->getAssociationOption('foreign_key');
 172          Ak::import($class_name);
 173          $record =& new $class_name($attributes);
 174          if ($replace_existing){
 175              $record =& $this->replace($association_id, $record, true);
 176          }
 177          if(!$this->Owner->isNewRecord()){
 178              $record->set($foreign_key, $this->Owner->getId());
 179          }
 180  
 181          $record =& $this->_build($association_id, &$record);
 182  
 183          return $record;
 184      }
 185  
 186  
 187      /**
 188      * Returns a new object of the associated type that has been instantiated with attributes 
 189      * and linked to this object through a foreign key and that has already been 
 190      * saved (if it passed the validation)
 191      */
 192      function &create($association_id, $attributes = array(), $replace_existing = true)
 193      {
 194          $this->build($association_id, $attributes, $replace_existing);
 195          $this->Owner->$association_id->save();
 196          $this->Owner->$association_id->_loaded = true;
 197          return $this->Owner->$association_id;
 198      }
 199  
 200      function &replace($association_id, &$NewAssociated, $dont_save = false)
 201      {
 202          $Associated =& $this->loadAssociated($association_id);
 203          if(!empty($Associated->__activeRecordObject) && !empty($NewAssociated->__activeRecordObject) && $Associated->getId() == $NewAssociated->getId()){
 204              return $NewAssociated;
 205          }
 206  
 207          if(!empty($Associated->__activeRecordObject)){
 208              if ($Associated->getAssociationOption('dependent') && !$dont_save){
 209                  if(!$Associated->isNewRecord()){
 210                      $Associated->destroy();
 211                  }
 212              }elseif(!$dont_save){
 213                  $Associated->set($Associated->getAssociationOption('foreign_key'), null);
 214                  if($Associated->isNewRecord()){
 215                      $Associated->save();
 216                  }
 217              }
 218          }
 219  
 220          $result = false;
 221  
 222          if (!empty($NewAssociated->__activeRecordObject)){
 223              if(!$this->Owner->isNewRecord()){
 224                  $NewAssociated->set($Associated->getAssociationOption('foreign_key'), $this->Owner->getId());
 225              }
 226  
 227              $NewAssociated =& $this->_build($association_id, &$NewAssociated);
 228  
 229              $NewAssociated->_loaded = true;
 230              if(!$NewAssociated->isNewRecord() || !$dont_save){
 231                  if($NewAssociated->save()){
 232                      return $NewAssociated;
 233                  }
 234              }else{
 235                  return $NewAssociated;
 236              }
 237          }
 238          return $result;
 239      }
 240  
 241      function &findAssociated($association_id)
 242      {
 243          $false = false;
 244          if(!$this->Owner->getId()){
 245              return $false;
 246          }
 247          if(empty($this->Owner->$association_id->__activeRecordObject)){
 248              $this->build($association_id, array(), false);
 249          }
 250  
 251          $table_name = $this->Owner->$association_id->getAssociationOption('table_name');
 252  
 253          $finder_options =         array(
 254          'conditions' => trim($this->Owner->$association_id->_addTableAliasesToAssociatedSql($table_name, $this->constructSqlConditions($association_id))),
 255          'selection' => $table_name,
 256          'joins' => trim($this->Owner->$association_id->_addTableAliasesToAssociatedSql($table_name, $this->constructSql($association_id))),
 257          'order' => trim($this->Owner->$association_id->_addTableAliasesToAssociatedSql($table_name, $this->Owner->$association_id->getAssociationOption('order')))
 258          );
 259          
 260          /**
 261          * todo we will use a select statement later
 262          */
 263          $sql = $this->Owner->constructFinderSqlWithAssociations($finder_options, false);//.' LIMIT 1';
 264          if($results =& $this->Owner->$association_id->findBySql($sql)){
 265              $result =& $results[0];
 266          }
 267  
 268          return $result;
 269      }
 270  
 271  
 272      function constructSqlConditions($association_id)
 273      {
 274          $foreign_key = $this->Owner->$association_id->getAssociationOption('foreign_key');
 275          $conditions = $this->Owner->$association_id->getAssociationOption('conditions');
 276  
 277          $foreign_key_value = $this->Owner->getId();
 278          if(empty($foreign_key_value)){
 279              return $conditions;
 280          }
 281          return (empty($conditions) ? '' : $conditions.' AND ').$foreign_key.' = '.$this->Owner->castAttributeForDatabase($foreign_key, $foreign_key_value);
 282      }
 283  
 284      function constructSql($association_id)
 285      {
 286          $foreign_key = $this->Owner->$association_id->getAssociationOption('foreign_key');
 287          $table_name = $this->Owner->$association_id->getAssociationOption('table_name');
 288          $owner_table = $this->Owner->getTableName();
 289  
 290          return ' LEFT OUTER JOIN '.$owner_table.' ON '.$owner_table.'.'.$this->Owner->getPrimaryKey().' = '.$table_name.'.'.$foreign_key;
 291      }
 292  
 293  
 294      /**
 295       * Triggers
 296       */
 297      function afterSave(&$object)
 298      {
 299          $success = true;
 300          $associated_ids = $object->getAssociatedIds();
 301  
 302          foreach ($associated_ids as $associated_id){
 303              if(!empty($object->$associated_id->__activeRecordObject)){
 304  
 305                  if(strtolower($object->hasOne->getOption($associated_id, 'class_name')) == strtolower($object->$associated_id->getType())){
 306                      $object->hasOne->replace($associated_id, $object->$associated_id, false);
 307                      $object->$associated_id->set($object->hasOne->getOption($associated_id, 'foreign_key'), $object->getId());
 308                      $success = $object->$associated_id->save() ? $success : false;
 309  
 310                  }elseif($object->$associated_id->getType() == 'hasOne'){
 311                      $attributes = array();
 312                      foreach ((array)$object->$associated_id as $k=>$v){
 313                          $k[0] != '_' ? $attributes[$k] = $v : null;
 314                      }
 315                      $attributes = array_diff($attributes, array(''));
 316                      if(!empty($attributes)){
 317                          $object->hasOne->build($associated_id, $attributes);
 318                      }
 319                  }
 320              }
 321          }
 322          return $success;
 323      }
 324  
 325  
 326      function afterDestroy(&$object)
 327      {
 328          $success = true;
 329          $associated_ids = $object->getAssociatedIds();
 330          foreach ($associated_ids as $associated_id){
 331              if( isset($object->$associated_id->_associatedAs) &&
 332              $object->$associated_id->_associatedAs == 'hasOne' &&
 333              $object->$associated_id->getAssociationOption('dependent')){
 334                  if ($object->$associated_id->getType() == 'hasOne'){
 335                      $object->$associated_id->load();
 336                  }
 337                  if(method_exists($object->$associated_id, 'destroy')){
 338                      $success = $object->$associated_id->destroy() ? $success : false;
 339                  }
 340              }
 341          }
 342          return $success;
 343      }
 344  }
 345  
 346  ?>


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