1: <?php
2:
3: /**
4: * This file contains the property collection and item class.
5: *
6: * Custom properties
7: * -----------------
8: * Custom properties are properties which can be assigned to virtually any element
9: * in CONTENIDO and underlaying websites.
10: *
11: * Table structure
12: * ---------------
13: *
14: * Field Size Description
15: * ----- ---- -----------
16: * idproperty int(10) idproperty (automatically handled by this class)
17: * idclient int(10) Id of client
18: * itemtype varchar(32) Custom item type (e.g. idcat, idart, idartlang, custom)
19: * itemid varchar(32) ID of the item
20: * type varchar(32) Property type
21: * name varchar(32) Property name value text Property value
22: * author varchar(32) Author (md5-hash of the username)
23: * created datetime Created date and time
24: * modified datetime Modified date and time
25: * modifiedby varchar(32) Modified by (md5-hash of the username)
26: *
27: * Example:
28: * --------
29: * A module needs to store custom properties for categories. Modifying the database
30: * would be a bad thing, since the changes might get lost during an upgrade or
31: * reinstall. If the custom property for a category would be the path to a category
32: * image, we would fill a row as follows:
33: *
34: * itemtype: idcat
35: * itemid: <number of your category>
36: * type: category
37: * name: image
38: * value: images/category01.gif
39: *
40: * idproperty, author, created, modified and modifiedby are automatically handled
41: * by the class. If caching is enabled, see $cfg['properties']['properties']['enable_cache'],
42: * configured entries will be loaded at first time. If enabled, each call of
43: * cApiPropertyCollection functions to retrieve cacheable properties will return
44: * the cached entries without stressing the database. The cApiPropertyCollection
45: * class keeps also track of changed and deleted properties and synchronizes
46: * them with cached values, as long as you use the interface of
47: * cApiPropertyCollection to manage the properties.
48: *
49: * @package Core
50: * @subpackage GenericDB_Model
51: * @author Murat Purc <murat@purc.de>
52: * @copyright four for business AG <www.4fb.de>
53: * @license http://www.contenido.org/license/LIZENZ.txt
54: * @link http://www.4fb.de
55: * @link http://www.contenido.org
56: */
57:
58: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
59:
60: /**
61: * Property collection
62: *
63: * @package Core
64: * @subpackage GenericDB_Model
65: */
66: class cApiPropertyCollection extends ItemCollection {
67:
68: /**
69: * Client id
70: *
71: * @var int
72: */
73: public $client;
74:
75: /**
76: * List of cached entries
77: *
78: * @var array
79: */
80: protected static $_entries;
81:
82: /**
83: * Flag to enable caching.
84: *
85: * @var bool
86: */
87: protected static $_enableCache;
88:
89: /**
90: * Itemtypes and itemids array
91: *
92: * @var array
93: */
94: protected static $_cacheItemtypes;
95:
96: /**
97: * Constructor to create an instance of this class.
98: *
99: * @param int $idclient [optional]
100: * Client id
101: *
102: * @throws cDbException
103: * @throws cException
104: * @throws cInvalidArgumentException
105: */
106: public function __construct($idclient = 0) {
107: global $cfg, $client, $lang;
108:
109: if (0 === $idclient) {
110: // @todo Make client id parameter mandatory, otherwise using the global variable
111: // may lead to unwanted issues!
112: $idclient = $client;
113: }
114:
115: $this->client = cSecurity::toInteger($idclient);
116: parent::__construct($cfg['tab']['properties'], 'idproperty');
117: $this->_setItemClass('cApiProperty');
118:
119: // set the join partners so that joins can be used via link() method
120: $this->_setJoinPartner('cApiClientCollection');
121:
122: if (!isset(self::$_enableCache)) {
123: if (isset($cfg['properties']) && isset($cfg['properties']['properties']) && isset($cfg['properties']['properties']['enable_cache'])) {
124: self::$_enableCache = (bool) $cfg['properties']['properties']['enable_cache'];
125:
126: if (isset($cfg['properties']['properties']['itemtypes']) && is_array($cfg['properties']['properties']['itemtypes'])) {
127: self::$_cacheItemtypes = $cfg['properties']['properties']['itemtypes'];
128: foreach (self::$_cacheItemtypes as $name => $value) {
129: if ('%client%' == $value) {
130: self::$_cacheItemtypes[$name] = (int) $idclient;
131: } elseif ('%lang%' == $value) {
132: self::$_cacheItemtypes[$name] = (int) $lang;
133: } else {
134: unset(self::$_cacheItemtypes[$name]);
135: }
136: }
137: }
138: } else {
139: self::$_enableCache = false;
140: }
141: }
142:
143: if (self::$_enableCache && !isset(self::$_entries)) {
144: $this->_loadFromCache();
145: }
146: }
147:
148: /**
149: * Resets the states of static properties.
150: */
151: public static function reset() {
152: self::$_enableCache = false;
153: self::$_entries = array();
154: self::$_cacheItemtypes = array();
155: }
156:
157: /**
158: * Creates a new property item.
159: *
160: * Example:
161: * <pre>
162: * $properties = new cApiPropertyCollection($clientid);
163: * $property = $properties->create('idcat', 27, 'visual', 'image', 'images/tool.gif');
164: * </pre>
165: *
166: * @param mixed $itemtype
167: * Type of the item (example: idcat)
168: * @param mixed $itemid
169: * ID of the item (example: 31)
170: * @param mixed $type
171: * Type of the data to store (arbitary data)
172: * @param mixed $name
173: * Entry name
174: * @param mixed $value
175: * Value
176: * @param bool $bDontEscape [optional; default false]
177: * on internal call do not escape parameters again
178: * NOTE: This parameter is deprecated since 2013-11-26
179: *
180: * @return cApiProperty
181: * @throws cDbException
182: * @throws cException
183: * @throws cInvalidArgumentException
184: */
185: public function create($itemtype, $itemid, $type, $name, $value, $bDontEscape = false) {
186: global $auth;
187:
188: $item = $this->createNewItem();
189:
190: $item->set('idclient', $this->client);
191: $item->set('itemtype', $itemtype, false);
192: $item->set('itemid', $itemid, false);
193: $item->set('type', $type);
194: $item->set('name', $name);
195: $item->set('value', $value);
196:
197: $item->set('created', date('Y-m-d H:i:s'), false);
198: $item->set('author', $auth->auth['uid']);
199: $item->store();
200:
201: if ($this->_useCache($itemtype, $itemid)) {
202: $this->_addToCache($item);
203: }
204:
205: return $item;
206: }
207:
208: /**
209: * Returns the value for a given item.
210: *
211: * Example:
212: * <pre>
213: * $properties = new cApiPropertyCollection($clientid);
214: * $value = $properties->getValue('idcat', 27, 'visual', 'image');
215: * </pre>
216: *
217: * @param mixed $itemtype
218: * Type of the item (example: idcat)
219: * @param mixed $itemid
220: * ID of the item (example: 31)
221: * @param mixed $type
222: * Type of the data to store (arbitary data)
223: * @param mixed $name
224: * Entry name
225: * @param mixed $default [optional]
226: * to be returned if no item was found
227: *
228: * @return mixed Value
229: * @throws cDbException
230: * @throws cException
231: */
232: public function getValue($itemtype, $itemid, $type, $name, $default = false) {
233: if ($this->_useCache($itemtype, $itemid)) {
234: return $this->_getValueFromCache($itemtype, $itemid, $type, $name, $default);
235: }
236:
237: if (isset($this->client)) {
238: $sql = $this->db->prepare("idclient = %d AND itemtype = '%s' AND itemid = '%s' AND type = '%s' AND name = '%s'", $this->client, $itemtype, $itemid, $type, $name);
239: } else {
240: // @todo We never get here, since this class will always have a set client property!
241: $sql = $this->db->prepare("itemtype = '%s' AND itemid = '%s' AND type = '%s' AND name = '%s'", $itemtype, $itemid, $type, $name);
242: }
243: $this->select($sql);
244:
245: if (false !== $item = $this->next()) {
246: return cSecurity::unescapeDB($item->get('value'));
247: }
248:
249: return $default;
250: }
251:
252: /**
253: * Returns the value for a given item.
254: *
255: * Example:
256: * <pre>
257: * $properties = new cApiPropertyCollection($clientid);
258: * $values = $properties->getValuesByType('idcat', 27, 'visual');
259: * </pre>
260: *
261: * @param mixed $itemtype
262: * Type of the item (example: idcat)
263: * @param mixed $itemid
264: * ID of the item (example: 31)
265: * @param mixed $type
266: * Type of the data to store (arbitary data)
267: *
268: * @return array
269: * Value
270: *
271: * @throws cDbException
272: * @throws cException
273: */
274: public function getValuesByType($itemtype, $itemid, $type) {
275: if ($this->_useCache($itemtype, $itemid)) {
276: return $this->_getValuesByTypeFromCache($itemtype, $itemid, $type);
277: }
278:
279: $aResult = array();
280:
281: if (isset($this->client)) {
282: $sql = $this->db->prepare("idclient = %d AND itemtype = '%s' AND itemid = '%s' AND type = '%s'", $this->client, $itemtype, $itemid, $type);
283: } else {
284: // @fixme We never get here, since this class will always have a set client property!
285: $sql = $this->db->prepare("itemtype = '%s' AND itemid = '%s' AND type = '%s'", $itemtype, $itemid, $type);
286: }
287: $this->select($sql);
288:
289: while (($item = $this->next()) !== false) {
290: $aResult[$item->get('name')] = cSecurity::unescapeDB($item->get('value'));
291: }
292:
293: return $aResult;
294: }
295:
296: /**
297: * Returns the values only by type and name.
298: *
299: * Example:
300: * <pre>
301: * $properties = new cApiPropertyCollection($clientid);
302: * $values = $properties->getValuesOnlyByTypeName('note', 'category');
303: * </pre>
304: *
305: * @param $type
306: * @param mixed $name
307: * Type of the data to store (arbitary data)
308: *
309: * @return array
310: * Value
311: *
312: * @throws cDbException
313: * @throws cException
314: */
315: public function getValuesOnlyByTypeName($type, $name) {
316: $aResult = array();
317:
318: $sql = $this->db->prepare("type = '%s' AND name = '%s'", $type, $name);
319:
320: while (($item = $this->next()) !== false) {
321: $aResult[] = cSecurity::unescapeDB($item->get('value'));
322: }
323:
324: return $aResult;
325: }
326:
327: /**
328: * Sets a property item.
329: * Handles creation and updating.
330: * Existing item will be updated, not existing item will be created.
331: *
332: * Example:
333: * <pre>
334: * $properties = new cApiPropertyCollection($clientid);
335: * $properties->setValue('idcat', 27, 'visual', 'image', 'images/tool.gif');
336: * </pre>
337: *
338: * @param mixed $itemtype
339: * Type of the item (example: idcat)
340: * @param mixed $itemid
341: * ID of the item (example: 31)
342: * @param mixed $type
343: * Type of the data to store (arbitary data)
344: * @param mixed $name
345: * Entry name
346: * @param mixed $value
347: * Value
348: * @param int $idProp [optional]
349: * Id of database record (if set, update on this basis
350: * (possiblity to update name value and type))
351: *
352: * @throws cDbException
353: * @throws cException
354: * @throws cInvalidArgumentException
355: */
356: public function setValue($itemtype, $itemid, $type, $name, $value, $idProp = 0) {
357: $idProp = (int) $idProp;
358:
359: if ($idProp == 0) {
360: $sql = $this->db->prepare("idclient = %d AND itemtype = '%s' AND itemid = '%s' AND type = '%s' AND name = '%s'", $this->client, $itemtype, $itemid, $type, $name);
361: } else {
362: $sql = $this->db->prepare("idclient = %d AND itemtype = '%s' AND itemid = '%s' AND idproperty = %d", $this->client, $itemtype, $itemid, $idProp);
363: }
364: $this->select($sql);
365:
366: if (($item = $this->next()) !== false) {
367: $item->set('value', $value);
368: $item->set('name', $name);
369: $item->set('type', $type);
370: $item->store();
371:
372: if ($this->_useCache($itemtype, $itemid)) {
373: $this->_addToCache($item);
374: }
375: } else {
376: $this->create($itemtype, $itemid, $type, $name, $value, true);
377: }
378: }
379:
380: /**
381: * Delete a property item.
382: *
383: * Example:
384: * <pre>
385: * $properties = new cApiPropertyCollection($clientid);
386: * $properties->deleteValue('idcat', 27, 'visual', 'image');
387: * </pre>
388: *
389: * @param mixed $itemtype
390: * Type of the item (example: idcat)
391: * @param mixed $itemid
392: * ID of the item (example: 31)
393: * @param mixed $type
394: * Type of the data to store (arbitary data)
395: * @param mixed $name
396: * Entry name
397: *
398: * @throws cDbException
399: * @throws cInvalidArgumentException
400: */
401: public function deleteValue($itemtype, $itemid, $type, $name) {
402: if (isset($this->client)) {
403: $where = $this->db->prepare("idclient = %d AND itemtype = '%s' AND itemid = '%s' AND type = '%s' AND name = '%s'", $this->client, $itemtype, $itemid, $type, $name);
404: } else {
405: // @fixme We never get here, since this class will always have a set client property!
406: $where = $this->db->prepare("itemtype = '%s' AND itemid = '%s' AND type = '%s' AND name = '%s'", $itemtype, $itemid, $type, $name);
407: }
408:
409: $idproperties = $this->getIdsByWhereClause($where);
410:
411: $this->_deleteMultiple($idproperties);
412: if ($this->_useCache()) {
413: $this->_deleteFromCacheMultiple($idproperties);
414: }
415: }
416:
417: /**
418: * Checks if values for a given item are available.
419: *
420: * @param mixed $itemtype
421: * Type of the item (example: idcat)
422: * @param mixed $itemid
423: * ID of the item (example: 31)
424: *
425: * @return array
426: * For each given item
427: *
428: * @throws cDbException
429: * @throws cException
430: */
431: public function getProperties($itemtype, $itemid) {
432: if ($this->_useCache($itemtype, $itemid)) {
433: return $this->_getPropertiesFromCache($itemtype, $itemid);
434: }
435:
436: if (isset($this->client)) {
437: $sql = $this->db->prepare("idclient = %d AND itemtype = '%s' AND itemid = '%s'", $this->client, $itemtype, $itemid);
438: } else {
439: // @fixme We never get here, since this class will always have a set client property!
440: $sql = $this->db->prepare("itemtype = '%s' AND itemid = '%s'", $itemtype, $itemid);
441: }
442: $this->select($sql);
443:
444: $result[$itemid] = false;
445:
446: while (($item = $this->next()) !== false) {
447: // enable accessing property values per number and field name
448: $result[$item->get('itemid')][$item->get('idproperty')] = array(
449: 0 => $item->get('type'),
450: 'type' => $item->get('type'),
451: 1 => $item->get('name'),
452: 'name' => $item->get('name'),
453: 2 => $item->get('value'),
454: 'value' => $item->get('value')
455: );
456: }
457: return $result;
458: }
459:
460: /**
461: * Returns all datasets selected by given field and value combination
462: *
463: * @param mixed $field
464: * Field to search in
465: * @param mixed $fieldValue
466: * Value to search for
467: * @param cAuth $auth [optional]
468: * Narrow result down to user in auth objext
469: * @return array
470: * For each given item
471: * @throws cDbException
472: * @throws cException
473: */
474: public function getAllValues($field, $fieldValue, $auth = NULL) {
475: $authString = '';
476: if (!is_null($auth) && is_object($auth) && sizeof($auth->auth) > 0) {
477: $authString .= " AND author = '" . $this->db->escape($auth->auth["uid"]) . "'";
478: }
479:
480: $field = $this->db->escape($field);
481: $fieldValue = $this->db->escape($fieldValue);
482:
483: if (isset($this->client)) {
484: $this->select("idclient = " . (int) $this->client . " AND " . $field . " = '" . $fieldValue . "'" . $authString, '', 'itemid');
485: } else {
486: // @fixme We never get here, since this class will always have a set client property!
487: $this->select($field . " = '" . $fieldValue . "'" . $authString);
488: }
489:
490: $retValue = array();
491: while (($item = $this->next()) !== false) {
492: $dbLine = array(
493: 'idproperty' => $item->get('idproperty'),
494: 'idclient' => $item->get('idclient'),
495: 'itemtype' => $item->get('itemtype'),
496: 'itemid' => $item->get('itemid'),
497: 'type' => $item->get('type'),
498: 'name' => $item->get('name'),
499: 'value' => $item->get('value'),
500: 'author' => $item->get('author'),
501: 'created' => $item->get('created'),
502: 'modified' => $item->get('modified'),
503: 'modifiedby' => $item->get('modifiedby')
504: );
505: $retValue[] = $dbLine;
506: }
507: return $retValue;
508: }
509:
510: /**
511: * Delete all properties which match itemtype and itemid
512: *
513: * @param mixed $itemtype
514: * Type of the item (example: idcat)
515: * @param mixed $itemid
516: * ID of the item (example: 31)
517: *
518: * @throws cDbException
519: * @throws cInvalidArgumentException
520: */
521: public function deleteProperties($itemtype, $itemid) {
522: if (isset($this->client)) {
523: $where = $this->db->prepare("idclient = %d AND itemtype = '%s' AND itemid = '%s'", $this->client, $itemtype, $itemid);
524: } else {
525: // @fixme We never get here, since this class will always have a set client property!
526: $where = $this->db->prepare("itemtype = '%s' AND itemid = '%s'", $itemtype, $itemid);
527: }
528:
529: $idproperties = $this->getIdsByWhereClause($where);
530:
531: $this->_deletePropertiesByIds($idproperties);
532: }
533:
534: /**
535: * Delete all properties which match itemtype and multiple itemids.
536: *
537: * @param mixed $itemtype
538: * Type of the item (example: idcat)
539: * @param array $itemids
540: * Ids of multiple items (example: array(31,12,22))
541: *
542: * @throws cDbException
543: * @throws cInvalidArgumentException
544: */
545: public function deletePropertiesMultiple($itemtype, array $itemids) {
546: $itemtype = $this->db->escape($itemtype);
547: $itemids = array_map(array($this, 'escape'), $itemids);
548: $in = "'" . implode("', '", $itemids) . "'";
549:
550: if (isset($this->client)) {
551: $where = "idclient = " . (int) $this->client . " AND itemtype = '" . $itemtype . "' AND itemid IN (" . $in . ")";
552: } else {
553: // @fixme We never get here, since this class will always have a set client property!
554: $where = "itemtype = '" . $itemtype . "' AND itemid IN (" . $in . ")";
555: }
556:
557: $idproperties = $this->getIdsByWhereClause($where);
558:
559: $this->_deletePropertiesByIds($idproperties);
560: }
561:
562: /**
563: * Changes the client
564: *
565: * @param int $idclient
566: */
567: public function changeClient($idclient) {
568: $this->client = (int) $idclient;
569: }
570:
571: /**
572: * Loads/Caches configured properties, but only for current client!
573: * NOTE: It loads properties for global set client, not for the client set
574: * in this instance!
575: *
576: * @throws cDbException
577: * @throws cException
578: */
579: protected function _loadFromCache() {
580: global $client;
581: if (!isset(self::$_entries)) {
582: self::$_entries = array();
583: }
584:
585: $where = array();
586: foreach (self::$_cacheItemtypes as $itemtype => $itemid) {
587: if (is_numeric($itemid)) {
588: $where[] = "(itemtype = '" . $itemtype . "' AND itemid = " . $itemid . ")";
589: } else {
590: $where[] = "(itemtype = '" . $itemtype . "' AND itemid = '" . $itemid . "')";
591: }
592: }
593:
594: if (count($where) == 0) {
595: return;
596: }
597:
598: $where = "idclient = " . (int) $client . ' AND ' . implode(' OR ', $where);
599: $this->select($where);
600: /** @var cApiUserProperty $property */
601: while (($property = $this->next()) !== false) {
602: $this->_addToCache($property);
603: }
604: }
605:
606: /**
607: *
608: * @param string $itemtype [optional]
609: * @param int $itemid [optional]
610: * @return bool
611: */
612: protected function _useCache($itemtype = NULL, $itemid = NULL) {
613: global $client;
614: $ok = (self::$_enableCache && $this->client == $client);
615: if (!$ok) {
616: return $ok;
617: } elseif ($itemtype == NULL || $itemid == NULL) {
618: return $ok;
619: }
620:
621: foreach (self::$_cacheItemtypes as $name => $value) {
622: if ($itemtype == $value['itemtype'] || $itemid == $value['itemid']) {
623: return true;
624: }
625: }
626: }
627:
628: /**
629: * Deletes multiple property entries by their ids.
630: * Deletes them also from internal cache.
631: *
632: * @param array $ids
633: * @throws cDbException
634: * @throws cInvalidArgumentException
635: */
636: protected function _deletePropertiesByIds(array $ids) {
637: if (count($ids) > 0) {
638: $this->_deleteMultiple($ids);
639: if ($this->_useCache()) {
640: $this->_deleteFromCacheMultiple($ids);
641: }
642: }
643: }
644:
645: /**
646: * Adds a entry to the cache.
647: *
648: * @param cApiUserProperty $entry
649: */
650: protected function _addToCache($entry) {
651: $data = $entry->toArray();
652: self::$_entries[$data['idproperty']] = $data;
653: }
654:
655: /**
656: * Removes a entry from cache.
657: *
658: * @param int $id
659: */
660: protected function _deleteFromCache($id) {
661: if (isset(self::$_entries[$id])) {
662: unset(self::$_entries[$id]);
663: }
664: }
665:
666: /**
667: * Removes multiple entries from cache.
668: *
669: * @param array $ids
670: */
671: protected function _deleteFromCacheMultiple(array $ids) {
672: foreach ($ids as $id) {
673: if (isset(self::$_entries[$id])) {
674: unset(self::$_entries[$id]);
675: }
676: }
677: }
678:
679: /**
680: * Returns the value for a given item from cache.
681: *
682: * @param mixed $itemtype
683: * Type of the item (example: idcat)
684: * @param mixed $itemid
685: * ID of the item (example: 31)
686: * @param mixed $type
687: * Type of the data to store (arbitary data)
688: * @param mixed $name
689: * Entry name
690: * @param mixed $default [optional]
691: * to be returned if no item was found
692: * @return mixed
693: * Value
694: */
695: protected function _getValueFromCache($itemtype, $itemid, $type, $name, $default = false) {
696: foreach (self::$_entries as $id => $entry) {
697: if ($entry['itemtype'] == $itemtype && $entry['itemid'] == $itemid && $entry['type'] == $type && $entry['name'] == $name) {
698: return cSecurity::unescapeDB($entry['value']);
699: }
700: }
701:
702: return $default;
703: }
704:
705: /**
706: * Returns the values for a given item by its type from cache.
707: *
708: * @param mixed $itemtype
709: * Type of the item (example: idcat)
710: * @param mixed $itemid
711: * ID of the item (example: 31)
712: * @param mixed $type
713: * Type of the data to store (arbitary data)
714: * @return array
715: * Value
716: *
717: */
718: protected function _getValuesByTypeFromCache($itemtype, $itemid, $type) {
719: $result = array();
720:
721: foreach (self::$_entries as $id => $entry) {
722: if ($entry['itemtype'] == $itemtype && $entry['itemid'] == $itemid && $entry['type'] == $type) {
723: $result[$entry['name']] = cSecurity::unescapeDB($entry['value']);
724: }
725: }
726:
727: return $result;
728: }
729:
730: /**
731: * Returns poperties for given item are available.
732: *
733: * @param mixed $itemtype
734: * Type of the item (example: idcat)
735: * @param mixed $itemid
736: * ID of the item (example: 31)
737: * @return array
738: * For each given item
739: */
740: public function _getPropertiesFromCache($itemtype, $itemid) {
741: $result = array();
742: $result[$itemid] = false;
743:
744: foreach (self::$_entries as $id => $entry) {
745: if ($entry['itemtype'] == $itemtype && $entry['itemid'] == $itemid) {
746: // enable accessing property values per number and field name
747: $result[$entry['itemid']][$entry['idproperty']] = array(
748: 0 => $entry['type'],
749: 'type' => $entry['type'],
750: 1 => $entry['name'],
751: 'name' => $entry['name'],
752: 2 => $entry['value'],
753: 'value' => $entry['value']
754: );
755: }
756: }
757:
758: return $result;
759: }
760:
761: }
762:
763: /**
764: * Property item
765: *
766: * @package Core
767: * @subpackage GenericDB_Model
768: */
769: class cApiProperty extends Item {
770:
771: /**
772: * Array which stores the maximum string length of each field
773: *
774: * @var array
775: */
776: public $maximumLength;
777:
778: /**
779: * Constructor to create an instance of this class.
780: *
781: * @param mixed $mId [optional]
782: * Specifies the ID of item to load
783: *
784: * @throws cDbException
785: * @throws cException
786: */
787: public function __construct($mId = false) {
788: global $cfg;
789: parent::__construct($cfg['tab']['properties'], 'idproperty');
790:
791: // Initialize maximum lengths for each column
792: $this->maximumLength = array(
793: 'itemtype' => 64,
794: 'itemid' => 255,
795: 'type' => 96,
796: 'name' => 96
797: );
798:
799: if ($mId !== false) {
800: $this->loadByPrimaryKey($mId);
801: }
802: }
803:
804: /**
805: * Stores changed cApiProperty
806: *
807: * @return bool
808: * @throws cDbException
809: * @throws cInvalidArgumentException
810: */
811: public function store() {
812: global $auth;
813:
814: $this->set('modified', date('Y-m-d H:i:s'), false);
815: $this->set('modifiedby', $auth->auth['uid']);
816:
817: return parent::store();
818: }
819:
820: /**
821: * Sets value of a field
822: *
823: * @param string $field
824: * @param string $value
825: * @param bool $safe [optional]
826: * Flag to run filter on passed value
827: * @return bool
828: * @throws cInvalidArgumentException
829: * if the field is too small for the given value
830: */
831: public function setField($field, $value, $safe = true) {
832: if (array_key_exists($field, $this->maximumLength)) {
833: if (cString::getStringLength($value) > $this->maximumLength[$field]) {
834: throw new cInvalidArgumentException("Tried to set field $field to value $value, but the field is too small. Truncated.");
835: }
836: }
837:
838: return parent::setField($field, $value, $safe);
839: }
840:
841: }
842: