1: <?php
2: /**
3: * This file contains the category collection and item class.
4: *
5: * @package Core
6: * @subpackage GenericDB_Model
7: * @author Timo Hummel
8: * @copyright four for business AG <www.4fb.de>
9: * @license http://www.contenido.org/license/LIZENZ.txt
10: * @link http://www.4fb.de
11: * @link http://www.contenido.org
12: */
13:
14: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
15:
16: /**
17: * Category collection
18: *
19: * @package Core
20: * @subpackage GenericDB_Model
21: */
22: class cApiCategoryCollection extends ItemCollection {
23:
24: /**
25: * Create a new collection of items.
26: *
27: * @param string $select [optional]
28: * where clause to use for selection (see ItemCollection::select())
29: */
30: public function __construct($select = false) {
31: global $cfg;
32: parent::__construct($cfg['tab']['cat'], 'idcat');
33: $this->_setItemClass('cApiCategory');
34:
35: // set the join partners so that joins can be used via link() method
36: $this->_setJoinPartner('cApiClientCollection');
37:
38: if ($select !== false) {
39: $this->select($select);
40: }
41: }
42:
43: /**
44: * Creates a category entry.
45: *
46: * @param int $idclient
47: * @param int $parentid [optional]
48: * @param int $preid [optional]
49: * @param int $postid [optional]
50: * @param int $status [optional]
51: * @param string $author [optional]
52: * @param string $created [optional]
53: * @param string $lastmodified [optional]
54: * @return cApiCategory
55: */
56: public function create($idclient, $parentid = 0, $preid = 0, $postid = 0, $status = 0, $author = '', $created = '', $lastmodified = '') {
57: global $auth;
58:
59: if (empty($author)) {
60: $author = $auth->auth['uname'];
61: }
62: if (empty($created)) {
63: $created = date('Y-m-d H:i:s');
64: }
65: if (empty($lastmodified)) {
66: $lastmodified = date('Y-m-d H:i:s');
67: }
68:
69: $oItem = $this->createNewItem();
70:
71: $oItem->set('idclient', $idclient);
72: $oItem->set('parentid', $parentid);
73: $oItem->set('preid', $preid);
74: $oItem->set('postid', $postid);
75: $oItem->set('status', $status);
76: $oItem->set('author', $author);
77: $oItem->set('created', $created);
78: $oItem->set('lastmodified', $lastmodified);
79: $oItem->store();
80:
81: return $oItem;
82: }
83:
84: /**
85: * Returns the last category tree entry from the category table for a
86: * specific client.
87: * Last entry has no parentid and no postid.
88: *
89: * @param int $idclient
90: * @return cApiCategory|NULL
91: */
92: public function fetchLastCategoryTree($idclient) {
93: $where = 'parentid=0 AND postid=0 AND idclient=' . (int) $idclient;
94: $this->select($where);
95: return $this->next();
96: }
97:
98: /**
99: * Returns list of categories (category ids) by passed client.
100: *
101: * @param int $idclient
102: * @return array
103: */
104: public function getCategoryIdsByClient($idclient) {
105: $list = array();
106: $sql = 'SELECT idcat FROM `%s` WHERE idclient=%d';
107: $this->db->query($sql, $this->table, $idclient);
108: while ($this->db->nextRecord()) {
109: $list[] = $this->db->f('idcat');
110: }
111: return $list;
112: }
113:
114: /**
115: * Returns the id of category which is located after passed category id.
116: *
117: * Example:
118: * <pre>
119: * ...
120: * parent_category
121: * this_category
122: * post_category (*)
123: * ...
124: * (*) Returned category id
125: * </pre>
126: *
127: * @param int $idcat
128: * @return int
129: */
130: public function getNextPostCategoryId($idcat) {
131: $sql = "SELECT idcat FROM `%s` WHERE preid = %d";
132: $this->db->query($sql, $this->table, $idcat);
133: if ($this->db->nextRecord()) {
134: // Post element exists
135: $idcat = $this->db->f('idcat');
136: $sql = "SELECT parentid FROM `%s` WHERE idcat = %d";
137: $this->db->query($sql, $this->table, $idcat);
138: if ($this->db->nextRecord()) {
139: // Parent from post can't be 0
140: $parentid = (int) $this->db->f('parentid');
141: return ($parentid != 0) ? $idcat : 0;
142: } else {
143: return 99;
144: }
145: } else {
146: // Post element does not exist
147: return 0;
148: }
149: }
150:
151: /**
152: * Returns the id of category which is located after passed category ids
153: * parent category.
154: *
155: * Example:
156: * <pre>
157: * ...
158: * root_category
159: * parent_category
160: * previous_cateory
161: * this_category
162: * post_category
163: * parents_post_category (*)
164: * ...
165: * (*) Returned category id
166: * </pre>
167: *
168: * @param int $idcat
169: * Category id
170: * @return int
171: */
172: public function getParentsNextPostCategoryId($idcat) {
173: $sql = "SELECT parentid FROM `%s` WHERE idcat = %d";
174: $this->db->query($sql, $this->table, $idcat);
175: if ($this->db->nextRecord()) {
176: // Parent exists
177: $idcat = $this->db->f('parentid');
178: if ($idcat != 0) {
179: $sql = "SELECT idcat FROM `%s` WHERE preid = %d";
180: $this->db->query($sql, $this->table, $idcat);
181: if ($this->db->nextRecord()) {
182: // Parent has post
183: $idcat = (int) $this->db->f('idcat');
184: $sql = "SELECT parentid FROM `%s` WHERE idcat = %d";
185: $this->db->query($sql, $this->table, $idcat);
186: if ($this->db->nextRecord()) {
187: // Parent from post must not be 0
188: $parentid = (int) $this->db->f('parentid');
189: return ($parentid != 0) ? $idcat : 0;
190: } else {
191: return 99;
192: }
193: } else {
194: // Parent has no post
195: return $this->getNextBackwardsCategoryId($idcat);
196: }
197: } else {
198: return 0;
199: }
200: } else {
201: // No parent
202: return 0;
203: }
204: }
205:
206: /**
207: * Returns id of first child category, where parent id is the same as passed
208: * id and the previous id is 0.
209: *
210: * Example:
211: * <pre>
212: * ...
213: * this_category
214: * child_category (*)
215: * child_category2
216: * child_category3
217: * ...
218: * (*) Returned category id
219: * </pre>
220: *
221: * @global array $cfg
222: * @param int $idcat
223: * @param int|NULL $idlang [optional]
224: * If defined, it checks also if there is a next deeper category in this language.
225: * @return int
226: */
227: public function getFirstChildCategoryId($idcat, $idlang = NULL) {
228: global $cfg;
229:
230: $sql = "SELECT idcat FROM `%s` WHERE parentid = %d AND preid = 0";
231: $sql = $this->db->prepare($sql, $this->table, $idcat);
232: $this->db->query($sql);
233: if ($this->db->nextRecord()) {
234: $midcat = (int) $this->db->f('idcat');
235: if (NULL == $idlang) {
236: return $midcat;
237: }
238:
239: // Deeper element exists, check for language dependent part
240: $sql = "SELECT idcatlang FROM `%s` WHERE idcat = %d AND idlang = %d";
241: $sql = $this->db->prepare($sql, $cfg['tab']['cat_lang'], $idcat, $idlang);
242: $this->db->query($sql);
243: return ($this->db->nextRecord()) ? $midcat : 0;
244: } else {
245: // Deeper element does not exist
246: return 0;
247: }
248: }
249:
250: /**
251: * Returns list of all child category ids, only them on next deeper level
252: * (not recursive!)
253: * The returned array contains already the order of the categories.
254: * Example:
255: * <pre>
256: * ...
257: * this_category
258: * child_category (*)
259: * child_category2 (*)
260: * child_of_child_category2
261: * child_category3 (*)
262: * ...
263: * (*) Returned category ids
264: * </pre>
265: *
266: * @global array $cfg
267: * @param int $idcat
268: * @param int|NULL $idlang [optional]
269: * @return array
270: */
271: public function getAllChildCategoryIds($idcat, $idlang = NULL) {
272: global $cfg;
273:
274: $aCats = array();
275: $bLoop = true;
276: $db2 = $this->_getSecondDBInstance();
277:
278: $sql = "SELECT idcat FROM `%s` WHERE parentid = %d AND preid = 0";
279: $this->db->query($sql, $this->table, $idcat);
280: if ($this->db->nextRecord()) {
281: while ($bLoop) {
282: $midcat = $this->db->f('idcat');
283: if (NULL == $idlang) {
284: $aCats[] = $midcat;
285: } else {
286: // Deeper element exists, check for language dependent part
287: $sql = "SELECT idcatlang FROM `%s` WHERE idcat = %d AND idlang = %d";
288: $db2->query($sql, $cfg['tab']['cat_lang'], $midcat, $idlang);
289: if ($db2->nextRecord()) {
290: $aCats[] = $midcat;
291: }
292: }
293:
294: $sql = "SELECT idcat FROM `%s` WHERE parentid = %d AND preid = %d";
295: $this->db->query($sql, $this->table, $idcat, $midcat);
296: if (!$this->db->nextRecord()) {
297: $bLoop = false;
298: }
299: }
300: }
301: return $aCats;
302: }
303:
304: /**
305: * Returns list of all child category ids and their child category ids of
306: * passed category id.
307: * The list also contains the id of passed category.
308: *
309: * The return value of this function could be used to perform bulk actions
310: * on a specific category an all of its childcategories.
311: *
312: * NOTE: The returned array is not sorted!
313: * Return value is similar to getAllCategoryIdsRecursive2, only the sorting
314: * differs
315: *
316: * Example:
317: * <pre>
318: * ...
319: * this_category (*)
320: * child_category (*)
321: * child_category2 (*)
322: * child_of_child_category2 (*)
323: * child_category3 (*)
324: * child_of_child_category3 (*)
325: * ...
326: * (*) Returned category ids
327: * </pre>
328: *
329: * @global array $cfg
330: * @param int $idcat
331: * @param int $idclient
332: * @return array
333: */
334: public function getAllCategoryIdsRecursive($idcat, $idclient) {
335: global $cfg;
336:
337: $catList = array();
338: $openList = array();
339:
340: $openList[] = $idcat;
341:
342: while (($actId = array_pop($openList)) != NULL) {
343: if (in_array($actId, $catList)) {
344: continue;
345: }
346:
347: $catList[] = $actId;
348:
349: $sql = "SELECT * FROM `:cat_tree` AS A, `:cat` AS B WHERE A.idcat=B.idcat AND B.parentid=:parentid AND idclient=:idclient ORDER BY idtree";
350: $sql = $this->db->prepare($sql, array(
351: 'cat_tree' => $cfg['tab']['cat_tree'],
352: 'cat' => $this->table,
353: 'parentid' => (int) $actId,
354: 'idclient' => (int) $idclient
355: ));
356: $this->db->query($sql);
357:
358: while ($this->db->nextRecord()) {
359: $openList[] = $this->db->f('idcat');
360: }
361: }
362:
363: return $catList;
364: }
365:
366: /**
367: * Returns list of all child category ids and their child category ids of
368: * passed category id.
369: * The list also contains the id of passed category.
370: *
371: * The return value of this function could be used to perform bulk actions
372: * on a specific category an all of its childcategories.
373: *
374: * NOTE: Return value is similar to getAllCategoryIdsRecursive, only the
375: * sorting differs
376: *
377: * Example:
378: * <pre>
379: * ...
380: * this_category (*)
381: * child_category (*)
382: * child_category2 (*)
383: * child_of_child_category2 (*)
384: * child_category3 (*)
385: * child_of_child_category3 (*)
386: * ...
387: * (*) Returned category ids
388: * </pre>
389: *
390: * @global array $cfg
391: * @param int $idcat
392: * @param int $client
393: * @return array
394: * Sorted by category id
395: */
396: public function getAllCategoryIdsRecursive2($idcat, $idclient) {
397: global $cfg;
398:
399: $aCats = array();
400: $found = false;
401: $curLevel = 0;
402:
403: $sql = "SELECT * FROM `%s` AS a, `%s` AS b WHERE a.idcat = b.idcat AND idclient = %d ORDER BY idtree";
404: $sql = $this->db->prepare($sql, $cfg['tab']['cat_tree'], $cfg['tab']['cat'], $idclient);
405: $this->db->query($sql);
406:
407: while ($this->db->nextRecord()) {
408: if ($found && $this->db->f('level') <= $curLevel) { // ending part
409: // of tree
410: $found = false;
411: }
412:
413: if ($this->db->f('idcat') == $idcat) { // starting part of tree
414: $found = true;
415: $curLevel = $this->db->f('level');
416: }
417:
418: if ($found) {
419: $aCats[] = $this->db->f('idcat');
420: }
421: }
422:
423: return $aCats;
424: }
425: }
426:
427: /**
428: * Category item
429: *
430: * @package Core
431: * @subpackage GenericDB_Model
432: */
433: class cApiCategory extends Item {
434:
435: /**
436: * Constructor Function
437: *
438: * @param mixed $mId [optional]
439: * Specifies the ID of item to load
440: */
441: public function __construct($mId = false) {
442: global $cfg;
443: parent::__construct($cfg['tab']['cat'], 'idcat');
444: $this->setFilters(array(), array());
445:
446: if ($mId !== false) {
447: $this->loadByPrimaryKey($mId);
448: }
449: }
450:
451: /**
452: * Updates lastmodified field and calls parents store method
453: *
454: * @return bool
455: */
456: public function store() {
457: $this->set('lastmodified', date('Y-m-d H:i:s'));
458: return parent::store();
459: }
460:
461: /**
462: * Userdefined setter for category fields.
463: *
464: * @todo should return return value of overloaded method
465: * @param string $name
466: * @param mixed $value
467: * @param bool $safe [optional]
468: * Flag to run defined inFilter on passed value
469: */
470: public function setField($name, $value, $safe = true) {
471: switch ($name) {
472: case 'idcat':
473: case 'idclient':
474: case 'parentid':
475: case 'preid':
476: case 'postid':
477: case 'status':
478: $value = (int) $value;
479: break;
480: }
481:
482: parent::setField($name, $value, $safe);
483: }
484:
485: /**
486: * Returns the link to the current object.
487: *
488: * @param int $changeLangId [optional]
489: * change language id for URL (optional)
490: * @return string
491: * link
492: */
493: public function getLink($changeLangId = 0) {
494: if ($this->isLoaded() === false) {
495: return '';
496: }
497:
498: $options = array();
499: $options['idcat'] = $this->get('idcat');
500: $options['lang'] = ($changeLangId == 0) ? cRegistry::getLanguageId() : $changeLangId;
501: if ($changeLangId > 0) {
502: $options['changelang'] = $changeLangId;
503: }
504:
505: return cUri::getInstance()->build($options);
506: }
507: }
508: