1: <?php
2: /**
3: * Extension of the Horde_DataTreeObject class for storing Permission information in
4: * the Horde_DataTree driver. If you want to store specialized Permission
5: * information, you should extend this class instead of extending
6: * Horde_DataTreeObject directly.
7: *
8: * @TODO This class duplicates most of the functionality of the
9: * Horde_Permission class. However, because for BC/DataTree reasons it
10: * must extend Horde_DataTreeObject, we can't remove these methods yet.
11: *
12: * @author Chuck Hagenbuch <chuck@horde.org>
13: * @author Jan Schneider <jan@horde.org>
14: * @category Horde
15: * @package Perms
16: */
17: class Horde_Perms_Permission_Datatree extends Horde_DataTreeObject
18: {
19: /**
20: * Cache object.
21: *
22: * @var Horde_Cache
23: */
24: protected $_cache;
25:
26: /**
27: * Constructor. Just makes sure to call the parent constructor so that
28: * the perm's name is set properly.
29: *
30: * @param string $name The name of the perm.
31: * @param string $type The permission type.
32: * @param array $params A hash with any parameters that the permission
33: * type needs.
34: */
35: public function __construct($name, $type = 'matrix', $params = null)
36: {
37: parent::__construct($name);
38:
39: $this->data['type'] = $type;
40: if (is_array($params)) {
41: $this->data['params'] = $params;
42: }
43: }
44:
45: /**
46: * Don't store cache object on serialize().
47: *
48: * @return array List of variables to serialize.
49: */
50: public function __sleep()
51: {
52: return array_diff(array_keys(get_class_vars(__CLASS__)), array('_cache'));
53: }
54:
55: /**
56: * Sets the cache instance in the object.
57: *
58: * @param Horde_Cache $cache The cache object.
59: */
60: public function setCacheOb(Horde_Cache $cache)
61: {
62: $this->_cache = $cache;
63: }
64:
65: /**
66: * Gets one of the attributes of the object, or null if it isn't defined.
67: *
68: * @param string $attribute The attribute to get.
69: *
70: * @return mixed The value of the attribute, or null.
71: */
72: public function get($attribute)
73: {
74: $value = parent::get($attribute);
75:
76: return (is_null($value) && $attribute == 'type')
77: ? 'matrix'
78: : $value;
79: }
80:
81: /**
82: * Updates the permissions based on data passed in the array.
83: *
84: * @param array $perms An array containing the permissions which are to
85: * be updated.
86: */
87: public function updatePermissions($perms)
88: {
89: $type = $this->get('type');
90:
91: if ($type == 'matrix') {
92: /* Array of permission types to iterate through. */
93: $perm_types = Horde_Perms::getPermsArray();
94: }
95:
96: foreach ($perms as $perm_class => $perm_values) {
97: switch ($perm_class) {
98: case 'default':
99: case 'guest':
100: case 'creator':
101: if ($type == 'matrix') {
102: foreach ($perm_types as $val => $label) {
103: if (!empty($perm_values[$val])) {
104: $this->setPerm($perm_class, $val, false);
105: } else {
106: $this->unsetPerm($perm_class, $val, false);
107: }
108: }
109: } elseif (!empty($perm_values)) {
110: $this->setPerm($perm_class, $perm_values, false);
111: } else {
112: $this->unsetPerm($perm_class, null, false);
113: }
114: break;
115:
116: case 'u':
117: case 'g':
118: $permId = array('class' => $perm_class == 'u' ? 'users' : 'groups');
119: /* Figure out what names that are stored in this permission
120: * class have not been submitted for an update, ie. have been
121: * removed entirely. */
122: $current_names = isset($this->data[$permId['class']])
123: ? array_keys($this->data[$permId['class']])
124: : array();
125: $updated_names = array_keys($perm_values);
126: $removed_names = array_diff($current_names, $updated_names);
127:
128: /* Remove any names that have been completely unset. */
129: foreach ($removed_names as $name) {
130: unset($this->data[$permId['class']][$name]);
131: }
132:
133: /* If nothing to actually update finish with this case. */
134: if (is_null($perm_values)) {
135: continue;
136: }
137:
138: /* Loop through the names and update permissions for each. */
139: foreach ($perm_values as $name => $name_values) {
140: $permId['name'] = $name;
141:
142: if ($type == 'matrix') {
143: foreach ($perm_types as $val => $label) {
144: if (!empty($name_values[$val])) {
145: $this->setPerm($permId, $val, false);
146: } else {
147: $this->unsetPerm($permId, $val, false);
148: }
149: }
150: } elseif (!empty($name_values)) {
151: $this->setPerm($permId, $name_values, false);
152: } else {
153: $this->unsetPerm($permId, null, false);
154: }
155: }
156: break;
157: }
158: }
159: }
160:
161: /**
162: * TODO
163: */
164: public function setPerm($permId, $permission, $update = true)
165: {
166: if (is_array($permId)) {
167: if (empty($permId['name'])) {
168: return;
169: }
170: if ($this->get('type') == 'matrix' &&
171: isset($this->data[$permId['class']][$permId['name']])) {
172: $this->data[$permId['class']][$permId['name']] |= $permission;
173: } else {
174: $this->data[$permId['class']][$permId['name']] = $permission;
175: }
176: } else {
177: if ($this->get('type') == 'matrix' &&
178: isset($this->data[$permId])) {
179: $this->data[$permId] |= $permission;
180: } else {
181: $this->data[$permId] = $permission;
182: }
183: }
184:
185: if ($update) {
186: $this->save();
187: }
188: }
189:
190: /**
191: * TODO
192: */
193: public function unsetPerm($permId, $permission, $update = true)
194: {
195: if (is_array($permId)) {
196: if (empty($permId['name'])) {
197: return;
198: }
199: if ($this->get('type') == 'matrix') {
200: if (isset($this->data[$permId['class']][$permId['name']])) {
201: $this->data[$permId['class']][$permId['name']] &= ~$permission;
202: if (empty($this->data[$permId['class']][$permId['name']])) {
203: unset($this->data[$permId['class']][$permId['name']]);
204: }
205: if ($update) {
206: $this->save();
207: }
208: }
209: } else {
210: unset($this->data[$permId['class']][$permId['name']]);
211: if ($update) {
212: $this->save();
213: }
214: }
215: } else {
216: if ($this->get('type') == 'matrix') {
217: if (isset($this->data[$permId])) {
218: $this->data[$permId] &= ~$permission;
219: if ($update) {
220: $this->save();
221: }
222: }
223: } else {
224: unset($this->data[$permId]);
225: if ($update) {
226: $this->save();
227: }
228: }
229: }
230: }
231:
232: /**
233: * Grants a user additional permissions to this object.
234: *
235: * @param string $user The user to grant additional permissions
236: * to.
237: * @param integer $permission The permission (DELETE, etc.) to add.
238: * @param boolean $update Whether to automatically update the
239: * backend.
240: */
241: public function addUserPermission($user, $permission, $update = true)
242: {
243: if (empty($user)) {
244: return;
245: }
246:
247: if ($this->get('type') == 'matrix' &&
248: isset($this->data['users'][$user])) {
249: $this->data['users'][$user] |= $permission;
250: } else {
251: $this->data['users'][$user] = $permission;
252: }
253:
254: if ($update) {
255: $this->save();
256: }
257: }
258:
259: /**
260: * Grants guests additional permissions to this object.
261: *
262: * @param integer $permission The permission (DELETE, etc.) to add.
263: * @param boolean $update Whether to automatically update the
264: * backend.
265: */
266: public function addGuestPermission($permission, $update = true)
267: {
268: if ($this->get('type') == 'matrix' &&
269: isset($this->data['guest'])) {
270: $this->data['guest'] |= $permission;
271: } else {
272: $this->data['guest'] = $permission;
273: }
274:
275: if ($update) {
276: $this->save();
277: }
278: }
279:
280: /**
281: * Grants creators additional permissions to this object.
282: *
283: * @param integer $permission The permission (DELETE, etc.) to add.
284: * @param boolean $update Whether to automatically update the
285: * backend.
286: */
287: public function addCreatorPermission($permission, $update = true)
288: {
289: if ($this->get('type') == 'matrix' &&
290: isset($this->data['creator'])) {
291: $this->data['creator'] |= $permission;
292: } else {
293: $this->data['creator'] = $permission;
294: }
295:
296: if ($update) {
297: $this->save();
298: }
299: }
300:
301: /**
302: * Grants additional default permissions to this object.
303: *
304: * @param integer $permission The permission (DELETE, etc.) to add.
305: * @param boolean $update Whether to automatically update the
306: * backend.
307: */
308: public function addDefaultPermission($permission, $update = true)
309: {
310: if ($this->get('type') == 'matrix' &&
311: isset($this->data['default'])) {
312: $this->data['default'] |= $permission;
313: } else {
314: $this->data['default'] = $permission;
315: }
316:
317: if ($update) {
318: $this->save();
319: }
320: }
321:
322: /**
323: * Grants a group additional permissions to this object.
324: *
325: * @param integer $groupId The id of the group to grant additional
326: * permissions to.
327: * @param integer $permission The permission (DELETE, etc.) to add.
328: * @param boolean $update Whether to automatically update the
329: * backend.
330: */
331: public function addGroupPermission($groupId, $permission, $update = true)
332: {
333: if (empty($groupId)) {
334: return;
335: }
336:
337: if ($this->get('type') == 'matrix' &&
338: isset($this->data['groups'][$groupId])) {
339: $this->data['groups'][$groupId] |= $permission;
340: } else {
341: $this->data['groups'][$groupId] = $permission;
342: }
343:
344: if ($update) {
345: $this->save();
346: }
347: }
348:
349: /**
350: * Removes a permission that a user currently has on this object.
351: *
352: * @param string $user The user to remove the permission from.
353: * @param integer $permission The permission (DELETE, etc.) to
354: * remove.
355: * @param boolean $update Whether to automatically update the
356: * backend.
357: */
358: public function removeUserPermission($user, $permission, $update = true)
359: {
360: if (empty($user) || !isset($this->data['users'][$user])) {
361: return;
362: }
363:
364: if ($this->get('type') == 'matrix') {
365: $this->data['users'][$user] &= ~$permission;
366: if (empty($this->data['users'][$user])) {
367: unset($this->data['users'][$user]);
368: }
369: } else {
370: unset($this->data['users'][$user]);
371: }
372:
373: if ($update) {
374: $this->save();
375: }
376: }
377:
378: /**
379: * Removes a permission that guests currently have on this object.
380: *
381: * @param integer $permission The permission (DELETE, etc.) to remove.
382: * @param boolean $update Whether to automatically update the
383: * backend.
384: */
385: public function removeGuestPermission($permission, $update = true)
386: {
387: if (!isset($this->data['guest'])) {
388: return;
389: }
390:
391: if ($this->get('type') == 'matrix') {
392: $this->data['guest'] &= ~$permission;
393: } else {
394: unset($this->data['guest']);
395: }
396:
397: if ($update) {
398: $this->save();
399: }
400: }
401:
402: /**
403: * Removes a permission that creators currently have on this object.
404: *
405: * @param integer $permission The permission (DELETE, etc.) to remove.
406: * @param boolean $update Whether to automatically update the
407: * backend.
408: */
409: public function removeCreatorPermission($permission, $update = true)
410: {
411: if (!isset($this->data['creator'])) {
412: return;
413: }
414:
415: if ($this->get('type') == 'matrix') {
416: $this->data['creator'] &= ~$permission;
417: } else {
418: unset($this->data['creator']);
419: }
420:
421: if ($update) {
422: $this->save();
423: }
424: }
425:
426: /**
427: * Removes a default permission on this object.
428: *
429: * @param integer $permission The permission (DELETE, etc.) to remove.
430: * @param boolean $update Whether to automatically update the
431: * backend.
432: */
433: public function removeDefaultPermission($permission, $update = true)
434: {
435: if (!isset($this->data['default'])) {
436: return;
437: }
438:
439: if ($this->get('type') == 'matrix') {
440: $this->data['default'] &= ~$permission;
441: } else {
442: unset($this->data['default']);
443: }
444:
445: if ($update) {
446: $this->save();
447: }
448: }
449:
450: /**
451: * Removes a permission that a group currently has on this object.
452: *
453: * @param integer $groupId The id of the group to remove the
454: * permission from.
455: * @param integer $permission The permission (DELETE, etc.) to remove.
456: * @param boolean $update Whether to automatically update the
457: * backend.
458: */
459: public function removeGroupPermission($groupId, $permission,
460: $update = true)
461: {
462: if (empty($groupId) || !isset($this->data['groups'][$groupId])) {
463: return;
464: }
465:
466: if ($this->get('type') == 'matrix') {
467: $this->data['groups'][$groupId] &= ~$permission;
468: if (empty($this->data['groups'][$groupId])) {
469: unset($this->data['groups'][$groupId]);
470: }
471: } else {
472: unset($this->data['groups'][$groupId]);
473: }
474:
475: if ($update) {
476: $this->save();
477: }
478: }
479:
480: /**
481: * Returns an array of all user permissions on this object.
482: *
483: * @param integer $perm List only users with this permission level.
484: * Defaults to all users.
485: *
486: * @return array All user permissions for this object, indexed by user.
487: */
488: public function getUserPermissions($perm = null)
489: {
490: if (!isset($this->data['users']) || !is_array($this->data['users'])) {
491: return array();
492: } elseif (!$perm) {
493: return $this->data['users'];
494: }
495:
496: $users = array();
497: foreach ($this->data['users'] as $user => $uperm) {
498: if ($uperm & $perm) {
499: $users[$user] = $uperm;
500: }
501: }
502:
503: return $users;
504: }
505:
506: /**
507: * Returns the guest permissions on this object.
508: *
509: * @return integer The guest permissions on this object.
510: */
511: public function getGuestPermissions()
512: {
513: return empty($this->data['guest'])
514: ? null
515: : $this->data['guest'];
516: }
517:
518: /**
519: * Returns the creator permissions on this object.
520: *
521: * @return integer The creator permissions on this object.
522: */
523: public function getCreatorPermissions()
524: {
525: return empty($this->data['creator'])
526: ? null
527: : $this->data['creator'];
528: }
529:
530: /**
531: * Returns the default permissions on this object.
532: *
533: * @return integer The default permissions on this object.
534: */
535: public function getDefaultPermissions()
536: {
537: return empty($this->data['default'])
538: ? null
539: : $this->data['default'];
540: }
541:
542: /**
543: * Returns an array of all group permissions on this object.
544: *
545: * @param integer $perm List only users with this permission level.
546: * Defaults to all users.
547: *
548: * @return array All group permissions for this object, indexed by group.
549: */
550: public function getGroupPermissions($perm = null)
551: {
552: if (!isset($this->data['groups']) ||
553: !is_array($this->data['groups'])) {
554: return array();
555: } elseif (!$perm) {
556: return $this->data['groups'];
557: }
558:
559: $groups = array();
560: foreach ($this->data['groups'] as $group => $gperm) {
561: if ($gperm & $perm) {
562: $groups[$group] = $gperm;
563: }
564: }
565:
566: return $groups;
567: }
568:
569: /**
570: * Saves any changes to this object to the backend permanently. New
571: * objects are added instead.
572: *
573: * @throws Horde_Perms_Exception
574: */
575: public function save()
576: {
577: $name = $this->getName();
578: if (empty($name)) {
579: throw new Horde_Perms_Exception('Permission names must be non-empty');
580: }
581:
582: parent::save();
583:
584: if ($this->_cache) {
585: $this->_cache->expire('perm_' . $this->_cacheVersion . $name);
586: $this->_cache->expire('perm_exists_' . $this->_cacheVersion . $name);
587: }
588: }
589:
590: }
591: