Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
46.15% covered (danger)
46.15%
228 / 494
44.19% covered (danger)
44.19%
19 / 43
CRAP
0.00% covered (danger)
0.00%
0 / 2
SeedDMS_Core_Attribute
47.67% covered (danger)
47.67%
41 / 86
33.33% covered (danger)
33.33%
4 / 12
281.83
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 setDMS
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDMS
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getID
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getValue
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getParsedValue
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
30
 getValueAsArray
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
4.25
 setValue
49.06% covered (danger)
49.06%
26 / 53
0.00% covered (danger)
0.00%
0 / 1
92.94
 validate
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getValidationError
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setValidationError
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAttributeDefinition
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
SeedDMS_Core_AttributeDefinition
45.83% covered (danger)
45.83%
187 / 408
48.39% covered (danger)
48.39%
15 / 31
6752.20
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
 setDMS
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDMS
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getID
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setName
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 getObjType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setObjType
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 getType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setType
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 getMultipleValues
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setMultipleValues
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 getMinValues
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setMinValues
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 getMaxValues
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setMaxValues
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 getValueSet
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getValueSetSeparator
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
4.05
 getValueSetAsArray
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getValueSetValue
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 setValueSet
84.62% covered (warning)
84.62%
11 / 13
0.00% covered (danger)
0.00%
0 / 1
3.03
 getRegex
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setRegex
90.00% covered (success)
90.00%
9 / 10
0.00% covered (danger)
0.00%
0 / 1
4.02
 isUsed
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
56
 parseValue
24.24% covered (danger)
24.24%
8 / 33
0.00% covered (danger)
0.00%
0 / 1
112.83
 getStatistics
0.00% covered (danger)
0.00%
0 / 75
0.00% covered (danger)
0.00%
0 / 1
1190
 remove
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 getObjects
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
272
 removeValue
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 1
272
 validate
80.00% covered (warning)
80.00%
84 / 105
0.00% covered (danger)
0.00%
0 / 1
111.33
 getValidationError
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2declare(strict_types=1);
3
4/**
5 * Implementation of the attribute object in the document management system
6 *
7 * @category   DMS
8 * @package    SeedDMS_Core
9 * @license    GPL 2
10 * @version    @version@
11 * @author     Uwe Steinmann <uwe@steinmann.cx>
12 * @copyright  Copyright (C) 2012 Uwe Steinmann
13 * @version    Release: @package_version@
14 */
15
16/**
17 * Class to represent an attribute in the document management system
18 *
19 * Attributes are key/value pairs which can be attachted to documents,
20 * folders and document content. The number of attributes is unlimited.
21 * Each attribute has a value and is related to an attribute definition,
22 * which holds the name and other information about the attribute.
23 *
24 * @see SeedDMS_Core_AttributeDefinition
25 *
26 * @category   DMS
27 * @package    SeedDMS_Core
28 * @author     Uwe Steinmann <uwe@steinmann.cx>
29 * @copyright  Copyright (C) 2012-2013 Uwe Steinmann
30 * @version    Release: @package_version@
31 */
32class SeedDMS_Core_Attribute { /* {{{ */
33    /**
34     * @var integer id of attribute
35     *
36     * @access protected
37     */
38    protected $_id;
39
40    /**
41     * @var SeedDMS_Core_Folder|SeedDMS_Core_Document|SeedDMS_Core_DocumentContent SeedDMS_Core_Object folder, document or document content
42     * this attribute belongs to
43     *
44     * @access protected
45     */
46    protected $_obj;
47
48    /**
49     * @var SeedDMS_Core_AttributeDefinition definition of this attribute
50     *
51     * @access protected
52     */
53    protected $_attrdef;
54
55    /**
56     * @var mixed value of this attribute
57     *
58     * @access protected
59     */
60    protected $_value;
61
62    /**
63     * @var integer validation error
64     *
65     * @access protected
66     */
67    protected $_validation_error;
68
69    /**
70     * @var SeedDMS_Core_DMS reference to the dms instance this attribute belongs to
71     *
72     * @access protected
73     */
74    protected $_dms;
75
76    /**
77     * SeedDMS_Core_Attribute constructor.
78     * @param $id
79     * @param $obj
80     * @param $attrdef
81     * @param $value
82     */
83    function __construct($id, $obj, $attrdef, $value) { /* {{{ */
84        $this->_id = $id;
85        $this->_obj = $obj;
86        $this->_attrdef = $attrdef;
87        $this->_value = $value;
88        $this->_validation_error = 0;
89        $this->_dms = null;
90    } /* }}} */
91
92    /**
93     * Set reference to dms
94     *
95     * @param SeedDMS_Core_DMS $dms
96     */
97    function setDMS($dms) { /* {{{ */
98        $this->_dms = $dms;
99    } /* }}} */
100
101    /**
102     * Get dms of attribute
103     *
104     * @return object $dms
105     */
106    function getDMS() { return $this->_dms; }
107
108    /**
109     * Get internal id of attribute
110     *
111     * @return integer id
112     */
113    function getID() { return $this->_id; }
114
115    /**
116     * Return attribute value as stored in database
117     *
118     * This function will return the value of multi value attributes
119     * including the separator char.
120     *
121     * @return string the attribute value as it is stored in the database.
122     */
123    function getValue() { return $this->_value; }
124
125    /**
126     * Return attribute value parsed into a php type or object
127     *
128     * This function will return the value of multi value attributes
129     * including the separator char.
130     *
131     * @return string the attribute value as it is stored in the database.
132     */
133    function getParsedValue() { /* {{{ */
134        switch($this->_attrdef->getType()) {
135        case SeedDMS_Core_AttributeDefinition::type_float:
136            return (float) $this->_value;
137        case SeedDMS_Core_AttributeDefinition::type_boolean:
138            return (bool) $this->_value;
139        case SeedDMS_Core_AttributeDefinition::type_int:
140            return (int) $this->_value;
141        default:
142            return $this->_value;
143        }
144    } /* }}} */
145
146    /**
147     * Return attribute values as an array
148     *
149     * This function returns the attribute value as an array. The array
150     * has one element for non multi value attributes and n elements for
151     * multi value attributes.
152     *
153     * @return array the attribute values
154     */
155    function getValueAsArray() { /* {{{ */
156        if($this->_attrdef->getMultipleValues()) {
157            /* If the value doesn't start with the separator used in the value set,
158             * then assume that the value was not saved with a leading separator.
159             * This can happen, if the value was previously a single value from
160             * the value set and later turned into a multi value attribute.
161             */
162            $sep = substr($this->_value, 0, 1);
163            if(!($vsep = $this->_attrdef->getValueSetSeparator()))
164                $vsep = $sep;
165            if($sep == $vsep)
166                return(explode($sep, substr($this->_value, 1)));
167            else
168                return(array($this->_value));
169        } else {
170            return array($this->_value);
171        }
172    } /* }}} */
173
174    /**
175     * Set a value of an attribute
176     *
177     * The attribute is completely deleted if the value is an empty string
178     * or empty array. An array of values is only allowed if the attribute may
179     * have multiple values. If an array is passed and the attribute may
180     * have only a single value, then the first element of the array will
181     * be taken.
182     *
183     * @param string $values value as string or array to be set
184     * @return boolean true if operation was successfull, otherwise false
185     */
186    function setValue($values) { /* {{{*/
187        $db = $this->_dms->getDB();
188
189        if($this->_attrdef->getMultipleValues()) {
190            $valuesetstr = $this->_attrdef->getValueSet();
191            /* Multiple values without a value set is not allowed */
192            /* No need to have valueset anymore. If none is given, the values are
193             * expected to be separated by ','
194            if(!$valuesetstr)
195                return false;
196             */
197            $valueset = $this->_attrdef->getValueSetAsArray();
198
199            if(is_array($values)) {
200                if($values) {
201                    $vsep = $this->_attrdef->getValueSetSeparator();
202                    if($valueset) {
203                        /* Validation should have been done before
204                        $error = false;
205                        foreach($values as $v) {
206                            if(!in_array($v, $valueset)) { $error = true; break; }
207                        }
208                        if($error)
209                            return false;
210                         */
211                        $valuesetstr = $this->_attrdef->getValueSet();
212                        $value = $vsep.implode($vsep, $values);
213                    } else {
214                        $value = $vsep.implode($vsep, $values);
215                    }
216                } else {
217                    $value = '';
218                }
219            } else {
220                if($values) {
221                    if($valuesetstr) {
222                        if($valuesetstr[0] != $values[0])
223                            $values = explode($valuesetstr[0], $values);
224                        else
225                            $values = explode($valuesetstr[0], substr($values, 1));
226                    } else {
227                        $values = explode(',', substr($values, 1));
228                    }
229
230                    if($valueset) {
231                        /* Validation should have been done before
232                        $error = false;
233                        foreach($values as $v) {
234                            if(!in_array($v, $valueset)) { $error = true; break; }
235                        }
236                        if($error)
237                            return false;
238                         */
239                        $value = $valuesetstr[0].implode($valuesetstr[0], $values);
240                    } else {
241                        $value = ','.implode(',', $values);
242                    }
243                } else {
244                    $value = (string) $values;
245                }
246            }
247        } else {
248            if(is_array($values)) {
249                if($values)
250                    $value = (string) $values[0];
251                else
252                    $value = '';
253            } else {
254                $value = (string) $values;
255            }
256        }
257
258        switch(get_class($this->_obj)) {
259            case $this->_dms->getClassname('document'):
260                if(trim($value) === '')
261                    $queryStr = "DELETE FROM `tblDocumentAttributes` WHERE `document` = " . $this->_obj->getID() . " AND `attrdef` = " . $this->_attrdef->getId();
262                else
263                    $queryStr = "UPDATE `tblDocumentAttributes` SET `value` = ".$db->qstr($value)." WHERE `document` = " . $this->_obj->getID() .    " AND `attrdef` = " . $this->_attrdef->getId();
264                break;
265            case $this->_dms->getClassname('documentcontent'):
266                if(trim($value) === '')
267                    $queryStr = "DELETE FROM `tblDocumentContentAttributes` WHERE `content` = " . $this->_obj->getID() . " AND `attrdef` = " . $this->_attrdef->getId();
268                else
269                    $queryStr = "UPDATE `tblDocumentContentAttributes` SET `value` = ".$db->qstr($value)." WHERE `content` = " . $this->_obj->getID() .    " AND `attrdef` = " . $this->_attrdef->getId();
270                break;
271            case $this->_dms->getClassname('folder'):
272                if(trim($value) === '')
273                    $queryStr = "DELETE FROM `tblFolderAttributes` WHERE `folder` = " . $this->_obj->getID() .    " AND `attrdef` = " . $this->_attrdef->getId();
274                else
275                    $queryStr = "UPDATE `tblFolderAttributes` SET `value` = ".$db->qstr($value)." WHERE `folder` = " . $this->_obj->getID() .    " AND `attrdef` = " . $this->_attrdef->getId();
276                break;
277            default:
278                return false;
279        }
280        if (!$db->getResult($queryStr))
281            return false;
282
283        $oldvalue = $this->_value;
284        $this->_value = $value;
285
286        /* Check if 'onPostUpdateAttribute' callback is set */
287        $kk = (trim($value) === '') ? 'Remove' : 'Update';
288        if(isset($this->_dms->callbacks['onPost'.$kk.'Attribute'])) {
289            foreach($this->_dms->callbacks['onPost'.$kk.'Attribute'] as $callback) {
290                if(!call_user_func($callback[0], $callback[1], $this->_obj, $this->_attrdef, $value, $oldvalue)) {
291                }
292            }
293        }
294
295        return true;
296    } /* }}} */
297
298    /**
299     * Validate attribute value
300     *
301     * This function checks if the attribute values fits the attribute
302     * definition.
303     * If the validation fails the validation error will be set which
304     * can be requested by SeedDMS_Core_Attribute::getValidationError()
305     *
306     * @return boolean true if validation succeeds, otherwise false
307     */
308    function validate() { /* {{{ */
309        /** @var SeedDMS_Core_AttributeDefinition $attrdef */
310        $attrdef = $this->_attrdef;
311        $result = $attrdef->validate($this->_value);
312        $this->_validation_error = $attrdef->getValidationError();
313        return $result;
314    } /* }}} */
315
316    /**
317     * Get validation error from last validation
318     *
319     * @return integer error code
320     */
321    function getValidationError() { return $this->_validation_error; }
322
323    /**
324     * Set validation error
325     *
326     * @param integer error code
327     */
328    function setValidationError($error) { $this->_validation_error = $error; }
329
330    /**
331     * Get definition of attribute
332     *
333     * @return object attribute definition
334     */
335    function getAttributeDefinition() { return $this->_attrdef; }
336
337} /* }}} */
338
339/**
340 * Class to represent an attribute definition in the document management system
341 *
342 * Attribute definitions specify the name, type, object type, minimum and
343 * maximum values and a value set. The object type determines the object
344 * an attribute may be attached to. If the object type is set to object_all
345 * the attribute can be used for documents, document content and folders.
346 *
347 * The type of an attribute specifies the skalar data type.
348 *
349 * Attributes for which multiple values are allowed must have the
350 * multiple flag set to true and specify a value set. A value set
351 * is a string consisting of n separated values. The separator is the
352 * first char of the value set. A possible value could be '|REV-A|REV-B'
353 * If multiple values are allowed, then minvalues and maxvalues may
354 * restrict the allowed number of values.
355 *
356 * @see SeedDMS_Core_Attribute
357 *
358 * @category   DMS
359 * @package    SeedDMS_Core
360 * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
361 * @copyright  Copyright (C) 2012 Uwe Steinmann
362 * @version    Release: @package_version@
363 */
364class SeedDMS_Core_AttributeDefinition { /* {{{ */
365    /**
366     * @var integer id of attribute definition
367     *
368     * @access protected
369     */
370    protected $_id;
371
372    /**
373     * @var string name of attribute definition
374     *
375     * @access protected
376     */
377    protected $_name;
378
379    /**
380     * @var string object type of attribute definition. This can be one of
381     * type_int, type_float, type_string, type_boolean, type_url, or type_email.
382     *
383     * @access protected
384     */
385    protected $_type;
386
387    /**
388     * @var string type of attribute definition. This can be one of objtype_all,
389     * objtype_folder, objtype_document, or objtype_documentcontent.
390     *
391     * @access protected
392     */
393    protected $_objtype;
394
395    /**
396     * @var boolean whether an attribute can have multiple values
397     *
398     * @access protected
399     */
400    protected $_multiple;
401
402    /**
403     * @var integer minimum values of an attribute
404     *
405     * @access protected
406     */
407    protected $_minvalues;
408
409    /**
410     * @var integer maximum values of an attribute
411     *
412     * @access protected
413     */
414    protected $_maxvalues;
415
416    /**
417     * @var string list of possible values of an attribute
418     *
419     * @access protected
420     */
421    protected $_valueset;
422
423    /**
424     * @var string regular expression the value must match
425     *
426     * @access protected
427     */
428    protected $_regex;
429
430    /**
431     * @var integer validation error
432     *
433     * @access protected
434     */
435    protected $_validation_error;
436
437    /**
438     * @var SeedDMS_Core_DMS reference to the dms instance this attribute definition belongs to
439     *
440     * @access protected
441     */
442    protected $_dms;
443
444    /**
445     * @var string just the separator of a value set (not used)
446     *
447     * @access protected
448     */
449    protected $_separator;
450
451    /*
452     * Possible skalar data types of an attribute
453     */
454    const type_int = 1;
455    const type_float = 2;
456    const type_string = 3;
457    const type_boolean = 4;
458    const type_url = 5;
459    const type_email = 6;
460    const type_date = 7;
461
462    /*
463     * Addtional data types of an attribute representing objects in seeddms
464     */
465    const type_folder = 101;
466    const type_document = 102;
467    //const type_documentcontent = 103;
468    const type_user = 104;
469    const type_group = 105;
470
471    /*
472     * The object type for which a attribute may be used
473     */
474    const objtype_all = 0;
475    const objtype_folder = 1;
476    const objtype_document = 2;
477    const objtype_documentcontent = 3;
478
479    /*
480     * The validation error codes
481     */
482    const val_error_none = 0;
483    const val_error_min_values = 1;
484    const val_error_max_values = 2;
485    const val_error_boolean = 8;
486    const val_error_int = 6;
487    const val_error_date = 9;
488    const val_error_float = 7;
489    const val_error_regex = 3;
490    const val_error_email = 5;
491    const val_error_url = 4;
492    const val_error_document = 10;
493    const val_error_folder = 11;
494    const val_error_user = 12;
495    const val_error_group = 13;
496    const val_error_valueset = 14;
497
498    /**
499     * Constructor
500     *
501     * @param integer $id internal id of attribute definition
502     * @param string $name name of attribute
503     * @param integer $objtype type of object for which this attribute definition
504     *        may be used.
505     * @param integer $type skalar type of attribute
506     * @param boolean $multiple set to true if multiple values are allowed
507     * @param integer $minvalues minimum number of values
508     * @param integer $maxvalues maximum number of values
509     * @param string $valueset separated list of allowed values, the first char
510     *        is taken as the separator
511     * @param $regex
512     */
513    function __construct($id, $name, int $objtype, int $type, $multiple, $minvalues, $maxvalues, $valueset, $regex) { /* {{{ */
514        $this->_id = $id;
515        $this->_name = $name;
516        $this->_type = $type;
517        $this->_objtype = $objtype;
518        $this->_multiple = $multiple;
519        $this->_minvalues = $minvalues;
520        $this->_maxvalues = $maxvalues;
521        $this->_valueset = $valueset;
522        $this->_separator = substr($valueset, 0, 1);
523        $this->_regex = $regex;
524        $this->_dms = null;
525        $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_none;
526    } /* }}} */
527
528    /**
529     * Set reference to dms
530     *
531     * @param SeedDMS_Core_DMS $dms
532     */
533    function setDMS($dms) { /* {{{ */
534        $this->_dms = $dms;
535    } /* }}} */
536
537    /**
538     * Get dms of attribute definition
539     *
540     * @return object $dms
541     */
542    function getDMS() { return $this->_dms; }
543
544    /**
545     * Get internal id of attribute definition
546     *
547     * @return integer id
548     */
549    function getID() { return $this->_id; }
550
551    /**
552     * Get name of attribute definition
553     *
554     * @return string name
555     */
556    function getName() { return $this->_name; }
557
558    function setName($name) { /* {{{ */
559        $db = $this->_dms->getDB();
560
561        $queryStr = "UPDATE `tblAttributeDefinitions` SET `name` =".$db->qstr($name)." WHERE `id` = " . $this->_id;
562        $res = $db->getResult($queryStr);
563        if (!$res)
564            return false;
565
566        $this->_name = $name;
567        return true;
568    } /* }}} */
569
570    /**
571     * Get object type of attribute definition
572     * 
573     * This can be one of objtype_all,
574     * objtype_folder, objtype_document, or objtype_documentcontent.
575     *
576     * @return integer type
577     */
578    function getObjType() { return $this->_objtype; }
579
580    /**
581     * Set object type of attribute definition
582     *
583     * This can be one of objtype_all,
584     * objtype_folder, objtype_document, or objtype_documentcontent.
585     *
586     * @param integer $objtype type
587     * @return bool
588     */
589    function setObjType($objtype) { /* {{{ */
590        $db = $this->_dms->getDB();
591
592        $queryStr = "UPDATE `tblAttributeDefinitions` SET `objtype` =".intval($objtype)." WHERE `id` = " . $this->_id;
593        $res = $db->getResult($queryStr);
594        if (!$res)
595            return false;
596
597        $this->_objtype = $objtype;
598        return true;
599    } /* }}} */
600
601    /**
602     * Get type of attribute definition
603     * 
604     * This can be one of type_int, type_float, type_string, type_boolean,
605     * type_url, type_email.
606     *
607     * @return integer type
608     */
609    function getType() { return $this->_type; }
610
611    /**
612     * Set type of attribute definition
613     *
614     * This can be one of type_int, type_float, type_string, type_boolean,
615     * type_url, type_email.
616     *
617     * @param integer $type type
618     * @return bool
619     */
620    function setType($type) { /* {{{ */
621        $db = $this->_dms->getDB();
622
623        $queryStr = "UPDATE `tblAttributeDefinitions` SET `type` =".intval($type)." WHERE `id` = " . $this->_id;
624        $res = $db->getResult($queryStr);
625        if (!$res)
626            return false;
627
628        $this->_type = $type;
629        return true;
630    } /* }}} */
631
632    /**
633     * Check if attribute definition allows multi values for attribute
634     * 
635     * @return boolean true if attribute may have multiple values
636     */
637    function getMultipleValues() { return $this->_multiple; }
638
639    /**
640     * Set if attribute definition allows multi values for attribute
641     *
642     * @param boolean $mv true if attribute may have multiple values, otherwise
643     * false
644     * @return bool
645     */
646    function setMultipleValues($mv) { /* {{{ */
647        $db = $this->_dms->getDB();
648
649        $queryStr = "UPDATE `tblAttributeDefinitions` SET `multiple` =".intval($mv)." WHERE `id` = " . $this->_id;
650        $res = $db->getResult($queryStr);
651        if (!$res)
652            return false;
653
654        $this->_multiple = $mv;
655        return true;
656    } /* }}} */
657
658    /**
659     * Return minimum number of values for attributes
660     * 
661     * Attributes with multiple values may be limited to a range
662     * of values. This functions returns the minimum number of values.
663     *
664     * @return integer minimum number of values
665     */
666    function getMinValues() { return $this->_minvalues; }
667
668    function setMinValues($minvalues) { /* {{{ */
669        $db = $this->_dms->getDB();
670
671        $queryStr = "UPDATE `tblAttributeDefinitions` SET `minvalues` =".intval($minvalues)." WHERE `id` = " . $this->_id;
672        $res = $db->getResult($queryStr);
673        if (!$res)
674            return false;
675
676        $this->_minvalues = $minvalues;
677        return true;
678    } /* }}} */
679
680    /**
681     * Return maximum number of values for attributes
682     * 
683     * Attributes with multiple values may be limited to a range
684     * of values. This functions returns the maximum number of values.
685     *
686     * @return integer maximum number of values
687     */
688    function getMaxValues() { return $this->_maxvalues; }
689
690    function setMaxValues($maxvalues) { /* {{{ */
691        $db = $this->_dms->getDB();
692
693        $queryStr = "UPDATE `tblAttributeDefinitions` SET `maxvalues` =".intval($maxvalues)." WHERE `id` = " . $this->_id;
694        $res = $db->getResult($queryStr);
695        if (!$res)
696            return false;
697
698        $this->_maxvalues = $maxvalues;
699        return true;
700    } /* }}} */
701
702    /**
703     * Get the value set as saved in the database
704     *
705     * This is a string containing the list of valueÑ• separated by a
706     * delimiter which also precedes the whole string, e.g. '|Yes|No'
707     *
708     * Use {@link SeedDMS_Core_AttributeDefinition::getValueSetAsArray()}
709     * for a list of values returned as an array.
710     *
711     * @return string value set
712     */
713    function getValueSet() { /* {{{ */
714        return $this->_valueset;
715    } /* }}} */
716
717    /**
718     * Get the separator used for the value set
719     *
720     * This is the first char of the value set string.
721     *
722     * @return string separator or an empty string if a value set is not set
723     */
724    function getValueSetSeparator() { /* {{{ */
725        if(strlen($this->_valueset) > 1) {
726            return $this->_valueset[0];
727        } elseif($this->_multiple) {
728            if($this->_type == SeedDMS_Core_AttributeDefinition::type_boolean)
729                return '';
730            else
731                return ',';
732        } else {
733            return '';
734        }
735    } /* }}} */
736
737    /**
738     * Get the whole value set as an array
739     *
740     * Each element is trimmed.
741     *
742     * @return array values of value set or false if the value set has
743     *         less than 2 chars
744     */
745    function getValueSetAsArray() { /* {{{ */
746        if(strlen($this->_valueset) > 1)
747            return array_map('trim', explode($this->_valueset[0], substr($this->_valueset, 1)));
748        else
749            return array();
750    } /* }}} */
751
752    /**
753     * Get the n'th trimmed value of a value set
754     *
755     * @param $ind starting from 0 for the first element in the value set
756     * @return string n'th value of value set or false if the index is
757     *         out of range or the value set has less than 2 chars
758     * @internal param int $index
759     */
760    function getValueSetValue($ind) { /* {{{ */
761        if(strlen($this->_valueset) > 1) {
762            $tmp = explode($this->_valueset[0], substr($this->_valueset, 1));
763            if(isset($tmp[$ind]))
764                return trim($tmp[$ind]);
765            else
766                return false;
767        } else
768            return false;
769    } /* }}} */
770
771    /**
772     * Set the value set
773     *
774     * A value set is a list of values allowed for an attribute. The values
775     * are separated by a char which must also be the first char of the
776     * value set string. The method decomposes the value set, removes all
777     * leading and trailing white space from the elements and recombines them
778     * into a string.
779     *
780     * @param string $valueset
781     * @return boolean true if value set could be set, otherwise false
782     */
783    function setValueSet($valueset) { /* {{{ */
784    /*
785        $tmp = array();
786        foreach($valueset as $value) {
787            $tmp[] = str_replace('"', '""', $value);
788        }
789        $valuesetstr = implode(",", $tmp);
790     */
791        $valueset = trim($valueset);
792        if($valueset) {
793            $valuesetarr = array_map('trim', explode($valueset[0], substr($valueset, 1)));
794            $valuesetstr = $valueset[0].implode($valueset[0], $valuesetarr);
795        } else {
796            $valuesetstr = '';
797        }
798
799        $db = $this->_dms->getDB();
800
801        $queryStr = "UPDATE `tblAttributeDefinitions` SET `valueset` =".$db->qstr($valuesetstr)." WHERE `id` = " . $this->_id;
802        $res = $db->getResult($queryStr);
803        if (!$res)
804            return false;
805
806        $this->_valueset = $valuesetstr;
807        $this->_separator = substr($valuesetstr, 0, 1);
808        return true;
809    } /* }}} */
810
811    /**
812     * Get the regular expression as saved in the database
813     *
814     * @return string regular expression
815     */
816    function getRegex() { /* {{{ */
817        return $this->_regex;
818    } /* }}} */
819
820    /**
821     * Set the regular expression
822     *
823     * A value of the attribute must match this regular expression.
824     *
825     * The methods checks if the regular expression is valid by running
826     * preg_match() on an empty string and see if it fails. Trying to set
827     * an invalid regular expression will not overwrite the current
828     * regular expression.
829     *
830     * All leading and trailing spaces of $regex will be removed.
831     *
832     * @param string $regex
833     * @return boolean true if regex could be set or is invalid, otherwise false
834     */
835    function setRegex($regex) { /* {{{ */
836        $db = $this->_dms->getDB();
837
838        $regex = trim($regex);
839        if($regex && @preg_match($regex, '') === false)
840            return false;
841
842        $queryStr = "UPDATE `tblAttributeDefinitions` SET `regex` =".$db->qstr($regex)." WHERE `id` = " . $this->_id;
843        $res = $db->getResult($queryStr);
844        if (!$res)
845            return false;
846
847        $this->_regex = $regex;
848        return true;
849    } /* }}} */
850
851    /**
852     * Check if the attribute definition is used
853     *
854     * Checks all documents, folders and document content whether at least
855     * one of them referenceÑ• this attribute definition
856     *
857     * @return boolean true if attribute definition is used, otherwise false
858     */
859    function isUsed() { /* {{{ */
860        $db = $this->_dms->getDB();
861        
862        $queryStr = "SELECT * FROM `tblDocumentAttributes` WHERE `attrdef`=".$this->_id;
863        $resArr = $db->getResultArray($queryStr);
864        if (is_array($resArr) && count($resArr) == 0) {
865            $queryStr = "SELECT * FROM `tblFolderAttributes` WHERE `attrdef`=".$this->_id;
866            $resArr = $db->getResultArray($queryStr);
867            if (is_array($resArr) && count($resArr) == 0) {
868                $queryStr = "SELECT * FROM `tblDocumentContentAttributes` WHERE `attrdef`=".$this->_id;
869                $resArr = $db->getResultArray($queryStr);
870                if (is_array($resArr) && count($resArr) == 0) {
871
872                    return false;
873                }
874            }
875        }
876        return true;
877    } /* }}} */
878
879    /**
880     * Parse a given value according to attribute definition
881     *
882     * The return value is always an array, even if the attribute is a single
883     * value attribute. If the type of attribute is any of document, folder, user,
884     * or group then this method will fetch each object from the database and
885     * return an array of SeedDMS_Core_Document, SeedDMS_Core_Folder, etc.
886     *
887     * @param $value string
888     * @return array|bool
889     */
890    function parseValue(string $value) { /* {{{ */
891        if($this->getMultipleValues()) {
892            /* If the value doesn't start with the separator used in the value set,
893             * then assume that the value was not saved with a leading separator.
894             * This can happen, if the value was previously a single value from
895             * the value set and later turned into a multi value attribute.
896             */
897            $sep = substr($value, 0, 1);
898            $vsep = $this->getValueSetSeparator();
899            if($sep == $vsep)
900                $values = explode($sep, substr($value, 1));
901            else
902                $values = array($value);
903        } else {
904            $values = array($value);
905        }
906
907        switch((string) $this->getType()) {
908        case self::type_document:
909            foreach($values as $value) {
910                if($u = $this->_dms->getDocument((int) $value))
911                    $tmp[] = $u->getName();
912                else
913                    $tmp[] = '???';
914            }
915            $values = $tmp;    
916            break;
917        case self::type_folder:
918            foreach($values as $value) {
919                if($u = $this->_dms->getFolder((int) $value))
920                    $tmp[] = $u->getName();
921                else
922                    $tmp[] = '???';
923            }
924            $values = $tmp;    
925            break;
926        case self::type_user:
927            foreach($values as $value) {
928                if($u = $this->_dms->getUser((int) $value))
929                    $tmp[] = $u->getLogin();
930                else
931                    $tmp[] = '???';
932            }
933            $values = $tmp;    
934            break;
935        case self::type_group:
936            foreach($values as $value) {
937                if($u = $this->_dms->getGroup((int) $value))
938                    $tmp[] = $u->getName();
939                else
940                    $tmp[] = '???';
941            }
942            $values = $tmp;    
943            break;
944        }
945        return $values;
946    } /* }}} */
947
948    /**
949     * Return a list of documents, folders, document contents where this
950     * attribute definition is used
951     *
952     * @param integer $limit return not more the n objects of each type
953     * @return array|bool
954     */
955    function getStatistics($limit=0) { /* {{{ */
956        $db = $this->_dms->getDB();
957
958        $result = array('docs'=>array(), 'folders'=>array(), 'contents'=>array());
959        if($this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_all ||
960           $this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_document) {
961            $queryStr = "SELECT * FROM `tblDocumentAttributes` WHERE `attrdef`=".$this->_id;
962            if($limit)
963                $queryStr .= " limit ".(int) $limit;
964            $resArr = $db->getResultArray($queryStr);
965            if($resArr) {
966                foreach($resArr as $rec) {
967                    if($doc = $this->_dms->getDocument($rec['document'])) {
968                        $result['docs'][] = $doc;
969                    }
970                }
971            }
972            $valueset = $this->getValueSetAsArray();
973            $possiblevalues = array();
974            foreach($valueset as $value) {
975                $possiblevalues[md5($value)] = array('value'=>$value, 'c'=>0);
976            }
977            $queryStr = "SELECT count(*) c, `value` FROM `tblDocumentAttributes` WHERE `attrdef`=".$this->_id." GROUP BY `value` ORDER BY c DESC";
978            $resArr = $db->getResultArray($queryStr);
979            if($resArr) {
980                foreach($resArr as $row) {
981                    $tmpattr = new SeedDMS_Core_Attribute(0, null, $this, $row['value']);
982                    foreach($tmpattr->getValueAsArray() as $value) {
983                        if(isset($possiblevalues[md5($value)])) {
984                            $possiblevalues[md5($value)]['c'] += $row['c'];
985                        } else {
986                            $possiblevalues[md5($value)] = array('value'=>$value, 'c'=>$row['c']);
987                        }
988                    }
989                }
990                $result['frequencies']['document'] = $possiblevalues;
991            }
992        }
993
994        if($this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_all ||
995           $this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_folder) {
996            $queryStr = "SELECT * FROM `tblFolderAttributes` WHERE `attrdef`=".$this->_id;
997            if($limit)
998                $queryStr .= " limit ".(int) $limit;
999            $resArr = $db->getResultArray($queryStr);
1000            if($resArr) {
1001                foreach($resArr as $rec) {
1002                    if($folder = $this->_dms->getFolder($rec['folder'])) {
1003                        $result['folders'][] = $folder;
1004                    }
1005                }
1006            }
1007            $valueset = $this->getValueSetAsArray();
1008            $possiblevalues = array();
1009            foreach($valueset as $value) {
1010                $possiblevalues[md5($value)] = array('value'=>$value, 'c'=>0);
1011            }
1012            $queryStr = "SELECT count(*) c, `value` FROM `tblFolderAttributes` WHERE `attrdef`=".$this->_id." GROUP BY `value` ORDER BY c DESC";
1013            $resArr = $db->getResultArray($queryStr);
1014            if($resArr) {
1015                foreach($resArr as $row) {
1016                    $tmpattr = new SeedDMS_Core_Attribute(0, null, $this, $row['value']);
1017                    foreach($tmpattr->getValueAsArray() as $value) {
1018                        if(isset($possiblevalues[md5($value)])) {
1019                            $possiblevalues[md5($value)]['c'] += $row['c'];
1020                        } else {
1021                            $possiblevalues[md5($value)] = array('value'=>$value, 'c'=>$row['c']);
1022                        }
1023                    }
1024                }
1025                $result['frequencies']['folder'] = $possiblevalues;
1026            }
1027        }
1028
1029        if($this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_all ||
1030           $this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_documentcontent) {
1031            $queryStr = "SELECT * FROM `tblDocumentContentAttributes` WHERE `attrdef`=".$this->_id;
1032            if($limit)
1033                $queryStr .= " limit ".(int) $limit;
1034            $resArr = $db->getResultArray($queryStr);
1035            if($resArr) {
1036                foreach($resArr as $rec) {
1037                    if($content = $this->_dms->getDocumentContent($rec['content'])) {
1038                        $result['contents'][] = $content;
1039                    }
1040                }
1041            }
1042            $valueset = $this->getValueSetAsArray();
1043            $possiblevalues = array();
1044            foreach($valueset as $value) {
1045                $possiblevalues[md5($value)] = array('value'=>$value, 'c'=>0);
1046            }
1047            $queryStr = "SELECT count(*) c, `value` FROM `tblDocumentContentAttributes` WHERE `attrdef`=".$this->_id." GROUP BY `value` ORDER BY c DESC";
1048            $resArr = $db->getResultArray($queryStr);
1049            if($resArr) {
1050                foreach($resArr as $row) {
1051                    $tmpattr = new SeedDMS_Core_Attribute(0, null, $this, $row['value']);
1052                    foreach($tmpattr->getValueAsArray() as $value) {
1053                        if(isset($possiblevalues[md5($value)])) {
1054                            $possiblevalues[md5($value)]['c'] += $row['c'];
1055                        } else {
1056                            $possiblevalues[md5($value)] = array('value'=>$value, 'c'=>$row['c']);
1057                        }
1058                    }
1059                }
1060                $result['frequencies']['content'] = $possiblevalues;
1061            }
1062        }
1063
1064        return $result;
1065    } /* }}} */
1066
1067    /**
1068     * Remove the attribute definition
1069     * Removal is only executed when the definition is not used anymore.
1070     *
1071     * @return boolean true on success or false in case of an error
1072     */
1073    function remove() { /* {{{ */
1074        $db = $this->_dms->getDB();
1075
1076        if($this->isUsed())
1077            return false;
1078
1079        // Delete user itself
1080        $queryStr = "DELETE FROM `tblAttributeDefinitions` WHERE `id` = " . $this->_id;
1081        if (!$db->getResult($queryStr)) return false;
1082
1083        return true;
1084    } /* }}} */
1085
1086    /**
1087     * Get all documents and folders by a given attribute value
1088     *
1089     * @param string $attrvalue value of attribute
1090     * @param integer $limit limit number of documents/folders
1091     * @return array array containing list of documents and folders
1092     */
1093    public function getObjects($attrvalue, $limit=0, $op=O_EQ) { /* {{{ */
1094        $db = $this->_dms->getDB();
1095
1096        $result = array('docs'=>array(), 'folders'=>array(), 'contents'=>array());
1097        if($this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_all ||
1098          $this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_document) {
1099            $queryStr = "SELECT * FROM `tblDocumentAttributes` WHERE `attrdef`=".$this->_id;
1100            if($attrvalue != null) {
1101                $queryStr .= " AND ";
1102                if($this->getMultipleValues()) {
1103                    $sep = $this->getValueSetSeparator();
1104                    $queryStr .= "(`value` like ".$db->qstr($sep.$attrvalue.'%')." OR `value` like ".$db->qstr('%'.$sep.$attrvalue.$sep.'%')." OR `value` like ".$db->qstr('%'.$sep.$attrvalue).")";
1105                } else {
1106                    $queryStr .= "`value`".$op.$db->qstr((string) $attrvalue);
1107                }
1108            }
1109            if($limit)
1110                $queryStr .= " limit ".(int) $limit;
1111            $resArr = $db->getResultArray($queryStr);
1112            if($resArr) {
1113                foreach($resArr as $rec) {
1114                    if($doc = $this->_dms->getDocument($rec['document'])) {
1115                        $result['docs'][] = $doc;
1116                    }
1117                }
1118            }
1119        }
1120
1121        if($this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_all ||
1122           $this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_folder) {
1123            $queryStr = "SELECT * FROM `tblFolderAttributes` WHERE `attrdef`=".$this->_id." AND ";
1124            if($this->getMultipleValues()) {
1125                $sep = $this->getValueSetSeparator();
1126                $queryStr .= "(`value` like ".$db->qstr($sep.$attrvalue.'%')." OR `value` like ".$db->qstr('%'.$sep.$attrvalue.$sep.'%')." OR `value` like ".$db->qstr('%'.$sep.$attrvalue).")";
1127            } else {
1128                $queryStr .= "`value`=".$db->qstr($attrvalue);
1129            }
1130            if($limit)
1131                $queryStr .= " limit ".(int) $limit;
1132            $resArr = $db->getResultArray($queryStr);
1133            if($resArr) {
1134                foreach($resArr as $rec) {
1135                    if($folder = $this->_dms->getFolder($rec['folder'])) {
1136                        $result['folders'][] = $folder;
1137                    }
1138                }
1139            }
1140        }
1141
1142        return $result;
1143    } /* }}} */
1144
1145    /**
1146     * Remove a given attribute value from all documents, versions and folders
1147     *
1148     * @param string $attrvalue value of attribute
1149     * @return array array containing list of documents and folders
1150     */
1151    public function removeValue($attrvalue) { /* {{{ */
1152        $db = $this->_dms->getDB();
1153
1154        foreach(array('document', 'documentcontent', 'folder') as $type) {
1155            if($type == 'document') {
1156                $tablename = "tblDocumentAttributes";
1157                $objtype = SeedDMS_Core_AttributeDefinition::objtype_document;
1158            } elseif($type == 'documentcontent') {
1159                $tablename = "tblDocumentContentAttributes";
1160                $objtype = SeedDMS_Core_AttributeDefinition::objtype_documentcontent;
1161            } elseif($type == 'folder') {
1162                $tablename = "tblFolderAttributes";
1163                $objtype = SeedDMS_Core_AttributeDefinition::objtype_folder;
1164            }
1165            if($this->_objtype == SeedDMS_Core_AttributeDefinition::objtype_all || $objtype) {
1166                $queryStr = "SELECT * FROM `".$tablename."` WHERE `attrdef`=".$this->_id." AND ";
1167                if($this->getMultipleValues()) {
1168                    $sep = $this->getValueSetSeparator();
1169                    $queryStr .= "(`value` like ".$db->qstr($sep.$attrvalue.'%')." OR `value` like ".$db->qstr('%'.$sep.$attrvalue.$sep.'%')." OR `value` like ".$db->qstr('%'.$sep.$attrvalue).")";
1170                } else {
1171                    $queryStr .= "`value`=".$db->qstr($attrvalue);
1172                }
1173
1174                $resArr = $db->getResultArray($queryStr);
1175                if($resArr) {
1176                    $db->startTransaction();
1177                    foreach($resArr as $rec) {
1178                        if($rec['value'] == $attrvalue) {
1179                            $queryStr = "DELETE FROM `".$tablename."` WHERE `id`=".$rec['id'];
1180                        } else {
1181                            if($this->getMultipleValues()) {
1182                                $sep = substr($rec['value'], 0, 1);
1183                                $vsep = $this->getValueSetSeparator();
1184                                if($sep == $vsep)
1185                                    $values = explode($sep, substr($rec['value'], 1));
1186                                else
1187                                    $values = array($rec['value']);
1188                                if (($key = array_search($attrvalue, $values)) !== false) {
1189                                    unset($values[$key]);
1190                                }
1191                                if($values) {
1192                                    $queryStr = "UPDATE `".$tablename."` SET `value`=".$db->qstr($sep.implode($sep, $values))." WHERE `id`=".$rec['id'];
1193                                } else {
1194                                    $queryStr = "DELETE FROM `".$tablename."` WHERE `id`=".$rec['id'];
1195                                }
1196                            } else {
1197                            }
1198                        }
1199                        if (!$db->getResult($queryStr)) {
1200                            $db->rollbackTransaction();
1201                            return false;
1202                        }
1203                    }
1204                    $db->commitTransaction();
1205                }
1206            }
1207        }
1208        return true;
1209    } /* }}} */
1210
1211    /**
1212     * Validate value against attribute definition
1213     *
1214     * This function checks if the given value fits the attribute
1215     * definition.
1216     * If the validation fails the validation error will be set which
1217     * can be requested by SeedDMS_Core_Attribute::getValidationError()
1218     * Set $new to true if the value to be checked isn't saved to the database
1219     * already. It will just be passed to the callback onAttributeValidate where
1220     * it could be used to, e.g. check if a value is unique once it is saved to
1221     * the database. $object is set to a folder, document or documentcontent
1222     * if the attribute belongs to such an object. This will be null, if a
1223     * new object is created.
1224     *
1225     * @param string|array $attrvalue attribute value
1226     * @param object $object set if the current attribute is saved for this object
1227     *   (this will only be passed to the onAttributeValidate callback)
1228     * @param boolean $new set to true if the value is new value and not taken from
1229     *   an existing attribute
1230     *   (this will only be passed to the onAttributeValidate callback)
1231     * @return boolean true if validation succeeds, otherwise false
1232     */
1233    function validate($attrvalue, $object=null, $new=false) { /* {{{ */
1234        /* Check if 'onAttributeValidate' callback is set */
1235        if(isset($this->_dms->callbacks['onAttributeValidate'])) {
1236            foreach($this->_dms->callbacks['onAttributeValidate'] as $callback) {
1237                $ret = call_user_func($callback[0], $callback[1], $this, $attrvalue, $object, $new);
1238                if(is_bool($ret))
1239                    return $ret;
1240            }
1241        }
1242
1243        /* Turn $attrvalue into an array of values. Checks if $attrvalue starts
1244         * with a separator char as set in the value set and use it to explode
1245         * the $attrvalue. If the separator doesn't match or this attribute
1246         * definition doesn't have a value set, then just create a one element
1247         * array. if $attrvalue is empty, then create an empty array.
1248         */
1249        if($this->getMultipleValues()) {
1250            if(is_string($attrvalue) && $attrvalue) {
1251                $sep = $attrvalue[0];
1252                $vsep = $this->getValueSetSeparator();
1253                if($sep == $vsep)
1254                    $values = explode($attrvalue[0], substr($attrvalue, 1));
1255                else
1256                    $values = array($attrvalue);
1257            } elseif(is_array($attrvalue)) {
1258                $values = $attrvalue;
1259            } elseif(is_string($attrvalue) && !$attrvalue) {
1260                $values = array();
1261            } else
1262                $values = array($attrvalue);
1263        } elseif($attrvalue !== null) {
1264            $values = array($attrvalue);
1265        } else {
1266            $values = array();
1267        }
1268
1269        /* Check if attribute value has at least the minimum number of values */
1270        $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_none;
1271        if($this->getMinValues() > count($values)) {
1272            $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_min_values;
1273            return false;
1274        }
1275        /* Check if attribute value has not more than maximum number of values */
1276        if($this->getMaxValues() && $this->getMaxValues() < count($values)) {
1277            $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_max_values;
1278            return false;
1279        }
1280
1281        $success = true;
1282        switch((string) $this->getType()) {
1283        case self::type_boolean:
1284            foreach($values as $value) {
1285                $success = $success && (preg_match('/^[01]$/', (string) $value) ? true : false);
1286            }
1287            if(!$success)
1288                $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_boolean;
1289            break;
1290        case self::type_int:
1291            foreach($values as $value) {
1292                $success = $success && (preg_match('/^[0-9]*$/', (string) $value) ? true : false);
1293            }
1294            if(!$success)
1295                $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_int;
1296            break;
1297        case self::type_date:
1298            foreach($values as $value) {
1299                $d = explode('-', $value, 3);
1300                $success = $success && (count($d) == 3) && checkdate((int) $d[1], (int) $d[2], (int) $d[0]);
1301            }
1302            if(!$success)
1303                $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_date;
1304            break;
1305        case self::type_float:
1306            foreach($values as $value) {
1307                $success = $success && is_numeric($value);
1308            }
1309            if(!$success)
1310                $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_float;
1311            break;
1312        case self::type_string:
1313            if(trim($this->getRegex()) != '') {
1314                foreach($values as $value) {
1315                    $success = $success && (preg_match($this->getRegex(), $value) ? true : false);
1316                }
1317            }
1318            if(!$success)
1319                $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_regex;
1320            break;
1321        case self::type_email:
1322            foreach($values as $value) {
1323                //$success &= filter_var($value, FILTER_VALIDATE_EMAIL) ? true : false;
1324                $success = $success && (preg_match('/^[a-z0-9._-]+@[a-z0-9-]{2,63}(\.[a-z0-9-]{2,63})*\.[a-z]{2,63}$/i', $value) ? true : false);
1325            }
1326            if(!$success)
1327                $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_email;
1328            break;
1329        case self::type_url:
1330            foreach($values as $value) {
1331                $success = $success && (preg_match('/^http(s)?:\/\/[a-z0-9_-]+(\.[a-z0-9-]{2,63})*(:[0-9]+)?(\/.*)?$/i', $value) ? true : false);
1332            }
1333            if(!$success)
1334                $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_url;
1335            break;
1336        case self::type_document:
1337            foreach($values as $value) {
1338                $success = true;
1339                if(!$this->_dms->getDocument((int) $value))
1340                    $success = false;
1341            }
1342            if(!$success)
1343                $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_document;
1344            break;
1345        case self::type_folder:
1346            foreach($values as $value) {
1347                $success = true;
1348                if(!$this->_dms->getFolder((int) $value))
1349                    $success = false;
1350            }
1351            if(!$success)
1352                $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_folder;
1353            break;
1354        case self::type_user:
1355            foreach($values as $value) {
1356                $success = true;
1357                if(!$this->_dms->getUser((int) $value))
1358                    $success = false;
1359            }
1360            if(!$success)
1361                $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_user;
1362            break;
1363        case self::type_group:
1364            foreach($values as $value) {
1365                $success = true;
1366                if(!$this->_dms->getGroup((int) $value))
1367                    $success = false;
1368            }
1369            if(!$success)
1370                $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_group;
1371            break;
1372        }
1373
1374        if(!$success)
1375            return $success;
1376
1377        /* Check if value is in value set */
1378        if($valueset = $this->getValueSetAsArray()) {
1379            /* An empty value cannot be the value set */
1380            if(!$values) {
1381                $success = false;
1382                $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_valueset;
1383            } else {
1384                foreach($values as $value) {
1385                    if(!in_array($value, $valueset)) {
1386                        $success = false;
1387                        $this->_validation_error = SeedDMS_Core_AttributeDefinition::val_error_valueset;
1388                    }
1389                }
1390            }
1391        }
1392
1393        return $success;
1394
1395    } /* }}} */
1396
1397    /**
1398     * Get validation error from last validation
1399     *
1400     * @return integer error code
1401     */
1402    function getValidationError() { return $this->_validation_error; }
1403
1404} /* }}} */