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