1<?php 2/** 3 * Horde specific wrapper for Horde_Share drivers. Adds Horde hook calls etc... 4 * 5 * Copyright 2002-2017 Horde LLC (http://www.horde.org/) 6 * 7 * See the enclosed file COPYING for license information (LGPL). If you did 8 * not receive this file, see http://opensource.org/licenses/lgpl-2.1.php 9 * 10 * @author Michael J. Rubinsky <mrubinsk@horde.org> 11 * @category Horde 12 * @license http://opensource.org/licenses/lgpl-2.1.php LGPL 13 * @package Core 14 */ 15class Horde_Core_Share_Driver 16{ 17 /** 18 * The composed Horde_Share driver 19 * 20 * @var Horde_Share_Base 21 */ 22 protected $_share; 23 24 /** 25 * Maps the concrete share class to the required storage adapter. 26 * 27 * @var array 28 */ 29 protected $_storageMap = array( 30 'Horde_Share_Sql' => 'Horde_Db_Adapter', 31 'Horde_Share_Sqlng' => 'Horde_Db_Adapter', 32 'Horde_Share_Sql_Hierarchical' => 'Horde_Db_Adapter', 33 'Horde_Share_Kolab' => 'Horde_Kolab_Storage'); 34 35 /** 36 */ 37 public function __construct(Horde_Share_Base $share) 38 { 39 global $injector; 40 41 $this->_share = $share; 42 $this->_share->setStorage($injector->getInstance($this->_storageMap[get_class($this->_share)])); 43 $this->_share->addCallback('add', array($this, 'shareAddCallback')); 44 $this->_share->addCallback('modify', array($this, 'shareModifyCallback')); 45 $this->_share->addCallback('remove', array($this, 'shareRemoveCallback')); 46 $this->_share->addCallback('list', array($this, 'shareListCallback')); 47 48 try { 49 $injector->getInstance('Horde_Core_Hooks')->callHook('share_init', 'horde', array($this, $this->_share->getApp())); 50 } catch (Horde_Exception_HookNotSet $e) {} 51 } 52 53 /** 54 * Delegate method calls to the composed share object. 55 * 56 * @param string $method The method name 57 * @param array $args The method arguments 58 * 59 * @return mixed The result of the method call 60 */ 61 public function __call($method, $args) 62 { 63 return call_user_func_array(array($this->_share, $method), $args); 64 } 65 66 /** 67 * Lock an item belonging to a share, or an entire share itself. 68 * 69 * @param Horde_Lock $locks The lock object. 70 * @param string $uid The uid of a specific object to lock, if 71 * null, entire share is locked. 72 * 73 * @return mixed A lock ID on sucess, false if: 74 * - The share is already locked, 75 * - The item is already locked, 76 * - A share lock was requested and an item is already locked in the 77 * share. 78 */ 79 public function lock(Horde_Lock $locks, $uid = null) 80 { 81 $shareid = $this->_share->getId(); 82 83 // Default parameters. 84 $locktype = Horde_Lock::TYPE_EXCLUSIVE; 85 $timeout = 600; 86 $itemscope = $this->_share->getShareOb()->getApp() . ':' . $shareid; 87 88 if (!empty($uid)) { 89 // Check if the share is locked. Share locks are placed at app scope 90 try { 91 $result = $locks->getLocks($this->_share->getShareOb()->getApp(), $shareid, $locktype); 92 } catch (Horde_Lock_Exception $e) { 93 throw new Horde_Exception_Wrapped($e); 94 } 95 if (!empty($result)) { 96 // Lock found. 97 return false; 98 } 99 100 // Try to place the item lock at app:shareid scope. 101 return $locks->setLock($GLOBALS['registry']->getAuth(), 102 $itemscope, 103 $uid, 104 $timeout, 105 $locktype); 106 } else { 107 // Share lock requested. Check for locked items. 108 try { 109 $result = $locks->getLocks($itemscope, null, $locktype); 110 } catch (Horde_Lock_Exception $e) { 111 throw new Horde_Exception_Wrapped($e); 112 } 113 if (!empty($result)) { 114 // Lock found. 115 return false; 116 } 117 118 // Try to place the share lock 119 return $locks->setLock($GLOBALS['registry']->getAuth(), 120 $this->_share->getShareOb()->getApp(), 121 $shareid, 122 $timeout, 123 $locktype); 124 } 125 } 126 127 /** 128 * Removes the lock for a lock ID. 129 * 130 * @param Horde_Lock $locks The lock object 131 * @param string $lockid The lock ID as generated by a previous call 132 * to lock(). 133 * 134 * @return boolean 135 */ 136 public function unlock(Horde_Lock $locks, $lockid) 137 { 138 return $locks->clearLock($lockid); 139 } 140 141 /** 142 * Checks for existing locks. 143 * 144 * First this checks for share locks and if none exists, checks for item 145 * locks (if item_uid defined). It will return the first lock found. 146 * 147 * @param Horde_Lock $locks The lock object. 148 * @param string $item_uid A uid of an item from this share. 149 * 150 * @return array Hash with the found lock information in 'lock' and the 151 * lock type ('share' or 'item') in 'type', or an empty 152 * array if there are no locks. 153 */ 154 public function checkLocks(Horde_Lock $locks, $item_uid = null) 155 { 156 $shareid = $this->_share->getId(); 157 $locktype = Horde_Lock::TYPE_EXCLUSIVE; 158 159 // Check for share locks 160 try { 161 $result = $locks->getLocks($this->_share->getShareOb()->getApp(), $shareid, $locktype); 162 } catch (Horde_Lock_Exception $e) { 163 Horde::log($e, 'ERR'); 164 throw new Horde_Exception_Wrapped($e); 165 } 166 167 if (empty($result) && !empty($item_uid)) { 168 // Check for item locks 169 $locktargettype = 'item'; 170 try { 171 $result = $locks->getLocks($this->_share->getShareOb()->getApp() . ':' . $shareid, $item_uid, $locktype); 172 } catch (Horde_Lock_Exception $e) { 173 Horde::log($e, 'ERR'); 174 throw new Horde_Exception($e->getMessage()); 175 } 176 } else { 177 $locktargettype = 'share'; 178 } 179 180 if (empty($result)) { 181 return array(); 182 } 183 184 return array('type' => $locktargettype, 185 'lock' => reset($result)); 186 } 187 188 /** 189 * share_list callback 190 * 191 * @param string $userid The userid listShares was called with 192 * @param array $shares The result of the listShares() call 193 * @param array $params The params that listShares() was called with 194 * 195 * @return array An array of share objects 196 */ 197 public function shareListCallback($userid, $shares, $params = array()) 198 { 199 try { 200 $params = new Horde_Support_Array($params); 201 return $GLOBALS['injector']->getInstance('Horde_Core_Hooks') 202 ->callHook('share_list', 'horde', array($userid, $params['perm'], $params['attributes'], $shares)); 203 } catch (Horde_Exception_HookNotSet $e) {} 204 205 return $shares; 206 } 207 208 /** 209 * Adds the share_add hook before delegating to the share object. 210 * 211 * @param Horde_Share_Object The share object being added 212 */ 213 public function shareAddCallback(Horde_Share_Object $share) 214 { 215 try { 216 $GLOBALS['injector']->getInstance('Horde_Core_Hooks') 217 ->callHook('share_add', 'horde', array($share)); 218 } catch (Horde_Exception_HookNotSet $e) {} 219 } 220 221 /** 222 * Calls the share_remove hook before delegating to the share object. 223 * 224 * @see Horde_Share_Base::removeShare() 225 */ 226 public function shareRemoveCallback(Horde_Share_Object $share) 227 { 228 try { 229 $GLOBALS['injector']->getInstance('Horde_Core_Hooks') 230 ->callHook('share_remove', 'horde', array($share)); 231 } catch (Horde_Exception_HookNotSet $e) {} 232 } 233 234 public function shareModifyCallback(Horde_Share_Object $share) 235 { 236 try { 237 $GLOBALS['injector']->getInstance('Horde_Core_Hooks') 238 ->callHook('share_modify', 'horde', array($share)); 239 } catch (Horde_Exception_HookNotSet $e) {} 240 } 241 242} 243