1: <?php
2: /**
3: * Horde_Share_Datatree provides the datatree backend for the horde share
4: * driver.
5: *
6: * Copyright 2002-2012 Horde LLC (http://www.horde.org/)
7: * Copyright 2002-2007 Infoteck Internet <webmaster@infoteck.qc.ca>
8: *
9: * See the enclosed file COPYING for license information (LGPL). If you
10: * did not receive this file, see http://www.horde.org/licenses/lgpl21.
11: *
12: * @author Joel Vandal <joel@scopserv.com>
13: * @author Mike Cochrame <mike@graftonhall.co.nz>
14: * @author Chuck Hagenbuch <chuck@horde.org>
15: * @author Jan Schneider <jan@horde.org>
16: * @author Gunnar Wrobel <wrobel@pardus.de>
17: * @package Share
18: */
19: class Horde_Share_Datatree extends Horde_Share_Base
20: {
21: /**
22: * The Horde_Share_Object subclass to instantiate objects as
23: *
24: * @var string
25: */
26: protected $_shareObject = 'Horde_Share_Object_Datatree';
27:
28: /**
29: * Pointer to a Horde_DataTree instance to manage/store shares
30: *
31: * @var Horde_DataTree
32: */
33: protected $_datatree;
34:
35: /**
36: * Initializes the object.
37: *
38: * @throws Horde_Exception
39: */
40: public function __wakeup()
41: {
42: // TODO: Remove GLOBAL config access
43: if (empty($GLOBALS['conf']['datatree']['driver'])) {
44: throw new Horde_Exception('You must configure a Horde_DataTree backend to use Shares.');
45: }
46:
47: $driver = $GLOBALS['conf']['datatree']['driver'];
48: $this->_datatree = &Horde_DataTree::singleton(
49: $driver,
50: array_merge(Horde::getDriverConfig('datatree', $driver),
51: array('group' => 'horde.shares.' . $this->_app))
52: );
53:
54: foreach (array_keys($this->_cache) as $name) {
55: if (!is_a($this->_datatree, 'PEAR_Error')) {
56: $this->_cache[$name]->setShareOb($this);
57: $this->_cache[$name]->datatreeObject->setDataTree($this->_datatree);
58: }
59: }
60:
61: parent::__wakeup();
62: }
63:
64: /**
65: * Returns a Horde_Share_Object_datatree object corresponding to the given
66: * share name, with the details retrieved appropriately.
67: *
68: * @param string $name The name of the share to retrieve.
69: *
70: * @return Horde_Share_Object_datatree The requested share.
71: * @throws Horde_Share_Exception
72: */
73: public function _getShare($name)
74: {
75: $datatreeObject = $this->_datatree->getObject($name, 'Horde_Share_Object_DataTree_Share');
76: if ($datatreeObject instanceof PEAR_Error) {
77: throw new Horde_Share_Exception($datatreeObject->getMessage());
78: }
79: $share = $this->_createObject($datatreeObject);
80:
81: return $share;
82: }
83:
84: /**
85: * Returns a Horde_Share_Object_datatree object corresponding to the given
86: * unique ID, with the details retrieved appropriately.
87: *
88: * @param string $cid The id of the share to retrieve.
89: *
90: * @return Horde_Share_Object_datatree The requested share.
91: * @throws Horde_Share_Exception
92: */
93: protected function _getShareById($id)
94: {
95: $datatreeObject = $this->_datatree->getObjectById($id, 'Horde_Share_Object_DataTree_Share');
96: if (is_a($datatreeObject, 'PEAR_Error')) {
97: throw new Horde_Share_Exception($datatreeObject->getMessage());
98: }
99: $share = $this->_createObject($datatreeObject);
100:
101: return $share;
102: }
103:
104: /**
105: * Returns an array of Horde_Share_Object_datatree objects corresponding
106: * to the given set of unique IDs, with the details retrieved
107: * appropriately.
108: *
109: * @param array $cids The array of ids to retrieve.
110: *
111: * @return array The requested shares.
112: * @throws Horde_Share_Exception
113: */
114: protected function _getShares(array $ids)
115: {
116: $shares = array();
117: $objects = $this->_datatree->getObjects($ids, 'Horde_Share_Object_DataTree_Share');
118: if (is_a($objects, 'PEAR_Error')) {
119: throw new Horde_Share_Exception($objects->getMessage());
120: }
121: foreach (array_keys($objects) as $key) {
122: if (is_a($objects[$key], 'PEAR_Error')) {
123: return $objects[$key];
124: }
125: $shares[$key] = $this->_createObject($objects[$key]);
126: }
127: return $shares;
128: }
129:
130: /**
131: * Lists *all* shares for the current app/share, regardless of
132: * permissions.
133: *
134: * @return array All shares for the current app/share.
135: * @throws Horde_Share_Exception
136: */
137: protected function _listAllShares()
138: {
139: $sharelist = $this->_datatree->get(DATATREE_FORMAT_FLAT, DATATREE_ROOT, true);
140: if ($sharelist instanceof PEAR_Error) {
141: throw new Horde_Share_Exception($sharelist->getMessage());
142: }
143: if (!count($sharelist)) {
144: return $sharelist;
145: }
146: unset($sharelist[DATATREE_ROOT]);
147:
148: return $this->getShares(array_keys($sharelist));
149: }
150:
151: /**
152: * Returns an array of all shares that $userid has access to.
153: *
154: * @param string $userid The userid of the user to check access for.
155: * @param array $params See listShares().
156: *
157: * @return array The shares the user has access to.
158: * @throws Horde_Share_Exception
159: */
160: protected function _listShares($userid, array $params = array())
161: {
162: $key = serialize(array($userid, $params['perm'], $params['attributes']));
163: if (empty($this->_listCache[$key])) {
164: $criteria = $this->_getShareCriteria($userid, $params['perm'],
165: $params['attributes']);
166: $sharelist = $this->_datatree->getByAttributes($criteria,
167: DATATREE_ROOT,
168: true, 'id',
169: $params['from'],
170: $params['count'],
171: $params['sort_by'],
172: null,
173: $params['direction']);
174: if ($sharelist instanceof PEAR_Error) {
175: throw new Horde_Share_Exception($sharelist);
176: }
177: $this->_listCache[$key] = array_keys($sharelist);
178: }
179:
180: return $this->_listCache[$key];
181: }
182:
183: /**
184: * Returns the number of shares that $userid has access to.
185: *
186: * @param string $userid The userid of the user to check access for.
187: * @param integer $perm The level of permissions required.
188: * @param mixed $attributes Restrict the shares counted to those
189: * matching $attributes. An array of
190: * attribute/values pairs or a share owner
191: * username.
192: *
193: * @return integer The number of shares
194: */
195: protected function _countShares($userid, $perm = Horde_Perms::SHOW,
196: $attributes = null)
197: {
198: $criteria = $this->_getShareCriteria($userid, $perm, $attributes);
199: return $this->_datatree->countByAttributes($criteria, DATATREE_ROOT, true, 'id');
200: }
201:
202: /**
203: * Returns a new share object. Share objects should *ALWAYS* be instantiated
204: * via the Horde_Share object.
205: *
206: * @param string $name The share's name.
207: *
208: * @return Horde_Share_Object_datatree A new share object.
209: */
210: protected function _newShare($name)
211: {
212: if (empty($name)) {
213: throw new Horde_Share_Exception('Share names must be non-empty');
214: }
215: $datatreeObject = new Horde_Share_Object_DataTree_Share($name);
216: $datatreeObject->setDataTree($this->_datatree);
217: return $this->_createObject($datatreeObject);
218: }
219:
220: /**
221: * Adds a share to the shares system.
222: *
223: * The share must first be created with
224: * Horde_Share_datatreee::_newShare(), and have any initial details added
225: * to it, before this function is called.
226: *
227: * @param Horde_Share_Object_datatree $share The new share object.
228: */
229: protected function _addShare(Horde_Share_Object $share)
230: {
231: Horde_Exception_Pear::catchError($this->_datatree->add($share->datatreeObject));
232: }
233:
234: /**
235: * Removes a share from the shares system permanently.
236: *
237: * @param Horde_Share_Object_datatree $share The share to remove.
238: */
239: protected function _removeShare(Horde_Share_Object $share)
240: {
241: Horde_Exception_Pear::catchError($this->_datatree->remove($share->datatreeObject));
242: }
243:
244: /**
245: * Renames a share in the shares system.
246: *
247: * @param Horde_Share_Object $share The share to rename.
248: * @param string $name The share's new name.
249: *
250: * @throws Horde_Share_Exception
251: */
252: protected function _renameShare(Horde_Share_Object $share, $name)
253: {
254: Horde_Exception_Pear::catchError($this->_datatree->rename($share->datatreeObject, $name));
255: }
256:
257: /**
258: * Checks if a share exists in the system.
259: *
260: * @param string $share The share to check.
261: *
262: * @return boolean True if the share exists.
263: */
264: protected function _exists($share)
265: {
266: return $this->_datatree->exists($share);
267: }
268:
269: /**
270: * Check that a share id exists in the system.
271: *
272: * @param integer $id The share id
273: *
274: * @return boolean True if the share exists.
275: */
276: protected function _idExists($id)
277: {
278: try {
279: $this->_getShareById($id);
280: return true;
281: } catch (Horde_Share_Exception $e) {
282: return false;
283: }
284: }
285:
286: /**
287: * Returns an array of criteria for querying shares.
288: * @access protected
289: *
290: * @param string $userid The userid of the user to check access for.
291: * @param integer $perm The level of permissions required.
292: * @param mixed $attributes Restrict the shares returned to those who
293: * have these attribute values.
294: *
295: * @return array The criteria tree for fetching this user's shares.
296: */
297: protected function _getShareCriteria($userid, $perm = Horde_Perms::SHOW,
298: $attributes = null)
299: {
300: if (!empty($userid)) {
301: $criteria = array(
302: 'OR' => array(
303: // (owner == $userid)
304: array(
305: 'AND' => array(
306: array('field' => 'name', 'op' => '=', 'test' => 'owner'),
307: array('field' => 'value', 'op' => '=', 'test' => $userid))),
308:
309: // (name == perm_users and key == $userid and val & $perm)
310: array(
311: 'AND' => array(
312: array('field' => 'name', 'op' => '=', 'test' => 'perm_users'),
313: array('field' => 'key', 'op' => '=', 'test' => $userid),
314: array('field' => 'value', 'op' => '&', 'test' => $perm))),
315:
316: // (name == perm_creator and val & $perm)
317: array(
318: 'AND' => array(
319: array('field' => 'name', 'op' => '=', 'test' => 'perm_creator'),
320: array('field' => 'value', 'op' => '&', 'test' => $perm))),
321:
322: // (name == perm_default and val & $perm)
323: array(
324: 'AND' => array(
325: array('field' => 'name', 'op' => '=', 'test' => 'perm_default'),
326: array('field' => 'value', 'op' => '&', 'test' => $perm)))));
327:
328: // If the user has any group memberships, check for those also.
329: // @TODO: inject
330: try {
331: $groups = $this->_groups->listGroups($userid);
332: if ($groups) {
333: // (name == perm_groups and key in ($groups) and val & $perm)
334: $criteria['OR'][] = array(
335: 'AND' => array(
336: array('field' => 'name', 'op' => '=', 'test' => 'perm_groups'),
337: array('field' => 'key', 'op' => 'IN', 'test' => array_keys($groups)),
338: array('field' => 'value', 'op' => '&', 'test' => $perm)));
339: }
340: } catch (Horde_Group_Exception $e) {
341: }
342: } else {
343: $criteria = array(
344: 'AND' => array(
345: array('field' => 'name', 'op' => '=', 'test' => 'perm_guest'),
346: array('field' => 'value', 'op' => '&', 'test' => $perm)));
347: }
348:
349: if (is_array($attributes)) {
350: // Build attribute/key filter.
351: foreach ($attributes as $key => $value) {
352: $criteria = array(
353: 'AND' => array(
354: $criteria,
355: array(
356: 'JOIN' => array(
357: 'AND' => array(
358: array('field' => 'name', 'op' => '=', 'test' => $key),
359: array('field' => 'value', 'op' => '=', 'test' => $value))))));
360: }
361: } elseif (!is_null($attributes)) {
362: // Restrict to shares owned by the user specified in the
363: // $attributes string.
364: $criteria = array(
365: 'AND' => array(
366: $criteria,
367: array(
368: 'JOIN' => array(
369: array('field' => 'name', 'op' => '=', 'test' => 'owner'),
370: array('field' => 'value', 'op' => '=', 'test' => $attributes)))));
371: }
372:
373: return $criteria;
374: }
375: }
376: