1<?php
2
3use dokuwiki\plugin\struct\meta\Column;
4use dokuwiki\plugin\struct\meta\Schema;
5use dokuwiki\plugin\struct\meta\StructException;
6use dokuwiki\plugin\struct\meta\Value;
7use dokuwiki\plugin\struct\meta\ValueValidator;
8use dokuwiki\plugin\struct\types\Lookup;
9use dokuwiki\plugin\struct\types\Page;
10
11/**
12 * Allows adding a single struct field as a bureaucracy field
13 *
14 * This class is used when a field of the type struct_field is encountered in the
15 * bureaucracy syntax.
16 */
17class helper_plugin_struct_field extends helper_plugin_bureaucracy_field
18{
19    /** @var  Column */
20    public $column;
21
22    /**
23     * Initialize the appropriate column
24     *
25     * @param array $args
26     */
27    public function initialize($args)
28    {
29        $this->init($args);
30
31        // find the column
32        try {
33            $this->column = $this->findColumn($this->opt['label']);
34        } catch (StructException $e) {
35            msg(hsc($e->getMessage()), -1);
36        }
37
38        $this->standardArgs($args);
39    }
40
41    /**
42     * Sets the value and validates it
43     *
44     * @param mixed $value
45     * @return bool value was set successfully validated
46     */
47    protected function setVal($value)
48    {
49        if (!$this->column) {
50            $value = '';
51            //don't validate placeholders here
52        } elseif ($this->replace($value) == $value) {
53            $validator = new ValueValidator();
54            $this->error = !$validator->validateValue($this->column, $value);
55            if ($this->error) {
56                foreach ($validator->getErrors() as $error) {
57                    msg(hsc($error), -1);
58                }
59            }
60        }
61
62        if ($value === array() || $value === '') {
63            if (!isset($this->opt['optional'])) {
64                $this->error = true;
65                if ($this->column) {
66                    $label = $this->column->getTranslatedLabel();
67                } else {
68                    $label = $this->opt['label'];
69                }
70                msg(sprintf($this->getLang('e_required'), hsc($label)), -1);
71            }
72        }
73
74        $this->opt['value'] = $value;
75        return !$this->error;
76    }
77
78    /**
79     * Creates the HTML for the field
80     *
81     * @param array $params
82     * @param Doku_Form $form
83     * @param int $formid
84     */
85    public function renderfield($params, Doku_Form $form, $formid)
86    {
87        if (!$this->column) return;
88
89        // this is what parent does
90        $this->_handlePreload();
91        if (!$form->_infieldset) {
92            $form->startFieldset('');
93        }
94        if ($this->error) {
95            $params['class'] = 'bureaucracy_error';
96        }
97
98        // output the field
99        $value = $this->createValue();
100        $field = $this->makeField($value, $params['name']);
101        $form->addElement($field);
102    }
103
104    /**
105     * Returns a Value object for the current column.
106     * Special handling for Page and Lookup literal form values.
107     *
108     * @return Value
109     */
110    protected function createValue()
111    {
112        $preparedValue = $this->opt['value'];
113
114        // page fields might need to be JSON encoded depending on usetitles config
115        if (
116            $this->column->getType() instanceof Page
117            && $this->column->getType()->getConfig()['usetitles']
118        ) {
119            $preparedValue = json_encode([$this->opt['value'], null]);
120        }
121
122        $value = new Value($this->column, $preparedValue);
123
124        // no way to pass $israw parameter to constructor, so re-set the Lookup value
125        if ($this->column->getType() instanceof Lookup) {
126            $value->setValue($preparedValue, true);
127        }
128
129        return $value;
130    }
131
132    /**
133     * Create the input field
134     *
135     * @param Value $field
136     * @param String $name field's name
137     * @return string
138     */
139    protected function makeField(Value $field, $name)
140    {
141        $trans = hsc($field->getColumn()->getTranslatedLabel());
142        $hint = hsc($field->getColumn()->getTranslatedHint());
143        $class = $hint ? 'hashint' : '';
144        $lclass = $this->error ? 'bureaucracy_error' : '';
145        $colname = $field->getColumn()->getFullQualifiedLabel();
146        $required = !empty($this->opt['optional']) ? '' : ' <sup>*</sup>';
147
148        $id = uniqid('struct__', true);
149        $input = $field->getValueEditor($name, $id);
150
151        $html = '<div class="field">';
152        $html .= "<label class=\"$lclass\" data-column=\"$colname\" for=\"$id\">";
153        $html .= "<span class=\"label $class\" title=\"$hint\">$trans$required</span>";
154        $html .= '</label>';
155        $html .= "<span class=\"input\">$input</span>";
156        $html .= '</div>';
157
158        return $html;
159    }
160
161    /**
162     * Tries to find the correct column and schema
163     *
164     * @param string $colname
165     * @return \dokuwiki\plugin\struct\meta\Column
166     * @throws StructException
167     */
168    protected function findColumn($colname)
169    {
170        list($table, $label) = explode('.', $colname, 2);
171        if (!$table || !$label) {
172            throw new StructException('Field \'%s\' not given in schema.field form', $colname);
173        }
174        $schema = new Schema($table);
175        return $schema->findColumn($label);
176    }
177
178    /**
179     * This ensures all language strings are still working
180     *
181     * @return string always 'bureaucracy'
182     */
183    public function getPluginName()
184    {
185        return 'bureaucracy';
186    }
187}
188