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: * Constructor to create an instance of this class.
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 c.idcat
231: FROM `%s` AS c
232: LEFT JOIN `%s` AS l ON (l.idcat = c.idcat)
233: WHERE c.parentid = %d AND l.idlang = %d";
234: $sql = $this->db->prepare($sql, $this->table, $cfg['tab']['cat_lang'], $idcat, $idlang);
235: $this->db->query($sql);
236:
237: if ($this->db->nextRecord()) {
238: return $this->db->f('idcat');
239: }
240:
241: return 0;
242: }
243:
244: /**
245: * Returns list of all child category ids, only them on next deeper level
246: * (not recursive!)
247: * The returned array contains already the order of the categories.
248: * Example:
249: * <pre>
250: * ...
251: * this_category
252: * child_category (*)
253: * child_category2 (*)
254: * child_of_child_category2
255: * child_category3 (*)
256: * ...
257: * (*) Returned category ids
258: * </pre>
259: *
260: * @global array $cfg
261: * @param int $idcat
262: * @param int|NULL $idlang [optional]
263: * @return array
264: */
265: public function getAllChildCategoryIds($idcat, $idlang = NULL) {
266: global $cfg;
267:
268: $aCats = array();
269: $bLoop = true;
270: $db2 = $this->_getSecondDBInstance();
271:
272: $sql = "SELECT idcat FROM `%s` WHERE parentid = %d AND preid = 0";
273: $this->db->query($sql, $this->table, $idcat);
274: if ($this->db->nextRecord()) {
275: while ($bLoop) {
276: $midcat = $this->db->f('idcat');
277: if (NULL == $idlang) {
278: $aCats[] = $midcat;
279: } else {
280: // Deeper element exists, check for language dependent part
281: $sql = "SELECT idcatlang FROM `%s` WHERE idcat = %d AND idlang = %d";
282: $db2->query($sql, $cfg['tab']['cat_lang'], $midcat, $idlang);
283: if ($db2->nextRecord()) {
284: $aCats[] = $midcat;
285: }
286: }
287:
288: $sql = "SELECT idcat FROM `%s` WHERE parentid = %d AND preid = %d";
289: $this->db->query($sql, $this->table, $idcat, $midcat);
290: if (!$this->db->nextRecord()) {
291: $bLoop = false;
292: }
293: }
294: }
295: return $aCats;
296: }
297:
298: /**
299: * Returns list of all child category ids and their child category ids of
300: * passed category id.
301: * The list also contains the id of passed category.
302: *
303: * The return value of this function could be used to perform bulk actions
304: * on a specific category an all of its childcategories.
305: *
306: * NOTE: The returned array is not sorted!
307: * Return value is similar to getAllCategoryIdsRecursive2, only the sorting
308: * differs
309: *
310: * Example:
311: * <pre>
312: * ...
313: * this_category (*)
314: * child_category (*)
315: * child_category2 (*)
316: * child_of_child_category2 (*)
317: * child_category3 (*)
318: * child_of_child_category3 (*)
319: * ...
320: * (*) Returned category ids
321: * </pre>
322: *
323: * @global array $cfg
324: * @param int $idcat
325: * @param int $idclient
326: * @return array
327: */
328: public function getAllCategoryIdsRecursive($idcat, $idclient) {
329: global $cfg;
330:
331: $catList = array();
332: $openList = array();
333:
334: $openList[] = $idcat;
335:
336: while (($actId = array_pop($openList)) != NULL) {
337: if (in_array($actId, $catList)) {
338: continue;
339: }
340:
341: $catList[] = $actId;
342:
343: $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";
344: $sql = $this->db->prepare($sql, array(
345: 'cat_tree' => $cfg['tab']['cat_tree'],
346: 'cat' => $this->table,
347: 'parentid' => (int) $actId,
348: 'idclient' => (int) $idclient
349: ));
350: $this->db->query($sql);
351:
352: while ($this->db->nextRecord()) {
353: $openList[] = $this->db->f('idcat');
354: }
355: }
356:
357: return $catList;
358: }
359:
360: /**
361: * Returns list of all child category ids and their child category ids of
362: * passed category id.
363: * The list also contains the id of passed category.
364: *
365: * The return value of this function could be used to perform bulk actions
366: * on a specific category an all of its childcategories.
367: *
368: * NOTE: Return value is similar to getAllCategoryIdsRecursive, only the
369: * sorting differs
370: *
371: * Example:
372: * <pre>
373: * ...
374: * this_category (*)
375: * child_category (*)
376: * child_category2 (*)
377: * child_of_child_category2 (*)
378: * child_category3 (*)
379: * child_of_child_category3 (*)
380: * ...
381: * (*) Returned category ids
382: * </pre>
383: *
384: * @global array $cfg
385: * @param int $idcat
386: * @param int $client
387: * @return array
388: * Sorted by category id
389: */
390: public function getAllCategoryIdsRecursive2($idcat, $idclient) {
391: global $cfg;
392:
393: $aCats = array();
394: $found = false;
395: $curLevel = 0;
396:
397: $sql = "SELECT * FROM `%s` AS a, `%s` AS b WHERE a.idcat = b.idcat AND idclient = %d ORDER BY idtree";
398: $sql = $this->db->prepare($sql, $cfg['tab']['cat_tree'], $cfg['tab']['cat'], $idclient);
399: $this->db->query($sql);
400:
401: while ($this->db->nextRecord()) {
402: if ($found && $this->db->f('level') <= $curLevel) { // ending part
403: // of tree
404: $found = false;
405: }
406:
407: if ($this->db->f('idcat') == $idcat) { // starting part of tree
408: $found = true;
409: $curLevel = $this->db->f('level');
410: }
411:
412: if ($found) {
413: $aCats[] = $this->db->f('idcat');
414: }
415: }
416:
417: return $aCats;
418: }
419: }
420:
421: /**
422: * Category item
423: *
424: * @package Core
425: * @subpackage GenericDB_Model
426: */
427: class cApiCategory extends Item {
428:
429: /**
430: * Constructor to create an instance of this class.
431: *
432: * @param mixed $mId [optional]
433: * Specifies the ID of item to load
434: */
435: public function __construct($mId = false) {
436: global $cfg;
437: parent::__construct($cfg['tab']['cat'], 'idcat');
438: $this->setFilters(array(), array());
439:
440: if ($mId !== false) {
441: $this->loadByPrimaryKey($mId);
442: }
443: }
444:
445: /**
446: * Updates lastmodified field and calls parents store method
447: *
448: * @return bool
449: */
450: public function store() {
451: $this->set('lastmodified', date('Y-m-d H:i:s'));
452: return parent::store();
453: }
454:
455: /**
456: * Userdefined setter for category fields.
457: *
458: * @param string $name
459: * @param mixed $value
460: * @param bool $safe [optional]
461: * Flag to run defined inFilter on passed value
462: *
463: * @return bool
464: */
465: public function setField($name, $value, $safe = true) {
466: switch ($name) {
467: case 'idcat':
468: case 'idclient':
469: case 'parentid':
470: case 'preid':
471: case 'postid':
472: case 'status':
473: $value = (int) $value;
474: break;
475: }
476:
477: return parent::setField($name, $value, $safe);
478: }
479:
480: /**
481: * Returns the link to the current object.
482: *
483: * @param int $changeLangId [optional]
484: * change language id for URL (optional)
485: * @return string
486: * link
487: */
488: public function getLink($changeLangId = 0) {
489: if ($this->isLoaded() === false) {
490: return '';
491: }
492:
493: $options = array();
494: $options['idcat'] = $this->get('idcat');
495: $options['lang'] = ($changeLangId == 0) ? cRegistry::getLanguageId() : $changeLangId;
496: if ($changeLangId > 0) {
497: $options['changelang'] = $changeLangId;
498: }
499:
500: return cUri::getInstance()->build($options);
501: }
502: }
503: