| Code Coverage
| Lines | Functions and Methods | Classes and Traits
Total | 76.27% covered (warning) | 76.27% | 630 / 826 | 51.67% covered (warning) | 51.67% | 31 / 60 | CRAP | 0.00% covered (danger) | 0.00% | 0 / 1
SeedDMS_Core_Folder | 76.27% covered (warning) | 76.27% | 630 / 826 | 51.67% covered (warning) | 51.67% | 31 / 60 | 2561.14 | 0.00% covered (danger) | 0.00% | 0 / 1
__construct | 100.00% covered (success) | 100.00% | 11 / 11 | 100.00% covered (success) | 100.00% | 1 / 1 | 1 |
clearCache | 100.00% covered (success) | 100.00% | 7 / 7 | 100.00% covered (success) | 100.00% | 1 / 1 | 1 |
__toString | 0.00% covered (danger) | 0.00% | 0 / 1 | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 |
isType | 100.00% covered (success) | 100.00% | 1 / 1 | 100.00% covered (success) | 100.00% | 1 / 1 | 1 |
getSearchFields | 100.00% covered (success) | 100.00% | 11 / 11 | 100.00% covered (success) | 100.00% | 1 / 1 | 5 |
getSearchTables | 100.00% covered (success) | 100.00% | 2 / 2 | 100.00% covered (success) | 100.00% | 1 / 1 | 1 |
getInstanceByData | 100.00% covered (success) | 100.00% | 5 / 5 | 100.00% covered (success) | 100.00% | 1 / 1 | 1 |
getInstance | 100.00% covered (success) | 100.00% | 10 / 10 | 100.00% covered (success) | 100.00% | 1 / 1 | 6 |
getInstanceByName | 92.86% covered (success) | 92.86% | 13 / 14 | 0.00% covered (danger) | 0.00% | 0 / 1 | 8.02 |
applyDecorators | 33.33% covered (danger) | 33.33% | 2 / 6 | 0.00% covered (danger) | 0.00% | 0 / 1 | 5.67 |
getName | 100.00% covered (success) | 100.00% | 1 / 1 | 100.00% covered (success) | 100.00% | 1 / 1 | 1 |
setName | 88.24% covered (warning) | 88.24% | 15 / 17 | 0.00% covered (danger) | 0.00% | 0 / 1 | 8.10 |
getComment | 100.00% covered (success) | 100.00% | 1 / 1 | 100.00% covered (success) | 100.00% | 1 / 1 | 1 |
setComment | 88.24% covered (warning) | 88.24% | 15 / 17 | 0.00% covered (danger) | 0.00% | 0 / 1 | 8.10 |
getDate | 100.00% covered (success) | 100.00% | 1 / 1 | 100.00% covered (success) | 100.00% | 1 / 1 | 1 |
setDate | 100.00% covered (success) | 100.00% | 10 / 10 | 100.00% covered (success) | 100.00% | 1 / 1 | 4 |
getParent | 100.00% covered (success) | 100.00% | 5 / 5 | 100.00% covered (success) | 100.00% | 1 / 1 | 4 |
isSubFolder | 100.00% covered (success) | 100.00% | 4 / 4 | 100.00% covered (success) | 100.00% | 1 / 1 | 3 |
setParent | 85.00% covered (warning) | 85.00% | 34 / 40 | 0.00% covered (danger) | 0.00% | 0 / 1 | 15.76 |
getOwner | 100.00% covered (success) | 100.00% | 3 / 3 | 100.00% covered (success) | 100.00% | 1 / 1 | 2 |
setOwner | 57.89% covered (warning) | 57.89% | 11 / 19 | 0.00% covered (danger) | 0.00% | 0 / 1 | 12.78 |
getDefaultAccess | 100.00% covered (success) | 100.00% | 5 / 5 | 100.00% covered (success) | 100.00% | 1 / 1 | 3 |
setDefaultAccess | 100.00% covered (success) | 100.00% | 9 / 9 | 100.00% covered (success) | 100.00% | 1 / 1 | 3 |
inheritsAccess | 100.00% covered (success) | 100.00% | 1 / 1 | 100.00% covered (success) | 100.00% | 1 / 1 | 1 |
setInheritAccess | 100.00% covered (success) | 100.00% | 10 / 10 | 100.00% covered (success) | 100.00% | 1 / 1 | 4 |
getSequence | 100.00% covered (success) | 100.00% | 1 / 1 | 100.00% covered (success) | 100.00% | 1 / 1 | 1 |
setSequence | 100.00% covered (success) | 100.00% | 6 / 6 | 100.00% covered (success) | 100.00% | 1 / 1 | 2 |
hasSubFolders | 87.50% covered (warning) | 87.50% | 7 / 8 | 0.00% covered (danger) | 0.00% | 0 / 1 | 4.03 |
hasSubFolderByName | 100.00% covered (success) | 100.00% | 6 / 6 | 100.00% covered (success) | 100.00% | 1 / 1 | 3 |
getSubFolders | 100.00% covered (success) | 100.00% | 20 / 20 | 100.00% covered (success) | 100.00% | 1 / 1 | 16 |
addSubFolder | 65.52% covered (warning) | 65.52% | 19 / 29 | 0.00% covered (danger) | 0.00% | 0 / 1 | 17.90 |
getPath | 100.00% covered (success) | 100.00% | 8 / 8 | 100.00% covered (success) | 100.00% | 1 / 1 | 7 |
getFolderPathPlain | 87.50% covered (warning) | 87.50% | 7 / 8 | 0.00% covered (danger) | 0.00% | 0 / 1 | 5.05 |
isDescendant | 100.00% covered (success) | 100.00% | 5 / 5 | 100.00% covered (success) | 100.00% | 1 / 1 | 3 |
hasDocuments | 100.00% covered (success) | 100.00% | 6 / 6 | 100.00% covered (success) | 100.00% | 1 / 1 | 3 |
hasDocumentByName | 100.00% covered (success) | 100.00% | 6 / 6 | 100.00% covered (success) | 100.00% | 1 / 1 | 3 |
getDocuments | 100.00% covered (success) | 100.00% | 21 / 21 | 100.00% covered (success) | 100.00% | 1 / 1 | 17 |
countChildren | 93.18% covered (success) | 93.18% | 41 / 44 | 0.00% covered (danger) | 0.00% | 0 / 1 | 15.07 |
addDocument | 55.00% covered (warning) | 55.00% | 22 / 40 | 0.00% covered (danger) | 0.00% | 0 / 1 | 43.34 |
removeFromDatabase | 50.00% covered (danger) | 50.00% | 16 / 32 | 0.00% covered (danger) | 0.00% | 0 / 1 | 30.00 |
remove | 74.07% covered (warning) | 74.07% | 20 / 27 | 0.00% covered (danger) | 0.00% | 0 / 1 | 26.97 |
emptyFolder | 86.36% covered (warning) | 86.36% | 19 / 22 | 0.00% covered (danger) | 0.00% | 0 / 1 | 14.50 |
getAccessList | 90.91% covered (success) | 90.91% | 20 / 22 | 0.00% covered (danger) | 0.00% | 0 / 1 | 12.11 |
clearAccessList | 88.89% covered (warning) | 88.89% | 8 / 9 | 0.00% covered (danger) | 0.00% | 0 / 1 | 3.01 |
addAccess | 94.44% covered (success) | 94.44% | 17 / 18 | 0.00% covered (danger) | 0.00% | 0 / 1 | 8.01 |
changeAccess | 87.50% covered (warning) | 87.50% | 14 / 16 | 0.00% covered (danger) | 0.00% | 0 / 1 | 5.05 |
removeAccess | 87.50% covered (warning) | 87.50% | 14 / 16 | 0.00% covered (danger) | 0.00% | 0 / 1 | 6.07 |
getAccessMode | 70.00% covered (warning) | 70.00% | 28 / 40 | 0.00% covered (danger) | 0.00% | 0 / 1 | 44.25 |
getGroupAccessMode | 93.33% covered (success) | 93.33% | 14 / 15 | 0.00% covered (danger) | 0.00% | 0 / 1 | 7.01 |
getNotifyList | 50.00% covered (danger) | 50.00% | 8 / 16 | 0.00% covered (danger) | 0.00% | 0 / 1 | 22.50 |
cleanNotifyList | 60.00% covered (warning) | 60.00% | 6 / 10 | 0.00% covered (danger) | 0.00% | 0 / 1 | 8.30 |
addNotify | 0.00% covered (danger) | 0.00% | 0 / 40 | 0.00% covered (danger) | 0.00% | 0 / 1 | 306 |
removeNotify | 55.00% covered (warning) | 55.00% | 11 / 20 | 0.00% covered (danger) | 0.00% | 0 / 1 | 13.83 |
getApproversList | 0.00% covered (danger) | 0.00% | 0 / 1 | 0.00% covered (danger) | 0.00% | 0 / 1 | 2 |
getReadAccessList | 100.00% covered (success) | 100.00% | 55 / 55 | 100.00% covered (success) | 100.00% | 1 / 1 | 26 |
getFolderList | 100.00% covered (success) | 100.00% | 6 / 6 | 100.00% covered (success) | 100.00% | 1 / 1 | 3 |
repair | 0.00% covered (danger) | 0.00% | 0 / 15 | 0.00% covered (danger) | 0.00% | 0 / 1 | 30 |
getDocumentsMinMax | 100.00% covered (success) | 100.00% | 6 / 6 | 100.00% covered (success) | 100.00% | 1 / 1 | 3 |
getFoldersMinMax | 100.00% covered (success) | 100.00% | 6 / 6 | 100.00% covered (success) | 100.00% | 1 / 1 | 3 |
reorderDocuments | 0.00% covered (danger) | 0.00% | 0 / 15 | 0.00% covered (danger) | 0.00% | 0 / 1 | 30 |

1 | <?php
2 | declare(strict_types=1);
3 |
4 | /**
5 | * Implementation of a folder in the document management system
6 | *
7 | * @category DMS
8 | * @package SeedDMS_Core
9 | * @license GPL2
10 | * @author Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
11 | * Uwe Steinmann <uwe@steinmann.cx>
12 | * @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
13 | * 2010 Matteo Lucarelli, 2010-2024 Uwe Steinmann
14 | * @version Release: @package_version@
15 | */
16 |
17 | /**
18 | * Class to represent a folder in the document management system
19 | *
20 | * A folder in SeedDMS is equivalent to a directory in a regular file
21 | * system. It can contain further subfolders and documents. Each folder
22 | * has a single parent except for the root folder which has no parent.
23 | *
24 | * @category DMS
25 | * @package SeedDMS_Core
26 | * @version @version@
27 | * @author Uwe Steinmann <uwe@steinmann.cx>
28 | * @copyright Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
29 | * 2010 Matteo Lucarelli, 2010-2024 Uwe Steinmann
30 | * @version Release: @package_version@
31 | */
32 | class SeedDMS_Core_Folder extends SeedDMS_Core_Object {
33 | /**
34 | * @var string name of folder
35 | */
36 | protected $_name;
37 |
38 | /**
39 | * @var integer id of parent folder
40 | */
41 | protected $_parentID;
42 |
43 | /**
44 | * @var string comment of document
45 | */
46 | protected $_comment;
47 |
48 | /**
49 | * @var integer id of user who is the owner
50 | */
51 | protected $_ownerID;
52 |
53 | /**
54 | * @var boolean true if access is inherited, otherwise false
55 | */
56 | protected $_inheritAccess;
57 |
58 | /**
59 | * @var integer default access if access rights are not inherited
60 | */
61 | protected $_defaultAccess;
62 |
63 | /**
64 | * @var array list of notifications for users and groups
65 | */
66 | protected $_readAccessList;
67 |
68 | /**
69 | * @var array list of notifications for users and groups
70 | */
71 | public $_notifyList;
72 |
73 | /**
74 | * @var integer position of folder within the parent folder
75 | */
76 | protected $_sequence;
77 |
78 | /**
79 | * @var
80 | */
81 | protected $_date;
82 |
83 | /**
84 | * @var SeedDMS_Core_Folder cached parent folder
85 | */
86 | protected $_parent;
87 |
88 | /**
89 | * @var SeedDMS_Core_User cached owner of folder
90 | */
91 | protected $_owner;
92 |
93 | /**
94 | * @var SeedDMS_Core_Folder[] cached array of sub folders
95 | */
96 | protected $_subFolders;
97 |
98 | /**
99 | * @var SeedDMS_Core_Document[] cache array of child documents
100 | */
101 | protected $_documents;
102 |
103 | /**
104 | * @var SeedDMS_Core_UserAccess[]|SeedDMS_Core_GroupAccess[]
105 | */
106 | protected $_accessList;
107 |
108 | /**
109 | * SeedDMS_Core_Folder constructor.
110 | * @param $id
111 | * @param $name
112 | * @param $parentID
113 | * @param $comment
114 | * @param $date
115 | * @param $ownerID
116 | * @param $inheritAccess
117 | * @param $defaultAccess
118 | * @param $sequence
119 | */
120 | public function __construct($id, $name, $parentID, $comment, $date, $ownerID, $inheritAccess, $defaultAccess, $sequence) { /* {{{ */
121 | parent::__construct($id);
122 | $this->_id = $id;
123 | $this->_name = $name;
124 | $this->_parentID = $parentID;
125 | $this->_comment = $comment;
126 | $this->_date = $date;
127 | $this->_ownerID = $ownerID;
128 | $this->_inheritAccess = $inheritAccess;
129 | $this->_defaultAccess = $defaultAccess;
130 | $this->_sequence = $sequence;
131 | /* Cache */
132 | $this->clearCache();
133 | } /* }}} */
134 |
135 | /**
136 | * Clear cache of this instance.
137 | *
138 | * The result of some expensive database actions (e.g. get all subfolders
139 | * or documents) will be saved in a class variable to speed up consecutive
140 | * calls of the same method. If a second call of the same method shall not
141 | * use the cache, then it must be cleared.
142 | *
143 | */
144 | public function clearCache() { /* {{{ */
145 | $this->_parent = null;
146 | $this->_owner = null;
147 | $this->_subFolders = null;
148 | $this->_documents = null;
149 | $this->_accessList = null;
150 | $this->_notifyList = array();
151 | $this->_readAccessList = array();
152 | } /* }}} */
153 |
154 | /**
155 | * Cast to string
156 | *
157 | * @return string
158 | */
159 | public function __toString() { /* {{{ */
160 | return $this->_name;
161 | } /* }}} */
162 |
163 | /**
164 | * Check if this object is of type 'folder'.
165 | *
166 | * @param string $type type of object
167 | */
168 | public function isType($type) { /* {{{ */
169 | return $type == 'folder';
170 | } /* }}} */
171 |
172 | /**
173 | * Return an array of database fields which used for searching
174 | * a term entered in the database search form
175 | *
176 | * @param SeedDMS_Core_DMS $dms
177 | * @param array $searchin integer list of search scopes (2=name, 3=comment,
178 | * 4=attributes)
179 | * @return array list of database fields
180 | */
181 | public static function getSearchFields($dms, $searchin) { /* {{{ */
182 | $db = $dms->getDB();
183 |
184 | $searchFields = array();
185 | if (in_array(2, $searchin)) {
186 | $searchFields[] = "`tblFolders`.`name`";
187 | }
188 | if (in_array(3, $searchin)) {
189 | $searchFields[] = "`tblFolders`.`comment`";
190 | }
191 | if (in_array(4, $searchin)) {
192 | $searchFields[] = "`tblFolderAttributes`.`value`";
193 | }
194 | if (in_array(5, $searchin)) {
195 | $searchFields[] = $db->castToText("`tblFolders`.`id`");
196 | }
197 | return $searchFields;
198 | } /* }}} */
199 |
200 | /**
201 | * Return a sql statement with all tables used for searching.
202 | * This must be a syntactically correct left join of all tables.
203 | *
204 | * @return string sql expression for left joining tables
205 | */
206 | public static function getSearchTables() { /* {{{ */
207 | $sql = "`tblFolders` LEFT JOIN `tblFolderAttributes` on `tblFolders`.`id`=`tblFolderAttributes`.`folder`";
208 | return $sql;
209 | } /* }}} */
210 |
211 | /**
212 | * Return a folder by its database record
213 | *
214 | * @param array $resArr array of folder data as returned by database
215 | * @param SeedDMS_Core_DMS $dms
216 | * @return SeedDMS_Core_Folder|bool instance of SeedDMS_Core_Folder if document exists
217 | */
218 | public static function getInstanceByData($resArr, $dms) { /* {{{ */
219 | $classname = $dms->getClassname('folder');
220 | /** @var SeedDMS_Core_Folder $folder */
221 | $folder = new $classname($resArr["id"], $resArr["name"], $resArr["parent"], $resArr["comment"], $resArr["date"], $resArr["owner"], $resArr["inheritAccess"], $resArr["defaultAccess"], $resArr["sequence"]);
222 | $folder->setDMS($dms);
223 | $folder = $folder->applyDecorators();
224 | return $folder;
225 | } /* }}} */
226 |
227 | /**
228 | * Return a folder by its id
229 | *
230 | * @param integer $id id of folder
231 | * @param SeedDMS_Core_DMS $dms
232 | * @return SeedDMS_Core_Folder|bool instance of SeedDMS_Core_Folder if document exists, null
233 | * if document does not exist, false in case of error
234 | */
235 | public static function getInstance($id, $dms) { /* {{{ */
236 | $db = $dms->getDB();
237 |
238 | $queryStr = "SELECT * FROM `tblFolders` WHERE `id` = " . (int) $id;
239 | if ($dms->checkWithinRootDir && ($id != $dms->rootFolderID))
240 | $queryStr .= " AND `folderList` LIKE '%:".$dms->rootFolderID.":%'";
241 | $resArr = $db->getResultArray($queryStr);
242 | if (is_bool($resArr) && $resArr == false)
243 | return false;
244 | elseif (count($resArr) != 1)
245 | return null;
246 |
247 | return self::getInstanceByData($resArr[0], $dms);
248 | } /* }}} */
249 |
250 | /**
251 | * Return a folder by its name
252 | *
253 | * This method retrieves a folder from the database by its name. The
254 | * search covers the whole database. If
255 | * the parameter $folder is not null, it will search for the name
256 | * only within this parent folder. It will not be done recursively.
257 | *
258 | * @param string $name name of the folder
259 | * @param SeedDMS_Core_Folder $folder parent folder
260 | * @return SeedDMS_Core_Folder|boolean found folder or false
261 | */
262 | public static function getInstanceByName($name, $folder, $dms) { /* {{{ */
263 | if (!$name) return false;
264 |
265 | $db = $dms->getDB();
266 | $queryStr = "SELECT * FROM `tblFolders` WHERE `name` = " . $db->qstr($name);
267 | if ($folder)
268 | $queryStr .= " AND `parent` = ". $folder->getID();
269 | if ($dms->checkWithinRootDir && ($folder->getID() != $dms->rootFolderID))
270 | $queryStr .= " AND `folderList` LIKE '%:".$dms->rootFolderID.":%'";
271 | $queryStr .= " LIMIT 1";
272 | $resArr = $db->getResultArray($queryStr);
273 |
274 | if (is_bool($resArr) && $resArr == false)
275 | return false;
276 |
277 | if (!$resArr)
278 | return null;
279 |
280 | return self::getInstanceByData($resArr[0], $dms);
281 | } /* }}} */
282 |
283 | /**
284 | * Apply decorators
285 | *
286 | * @return object final object after all decorators has been applied
287 | */
288 | public function applyDecorators() { /* {{{ */
289 | if ($decorators = $this->_dms->getDecorators('folder')) {
290 | $s = $this;
291 | foreach ($decorators as $decorator) {
292 | $s = new $decorator($s);
293 | }
294 | return $s;
295 | } else {
296 | return $this;
297 | }
298 | } /* }}} */
299 |
300 | /**
301 | * Get the name of the folder.
302 | *
303 | * @return string name of folder
304 | */
305 | public function getName() { return $this->_name; }
306 |
307 | /**
308 | * Set the name of the folder.
309 | *
310 | * @param string $newName set a new name of the folder
311 | * @return bool
312 | */
313 | public function setName($newName) { /* {{{ */
314 | $db = $this->_dms->getDB();
315 |
316 | /* Check if 'onPreSetName' callback is set */
317 | if (isset($this->_dms->callbacks['onPreSetName'])) {
318 | foreach ($this->_dms->callbacks['onPreSetName'] as $callback) {
319 | $ret = call_user_func($callback[0], $callback[1], $this, $newName);
320 | if (is_bool($ret))
321 | return $ret;
322 | }
323 | }
324 |
325 | $queryStr = "UPDATE `tblFolders` SET `name` = " . $db->qstr($newName) . " WHERE `id` = ". $this->_id;
326 | if (!$db->getResult($queryStr))
327 | return false;
328 |
329 | $oldName = $this->_name;
330 | $this->_name = $newName;
331 |
332 | /* Check if 'onPostSetName' callback is set */
333 | if (isset($this->_dms->callbacks['onPostSetName'])) {
334 | foreach ($this->_dms->callbacks['onPostSetName'] as $callback) {
335 | $ret = call_user_func($callback[0], $callback[1], $this, $oldName);
336 | if (is_bool($ret))
337 | return $ret;
338 | }
339 | }
340 |
341 | return true;
342 | } /* }}} */
343 |
344 | /**
345 | * Returns comment of folder
346 | *
347 | * @return string comment
348 | */
349 | public function getComment() { return $this->_comment; }
350 |
351 | /**
352 | * Set comment of folder
353 | *
354 | * This method calls the hooks `onPreSetComment` and `onPostSetComment`.
355 | *
356 | * @param $newComment new comment
357 | * @return bool true if comment could be set, otherwise false
358 | */
359 | public function setComment($newComment) { /* {{{ */
360 | $db = $this->_dms->getDB();
361 |
362 | /* Check if 'onPreSetComment' callback is set */
363 | if (isset($this->_dms->callbacks['onPreSetComment'])) {
364 | foreach ($this->_dms->callbacks['onPreSetComment'] as $callback) {
365 | $ret = call_user_func($callback[0], $callback[1], $this, $newComment);
366 | if (is_bool($ret))
367 | return $ret;
368 | }
369 | }
370 |
371 | $queryStr = "UPDATE `tblFolders` SET `comment` = " . $db->qstr($newComment) . " WHERE `id` = ". $this->_id;
372 | if (!$db->getResult($queryStr))
373 | return false;
374 |
375 | $oldComment = $this->_comment;
376 | $this->_comment = $newComment;
377 |
378 | /* Check if 'onPostSetComment' callback is set */
379 | if (isset($this->_dms->callbacks['onPostSetComment'])) {
380 | foreach ($this->_dms->callbacks['onPostSetComment'] as $callback) {
381 | $ret = call_user_func($callback[0], $callback[1], $this, $oldComment);
382 | if (is_bool($ret))
383 | return $ret;
384 | }
385 | }
386 |
387 | return true;
388 | } /* }}} */
389 |
390 | /**
391 | * Return creation date of folder
392 | *
393 | * @return integer unix timestamp of creation date
394 | */
395 | public function getDate() { /* {{{ */
396 | return $this->_date;
397 | } /* }}} */
398 |
399 | /**
400 | * Set creation date of the folder
401 | *
402 | * @param integer $date timestamp of creation date. If false then set it
403 | * to the current timestamp
404 | * @return boolean true on success
405 | */
406 | public function setDate($date) { /* {{{ */
407 | $db = $this->_dms->getDB();
408 |
409 | if ($date === false)
410 | $date = time();
411 | else {
412 | if (!is_numeric($date))
413 | return false;
414 | }
415 |
416 | $queryStr = "UPDATE `tblFolders` SET `date` = " . (int) $date . " WHERE `id` = ". $this->_id;
417 | if (!$db->getResult($queryStr))
418 | return false;
419 | $this->_date = $date;
420 | return true;
421 | } /* }}} */
422 |
423 | /**
424 | * Returns the parent
425 | *
426 | * @return null|bool|SeedDMS_Core_Folder returns null, if there is no parent folder
427 | * and false in case of an error
428 | */
429 | public function getParent() { /* {{{ */
430 | if ($this->_id == $this->_dms->rootFolderID || empty($this->_parentID)) {
431 | return null;
432 | }
433 |
434 | if (!isset($this->_parent)) {
435 | $this->_parent = $this->_dms->getFolder($this->_parentID);
436 | }
437 | return $this->_parent;
438 | } /* }}} */
439 |
440 | /**
441 | * Check if the folder is subfolder
442 | *
443 | * This method checks if the current folder is in the path of the
444 | * passed subfolder. In that case the current folder is a parent,
445 | * grant parent, grant grant parent, etc. of the subfolder or
446 | * to say it differently the passed folder is somewhere below the
447 | * current folder.
448 | *
449 | * This is basically the opposite of {@see SeedDMS_Core_Folder::isDescendant()}
450 | *
451 | * @param SeedDMS_Core_Folder $subfolder folder to be checked if it is
452 | * a subfolder on any level of the current folder
453 | * @return bool true if passed folder is a subfolder, otherwise false
454 | */
455 | public function isSubFolder($subfolder) { /* {{{ */
456 | $target_path = $subfolder->getPath();
457 | foreach ($target_path as $next_folder) {
458 | // the target folder contains this instance in the parent path
459 | if ($this->getID() == $next_folder->getID()) return true;
460 | }
461 | return false;
462 | } /* }}} */
463 |
464 | /**
465 | * Set a new folder
466 | *
467 | * This method moves a folder from one parent folder into another parent
468 | * folder. It will fail if the root folder is moved or the folder is
469 | * moved into one of its own subfolders.
470 | *
471 | * @param SeedDMS_Core_Folder $newParent new parent folder
472 | * @return boolean true if operation was successful otherwise false
473 | */
474 | public function setParent($newParent) { /* {{{ */
475 | $db = $this->_dms->getDB();
476 |
477 | if ($this->_id == $this->_dms->rootFolderID || empty($this->_parentID)) {
478 | return false;
479 | }
480 |
481 | /* Check if the new parent is the folder to be moved or even
482 | * a subfolder of that folder
483 | */
484 | if ($this->isSubFolder($newParent)) {
485 | return false;
486 | }
487 |
488 | // Update the folderList of the folder
489 | $pathPrefix = "";
490 | $path = $newParent->getPath();
491 | foreach ($path as $f) {
492 | $pathPrefix .= ":".$f->getID();
493 | }
494 | if (strlen($pathPrefix)>1) {
495 | $pathPrefix .= ":";
496 | }
497 | $queryStr = "UPDATE `tblFolders` SET `parent` = ".$newParent->getID().", `folderList`='".$pathPrefix."' WHERE `id` = ". $this->_id;
498 | $res = $db->getResult($queryStr);
499 | if (!$res)
500 | return false;
501 |
502 | $this->_parentID = $newParent->getID();
503 | $this->_parent = $newParent;
504 |
505 | // Must also ensure that any documents in this folder tree have their
506 | // folderLists updated.
507 | $pathPrefix = "";
508 | $path = $this->getPath();
509 | foreach ($path as $f) {
510 | $pathPrefix .= ":".$f->getID();
511 | }
512 | if (strlen($pathPrefix)>1) {
513 | $pathPrefix .= ":";
514 | }
515 |
516 | /* Update path in folderList for all documents */
517 | $queryStr = "SELECT `tblDocuments`.`id`, `tblDocuments`.`folderList` FROM `tblDocuments` WHERE `folderList` LIKE '%:".$this->_id.":%'";
518 | $resArr = $db->getResultArray($queryStr);
519 | if (is_bool($resArr) && $resArr == false)
520 | return false;
521 |
522 | foreach ($resArr as $row) {
523 | $newPath = preg_replace("/^.*:".$this->_id.":(.*$)/", $pathPrefix."\\1", $row["folderList"]);
524 | $queryStr = "UPDATE `tblDocuments` SET `folderList` = '".$newPath."' WHERE `tblDocuments`.`id` = '".$row["id"]."'";
525 | /** @noinspection PhpUnusedLocalVariableInspection */
526 | $res = $db->getResult($queryStr);
527 | }
528 |
529 | /* Update path in folderList for all folders */
530 | $queryStr = "SELECT `tblFolders`.`id`, `tblFolders`.`folderList` FROM `tblFolders` WHERE `folderList` LIKE '%:".$this->_id.":%'";
531 | $resArr = $db->getResultArray($queryStr);
532 | if (is_bool($resArr) && $resArr == false)
533 | return false;
534 |
535 | foreach ($resArr as $row) {
536 | $newPath = preg_replace("/^.*:".$this->_id.":(.*$)/", $pathPrefix."\\1", $row["folderList"]);
537 | $queryStr = "UPDATE `tblFolders` SET `folderList` = '".$newPath."' WHERE `tblFolders`.`id` = '".$row["id"]."'";
538 | /** @noinspection PhpUnusedLocalVariableInspection */
539 | $res = $db->getResult($queryStr);
540 | }
541 |
542 | return true;
543 | } /* }}} */
544 |
545 | /**
546 | * Returns the owner
547 | *
548 | * @return object owner of the folder
549 | */
550 | public function getOwner() { /* {{{ */
551 | if (!isset($this->_owner))
552 | $this->_owner = $this->_dms->getUser($this->_ownerID);
553 | return $this->_owner;
554 | } /* }}} */
555 |
556 | /**
557 | * Set the owner
558 | *
559 | * @param SeedDMS_Core_User $newOwner of the folder
560 | * @return boolean true if successful otherwise false
561 | */
562 | public function setOwner($newOwner) { /* {{{ */
563 | $db = $this->_dms->getDB();
564 |
565 | /* Check if 'onPreSetOwner' callback is set */
566 | if (isset($this->_dms->callbacks['onPreSetOwner'])) {
567 | foreach ($this->_dms->callbacks['onPreSetOwner'] as $callback) {
568 | $ret = call_user_func($callback[0], $callback[1], $this, $newOwner);
569 | if (is_bool($ret))
570 | return $ret;
571 | }
572 | }
573 |
574 | $queryStr = "UPDATE `tblFolders` set `owner` = " . $newOwner->getID() . " WHERE `id` = " . $this->_id;
575 | if (!$db->getResult($queryStr))
576 | return false;
577 |
578 | $oldOwner = $this->_owner;
579 | $this->_ownerID = $newOwner->getID();
580 | $this->_owner = $newOwner;
581 |
582 | $this->_readAccessList = array();
583 |
584 | /* Check if 'onPostSetOwner' callback is set */
585 | if (isset($this->_dms->callbacks['onPostSetOwner'])) {
586 | foreach ($this->_dms->callbacks['onPostSetOwner'] as $callback) {
587 | $ret = call_user_func($callback[0], $callback[1], $this, $oldOwner);
588 | if (is_bool($ret))
589 | return $ret;
590 | }
591 | }
592 |
593 | return true;
594 | } /* }}} */
595 |
596 | /**
597 | * Returns default access
598 | *
599 | * If access rights are inherited, the method will return the
600 | * default access of the parent folder.
601 | *
602 | * @return boolean|int access right or fals in case of an error
603 | */
604 | public function getDefaultAccess() { /* {{{ */
605 | if ($this->inheritsAccess()) {
606 | /* Access is supposed to be inherited but it could be that there
607 | * is no parent because the configured root folder id is somewhere
608 | * below the actual root folder.
609 | */
610 | $res = $this->getParent();
611 | if ($res)
612 | return $this->_parent->getDefaultAccess();
613 | }
614 |
615 | return $this->_defaultAccess;
616 | } /* }}} */
617 |
618 | /**
619 | * Set default access mode
620 | *
621 | * This method sets the default access mode and also removes all notifiers which
622 | * will not have read access anymore.
623 | *
624 | * @param integer $mode access mode
625 | * @param boolean $noclean set to true if notifier list shall not be clean up
626 | * @return bool
627 | */
628 | public function setDefaultAccess($mode, $noclean = false) { /* {{{ */
629 | $db = $this->_dms->getDB();
630 |
631 | $queryStr = "UPDATE `tblFolders` set `defaultAccess` = " . (int) $mode . " WHERE `id` = " . $this->_id;
632 | if (!$db->getResult($queryStr))
633 | return false;
634 |
635 | $this->_defaultAccess = $mode;
636 | $this->_readAccessList = array();
637 |
638 | if (!$noclean)
639 | $this->cleanNotifyList();
640 |
641 | return true;
642 | } /* }}} */
643 |
644 | /**
645 | * Check, if folder inherits access rights
646 | *
647 | * @return boolean true, if access rights are inherited, otherwise false
648 | */
649 | public function inheritsAccess() { return $this->_inheritAccess; }
650 |
651 | /**
652 | * Set inherited access mode
653 | *
654 | * Setting inherited access mode will set or unset the internal flag which
655 | * controls if the access mode is inherited from the parent folder or not.
656 | * It will not modify the
657 | * access control list for the current object. It will remove all
658 | * notifications of users which do not even have read access anymore
659 | * after setting or unsetting inherited access.
660 | *
661 | * @param boolean $inheritAccess set to true for setting and false for
662 | * unsetting inherited access mode
663 | * @param boolean $noclean set to true if notifier list shall not be clean up
664 | * @return boolean true if operation was successful otherwise false
665 | */
666 | public function setInheritAccess($inheritAccess, $noclean = false) { /* {{{ */
667 | $db = $this->_dms->getDB();
668 |
669 | $inheritAccess = ($inheritAccess) ? "1" : "0";
670 |
671 | $queryStr = "UPDATE `tblFolders` SET `inheritAccess` = " . (int) $inheritAccess . " WHERE `id` = " . $this->_id;
672 | if (!$db->getResult($queryStr))
673 | return false;
674 |
675 | $this->_inheritAccess = $inheritAccess;
676 | $this->_readAccessList = array();
677 |
678 | if (!$noclean)
679 | $this->cleanNotifyList();
680 |
681 | return true;
682 | } /* }}} */
683 |
684 | public function getSequence() { return $this->_sequence; }
685 |
686 | public function setSequence($seq) { /* {{{ */
687 | $db = $this->_dms->getDB();
688 |
689 | $queryStr = "UPDATE `tblFolders` SET `sequence` = " . $seq . " WHERE `id` = " . $this->_id;
690 | if (!$db->getResult($queryStr))
691 | return false;
692 |
693 | $this->_sequence = $seq;
694 | return true;
695 | } /* }}} */
696 |
697 | /**
698 | * Check, if folder has subfolders
699 | *
700 | * This method just checks if a folder has subfolders disregarding
701 | * any access rights.
702 | *
703 | * @return int number of subfolders or false in case of an error
704 | */
705 | public function hasSubFolders() { /* {{{ */
706 | $db = $this->_dms->getDB();
707 | if (isset($this->_subFolders)) {
708 | /** @noinspection PhpUndefinedFieldInspection */
709 | return count($this->_subFolders);
710 | }
711 | $queryStr = "SELECT count(*) as c FROM `tblFolders` WHERE `parent` = " . $this->_id;
712 | $resArr = $db->getResultArray($queryStr);
713 | if (is_bool($resArr) && !$resArr)
714 | return false;
715 |
716 | return (int) $resArr[0]['c'];
717 | } /* }}} */
718 |
719 | /**
720 | * Check, if folder has as subfolder with the given name
721 | *
722 | * @param string $name
723 | * @return bool true if subfolder exists, false if not or in case
724 | * of an error
725 | */
726 | public function hasSubFolderByName($name) { /* {{{ */
727 | $db = $this->_dms->getDB();
728 | /* Always check the database instead of iterating over $this->_documents, because
729 | * it is probably not slower
730 | */
731 | $queryStr = "SELECT count(*) as c FROM `tblFolders` WHERE `parent` = " . $this->_id . " AND `name` = ".$db->qstr($name);
732 | $resArr = $db->getResultArray($queryStr);
733 | if (is_bool($resArr) && !$resArr)
734 | return false;
735 |
736 | return ($resArr[0]['c'] > 0);
737 | } /* }}} */
738 |
739 | /**
740 | * Returns a list of subfolders
741 | *
742 | * This method does not check for access rights. Use
743 | * {@link SeedDMS_Core_DMS::filterAccess} for checking each folder against
744 | * the currently logged in user and the access rights.
745 | *
746 | * @param string $orderby if set to 'n' the list is ordered by name, otherwise
747 | * it will be ordered by sequence
748 | * @param string $dir direction of sorting (asc or desc)
749 | * @param integer $limit limit number of subfolders
750 | * @param integer $offset offset in retrieved list of subfolders
751 | * @return SeedDMS_Core_Folder[]|bool list of folder objects or false in case of an error
752 | */
753 | public function getSubFolders($orderby = "", $dir = "asc", $limit = 0, $offset = 0) { /* {{{ */
754 | $db = $this->_dms->getDB();
755 |
756 | if (!isset($this->_subFolders)) {
757 | $queryStr = "SELECT * FROM `tblFolders` WHERE `parent` = " . $this->_id;
758 |
759 | if ($orderby && $orderby[0]=="n") $queryStr .= " ORDER BY `name`";
760 | elseif ($orderby && $orderby[0]=="s") $queryStr .= " ORDER BY `sequence`";
761 | elseif ($orderby && $orderby[0]=="d") $queryStr .= " ORDER BY `date`";
762 | if ($dir == 'desc')
763 | $queryStr .= " DESC";
764 | if (is_int($limit) && $limit > 0) {
765 | $queryStr .= " LIMIT ".$limit;
766 | if (is_int($offset) && $offset > 0)
767 | $queryStr .= " OFFSET ".$offset;
768 | }
769 |
770 | $resArr = $db->getResultArray($queryStr);
771 | if (is_bool($resArr) && $resArr == false)
772 | return false;
773 |
774 | $classname = $this->_dms->getClassname('folder');
775 | $this->_subFolders = array();
776 | for ($i = 0; $i < count($resArr); $i++)
777 | // $this->_subFolders[$i] = $this->_dms->getFolder($resArr[$i]["id"]);
778 | $this->_subFolders[$i] = $classname::getInstanceByData($resArr[$i], $this->_dms);
779 | }
780 |
781 | return $this->_subFolders;
782 | } /* }}} */
783 |
784 | /**
785 | * Add a new subfolder
786 | *
787 | * @param string $name name of folder
788 | * @param string $comment comment of folder
789 | * @param object $owner owner of folder
790 | * @param integer $sequence position of folder in list of sub folders.
791 | * @param array $attributes list of document attributes. The element key
792 | * must be the id of the attribute definition.
793 | * @return bool|SeedDMS_Core_Folder
794 | * an error.
795 | */
796 | public function addSubFolder($name, $comment, $owner, $sequence, $attributes = array()) { /* {{{ */
797 | $db = $this->_dms->getDB();
798 |
799 | // Set the folderList of the folder
800 | $pathPrefix = "";
801 | $path = $this->getPath();
802 | foreach ($path as $f) {
803 | $pathPrefix .= ":".$f->getID();
804 | }
805 | if (strlen($pathPrefix)>1) {
806 | $pathPrefix .= ":";
807 | }
808 |
809 | $db->startTransaction();
810 |
811 | //inheritAccess = true, defaultAccess = M_READ
812 | $queryStr = "INSERT INTO `tblFolders` (`name`, `parent`, `folderList`, `comment`, `date`, `owner`, `inheritAccess`, `defaultAccess`, `sequence`) ".
813 | "VALUES (".$db->qstr($name).", ".$this->_id.", ".$db->qstr($pathPrefix).", ".$db->qstr($comment).", ".$db->getCurrentTimestamp().", ".$owner->getID().", 1, ".M_READ.", ". $sequence.")";
814 | if (!$db->getResult($queryStr)) {
815 | $db->rollbackTransaction();
816 | return false;
817 | }
818 | $newFolder = $this->_dms->getFolder($db->getInsertID('tblFolders'));
819 | unset($this->_subFolders);
820 |
821 | if ($attributes) {
822 | foreach ($attributes as $attrdefid => $attribute) {
823 | if ($attribute) {
824 | if ($attrdef = $this->_dms->getAttributeDefinition($attrdefid)) {
825 | if (!$newFolder->setAttributeValue($attrdef, $attribute)) {
826 | $db->rollbackTransaction();
827 | return false;
828 | }
829 | } else {
830 | $db->rollbackTransaction();
831 | return false;
832 | }
833 | }
834 | }
835 | }
836 |
837 | $db->commitTransaction();
838 |
839 | /* Check if 'onPostAddSubFolder' callback is set */
840 | if (isset($this->_dms->callbacks['onPostAddSubFolder'])) {
841 | foreach ($this->_dms->callbacks['onPostAddSubFolder'] as $callback) {
842 | /** @noinspection PhpStatementHasEmptyBodyInspection */
843 | if (!call_user_func($callback[0], $callback[1], $newFolder)) {
844 | }
845 | }
846 | }
847 |
848 | return $newFolder;
849 | } /* }}} */
850 |
851 | /**
852 | * Returns an array of all parents, grand parent, etc. up to the root folder.
853 | *
854 | * The folder itself is the last element of the array.
855 | *
856 | * @return array|bool
857 | */
858 | public function getPath() { /* {{{ */
859 | if (!isset($this->_parentID) || ($this->_parentID == "") || ($this->_parentID == 0) || ($this->_id == $this->_dms->rootFolderID)) {
860 | return array($this);
861 | } else {
862 | $res = $this->getParent();
863 | if (!$res) return false;
864 |
865 | $path = $this->_parent->getPath();
866 | if (!$path) return false;
867 |
868 | array_push($path, $this);
869 | return $path;
870 | }
871 | } /* }}} */
872 |
873 | /**
874 | * Returns a path like used for a file system
875 | *
876 | * This path contains by default spaces around the slashes for better readability.
877 | * Run str_replace(' / ', '/', $path) on it or pass '/' as $sep to get a valid unix
878 | * file system path.
879 | *
880 | * The returned path is not a real path in a file system. It just uses
881 | * the common syntax on unix systems to format a path.
882 | *
883 | * @param bool $skiproot skip the name of the root folder and start with $sep
884 | * @param string $sep separator between path elements
885 | * @return string path separated with ' / '
886 | */
887 | public function getFolderPathPlain($skiproot = false, $sep = ' / ') { /* {{{ */
888 | $path = "".$sep;
889 | $folderPath = $this->getPath();
890 | for ($i = 0; $i < count($folderPath); $i++) {
891 | if ($i > 0 || !$skiproot) {
892 | $path .= $folderPath[$i]->getName();
893 | if ($i+1 < count($folderPath))
894 | $path .= $sep;
895 | }
896 | }
897 | return trim($path);
898 | } /* }}} */
899 |
900 | /**
901 | * Check, if this folder is a subfolder of a given folder
902 | *
903 | * This is basically the opposite of {@see SeedDMS_Core_Folder::isSubFolder()}
904 | *
905 | * @param object $folder parent folder
906 | * @return boolean true if folder is a subfolder
907 | */
908 | public function isDescendant($folder) { /* {{{ */
909 | /* If the current folder has no parent it cannot be a descendant */
910 | if (!$this->getParent())
911 | return false;
912 | /* Check if the passed folder is the parent of the current folder.
913 | * In that case the current folder is a subfolder of the passed folder.
914 | */
915 | if ($this->getParent()->getID() == $folder->getID())
916 | return true;
917 | /* Recursively go up to the root folder */
918 | return $this->getParent()->isDescendant($folder);
919 | } /* }}} */
920 |
921 | /**
922 | * Check, if folder has documents
923 | *
924 | * This method just checks if a folder has documents diregarding
925 | * any access rights.
926 | *
927 | * @return int number of documents or false in case of an error
928 | */
929 | public function hasDocuments() { /* {{{ */
930 | $db = $this->_dms->getDB();
931 | /* Do not use the cache because it may not contain all documents if
932 | * the former call getDocuments() limited the number of documents
933 | if (isset($this->_documents)) {
934 | return count($this->_documents);
935 | }
936 | */
937 | $queryStr = "SELECT count(*) as c FROM `tblDocuments` WHERE `folder` = " . $this->_id;
938 | $resArr = $db->getResultArray($queryStr);
939 | if (is_bool($resArr) && !$resArr)
940 | return false;
941 |
942 | return (int) $resArr[0]['c'];
943 | } /* }}} */
944 |
945 | /**
946 | * Check if folder has document with given name
947 | *
948 | * @param string $name
949 | * @return bool true if document exists, false if not or in case
950 | * of an error
951 | */
952 | public function hasDocumentByName($name) { /* {{{ */
953 | $db = $this->_dms->getDB();
954 | /* Always check the database instead of iterating over $this->_documents, because
955 | * it is probably not slower
956 | */
957 | $queryStr = "SELECT count(*) as c FROM `tblDocuments` WHERE `folder` = " . $this->_id . " AND `name` = ".$db->qstr($name);
958 | $resArr = $db->getResultArray($queryStr);
959 | if (is_bool($resArr) && !$resArr)
960 | return false;
961 |
962 | return ($resArr[0]['c'] > 0);
963 | } /* }}} */
964 |
965 | /**
966 | * Get all documents of the folder
967 | *
968 | * This method does not check for access rights. Use
969 | * {@link SeedDMS_Core_DMS::filterAccess} for checking each document against
970 | * the currently logged in user and the access rights.
971 | *
972 | * @param string $orderby if set to 'n' the list is ordered by name, otherwise
973 | * it will be ordered by sequence
974 | * @param string $dir direction of sorting (asc or desc)
975 | * @param integer $limit limit number of documents
976 | * @param integer $offset offset in retrieved list of documents
977 | * @return SeedDMS_Core_Document[]|bool list of documents or false in case of an error
978 | */
979 | public function getDocuments($orderby = "", $dir = "asc", $limit = 0, $offset = 0) { /* {{{ */
980 | $db = $this->_dms->getDB();
981 |
982 | if (!isset($this->_documents)) {
983 | $queryStr = "SELECT `tblDocuments`.*, `tblDocumentLocks`.`userID` as `lock` FROM `tblDocuments` LEFT JOIN `tblDocumentLocks` ON `tblDocuments`.`id` = `tblDocumentLocks`.`document` WHERE `folder` = " . $this->_id;
984 | if ($orderby && $orderby[0]=="n") $queryStr .= " ORDER BY `name`";
985 | elseif ($orderby && $orderby[0]=="s") $queryStr .= " ORDER BY `sequence`";
986 | elseif ($orderby && $orderby[0]=="d") $queryStr .= " ORDER BY `date`";
987 | if ($dir == 'desc')
988 | $queryStr .= " DESC";
989 | if (is_int($limit) && $limit > 0) {
990 | $queryStr .= " LIMIT ".$limit;
991 | if (is_int($offset) && $offset > 0)
992 | $queryStr .= " OFFSET ".$offset;
993 | }
994 |
995 | $resArr = $db->getResultArray($queryStr);
996 | if (is_bool($resArr) && !$resArr)
997 | return false;
998 |
999 | $this->_documents = array();
1000 | $classname = $this->_dms->getClassname('document');
1001 | foreach ($resArr as $row) {
1002 | $row['lock'] = !$row['lock'] ? -1 : $row['lock'];
1003 | // array_push($this->_documents, $this->_dms->getDocument($row["id"]));
1004 | array_push($this->_documents, $classname::getInstanceByData($row, $this->_dms));
1005 | }
1006 | }
1007 | return $this->_documents;
1008 | } /* }}} */
1009 |
1010 | /**
1011 | * Count all documents and subfolders of the folder
1012 | *
1013 | * This method also counts documents and folders of subfolders, so
1014 | * basically it works like recursively counting children.
1015 | *
1016 | * This method checks for access rights up the given limit. If more
1017 | * documents or folders are found, the returned value will be the number
1018 | * of objects available and the precise flag in the return array will be
1019 | * set to false. This number should not be revelead to the
1020 | * user, because it allows to gain information about the existens of
1021 | * objects without access right.
1022 | * Setting the parameter $limit to 0 will turn off access right checking
1023 | * which is reasonable if the $user is an administrator.
1024 | *
1025 | * @param SeedDMS_Core_User $user
1026 | * @param integer $limit maximum number of folders and documents that will
1027 | * be precisly counted by taken the access rights into account
1028 | * @return array|bool with four elements 'document_count', 'folder_count'
1029 | * 'document_precise', 'folder_precise' holding
1030 | * the counted number and a flag if the number is precise.
1031 | * @internal param string $orderby if set to 'n' the list is ordered by name, otherwise
1032 | * it will be ordered by sequence
1033 | */
1034 | public function countChildren($user, $limit = 10000) { /* {{{ */
1035 | $db = $this->_dms->getDB();
1036 |
1037 | $pathPrefix = "";
1038 | $path = $this->getPath();
1039 | foreach ($path as $f) {
1040 | $pathPrefix .= ":".$f->getID();
1041 | }
1042 | if (strlen($pathPrefix)>1) {
1043 | $pathPrefix .= ":";
1044 | }
1045 |
1046 | $queryStr = "SELECT id FROM `tblFolders` WHERE `folderList` like '".$pathPrefix. "%'";
1047 | $resArr = $db->getResultArray($queryStr);
1048 | if (is_bool($resArr) && !$resArr)
1049 | return false;
1050 |
1051 | $result = array();
1052 |
1053 | $folders = array();
1054 | $folderids = array($this->_id);
1055 | $cfolders = count($resArr);
1056 | if ($cfolders < $limit) {
1057 | foreach ($resArr as $row) {
1058 | $folder = $this->_dms->getFolder($row["id"]);
1059 | if ($folder->getAccessMode($user) >= M_READ) {
1060 | array_push($folders, $folder);
1061 | array_push($folderids, $row['id']);
1062 | }
1063 | }
1064 | $result['folder_count'] = count($folders);
1065 | $result['folder_precise'] = true;
1066 | } else {
1067 | foreach ($resArr as $row) {
1068 | array_push($folderids, $row['id']);
1069 | }
1070 | $result['folder_count'] = $cfolders;
1071 | $result['folder_precise'] = false;
1072 | }
1073 |
1074 | $documents = array();
1075 | if ($folderids) {
1076 | $queryStr = "SELECT id FROM `tblDocuments` WHERE `folder` in (".implode(',', $folderids). ")";
1077 | $resArr = $db->getResultArray($queryStr);
1078 | if (is_bool($resArr) && !$resArr)
1079 | return false;
1080 |
1081 | $cdocs = count($resArr);
1082 | if ($cdocs < $limit) {
1083 | foreach ($resArr as $row) {
1084 | $document = $this->_dms->getDocument($row["id"]);
1085 | if ($document->getAccessMode($user) >= M_READ)
1086 | array_push($documents, $document);
1087 | }
1088 | $result['document_count'] = count($documents);
1089 | $result['document_precise'] = true;
1090 | } else {
1091 | $result['document_count'] = $cdocs;
1092 | $result['document_precise'] = false;
1093 | }
1094 | }
1095 |
1096 | return $result;
1097 | } /* }}} */
1098 |
1099 | /**
1100 | * Add a new document to the folder
1101 | * This method will add a new document and its content from a given file.
1102 | * It does not check for access rights on the folder. The new documents
1103 | * default access right is read only and the access right is inherited.
1104 | *
1105 | * @param string $name name of new document
1106 | * @param string $comment comment of new document
1107 | * @param integer $expires expiration date as a unix timestamp or 0 for no
1108 | * expiration date
1109 | * @param object $owner owner of the new document
1110 | * @param SeedDMS_Core_User $keywords keywords of new document
1111 | * @param SeedDMS_Core_DocumentCategory[] $categories list of category objects
1112 | * @param string $tmpFile the path of the file containing the content
1113 | * @param string $orgFileName the original file name
1114 | * @param string $fileType usually the extension of the filename
1115 | * @param string $mimeType mime type of the content
1116 | * @param float $sequence position of new document within the folder
1117 | * @param array $reviewers list of users who must review this document
1118 | * @param array $approvers list of users who must approve this document
1119 | * @param int|string $reqversion version number of the content
1120 | * @param string $version_comment comment of the content. If left empty
1121 | * the $comment will be used.
1122 | * @param array $attributes list of document attributes. The element key
1123 | * must be the id of the attribute definition.
1124 | * @param array $version_attributes list of document version attributes.
1125 | * The element key must be the id of the attribute definition.
1126 | * @param SeedDMS_Core_Workflow $workflow
1127 | * @return array|bool false in case of error, otherwise an array
1128 | * containing two elements. The first one is the new document, the
1129 | * second one is the result set returned when inserting the content.
1130 | */
1131 | public function addDocument($name, $comment, $expires, $owner, $keywords, $categories, $tmpFile, $orgFileName, $fileType, $mimeType, $sequence, $reviewers = array(), $approvers = array(), $reqversion = 0, $version_comment = "", $attributes = array(), $version_attributes = array(), $workflow = null) { /* {{{ */
1132 | $db = $this->_dms->getDB();
1133 |
1134 | $expires = (!$expires) ? 0 : $expires;
1135 |
1136 | // Must also ensure that the document has a valid folderList.
1137 | $pathPrefix = "";
1138 | $path = $this->getPath();
1139 | foreach ($path as $f) {
1140 | $pathPrefix .= ":".$f->getID();
1141 | }
1142 | if (strlen($pathPrefix)>1) {
1143 | $pathPrefix .= ":";
1144 | }
1145 |
1146 | $db->startTransaction();
1147 |
1148 | $queryStr = "INSERT INTO `tblDocuments` (`name`, `comment`, `date`, `expires`, `owner`, `folder`, `folderList`, `inheritAccess`, `defaultAccess`, `locked`, `keywords`, `sequence`) VALUES ".
1149 | "(".$db->qstr($name).", ".$db->qstr($comment).", ".$db->getCurrentTimestamp().", ".(int) $expires.", ".$owner->getID().", ".$this->_id.",".$db->qstr($pathPrefix).", 1, ".M_READ.", -1, ".$db->qstr($keywords).", " . $sequence . ")";
1150 | if (!$db->getResult($queryStr)) {
1151 | $db->rollbackTransaction();
1152 | return false;
1153 | }
1154 |
1155 | $document = $this->_dms->getDocument($db->getInsertID('tblDocuments'));
1156 |
1157 | $res = $document->addContent($version_comment, $owner, $tmpFile, $orgFileName, $fileType, $mimeType, $reviewers, $approvers, $reqversion, $version_attributes, $workflow);
1158 |
1159 | if (is_bool($res) && !$res) {
1160 | $db->rollbackTransaction();
1161 | return false;
1162 | }
1163 |
1164 | if ($categories) {
1165 | if (!$document->setCategories($categories)) {
1166 | $document->remove();
1167 | $db->rollbackTransaction();
1168 | return false;
1169 | }
1170 | }
1171 |
1172 | if ($attributes) {
1173 | foreach ($attributes as $attrdefid => $attribute) {
1174 | /* $attribute can be a string or an array */
1175 | if ($attribute) {
1176 | if ($attrdef = $this->_dms->getAttributeDefinition($attrdefid)) {
1177 | if (!$document->setAttributeValue($attrdef, $attribute)) {
1178 | $document->remove();
1179 | $db->rollbackTransaction();
1180 | return false;
1181 | }
1182 | } else {
1183 | $document->remove();
1184 | $db->rollbackTransaction();
1185 | return false;
1186 | }
1187 | }
1188 | }
1189 | }
1190 |
1191 | $db->commitTransaction();
1192 |
1193 | /* Check if 'onPostAddDocument' callback is set */
1194 | if (isset($this->_dms->callbacks['onPostAddDocument'])) {
1195 | foreach ($this->_dms->callbacks['onPostAddDocument'] as $callback) {
1196 | /** @noinspection PhpStatementHasEmptyBodyInspection */
1197 | if (!call_user_func($callback[0], $callback[1], $document)) {
1198 | }
1199 | }
1200 | }
1201 |
1202 | return array($document, $res);
1203 | } /* }}} */
1204 |
1205 | /**
1206 | * Remove a single folder
1207 | *
1208 | * Removes just a single folder, but not its subfolders or documents
1209 | * This method will fail if the folder has subfolders or documents
1210 | * because of referencial integrity errors.
1211 | *
1212 | * @return boolean true on success, false in case of an error
1213 | */
1214 | protected function removeFromDatabase() { /* {{{ */
1215 | $db = $this->_dms->getDB();
1216 |
1217 | /* Check if 'onPreRemoveFolder' callback is set */
1218 | if (isset($this->_dms->callbacks['onPreRemoveFromDatabaseFolder'])) {
1219 | foreach ($this->_dms->callbacks['onPreRemoveFromDatabaseFolder'] as $callback) {
1220 | $ret = call_user_func($callback[0], $callback[1], $this);
1221 | if (is_bool($ret))
1222 | return $ret;
1223 | }
1224 | }
1225 |
1226 | $db->startTransaction();
1227 | // unset homefolder as it will no longer exist
1228 | $queryStr = "UPDATE `tblUsers` SET `homefolder`=NULL WHERE `homefolder` = " . $this->_id;
1229 | if (!$db->getResult($queryStr)) {
1230 | $db->rollbackTransaction();
1231 | return false;
1232 | }
1233 |
1234 | // Remove database entries
1235 | $queryStr = "DELETE FROM `tblFolders` WHERE `id` = " . $this->_id;
1236 | if (!$db->getResult($queryStr)) {
1237 | $db->rollbackTransaction();
1238 | return false;
1239 | }
1240 | $queryStr = "DELETE FROM `tblFolderAttributes` WHERE `folder` = " . $this->_id;
1241 | if (!$db->getResult($queryStr)) {
1242 | $db->rollbackTransaction();
1243 | return false;
1244 | }
1245 | $queryStr = "DELETE FROM `tblACLs` WHERE `target` = ". $this->_id. " AND `targetType` = " . T_FOLDER;
1246 | if (!$db->getResult($queryStr)) {
1247 | $db->rollbackTransaction();
1248 | return false;
1249 | }
1250 |
1251 | $queryStr = "DELETE FROM `tblNotify` WHERE `target` = ". $this->_id. " AND `targetType` = " . T_FOLDER;
1252 | if (!$db->getResult($queryStr)) {
1253 | $db->rollbackTransaction();
1254 | return false;
1255 | }
1256 | $db->commitTransaction();
1257 |
1258 | /* Check if 'onPostRemoveFolder' callback is set */
1259 | if (isset($this->_dms->callbacks['onPostRemoveFromDatabaseFolder'])) {
1260 | foreach ($this->_dms->callbacks['onPostRemoveFromDatabaseFolder'] as $callback) {
1261 | /** @noinspection PhpStatementHasEmptyBodyInspection */
1262 | if (!call_user_func($callback[0], $callback[1], $this->_id)) {
1263 | }
1264 | }
1265 | }
1266 |
1267 | return true;
1268 | } /* }}} */
1269 |
1270 | /**
1271 | * Remove recursively a folder
1272 | *
1273 | * Removes a folder, all its subfolders and documents
1274 | * This method triggers the callbacks onPreRemoveFolder and onPostRemoveFolder.
1275 | * If onPreRemoveFolder returns a boolean then this method will return
1276 | * imediately with the value returned by the callback. Otherwise the
1277 | * regular removal is executed, which in turn
1278 | * triggers further onPreRemoveFolder and onPostRemoveFolder callbacks
1279 | * and its counterparts for documents (onPreRemoveDocument, onPostRemoveDocument).
1280 | *
1281 | * @return boolean true on success, false in case of an error
1282 | */
1283 | public function remove() { /* {{{ */
1284 | /** @noinspection PhpUnusedLocalVariableInspection */
1285 | $db = $this->_dms->getDB();
1286 |
1287 | // Do not delete the root folder.
1288 | if ($this->_id == $this->_dms->rootFolderID || !isset($this->_parentID) || ($this->_parentID == null) || ($this->_parentID == "") || ($this->_parentID == 0)) {
1289 | return false;
1290 | }
1291 |
1292 | /* Check if 'onPreRemoveFolder' callback is set */
1293 | if (isset($this->_dms->callbacks['onPreRemoveFolder'])) {
1294 | foreach ($this->_dms->callbacks['onPreRemoveFolder'] as $callback) {
1295 | $ret = call_user_func($callback[0], $callback[1], $this);
1296 | if (is_bool($ret))
1297 | return $ret;
1298 | }
1299 | }
1300 |
1301 | //Entfernen der Unterordner und Dateien
1302 | $res = $this->getSubFolders();
1303 | if (is_bool($res) && !$res) return false;
1304 | $res = $this->getDocuments();
1305 | if (is_bool($res) && !$res) return false;
1306 |
1307 | foreach ($this->_subFolders as $subFolder) {
1308 | $res = $subFolder->remove();
1309 | if (!$res) {
1310 | return false;
1311 | }
1312 | }
1313 |
1314 | foreach ($this->_documents as $document) {
1315 | $res = $document->remove();
1316 | if (!$res) {
1317 | return false;
1318 | }
1319 | }
1320 |
1321 | $ret = $this->removeFromDatabase();
1322 | if (!$ret)
1323 | return $ret;
1324 |
1325 | /* Check if 'onPostRemoveFolder' callback is set */
1326 | if (isset($this->_dms->callbacks['onPostRemoveFolder'])) {
1327 | foreach ($this->_dms->callbacks['onPostRemoveFolder'] as $callback) {
1328 | call_user_func($callback[0], $callback[1], $this);
1329 | }
1330 | }
1331 |
1332 | return $ret;
1333 | } /* }}} */
1334 |
1335 | /**
1336 | * Empty recursively a folder
1337 | *
1338 | * Removes all subfolders and documents of a folder but not the folder itself
1339 | * This method will call remove() on all its children.
1340 | * This method triggers the callbacks onPreEmptyFolder and onPostEmptyFolder.
1341 | * If onPreEmptyFolder returns a boolean then this method will return
1342 | * imediately.
1343 | * Be aware that the recursive calls of remove() will trigger the callbacks
1344 | * onPreRemoveFolder, onPostRemoveFolder, onPreRemoveDocument and onPostRemoveDocument.
1345 | *
1346 | * @return boolean true on success, false in case of an error
1347 | */
1348 | public function emptyFolder() { /* {{{ */
1349 | /** @noinspection PhpUnusedLocalVariableInspection */
1350 | $db = $this->_dms->getDB();
1351 |
1352 | /* Check if 'onPreEmptyFolder' callback is set */
1353 | if (isset($this->_dms->callbacks['onPreEmptyFolder'])) {
1354 | foreach ($this->_dms->callbacks['onPreEmptyFolder'] as $callback) {
1355 | $ret = call_user_func($callback[0], $callback[1], $this);
1356 | if (is_bool($ret))
1357 | return $ret;
1358 | }
1359 | }
1360 |
1361 | //Entfernen der Unterordner und Dateien
1362 | $res = $this->getSubFolders();
1363 | if (is_bool($res) && !$res) return false;
1364 | $res = $this->getDocuments();
1365 | if (is_bool($res) && !$res) return false;
1366 |
1367 | foreach ($this->_subFolders as $subFolder) {
1368 | $res = $subFolder->remove();
1369 | if (!$res) {
1370 | return false;
1371 | }
1372 | }
1373 |
1374 | foreach ($this->_documents as $document) {
1375 | $res = $document->remove();
1376 | if (!$res) {
1377 | return false;
1378 | }
1379 | }
1380 |
1381 | /* Check if 'onPostEmptyFolder' callback is set */
1382 | if (isset($this->_dms->callbacks['onPostEmptyFolder'])) {
1383 | foreach ($this->_dms->callbacks['onPostEmptyFolder'] as $callback) {
1384 | call_user_func($callback[0], $callback[1], $this);
1385 | }
1386 | }
1387 |
1388 | return true;
1389 | } /* }}} */
1390 |
1391 | /**
1392 | * Returns a list of access rights
1393 | *
1394 | * If the folder inherits the access rights from the parent folder
1395 | * those will be returned.
1396 | * $mode and $op can be set to restrict the list of returned access
1397 | * rights. If $mode is set to M_ANY no restriction will apply
1398 | * regardless of the value of $op. The returned array contains a list
1399 | * of {@link SeedDMS_Core_UserAccess} and
1400 | * {@link SeedDMS_Core_GroupAccess} objects. Even if the document
1401 | * has no access list the returned array contains the two elements
1402 | * 'users' and 'groups' which are than empty. The methode returns false
1403 | * if the function fails.
1404 | *
1405 | * @param integer $mode access mode (defaults to M_ANY)
1406 | * @param integer $op operation (defaults to O_EQ)
1407 | * @return bool|SeedDMS_Core_GroupAccess|SeedDMS_Core_UserAccess
1408 | */
1409 | public function getAccessList($mode = M_ANY, $op = O_EQ) { /* {{{ */
1410 | $db = $this->_dms->getDB();
1411 |
1412 | if ($this->inheritsAccess()) {
1413 | /* Access is supposed to be inherited but it could be that there
1414 | * is no parent because the configured root folder id is somewhere
1415 | * below the actual root folder.
1416 | */
1417 | $res = $this->getParent();
1418 | if ($res)
1419 | return $this->_parent->getAccessList($mode, $op);
1420 | }
1421 |
1422 | if (!isset($this->_accessList[$mode])) {
1423 | if ($op!=O_GTEQ && $op!=O_LTEQ && $op!=O_EQ) {
1424 | return false;
1425 | }
1426 | $modeStr = "";
1427 | if ($mode!=M_ANY) {
1428 | $modeStr = " AND `mode`".$op.(int)$mode;
1429 | }
1430 | $queryStr = "SELECT * FROM `tblACLs` WHERE `targetType` = ".T_FOLDER.
1431 | " AND `target` = " . $this->_id . $modeStr . " ORDER BY `targetType`";
1432 | $resArr = $db->getResultArray($queryStr);
1433 | if (is_bool($resArr) && !$resArr)
1434 | return false;
1435 |
1436 | $this->_accessList[$mode] = array("groups" => array(), "users" => array());
1437 | foreach ($resArr as $row) {
1438 | if ($row["userID"] != -1)
1439 | array_push($this->_accessList[$mode]["users"], new SeedDMS_Core_UserAccess($this->_dms->getUser($row["userID"]), (int) $row["mode"]));
1440 | else //if ($row["groupID"] != -1)
1441 | array_push($this->_accessList[$mode]["groups"], new SeedDMS_Core_GroupAccess($this->_dms->getGroup($row["groupID"]), (int) $row["mode"]));
1442 | }
1443 | }
1444 |
1445 | return $this->_accessList[$mode];
1446 | } /* }}} */
1447 |
1448 | /**
1449 | * Delete all entries for this folder from the access control list
1450 | *
1451 | * @param boolean $noclean set to true if notifier list shall not be clean up
1452 | * @return boolean true if operation was successful otherwise false
1453 | */
1454 | public function clearAccessList($noclean = false) { /* {{{ */
1455 | $db = $this->_dms->getDB();
1456 |
1457 | $queryStr = "DELETE FROM `tblACLs` WHERE `targetType` = " . T_FOLDER . " AND `target` = " . $this->_id;
1458 | if (!$db->getResult($queryStr))
1459 | return false;
1460 |
1461 | unset($this->_accessList);
1462 | $this->_readAccessList = array();
1463 |
1464 | if (!$noclean)
1465 | $this->cleanNotifyList();
1466 |
1467 | return true;
1468 | } /* }}} */
1469 |
1470 | /**
1471 | * Add access right to folder
1472 | *
1473 | * This method may change in the future. Instead of passing the a flag
1474 | * and a user/group id a user or group object will be expected.
1475 | *
1476 | * @param integer $mode access mode
1477 | * @param integer $userOrGroupID id of user or group
1478 | * @param integer $isUser set to 1 if $userOrGroupID is the id of a
1479 | * user
1480 | * @return bool
1481 | */
1482 | public function addAccess($mode, $userOrGroupID, $isUser) { /* {{{ */
1483 | $db = $this->_dms->getDB();
1484 |
1485 | if ($mode < M_NONE || $mode > M_ALL)
1486 | return false;
1487 |
1488 | $userOrGroup = ($isUser) ? "`userID`" : "`groupID`";
1489 |
1490 | /* Adding a second access right will return false */
1491 | $queryStr = "SELECT * FROM `tblACLs` WHERE `targetType` = ".T_FOLDER.
1492 | " AND `target` = " . $this->_id . " AND ". $userOrGroup . " = ". (int) $userOrGroupID;
1493 | $resArr = $db->getResultArray($queryStr);
1494 | if (is_bool($resArr) || $resArr)
1495 | return false;
1496 |
1497 | $queryStr = "INSERT INTO `tblACLs` (`target`, `targetType`, ".$userOrGroup.", `mode`) VALUES
1498 | (".$this->_id.", ".T_FOLDER.", " . (int) $userOrGroupID . ", " .(int) $mode. ")";
1499 | if (!$db->getResult($queryStr))
1500 | return false;
1501 |
1502 | unset($this->_accessList);
1503 | $this->_readAccessList = array();
1504 |
1505 | // Update the notify list, if necessary.
1506 | if ($mode == M_NONE) {
1507 | $this->removeNotify($userOrGroupID, $isUser);
1508 | }
1509 |
1510 | return true;
1511 | } /* }}} */
1512 |
1513 | /**
1514 | * Change access right of folder
1515 | *
1516 | * This method may change in the future. Instead of passing the a flag
1517 | * and a user/group id a user or group object will be expected.
1518 | *
1519 | * @param integer $newMode access mode
1520 | * @param integer $userOrGroupID id of user or group
1521 | * @param integer $isUser set to 1 if $userOrGroupID is the id of a
1522 | * user
1523 | * @return bool
1524 | */
1525 | public function changeAccess($newMode, $userOrGroupID, $isUser) { /* {{{ */
1526 | $db = $this->_dms->getDB();
1527 |
1528 | $userOrGroup = ($isUser) ? "`userID`" : "`groupID`";
1529 |
1530 | /* Get the old access right */
1531 | $queryStr = "SELECT * FROM `tblACLs` WHERE `targetType` = ".T_FOLDER.
1532 | " AND `target` = " . $this->_id . " AND ". $userOrGroup . " = ". (int) $userOrGroupID;
1533 | $resArr = $db->getResultArray($queryStr);
1534 | if (!$resArr)
1535 | return false;
1536 |
1537 | $oldmode = $resArr[0]['mode'];
1538 |
1539 | $queryStr = "UPDATE `tblACLs` SET `mode` = " . (int) $newMode . " WHERE `targetType` = ".T_FOLDER." AND `target` = " . $this->_id . " AND " . $userOrGroup . " = " . (int) $userOrGroupID;
1540 | if (!$db->getResult($queryStr))
1541 | return false;
1542 |
1543 | unset($this->_accessList);
1544 | $this->_readAccessList = array();
1545 |
1546 | // Update the notify list, if necessary.
1547 | if ($newMode == M_NONE) {
1548 | $this->removeNotify($userOrGroupID, $isUser);
1549 | }
1550 |
1551 | return $oldmode;
1552 | } /* }}} */
1553 |
1554 | /**
1555 | * Remove all access rights of folder
1556 | *
1557 | * This method removes all access rights of a given user or group.
1558 | *
1559 | * @param $userOrGroupID
1560 | * @param $isUser
1561 | * @return bool
1562 | */
1563 | public function removeAccess($userOrGroupID, $isUser) { /* {{{ */
1564 | $db = $this->_dms->getDB();
1565 |
1566 | $userOrGroup = ($isUser) ? "`userID`" : "`groupID`";
1567 |
1568 | /* Get the old access right */
1569 | $queryStr = "SELECT * FROM `tblACLs` WHERE `targetType` = ".T_FOLDER.
1570 | " AND `target` = " . $this->_id . " AND ". $userOrGroup . " = ". (int) $userOrGroupID;
1571 | $resArr = $db->getResultArray($queryStr);
1572 | if (!$resArr)
1573 | return false;
1574 |
1575 | $queryStr = "DELETE FROM `tblACLs` WHERE `targetType` = ".T_FOLDER." AND `target` = ".$this->_id." AND ".$userOrGroup." = " . (int) $userOrGroupID;
1576 | if (!$db->getResult($queryStr))
1577 | return false;
1578 |
1579 | unset($this->_accessList);
1580 | $this->_readAccessList = array();
1581 |
1582 | // Update the notify list, if necessary.
1583 | $mode = ($isUser ? $this->getAccessMode($this->_dms->getUser($userOrGroupID)) : $this->getGroupAccessMode($this->_dms->getGroup($userOrGroupID)));
1584 | if ($mode == M_NONE) {
1585 | $this->removeNotify($userOrGroupID, $isUser);
1586 | }
1587 |
1588 | return true;
1589 | } /* }}} */
1590 |
1591 | /**
1592 | * Get the access mode of a user on the folder
1593 | *
1594 | * The access mode is either M_READ, M_READWRITE, M_ALL, or M_NONE.
1595 | * It is determined
1596 | * - by the user (admins and owners have always access mode M_ALL)
1597 | * - by the access list for the user (possibly inherited)
1598 | * - by the default access mode
1599 | *
1600 | * This method returns the access mode for a given user. An administrator
1601 | * and the owner of the folder has unrestricted access. A guest user has
1602 | * read only access or no access if access rights are further limited
1603 | * by access control lists all the default access.
1604 | * All other users have access rights according
1605 | * to the access control lists or the default access. This method will
1606 | * recursively check for access rights of parent folders if access rights
1607 | * are inherited.
1608 | *
1609 | * Before checking the access itself a callback 'onCheckAccessFolder'
1610 | * is called. If it returns a value > 0, then this will be returned by this
1611 | * method without any further checks. The optional paramater $context
1612 | * will be passed as a third parameter to the callback. It contains
1613 | * the operation for which the access mode is retrieved. It is for example
1614 | * set to 'removeDocument' if the access mode is used to check for sufficient
1615 | * permission on deleting a document. This callback could be used to
1616 | * override any existing access mode in a certain context.
1617 | *
1618 | * @param SeedDMS_Core_User $user user for which access shall be checked
1619 | * @param string $context context in which the access mode is requested
1620 | * @return integer access mode
1621 | */
1622 | public function getAccessMode($user, $context = '') { /* {{{ */
1623 | if (!$user)
1624 | return M_NONE;
1625 |
1626 | /* Check if 'onCheckAccessFolder' callback is set */
1627 | if (isset($this->_dms->callbacks['onCheckAccessFolder'])) {
1628 | foreach ($this->_dms->callbacks['onCheckAccessFolder'] as $callback) {
1629 | if (($ret = call_user_func($callback[0], $callback[1], $this, $user, $context)) > 0) {
1630 | return $ret;
1631 | }
1632 | }
1633 | }
1634 |
1635 | /* Administrators have unrestricted access */
1636 | if ($user->isAdmin()) return M_ALL;
1637 |
1638 | /* The owner of the folder has unrestricted access */
1639 | if ($user->getID() == $this->_ownerID) return M_ALL;
1640 |
1641 | if ($this->_dms->memcache) {
1642 | $ck = "am:f".$this->_id.":".$user->getId().":".$context;
1643 | if ($cobj = $this->_dms->memcache->get($ck))
1644 | return $cobj;
1645 | }
1646 |
1647 | /* Check ACLs */
1648 | $accessList = $this->getAccessList();
1649 | if (!$accessList) return false;
1650 |
1651 | /** @var SeedDMS_Core_UserAccess $userAccess */
1652 | foreach ($accessList["users"] as $userAccess) {
1653 | if ($userAccess->getUserID() == $user->getID()) {
1654 | $mode = $userAccess->getMode();
1655 | if ($user->isGuest()) {
1656 | if ($mode >= M_READ) $mode = M_READ;
1657 | }
1658 | if ($this->_dms->memcache)
1659 | $this->_dms->memcache->set($ck, $mode, 600);
1660 | return $mode;
1661 | }
1662 | }
1663 |
1664 | /* Get the highest right defined by a group */
1665 | if ($accessList['groups']) {
1666 | $mode = 0;
1667 | /** @var SeedDMS_Core_GroupAccess $groupAccess */
1668 | foreach ($accessList["groups"] as $groupAccess) {
1669 | if ($user->isMemberOfGroup($groupAccess->getGroup())) {
1670 | if ($groupAccess->getMode() > $mode)
1671 | $mode = $groupAccess->getMode();
1672 | }
1673 | }
1674 | if ($mode) {
1675 | if ($user->isGuest()) {
1676 | if ($mode >= M_READ) $mode = M_READ;
1677 | }
1678 | if ($this->_dms->memcache)
1679 | $this->_dms->memcache->set($ck, $mode, 600);
1680 | return $mode;
1681 | }
1682 | }
1683 |
1684 | $mode = $this->getDefaultAccess();
1685 | if ($user->isGuest()) {
1686 | if ($mode >= M_READ) $mode = M_READ;
1687 | }
1688 | if ($this->_dms->memcache)
1689 | $this->_dms->memcache->set($ck, $mode, 600);
1690 | return $mode;
1691 | } /* }}} */
1692 |
1693 | /**
1694 | * Get the access mode for a group on the folder
1695 | *
1696 | * This method returns the access mode for a given group. The algorithmn
1697 | * applied to get the access mode is the same as describe at
1698 | * {@link getAccessMode}
1699 | *
1700 | * @param SeedDMS_Core_Group $group group for which access shall be checked
1701 | * @return integer access mode
1702 | */
1703 | public function getGroupAccessMode($group) { /* {{{ */
1704 | $highestPrivileged = M_NONE;
1705 | $foundInACL = false;
1706 | $accessList = $this->getAccessList();
1707 | if (!$accessList)
1708 | return false;
1709 |
1710 | /** @var SeedDMS_Core_GroupAccess $groupAccess */
1711 | foreach ($accessList["groups"] as $groupAccess) {
1712 | if ($groupAccess->getGroupID() == $group->getID()) {
1713 | $foundInACL = true;
1714 | if ($groupAccess->getMode() > $highestPrivileged)
1715 | $highestPrivileged = $groupAccess->getMode();
1716 | if ($highestPrivileged == M_ALL) /* no need to check further */
1717 | return $highestPrivileged;
1718 | }
1719 | }
1720 | if ($foundInACL)
1721 | return $highestPrivileged;
1722 |
1723 | /* Take default access */
1724 | return $this->getDefaultAccess();
1725 | } /* }}} */
1726 |
1727 | /**
1728 | * Get a list of all notification
1729 | *
1730 | * This method returns all users and groups that have registerd a
1731 | * notification for the folder
1732 | *
1733 | * @param integer $type type of notification (not yet used)
1734 | * @param bool $incdisabled set to true if disabled user shall be included
1735 | * @return SeedDMS_Core_User[]|SeedDMS_Core_Group[]|bool array with a the elements 'users' and 'groups' which
1736 | * contain a list of users and groups.
1737 | */
1738 | public function getNotifyList($type = 0, $incdisabled = false) { /* {{{ */
1739 | if (empty($this->_notifyList)) {
1740 | $db = $this->_dms->getDB();
1741 |
1742 | $queryStr ="SELECT * FROM `tblNotify` WHERE `targetType` = " . T_FOLDER . " AND `target` = " . $this->_id;
1743 | $resArr = $db->getResultArray($queryStr);
1744 | if (is_bool($resArr) && $resArr == false)
1745 | return false;
1746 |
1747 | $this->_notifyList = array("groups" => array(), "users" => array());
1748 | foreach ($resArr as $row) {
1749 | if ($row["userID"] != -1) {
1750 | $u = $this->_dms->getUser($row["userID"]);
1751 | if ($u && (!$u->isDisabled() || $incdisabled))
1752 | array_push($this->_notifyList["users"], $u);
1753 | } else {//if ($row["groupID"] != -1)
1754 | $g = $this->_dms->getGroup($row["groupID"]);
1755 | if ($g)
1756 | array_push($this->_notifyList["groups"], $g);
1757 | }
1758 | }
1759 | }
1760 | return $this->_notifyList;
1761 | } /* }}} */
1762 |
1763 | /**
1764 | * Make sure only users/groups with read access are in the notify list
1765 | *
1766 | */
1767 | public function cleanNotifyList() { /* {{{ */
1768 | // If any of the notification subscribers no longer have read access,
1769 | // remove their subscription.
1770 | if (empty($this->_notifyList))
1771 | $this->getNotifyList();
1772 |
1773 | /* Make a copy of both notifier lists because removeNotify will empty
1774 | * $this->_notifyList and the second foreach will not work anymore.
1775 | */
1776 | /** @var SeedDMS_Core_User[] $nusers */
1777 | $nusers = $this->_notifyList["users"];
1778 | $ngroups = $this->_notifyList["groups"];
1779 | foreach ($nusers as $u) {
1780 | if ($this->getAccessMode($u) < M_READ) {
1781 | $this->removeNotify($u->getID(), true);
1782 | }
1783 | }
1784 |
1785 | /** @var SeedDMS_Core_Group[] $ngroups */
1786 | foreach ($ngroups as $g) {
1787 | if ($this->getGroupAccessMode($g) < M_READ) {
1788 | $this->removeNotify($g->getID(), false);
1789 | }
1790 | }
1791 | } /* }}} */
1792 |
1793 | /**
1794 | * Add a user/group to the notification list
1795 | *
1796 | * This method does not check if the currently logged in user
1797 | * is allowed to add a notification. This must be checked by the calling
1798 | * application.
1799 | *
1800 | * @param integer $userOrGroupID
1801 | * @param boolean $isUser true if $userOrGroupID is a user id otherwise false
1802 | * @return integer error code
1803 | * -1: Invalid User/Group ID.
1804 | * -2: Target User / Group does not have read access.
1805 | * -3: User is already subscribed.
1806 | * -4: Database / internal error.
1807 | * 0: Update successful.
1808 | */
1809 | public function addNotify($userOrGroupID, $isUser) { /* {{{ */
1810 | $db = $this->_dms->getDB();
1811 |
1812 | $userOrGroup = ($isUser) ? "`userID`" : "`groupID`";
1813 |
1814 | /* Verify that user / group exists */
1815 | /** @var SeedDMS_Core_User|SeedDMS_Core_Group $obj */
1816 | $obj = ($isUser ? $this->_dms->getUser($userOrGroupID) : $this->_dms->getGroup($userOrGroupID));
1817 | if (!is_object($obj)) {
1818 | return -1;
1819 | }
1820 |
1821 | /* Verify that the requesting user has permission to add the target to
1822 | * the notification system.
1823 | */
1824 | /*
1825 | * The calling application should enforce the policy on who is allowed
1826 | * to add someone to the notification system. If is shall remain here
1827 | * the currently logged in user should be passed to this function
1828 | *
1829 | GLOBAL $user;
1830 | if ($user->isGuest()) {
1831 | return -2;
1832 | }
1833 | if (!$user->isAdmin()) {
1834 | if ($isUser) {
1835 | if ($user->getID() != $obj->getID()) {
1836 | return -2;
1837 | }
1838 | }
1839 | else {
1840 | if (!$obj->isMember($user)) {
1841 | return -2;
1842 | }
1843 | }
1844 | }
1845 | */
1846 |
1847 | //
1848 | // Verify that user / group has read access to the document.
1849 | //
1850 | if ($isUser) {
1851 | // Users are straightforward to check.
1852 | if ($this->getAccessMode($obj) < M_READ) {
1853 | return -2;
1854 | }
1855 | } else {
1856 | // FIXME: Why not check the access list first and if this returns
1857 | // not result, then use the default access?
1858 | // Groups are a little more complex.
1859 | if ($this->getDefaultAccess() >= M_READ) {
1860 | // If the default access is at least READ-ONLY, then just make sure
1861 | // that the current group has not been explicitly excluded.
1862 | $acl = $this->getAccessList(M_NONE, O_EQ);
1863 | $found = false;
1864 | /** @var SeedDMS_Core_GroupAccess $group */
1865 | foreach ($acl["groups"] as $group) {
1866 | if ($group->getGroupID() == $userOrGroupID) {
1867 | $found = true;
1868 | break;
1869 | }
1870 | }
1871 | if ($found) {
1872 | return -2;
1873 | }
1874 | } else {
1875 | // The default access is restricted. Make sure that the group has
1876 | // been explicitly allocated access to the document.
1877 | $acl = $this->getAccessList(M_READ, O_GTEQ);
1878 | if (is_bool($acl)) {
1879 | return -4;
1880 | }
1881 | $found = false;
1882 | /** @var SeedDMS_Core_GroupAccess $group */
1883 | foreach ($acl["groups"] as $group) {
1884 | if ($group->getGroupID() == $userOrGroupID) {
1885 | $found = true;
1886 | break;
1887 | }
1888 | }
1889 | if (!$found) {
1890 | return -2;
1891 | }
1892 | }
1893 | }
1894 | //
1895 | // Check to see if user/group is already on the list.
1896 | //
1897 | $queryStr = "SELECT * FROM `tblNotify` WHERE `tblNotify`.`target` = '".$this->_id."' ".
1898 | "AND `tblNotify`.`targetType` = '".T_FOLDER."' ".
1899 | "AND `tblNotify`.".$userOrGroup." = '". (int) $userOrGroupID."'";
1900 | $resArr = $db->getResultArray($queryStr);
1901 | if (is_bool($resArr)) {
1902 | return -4;
1903 | }
1904 | if (count($resArr)>0) {
1905 | return -3;
1906 | }
1907 |
1908 | $queryStr = "INSERT INTO `tblNotify` (`target`, `targetType`, " . $userOrGroup . ") VALUES (" . $this->_id . ", " . T_FOLDER . ", " . (int) $userOrGroupID . ")";
1909 | if (!$db->getResult($queryStr))
1910 | return -4;
1911 |
1912 | unset($this->_notifyList);
1913 | return 0;
1914 | } /* }}} */
1915 |
1916 | /**
1917 | * Removes notify for a user or group to folder
1918 | *
1919 | * This method does not check if the currently logged in user
1920 | * is allowed to remove a notification. This must be checked by the calling
1921 | * application.
1922 | *
1923 | * @param integer $userOrGroupID
1924 | * @param boolean $isUser true if $userOrGroupID is a user id otherwise false
1925 | * @param int $type type of notification (0 will delete all) Not used yet!
1926 | * @return int error code
1927 | * -1: Invalid User/Group ID.
1928 | * -3: User is not subscribed.
1929 | * -4: Database / internal error.
1930 | * 0: Update successful.
1931 | */
1932 | public function removeNotify($userOrGroupID, $isUser, $type = 0) { /* {{{ */
1933 | $db = $this->_dms->getDB();
1934 |
1935 | /* Verify that user / group exists. */
1936 | $obj = ($isUser ? $this->_dms->getUser($userOrGroupID) : $this->_dms->getGroup($userOrGroupID));
1937 | if (!is_object($obj)) {
1938 | return -1;
1939 | }
1940 |
1941 | $userOrGroup = ($isUser) ? "`userID`" : "`groupID`";
1942 |
1943 | /* Verify that the requesting user has permission to add the target to
1944 | * the notification system.
1945 | */
1946 | /*
1947 | * The calling application should enforce the policy on who is allowed
1948 | * to add someone to the notification system. If is shall remain here
1949 | * the currently logged in user should be passed to this function
1950 | *
1951 | GLOBAL $user;
1952 | if ($user->isGuest()) {
1953 | return -2;
1954 | }
1955 | if (!$user->isAdmin()) {
1956 | if ($isUser) {
1957 | if ($user->getID() != $obj->getID()) {
1958 | return -2;
1959 | }
1960 | }
1961 | else {
1962 | if (!$obj->isMember($user)) {
1963 | return -2;
1964 | }
1965 | }
1966 | }
1967 | */
1968 |
1969 | //
1970 | // Check to see if the target is in the database.
1971 | //
1972 | $queryStr = "SELECT * FROM `tblNotify` WHERE `tblNotify`.`target` = '".$this->_id."' ".
1973 | "AND `tblNotify`.`targetType` = '".T_FOLDER."' ".
1974 | "AND `tblNotify`.".$userOrGroup." = '". (int) $userOrGroupID."'";
1975 | $resArr = $db->getResultArray($queryStr);
1976 | if (is_bool($resArr)) {
1977 | return -4;
1978 | }
1979 | if (count($resArr)==0) {
1980 | return -3;
1981 | }
1982 |
1983 | $queryStr = "DELETE FROM `tblNotify` WHERE `target` = " . $this->_id . " AND `targetType` = " . T_FOLDER . " AND " . $userOrGroup . " = " . (int) $userOrGroupID;
1984 | /* If type is given then delete only those notifications */
1985 | if ($type)
1986 | $queryStr .= " AND `type` = ".(int) $type;
1987 | if (!$db->getResult($queryStr))
1988 | return -4;
1989 |
1990 | unset($this->_notifyList);
1991 | return 0;
1992 | } /* }}} */
1993 |
1994 | /**
1995 | * Get List of users and groups which have read access on the folder.
1996 | * The list will not include any guest users,
1997 | * administrators and the owner of the folder.
1998 | *
1999 | * This method is deprecated. Use
2000 | * {@see SeedDMS_Core_Folder::getReadAccessList()} instead.
2001 | */
2002 | public function getApproversList() { /* {{{ */
2003 | return $this->getReadAccessList(0, 0);
2004 | } /* }}} */
2005 |
2006 | /**
2007 | * Returns a list of groups and users with read access on the folder
2008 | *
2009 | * The list will not include any guest users,
2010 | * administrators and the owner of the folder unless $listadmin resp.
2011 | * $listowner is set to true.
2012 | *
2013 | * @param boolean $listadmin if set to true any admin will be listed too
2014 | * @param boolean $listowner if set to true the owner will be listed too
2015 | * @param boolean $listguest if set to true any guest will be listed too
2016 | * @return array list of users and groups
2017 | */
2018 | public function getReadAccessList($listadmin = 0, $listowner = 0, $listguest = 0) { /* {{{ */
2019 | $db = $this->_dms->getDB();
2020 |
2021 | $cachehash = substr(md5($listadmin.$listowner.$listguest), 0, 3);
2022 | if (!isset($this->_readAccessList[$cachehash])) {
2023 | $this->_readAccessList[$cachehash] = array("groups" => array(), "users" => array());
2024 | $userIDs = "";
2025 | $groupIDs = "";
2026 | $defAccess = $this->getDefaultAccess();
2027 |
2028 | /* Check if the default access is < read access or >= read access.
2029 | * If default access is less than read access, then create a list
2030 | * of users and groups with read access.
2031 | * If default access is equal or greater then read access, then
2032 | * create a list of users and groups without read access.
2033 | */
2034 | if ($defAccess<M_READ) {
2035 | // Get the list of all users and groups that are listed in the ACL as
2036 | // having read access to the folder.
2037 | $tmpList = $this->getAccessList(M_READ, O_GTEQ);
2038 | } else {
2039 | // Get the list of all users and groups that DO NOT have read access
2040 | // to the folder.
2041 | $tmpList = $this->getAccessList(M_NONE, O_LTEQ);
2042 | }
2043 | /** @var SeedDMS_Core_GroupAccess $groupAccess */
2044 | foreach ($tmpList["groups"] as $groupAccess) {
2045 | $groupIDs .= (strlen($groupIDs)==0 ? "" : ", ") . $groupAccess->getGroupID();
2046 | }
2047 |
2048 | /** @var SeedDMS_Core_UserAccess $userAccess */
2049 | foreach ($tmpList["users"] as $userAccess) {
2050 | $user = $userAccess->getUser();
2051 | // if (!$listadmin && $user->isAdmin()) continue;
2052 | // if (!$listowner && $user->getID() == $this->_ownerID) continue;
2053 | // if (!$listguest && $user->isGuest()) continue;
2054 | $userIDs .= (strlen($userIDs)==0 ? "" : ", ") . $user->getID();
2055 | }
2056 |
2057 | // Construct a query against the users table to identify those users
2058 | // that have read access on this folder, either directly through an
2059 | // ACL entry, by virtue of ownership or by having administrative rights
2060 | // on the database.
2061 | $queryStr = "";
2062 | /* If default access is less then read, $userIDs and $groupIDs contains
2063 | * a list of user with read access
2064 | */
2065 | if ($defAccess < M_READ) {
2066 | $queryStr = "SELECT DISTINCT `tblUsers`.* FROM `tblUsers` ".
2067 | "LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
2068 | "WHERE 1=0".
2069 | ((strlen($groupIDs) > 0) ? " OR (`tblGroupMembers`.`groupID` IN (". $groupIDs ."))" : "").
2070 | ((strlen($userIDs) > 0) ? " OR (`tblUsers`.`id` IN (". $userIDs ."))" : "").
2071 | " OR (`tblUsers`.`role` = ".SeedDMS_Core_User::role_admin.")".
2072 | " OR (`tblUsers`.`id` = ". $this->_ownerID . ")".
2073 | " ORDER BY `login`";
2074 | } else {
2075 | /* If default access is equal or greater than M_READ, $userIDs and
2076 | * $groupIDs contains a list of user without read access
2077 | * The sql statement will exclude those users and groups but include
2078 | * admins and the owner
2079 | */
2080 | $queryStr = "SELECT DISTINCT `tblUsers`.* FROM `tblUsers` ".
2081 | "LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
2082 | "WHERE 1=1".
2083 | (strlen($groupIDs) == 0 ? "" : " AND (`tblGroupMembers`.`groupID` NOT IN (". $groupIDs .") OR `tblGroupMembers`.`groupID` IS NULL)").
2084 | (strlen($userIDs) == 0 ? "" : " AND (`tblUsers`.`id` NOT IN (". $userIDs ."))").
2085 | " OR `tblUsers`.`id` = ". $this->_ownerID . " OR `tblUsers`.`role` = ".SeedDMS_Core_User::role_admin." ORDER BY `login` ";
2086 | }
2087 | $resArr = $db->getResultArray($queryStr);
2088 | if (!is_bool($resArr)) {
2089 | foreach ($resArr as $row) {
2090 | $user = $this->_dms->getUser($row['id']);
2091 | if (!$listadmin && $user->isAdmin()) continue;
2092 | if (!$listowner && $user->getID() == $this->_ownerID) continue;
2093 | if (!$listguest && $user->isGuest()) continue;
2094 | $this->_readAccessList[$cachehash]["users"][] = $user;
2095 | }
2096 | }
2097 |
2098 | // Assemble the list of groups that have read access to the folder.
2099 | $queryStr = "";
2100 | if ($defAccess < M_READ) {
2101 | if (strlen($groupIDs)>0) {
2102 | $queryStr = "SELECT `tblGroups`.* FROM `tblGroups` ".
2103 | "WHERE `tblGroups`.`id` IN (". $groupIDs .") ORDER BY `name`";
2104 | }
2105 | } else {
2106 | if (strlen($groupIDs)>0) {
2107 | $queryStr = "SELECT `tblGroups`.* FROM `tblGroups` ".
2108 | "WHERE `tblGroups`.`id` NOT IN (". $groupIDs .") ORDER BY `name`";
2109 | } else {
2110 | $queryStr = "SELECT `tblGroups`.* FROM `tblGroups` ORDER BY `name`";
2111 | }
2112 | }
2113 | if (strlen($queryStr)>0) {
2114 | $resArr = $db->getResultArray($queryStr);
2115 | if (!is_bool($resArr)) {
2116 | foreach ($resArr as $row) {
2117 | $group = $this->_dms->getGroup($row["id"]);
2118 | $this->_readAccessList[$cachehash]["groups"][] = $group;
2119 | }
2120 | }
2121 | }
2122 | }
2123 | return $this->_readAccessList[$cachehash];
2124 | } /* }}} */
2125 |
2126 | /**
2127 | * Get the internally used folderList which stores the ids of folders from
2128 | * the root folder to the parent folder.
2129 | *
2130 | * @return string column separated list of folder ids
2131 | */
2132 | public function getFolderList() { /* {{{ */
2133 | $db = $this->_dms->getDB();
2134 |
2135 | $queryStr = "SELECT `folderList` FROM `tblFolders` where `id` = ".$this->_id;
2136 | $resArr = $db->getResultArray($queryStr);
2137 | if (is_bool($resArr) && !$resArr)
2138 | return false;
2139 | return $resArr[0]['folderList'];
2140 | } /* }}} */
2141 |
2142 | /**
2143 | * Checks the internal data of the folder and repairs it.
2144 | * Currently, this function only repairs an incorrect folderList
2145 | *
2146 | * @return boolean true on success, otherwise false
2147 | */
2148 | public function repair() { /* {{{ */
2149 | $db = $this->_dms->getDB();
2150 |
2151 | $curfolderlist = $this->getFolderList();
2152 |
2153 | // calculate the folderList of the folder
2154 | $parent = $this->getParent();
2155 | $pathPrefix = "";
2156 | $path = $parent->getPath();
2157 | foreach ($path as $f) {
2158 | $pathPrefix .= ":".$f->getID();
2159 | }
2160 | if (strlen($pathPrefix)>1) {
2161 | $pathPrefix .= ":";
2162 | }
2163 | if ($curfolderlist != $pathPrefix) {
2164 | $queryStr = "UPDATE `tblFolders` SET `folderList`='".$pathPrefix."' WHERE `id` = ". $this->_id;
2165 | $res = $db->getResult($queryStr);
2166 | if (!$res)
2167 | return false;
2168 | }
2169 | return true;
2170 | } /* }}} */
2171 |
2172 | /**
2173 | * Get the min and max sequence value for documents
2174 | *
2175 | * @return bool|array array with keys 'min' and 'max', false in case of an error
2176 | */
2177 | public function getDocumentsMinMax() { /* {{{ */
2178 | $db = $this->_dms->getDB();
2179 |
2180 | $queryStr = "SELECT min(`sequence`) AS `min`, max(`sequence`) AS `max` FROM `tblDocuments` WHERE `folder` = " . (int) $this->_id;
2181 | $resArr = $db->getResultArray($queryStr);
2182 | if (is_bool($resArr) && $resArr == false)
2183 | return false;
2184 |
2185 | return $resArr[0];
2186 | } /* }}} */
2187 |
2188 | /**
2189 | * Get the min and max sequence value for folders
2190 | *
2191 | * @return bool|array array with keys 'min' and 'max', false in case of an error
2192 | */
2193 | public function getFoldersMinMax() { /* {{{ */
2194 | $db = $this->_dms->getDB();
2195 |
2196 | $queryStr = "SELECT min(`sequence`) AS `min`, max(`sequence`) AS `max` FROM `tblFolders` WHERE `parent` = " . (int) $this->_id;
2197 | $resArr = $db->getResultArray($queryStr);
2198 | if (is_bool($resArr) && $resArr == false)
2199 | return false;
2200 |
2201 | return $resArr[0];
2202 | } /* }}} */
2203 |
2204 | /**
2205 | * Reorder documents of folder
2206 | *
2207 | * Fix the sequence numbers of all documents in the folder, by assigning new
2208 | * numbers starting from 1 incrementing by 1. This can be necessary if sequence
2209 | * numbers are not unique which makes manual reordering for documents with
2210 | * identical sequence numbers impossible.
2211 | *
2212 | * @return bool false in case of an error, otherwise true
2213 | */
2214 | public function reorderDocuments() { /* {{{ */
2215 | $db = $this->_dms->getDB();
2216 |
2217 | $queryStr = "SELECT `id` FROM `tblDocuments` WHERE `folder` = " . (int) $this->_id . " ORDER BY `sequence`";
2218 | $resArr = $db->getResultArray($queryStr);
2219 | if (is_bool($resArr) && $resArr == false)
2220 | return false;
2221 |
2222 | $db->startTransaction();
2223 | $no = 1.0;
2224 | foreach ($resArr as $doc) {
2225 | $queryStr = "UPDATE `tblDocuments` SET `sequence` = " . $no . " WHERE `id` = ". $doc['id'];
2226 | if (!$db->getResult($queryStr)) {
2227 | $db->rollbackTransaction();
2228 | return false;
2229 | }
2230 | $no += 1.0;
2231 | }
2232 | $db->commitTransaction();
2233 |
2234 | return true;
2235 | } /* }}} */
2236 |
2237 |
2238 | }