1<?php
2
3namespace dokuwiki\plugin\struct\meta;
4
5use dokuwiki\plugin\struct\types\AbstractBaseType;
6
7/**
8 * Validator to validate a single value
9 */
10class ValueValidator
11{
12    /** @var  \helper_plugin_struct_db */
13    protected $hlp;
14
15    /** @var  array list of validation errors */
16    protected $errors = [];
17
18    /**
19     * ValueValidator constructor.
20     */
21    public function __construct()
22    {
23        $this->hlp = plugin_load('helper', 'struct_db');
24    }
25
26    /**
27     * Validate a single value
28     *
29     * @param Column $col the column of that value
30     * @param mixed &$rawvalue the value, will be fixed according to the type
31     * @return bool
32     */
33    public function validateValue(Column $col, &$rawvalue)
34    {
35        if ($rawvalue === null) $rawvalue = ''; // no data was passed
36
37        // fix multi value types
38        $type = $col->getType();
39        $trans = $type->getTranslatedLabel();
40        if ($type->isMulti() && !is_array($rawvalue)) {
41            $rawvalue = $type->splitValues($rawvalue);
42        }
43        // strip empty fields from multi vals
44        // but keep at least one so we can properly delete multivalues on update
45        // some fields like media or date can post an array with multiple empty strings
46        // because they use multiple inputs instead of comma separation in one input
47        if (is_array($rawvalue)) {
48            $rawvalue = array_filter($rawvalue, [$this, 'filter']);
49            $rawvalue = array_values($rawvalue); // reset the array keys
50            if ($rawvalue === []) {
51                $rawvalue = [''];
52            }
53        }
54
55        // validate data
56        return $this->validateField($type, $trans, $rawvalue);
57    }
58
59    /**
60     * The errors that occured during validation
61     *
62     * @return string[] already translated error messages
63     */
64    public function getErrors()
65    {
66        return $this->errors;
67    }
68
69    /**
70     * Validate the given data for a single field
71     *
72     * Catches the Validation exceptions and transforms them into proper error messages.
73     *
74     * Blank values are not validated and always pass
75     *
76     * @param AbstractBaseType $type
77     * @param string $label
78     * @param array|string|int &$data may be modified by the validation function
79     * @return bool true if the data validates, otherwise false
80     */
81    protected function validateField(AbstractBaseType $type, $label, &$data)
82    {
83        $prefix = sprintf($this->hlp->getLang('validation_prefix'), $label);
84
85        $ok = true;
86        if (is_array($data)) {
87            foreach ($data as &$value) {
88                if (!blank($value)) {
89                    try {
90                        $value = $type->validate($value);
91                    } catch (ValidationException $e) {
92                        $this->errors[] = $prefix . $e->getMessage();
93                        $ok = false;
94                    }
95                }
96            }
97            return $ok;
98        }
99
100        if (!blank($data)) {
101            try {
102                $data = $type->validate($data);
103            } catch (ValidationException $e) {
104                $this->errors[] = $prefix . $e->getMessage();
105                $ok = false;
106            }
107        }
108        return $ok;
109    }
110
111    /**
112     * Simple filter to remove blank values
113     *
114     * @param string $val
115     * @return bool
116     */
117    public function filter($val)
118    {
119        return !blank($val);
120    }
121}
122