ACL Extension  0.3
 All Data Structures Namespaces Files Functions Variables
RestrictedActiveRecordBehavior.php
Go to the documentation of this file.
1 <?php
2 
17 class RestrictedActiveRecordBehavior extends CActiveRecordBehavior{
18 
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 
40  $options = array_merge(RestrictedActiveRecord::$defaultOptions, $options);
41 
42  //If the check is bypassed, return criteria without check
44  return $criteria;
45 
46  $criteria->distinct = true; //Important: there can be multiple locations which grant permission
47 
48  //Inner join to get the collection associated with this content
49  $acoClass = Strategy::getClass('Aco');
50  $collection = 'INNER JOIN `'.$acoClass::model()->tableName().'` AS acoC ON acoC.model = :RAR_model AND acoC.foreign_key = t.id';
51  $criteria->params[':RAR_model'] = get_class($this->getOwner());
52 
53  //Inner join to the associated aco-nodes themselves to get the positions
54  $acoNodeClass = Strategy::getClass('AcoNode');
55  $nodes = ' INNER JOIN `'.$acoNodeClass::model()->tableName().'` AS aco ON aco.collection_id = acoC.id';
56 
57  //But before: fetch the positions of the current user
58  $aroClass = Strategy::getClass('Aro');
60  $aro = $aroClass::model()->find('model = :model AND foreign_key = :foreign_key',
61  array(':model'=> RestrictedActiveRecord::$model, ':foreign_key' => $user->id));
62 
63  //If we are nobody... we are a guest^^
64  $guest = Strategy::get('guestGroup');
65  if(!$aro && $guest){
66  $aro = $aroClass::model()->find('alias = :alias',
67  array(':alias' => $guest));
68 
69  //If there's no guest group... we are nobody and we may nothing ;)
70  if(!$aro)
71  return array();
72  }
73 
74 
75  $aroPositions = $aro->fetchComprisedPositions();
76  $aroPositionCheck = $aro->addPositionCheck($aroPositions, "aro", "map");
77 
78  //Get our action :)
79  $action = Action::model()->find('name = :name', array(':name' => 'read'));
80 
81  if($action === NULL)
82  throw new RuntimeException('Unable to find action read');
83 
84  //Now, join connecting table
85  $acoCondition = $acoClass::buildTreeQueryCondition(
86  array('table' => 'aco'),
87  array('table' => 'map', 'field' => 'aco'),
88  $options['disableInheritance']
89  );
90  $connection = ' INNER JOIN `'.Permission::model()->tableName().'` AS map ON '.$acoCondition.' AND '.$aroPositionCheck.' AND map.action_id = :acl_action_id';
91  $criteria->params[':acl_action_id'] = $action->id;
92 
93  $joins = array($collection, $nodes, $connection);
94 
95  foreach($joins as $join){
96  $criteria->mergeWith(array('join' => $join), true);
97  }
98 
99 
100  return $criteria;
101  }
102 
103  public function beforeFind($event){
104  $event = $this->generateAccessCheck($event->criteria);
105  }
106 
107 
114  public function getDirectlyPermitted($actions = '*'){
115  //First, fetch all of the action Ids
116  $owner = $this->getOwner();
117  $actions = Action::translateActions($owner, $actions);
118  $actionCondition = Util::generateInStatement($actions);
119  $actions = Action::model()->findAll('name '.$actionCondition);
120 
121  $actionIds = array();
122  foreach($actions as $action){
123  $actionIds[] = $action->id;
124  }
125  $actionIdCondition = Util::generateInStatement($actionIds);
126 
127  //Get the associated Aco first
128  $aco = AclObject::loadObjectStatic($owner, 'Aco');
129  //Fetch all of the own positions and build condition
130  $positions = $aco->fetchComprisedPositions();
131  $acoCondition = Util::generateInStatement($positions);
132 
133  $aroNodeClass = Strategy::getClass('AroNode');
134 
135  $rGroupTable = RGroup::model()->tableName();
136  $nodeTable = $aroNodeClass::model()->tableName();
137  $permTable = Permission::model()->tableName();
138  return Yii::app()->db->createCommand()
139  ->selectDistinct('t.id AS collection_id, t.foreign_key, t.model, p.action_id')
140  ->from($rGroupTable.' t')
141  ->join($nodeTable.' n', 'n.collection_id = t.id')
142  ->join($permTable.' p',
143  'p.aro_id = n.id AND p.aco_path '.$acoCondition.' AND p.action_id '. $actionIdCondition)
144  ->queryAll()
145  ;
146  }
147 
152  public function beforeSave($event){
153  //The Record is updated
154  if(!$this->getOwner()->isNewRecord){
156 
157  if(!$aro->may($this->getOwner(), 'update'))
158  throw new RuntimeException('You are not allowed to update this record');
159  }
160 
161  return true;
162  }
163 
168  public function beforeDelete($event){
170  $owner = $this->getOwner();
171  if(!$aro->may($owner, 'delete'))
172  throw new RuntimeException('You are not allowed to delete this record');
173 
174  //Ok he has the right to do that - remove all the ACL-objects associated with this object
175  $class = Strategy::getClass('Aco');
176  $aco = $class::model()->find('model = :model AND foreign_key = :key', array(':model' => get_class($owner), ':key' => $owner->id));
177  if(!$aco)
178  throw new RuntimeException('No associated Aco!');
179 
180  if(!$aco->delete())
181  throw new RuntimeException('Unable to delete associated Aco');
182 
183  return true;
184  }
185 
186 
192  public function afterSave($event){
193  $owner = $this->getOwner();
194  if($owner){
196  //As the object is newly created, it needs a representation
197  //If strict mode is disabled, this is not necessary
198  $class = Strategy::getClass('Aco');
199  $aco = new $class();
200  $aco->model = get_class(owner);
201  $aco->foreign_key = $owner->getPrimaryKey();
202 
203  if(!$aco->save()){
204  throw new RuntimeException('Unable to create corresponding Aco for new '.get_class($owner));
205  }
206 
207  $aro->grant($aco, '*');
208  }
209  }
210 
211 
216  public function grants($permission){
218  return $aro->may($this->getOwner(), $permission);
219  }
220 
221 
222 }
223 ?>