[ Index ]

PHP Cross Reference of ACL Module

title

Body

[close]

/models/behaviors/ -> RestrictedActiveRecordBehavior.php (source)

   1  <?php
   2  
   3  /**

   4   * RestrictedActiveRecordBehavior Class File

   5   * This class serves as a behavior for all the objects which have to control 

   6   * their access

   7   *

   8   * @author dispy <dispyfree@googlemail.com>

   9   * @license LGPLv2

  10   * @package acl.base

  11   */
  12  
  13  /**

  14   * This class is intended tobe used as a behavior for objects which have restrictions on their access

  15   * It automatically checks, if the current user has the permissions to commit the regular CRUD-tasks

  16   */
  17  class RestrictedActiveRecordBehavior extends CActiveRecordBehavior{
  18  
  19      /**

  20       * The following functions generates the CDbCriteria necessary to filter all accessable rows

  21       * The CDbCriteria is solely passsed to the wrapped methods

  22       * @param sql $conditions the conditions being passed to the real method

  23       * @param array $params the params being passed to the real method

  24       * @param   array   $options    options to be used by the method itself (keys: disableInheritance)

  25       * @return CDbCriteria the criteria assuring that the user only gets what he has access to

  26       */
  27      protected function generateAccessCheck($conditions = '', $params = array(), $options = array()){
  28          if(is_object($conditions) && get_class($conditions) == 'CDbCriteria'){
  29              $criteria = $conditions;
  30          }
  31          else{
  32              $criteria = new CDbCriteria;
  33              $criteria->mergeWith(array(
  34                  'condition' => $conditions,
  35                  'params'    => $params
  36              ));
  37          }
  38          
  39          //If he's generally allowed, don't filter at all

  40          if(RestrictedActiveRecord::mayGenerally(get_class($this->getOwner()), 'read'))
  41                  return $criteria;
  42          
  43          $options = array_merge(RestrictedActiveRecord::$defaultOptions, $options);
  44          
  45          //If the check is bypassed, return criteria without check

  46          if(RestrictedActiveRecord::$byPassCheck)
  47              return $criteria;
  48          
  49          $criteria->distinct = true; //Important: there can be multiple locations which grant permission

  50              
  51              //Inner join to get the collection associated with this content

  52              $acoClass = Strategy::getClass('Aco');
  53              $collection = 'INNER JOIN `'.$acoClass::model()->tableName().'` AS acoC ON acoC.model = :RAR_model AND acoC.foreign_key = t.id';
  54                  $criteria->params[':RAR_model'] = get_class($this->getOwner());
  55              
  56              //Inner join to the associated aco-nodes themselves to get the positions

  57              $acoNodeClass = Strategy::getClass('AcoNode');
  58              $nodes = ' INNER JOIN `'.$acoNodeClass::model()->tableName().'` AS aco ON aco.collection_id = acoC.id';
  59              
  60              //But before: fetch the positions of the current user

  61              $aroClass = Strategy::getClass('Aro');
  62              $user = RestrictedActiveRecord::getUser();
  63              $aro = $aroClass::model()->find('model = :model AND foreign_key = :foreign_key', 
  64                      array(':model'=> RestrictedActiveRecord::$model, ':foreign_key' => $user->id));
  65              
  66              //If we are nobody... we are a guest^^

  67              $guest = Strategy::get('guestGroup');
  68              if(!$aro && $guest){
  69                   $aro = $aroClass::model()->find('alias = :alias', 
  70                      array(':alias' => $guest));
  71                   
  72                   //If there's no guest group... we are nobody and we may nothing ;)

  73                   if(!$aro)
  74                       return array();
  75              }
  76                 
  77              
  78              $aroPositions = $aro->fetchComprisedPositions();
  79              $aroPositionCheck = $aro->addPositionCheck($aroPositions, "aro", "map"); 
  80              
  81              //Get our action :)

  82              $action = Action::model()->find('name = :name', array(':name' => 'read'));
  83              
  84              if($action === NULL)
  85                  throw new RuntimeException('Unable to find action read');
  86              
  87              //Now, join connecting table

  88              $acoCondition = $acoClass::buildTreeQueryCondition(
  89                      array('table' => 'aco'),
  90                      array('table' => 'map', 'field' => 'aco'),
  91                      $options['disableInheritance']
  92                      );
  93              $connection = ' INNER JOIN `'.Permission::model()->tableName().'` AS map ON '.$acoCondition.' AND '.$aroPositionCheck.' AND map.action_id = :acl_action_id';
  94              $criteria->params[':acl_action_id'] = $action->id;
  95          
  96         $joins = array($collection, $nodes, $connection);
  97         
  98         foreach($joins as $join){
  99             $criteria->mergeWith(array('join' => $join), true);
 100         }
 101         
 102         
 103         return $criteria;
 104      }
 105      
 106      public function beforeFind($event){
 107          $event = $this->generateAccessCheck($event->criteria);
 108      }
 109      
 110      
 111      /**

 112       * Gets the Aros who are directly (no inheritance!) permitted to perform

 113       * one of the specified actions on this object

 114       * @param mixed $actions the actions to be considered

 115       * @return array All of the objects which have one of the permissions

 116       */
 117      public function getDirectlyPermitted($actions = '*'){
 118          //First, fetch all of the action Ids

 119          $owner = $this->getOwner();
 120          $actions = Action::translateActions($owner, $actions);
 121          $actionCondition = Util::generateInStatement($actions);
 122          $actions = Action::model()->findAll('name '.$actionCondition);
 123          
 124          $actionIds = array();
 125          foreach($actions as $action){
 126              $actionIds[] = $action->id;
 127          }
 128          $actionIdCondition = Util::generateInStatement($actionIds);
 129          
 130          //Get the associated Aco first

 131          $aco = AclObject::loadObjectStatic($owner, 'Aco');
 132          //Fetch all of the own positions and build condition

 133          $positions = $aco->fetchComprisedPositions();
 134          $acoCondition = Util::generateInStatement($positions);
 135          
 136          $aroNodeClass   = Strategy::getClass('AroNode');
 137          
 138          $rGroupTable    = RGroup::model()->tableName();
 139          $nodeTable      = $aroNodeClass::model()->tableName();
 140          $permTable      = Permission::model()->tableName();
 141          return Yii::app()->db->createCommand()
 142                  ->selectDistinct('t.id AS collection_id, t.foreign_key, t.model, p.action_id')
 143                  ->from($rGroupTable.' t')
 144                  ->join($nodeTable.' n', 'n.collection_id = t.id')
 145                  ->join($permTable.' p', 
 146                          'p.aro_id = n.id AND p.aco_path '.$acoCondition.' AND p.action_id '. $actionIdCondition)
 147                  ->queryAll()
 148                  ;
 149      }
 150      
 151      /**

 152       * This method checks whether the user has the right to update the current record

 153       * By default, it's always allowed to create a new object. This object is automatically assigned to the user who created it with full permissions

 154       */
 155      public function beforeSave($event){
 156          //The Record is updated

 157          $aro = RestrictedActiveRecord::getUser();
 158          
 159          if(!$this->getOwner()->isNewRecord){
 160              if(!$aro->may($this->getOwner(), 'update'))
 161                  throw new RuntimeException('You are not allowed to update this record');            
 162          }
 163          else{
 164              if(!$aro->may(get_class($this->getOwner()), 'create'))
 165                      throw new RuntimeException('You are not allowed to create this object');
 166          }
 167          
 168          return true;
 169      }
 170      
 171      /**

 172       * This method checks whether the user has the right to delete the current record

 173       * 

 174       */
 175      public function beforeDelete($event){
 176          $aro = RestrictedActiveRecord::getUser();
 177          $owner = $this->getOwner();
 178          
 179          //If he's generally allowed, don't filter at all

 180          if(RestrictedActiveRecord::mayGenerally(get_class($this->getOwner()), 'delete'))
 181              return true;
 182              
 183          if(!$aro->may($owner, 'delete'))
 184                  throw new RuntimeException('You are not allowed to delete this record');
 185          
 186          //Ok he has the right to do that - remove all the ACL-objects associated with this object

 187          $class = Strategy::getClass('Aco');
 188          $aco = $class::model()->find('model = :model AND foreign_key = :key', array(':model' => get_class($owner), ':key' => $owner->id));
 189          if(!$aco)
 190              throw new RuntimeException('No associated Aco!');
 191          
 192          if(!$aco->delete())
 193              throw new RuntimeException('Unable to delete associated Aco');
 194          
 195          return true;
 196      }
 197      
 198      
 199      /**

 200       * This method takes care to assign individual rights to newly created objects

 201       * 

 202       * @param CEvent $evt 

 203       */
 204      public function afterSave($event){
 205          $owner = $this->getOwner();
 206          if($owner){
 207              $aro = RestrictedActiveRecord::getUser();
 208              //As the object is newly created, it needs a representation

 209              //If strict mode is disabled, this is not necessary

 210              $class = Strategy::getClass('Aco');
 211              $aco = new $class();
 212              $aco->model = get_class($owner);
 213              $aco->foreign_key = $owner->getPrimaryKey();
 214              
 215              if(!$aco->save()){
 216                  throw new RuntimeException('Unable to create corresponding Aco for new '.get_class($owner));
 217              }
 218              
 219              $aro->grant($aco, RestrictedActiveRecord::getAutoPermissions($this->getOwner()), true);
 220          }
 221      }
 222      
 223      
 224      /**

 225       * Checks whether the current ARO has the given permission on this object

 226       * @param string $permission 

 227       */
 228      public function grants($permission){
 229          $aro = RestrictedActiveRecord::getUser();
 230          return $aro->may($this->getOwner(), $permission);
 231      }
 232      
 233      
 234  }
 235  ?>


Generated: Sun Jul 1 19:24:45 2012 Cross-referenced by PHPXref 0.7.1