[ Index ]

PHP Cross Reference of Akelos Framework

title

Body

[close]

/AkActiveRecord/AkActsAsBehaviours/ -> AkActsAsList.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 Behaviours
  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.'AkObserver.php');
  20  
  21  /**
  22  * This act provides the capabilities for sorting and reordering a number of objects in list.
  23  * The class that has this specified needs to have a "position" column defined as an integer on
  24  * the mapped database table.
  25  * 
  26  * Todo list example:
  27  * <code>
  28  *   class TodoList extends ActiveRecord
  29  *   {
  30  *       var $has_many = array('todo_items', array('order' => "position"));
  31  *   }
  32  * 
  33  *   class TodoItem extends ActiveRecord
  34  *   {
  35  *       var $belongs_to = 'todo_list';
  36  *       var $acts_as = array('list' => array('scope' => 'todo_list')); 
  37  *   }
  38  *     
  39  *   $TodoList =& new TodoList();
  40  *
  41  *   $TodoList->list->moveToBottom();
  42  * </code>
  43  */
  44  class AkActsAsList extends AkObserver
  45  {
  46      var $column = 'position';
  47      var $scope = '';
  48      var $scope_condition;
  49      /**
  50      * Configuration options are:
  51      * 
  52      * * +column+ - specifies the column name to use for keeping the position integer (default: position)
  53      * * +scope+ - restricts what is to be considered a list. 
  54      *   Example: 
  55      * 
  56      * class TodoTask extends ActiveRecord
  57      * {
  58      *   var $acts_as = array('list'=> array('scope'=> array('todo_list_id','completed = 0')));
  59      *   var $belongs_to = 'todo_list';
  60      * }
  61      */
  62      var $_ActiveRecordInstance;
  63      function AkActsAsList(&$ActiveRecordInstance)
  64      {
  65          $this->_ActiveRecordInstance =& $ActiveRecordInstance;
  66      }
  67  
  68      function init($options = array())
  69      {
  70          $this->column = !empty($options['column']) ? $options['column'] : $this->column;
  71          $this->scope = !empty($options['scope']) ? $options['scope'] : $this->scope;
  72          return $this->_ensureIsActiveRecordInstance($this->_ActiveRecordInstance);
  73      }
  74  
  75      function _ensureIsActiveRecordInstance(&$ActiveRecordInstance)
  76      {
  77          if(is_object($ActiveRecordInstance) && method_exists($ActiveRecordInstance,'actsLike')){
  78              $this->_ActiveRecordInstance =& $ActiveRecordInstance;
  79              if(!$this->_ActiveRecordInstance->hasColumn($this->column)){
  80                  trigger_error(Ak::t('Could not find the column "%column" into the table "%table". This column is needed in order to make "%model" act as a list.',array('%column'=>$this->column,'%table'=>$this->_ActiveRecordInstance->getTableName(),'%model'=>$this->_ActiveRecordInstance->getModelName())),E_USER_ERROR);
  81                  unset($this->_ActiveRecordInstance->list);
  82                  return false;
  83              }else {
  84                  $this->observe(&$ActiveRecordInstance);
  85              }
  86          }else{
  87              trigger_error(Ak::t('You are trying to set an object that is not an active record.'), E_USER_ERROR);
  88              return false;
  89          }
  90          return true;
  91      }
  92  
  93      function reloadActiveRecordInstance(&$listObject)
  94      {
  95          AK_PHP5 ? null : $listObject->list->setActiveRecordInstance(&$listObject);
  96      }
  97  
  98      function getType()
  99      {
 100          return 'list';
 101      }
 102  
 103      function beforeDestroy(&$object)
 104      {
 105          $object->list->_ActiveRecordInstance->reload();
 106          return true;
 107      }
 108  
 109      function afterSave(&$object)
 110      {
 111          $object->list->_ActiveRecordInstance->reload();
 112          return true;
 113      }
 114  
 115      function afterDestroy(&$object)
 116      {
 117          return $object->list->removeFromList();
 118      }
 119  
 120      function beforeCreate(&$object)
 121      {
 122          $object->list->_addToBottom();
 123          return true;
 124      }
 125  
 126      /**
 127      * All the methods available to a record that has had <tt>acts_as list</tt> specified. Each method works
 128      * by assuming the object to be the item in the list, so <tt>$Chapter->list->moveLower()</tt> would move that chapter
 129      * lower in the list of all chapters. Likewise, <tt>$Chapter->list->isFirst()</tt> would return true if that chapter is
 130      * the first in the list of all chapters.
 131      */
 132  
 133  
 134      function insertAt($position = 1)
 135      {
 136          return $this->insertAtPosition($position);
 137      }
 138  
 139      /**
 140      * This function saves the object using save() before inserting it into the list
 141      */
 142      function insertAtPosition($position)
 143      {
 144          $this->_ActiveRecordInstance->transactionStart();
 145          if($this->_ActiveRecordInstance->isNewRecord()){
 146              $this->_ActiveRecordInstance->save();
 147          }
 148          $this->removeFromList();
 149          $this->incrementPositionsOnLowerItems($position);
 150  
 151          $this->_ActiveRecordInstance->updateAttribute($this->column, $position);
 152          if($this->_ActiveRecordInstance->transactionHasFailed()){
 153              $this->_ActiveRecordInstance->transactionComplete();
 154              return false;
 155          }
 156  
 157          $this->_ActiveRecordInstance->transactionComplete();
 158          return true;
 159      }
 160  
 161      function moveLower()
 162      {
 163          $this->_ActiveRecordInstance->transactionStart();
 164          if($LowerItem = $this->getLowerItem()){
 165              if($LowerItem->list->decrementPosition() && $this->incrementPosition()){
 166                  $this->_ActiveRecordInstance->transactionComplete();
 167                  return true;
 168              }else{
 169                  $this->_ActiveRecordInstance->transactionFail();
 170              }
 171          }
 172          $this->_ActiveRecordInstance->transactionComplete();
 173          return false;
 174      }
 175  
 176      function moveHigher()
 177      {
 178          $this->_ActiveRecordInstance->transactionStart();
 179          if($HigherItem = $this->getHigherItem()){
 180              if($HigherItem->list->incrementPosition() && $this->decrementPosition()){
 181                  $this->_ActiveRecordInstance->transactionComplete();
 182                  return true;
 183              }else{
 184                  $this->_ActiveRecordInstance->transactionFail();
 185              }
 186          }
 187          $this->_ActiveRecordInstance->transactionComplete();
 188          return false;
 189      }
 190  
 191      function moveToBottom()
 192      {
 193          if($this->isInList()){
 194              $this->_ActiveRecordInstance->transactionStart();
 195              if($this->decrementPositionsOnLowerItems() && $this->assumeBottomPosition()){
 196                  $this->_ActiveRecordInstance->transactionComplete();
 197                  return true;
 198              }else{
 199                  $this->_ActiveRecordInstance->transactionFail();
 200              }
 201              $this->_ActiveRecordInstance->transactionComplete();
 202          }
 203          return false;
 204      }
 205  
 206      function moveToTop()
 207      {
 208          if($this->isInList()){
 209              $this->_ActiveRecordInstance->transactionStart();
 210              if($this->incrementPositionsOnHigherItems() && $this->assumeTopPosition()){
 211                  $this->_ActiveRecordInstance->transactionComplete();
 212                  return true;
 213              }else{
 214                  $this->_ActiveRecordInstance->transactionFail();
 215              }
 216              $this->_ActiveRecordInstance->transactionComplete();
 217          }
 218          return false;
 219      }
 220  
 221      function assumeBottomPosition()
 222      {
 223          return $this->_ActiveRecordInstance->updateAttribute($this->column, $this->getBottomPosition($this->_ActiveRecordInstance->getId()) + 1);
 224      }
 225  
 226      function assumeTopPosition()
 227      {
 228          return $this->_ActiveRecordInstance->updateAttribute($this->column, 1);
 229      }
 230  
 231      function getBottomPosition($except = null)
 232      {
 233          return ($item = $this->getBottomItem($except)) ? $item->getAttribute($this->column) : 0;
 234      }
 235  
 236      /**
 237      * Returns an instance of the item that's on the very bottom of the list. Returns false if there's none
 238      */
 239      function getBottomItem($except = null)
 240      {
 241          $conditions = $this->getScopeCondition();
 242  
 243          if(isset($except)){
 244              $conditions .= " AND id != $except";
 245          }
 246          return $this->_ActiveRecordInstance->find('first', array('conditions' => $conditions, 'order' => "{$this->column} DESC"));
 247      }
 248  
 249      function isInList()
 250      {
 251          return !empty($this->_ActiveRecordInstance->{$this->column});
 252      }
 253  
 254      /**
 255      * This has the effect of moving all the higher items up one.
 256      */
 257      function decrementPositionsOnHigherItems($position)
 258      {
 259          return $this->_ActiveRecordInstance->updateAll("{$this->column} = ({$this->column} - 1)", $this->getScopeCondition()." AND {$this->column} <= $position");
 260      }
 261  
 262      /**
 263      * This has the effect of moving all the lower items up one.
 264      */
 265      function decrementPositionsOnLowerItems()
 266      {
 267          if($this->isInList()){
 268              $this->_ActiveRecordInstance->updateAll("{$this->column} = ({$this->column} - 1)", $this->getScopeCondition()." AND {$this->column} > ".$this->_ActiveRecordInstance->getAttribute($this->column));
 269              return true;
 270          }
 271          return false;
 272      }
 273  
 274      /**
 275      * This has the effect of moving all the higher items down one.
 276      */
 277      function incrementPositionsOnHigherItems()
 278      {
 279          if($this->isInList()){
 280              $this->_ActiveRecordInstance->updateAll("{$this->column} = ({$this->column} + 1)", $this->getScopeCondition()." AND {$this->column} < ".$this->_ActiveRecordInstance->getAttribute($this->column));
 281              return true;
 282          }
 283          return false;
 284      }
 285  
 286      /**
 287      * This has the effect of moving all the lower items down one.
 288      */
 289      function incrementPositionsOnLowerItems($position)
 290      {
 291          return $this->_ActiveRecordInstance->updateAll("{$this->column} = ({$this->column} + 1)", $this->getScopeCondition()." AND {$this->column} >= $position");
 292      }
 293  
 294      function incrementPositionsOnAllItems()
 295      {
 296          return $this->_ActiveRecordInstance->updateAll("{$this->column} = ({$this->column} + 1)",  $this->getScopeCondition());
 297      }
 298  
 299      function removeFromList()
 300      {
 301          if($this->isInList()){
 302              if($this->decrementPositionsOnLowerItems()){
 303                  $this->_ActiveRecordInstance->{$this->column} = null;
 304                  return true;
 305              }
 306          }
 307          return false;
 308      }
 309  
 310      function incrementPosition()
 311      {
 312          if($this->isInList()){
 313              return $this->_ActiveRecordInstance->updateAttribute($this->column, $this->_ActiveRecordInstance->getAttribute($this->column) + 1);
 314          }
 315          return false;
 316      }
 317  
 318      function decrementPosition()
 319      {
 320          if($this->isInList()){
 321              return $this->_ActiveRecordInstance->updateAttribute($this->column, $this->_ActiveRecordInstance->getAttribute($this->column) - 1);
 322          }
 323          return false;
 324      }
 325  
 326      function isFirst()
 327      {
 328          if($this->isInList()){
 329              return $this->_ActiveRecordInstance->getAttribute($this->column) == 1;
 330          }
 331          return false;
 332      }
 333  
 334      function isLast()
 335      {
 336          if($this->isInList()){
 337              return $this->_ActiveRecordInstance->getAttribute($this->column) == $this->getBottomPosition();
 338          }
 339          return false;
 340      }
 341  
 342      function getHigherItem()
 343      {
 344          if($this->isInList()){
 345              return $this->_ActiveRecordInstance->find('first', array('conditions' => $this->getScopeCondition()." AND {$this->column} = ".($this->_ActiveRecordInstance->getAttribute($this->column) - 1)));
 346          }
 347          return false;
 348      }
 349  
 350      function getLowerItem()
 351      {
 352          if($this->isInList()){
 353              return $this->_ActiveRecordInstance->find('first', array('conditions' => $this->getScopeCondition()." AND {$this->column} = ".($this->_ActiveRecordInstance->getAttribute($this->column) + 1)));
 354          }
 355          return false;
 356      }
 357  
 358      function addToListTop()
 359      {
 360          $this->incrementPositionsOnAllItems();
 361      }
 362  
 363      function _addToBottom()
 364      {
 365          $this->_ActiveRecordInstance->{$this->column} = $this->getBottomPosition() + 1;
 366      }
 367  
 368      function getScopeCondition()
 369      {
 370          if (!empty($this->variable_scope_condition)){
 371              return $this->_ActiveRecordInstance->_getVariableSqlCondition($this->variable_scope_condition);
 372  
 373              // True condition in case we don't have a scope
 374          }elseif(empty($this->scope_condition) && empty($this->scope)){
 375              $this->scope_condition = ($this->_ActiveRecordInstance->_db->type() == 'postgre') ? 'true' : '1';
 376          }elseif (!empty($this->scope)){
 377              $this->setScopeCondition(join(' AND ',array_map(array(&$this,'getScopedColumn'),(array)$this->scope)));
 378          }
 379          return  $this->scope_condition;
 380      }
 381  
 382      function setScopeCondition($scope_condition)
 383      {
 384          if(!is_array($scope_condition) && strstr($scope_condition, '?')){
 385              $this->variable_scope_condition = $scope_condition;
 386          }else{
 387              $this->scope_condition  = $scope_condition;
 388          }
 389      }
 390  
 391      function getScopedColumn($column)
 392      {
 393          if($this->_ActiveRecordInstance->hasColumn($column)){
 394              $value = $this->_ActiveRecordInstance->get($column);
 395              $condition = $this->_ActiveRecordInstance->getAttributeCondition($value);
 396              $value = $this->_ActiveRecordInstance->castAttributeForDatabase($column, $value);
 397              return $column.' '.str_replace('?', $value, $condition);
 398          }else{
 399              return $column;
 400          }
 401      }
 402  }
 403  
 404  ?>


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