1ed3de3d6SAndreas Gohr<?php 2d6d97f60SAnna Dabrowska 3ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Column; 4ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Schema; 5ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\StructException; 6ba766201SAndreas Gohruse dokuwiki\plugin\struct\meta\Value; 793ca6f4fSAndreas Gohruse dokuwiki\plugin\struct\meta\ValueValidator; 8e46eaffdSSzymon Olewniczakuse dokuwiki\plugin\struct\types\Lookup; 9d1482d40SAnna Dabrowskause dokuwiki\plugin\struct\types\Page; 10b360e3b5SAnna Dabrowskause dokuwiki\plugin\struct\types\User; 11ed3de3d6SAndreas Gohr 12ed3de3d6SAndreas Gohr/** 133ad9c1eaSAndreas Gohr * Allows adding a single struct field as a bureaucracy field 143ad9c1eaSAndreas Gohr * 153ad9c1eaSAndreas Gohr * This class is used when a field of the type struct_field is encountered in the 163ad9c1eaSAndreas Gohr * bureaucracy syntax. 17ed3de3d6SAndreas Gohr */ 18d6d97f60SAnna Dabrowskaclass helper_plugin_struct_field extends helper_plugin_bureaucracy_field 19d6d97f60SAnna Dabrowska{ 203ad9c1eaSAndreas Gohr /** @var Column */ 213ad9c1eaSAndreas Gohr public $column; 22ed3de3d6SAndreas Gohr 233ad9c1eaSAndreas Gohr /** 243ad9c1eaSAndreas Gohr * Initialize the appropriate column 253ad9c1eaSAndreas Gohr * 263ad9c1eaSAndreas Gohr * @param array $args 273ad9c1eaSAndreas Gohr */ 28d6d97f60SAnna Dabrowska public function initialize($args) 29d6d97f60SAnna Dabrowska { 3089be912bSSzymon Olewniczak $this->init($args); 31ed3de3d6SAndreas Gohr 323ad9c1eaSAndreas Gohr // find the column 333ad9c1eaSAndreas Gohr try { 343ad9c1eaSAndreas Gohr $this->column = $this->findColumn($this->opt['label']); 353ad9c1eaSAndreas Gohr } catch (StructException $e) { 363ad9c1eaSAndreas Gohr msg(hsc($e->getMessage()), -1); 373ad9c1eaSAndreas Gohr } 3889be912bSSzymon Olewniczak 3989be912bSSzymon Olewniczak $this->standardArgs($args); 403ad9c1eaSAndreas Gohr } 413ad9c1eaSAndreas Gohr 423ad9c1eaSAndreas Gohr /** 436c71c031SAndreas Gohr * Sets the value and validates it 443ad9c1eaSAndreas Gohr * 456c71c031SAndreas Gohr * @param mixed $value 466c71c031SAndreas Gohr * @return bool value was set successfully validated 473ad9c1eaSAndreas Gohr */ 48d6d97f60SAnna Dabrowska protected function setVal($value) 49d6d97f60SAnna Dabrowska { 506c71c031SAndreas Gohr if (!$this->column) { 516c71c031SAndreas Gohr $value = ''; 52131fd507SSzymon Olewniczak //don't validate placeholders here 53131fd507SSzymon Olewniczak } elseif ($this->replace($value) == $value) { 5493ca6f4fSAndreas Gohr $validator = new ValueValidator(); 556c71c031SAndreas Gohr $this->error = !$validator->validateValue($this->column, $value); 566c71c031SAndreas Gohr if ($this->error) { 576c71c031SAndreas Gohr foreach ($validator->getErrors() as $error) { 586c71c031SAndreas Gohr msg(hsc($error), -1); 596c71c031SAndreas Gohr } 606c71c031SAndreas Gohr } 616c71c031SAndreas Gohr } 626c71c031SAndreas Gohr 63*7234bfb1Ssplitbrain if ($value === [] || $value === '') { 646c71c031SAndreas Gohr if (!isset($this->opt['optional'])) { 656c71c031SAndreas Gohr $this->error = true; 662e0e9347SSzymon Olewniczak if ($this->column) { 672e0e9347SSzymon Olewniczak $label = $this->column->getTranslatedLabel(); 682e0e9347SSzymon Olewniczak } else { 692e0e9347SSzymon Olewniczak $label = $this->opt['label']; 702e0e9347SSzymon Olewniczak } 712e0e9347SSzymon Olewniczak msg(sprintf($this->getLang('e_required'), hsc($label)), -1); 726c71c031SAndreas Gohr } 736c71c031SAndreas Gohr } 746c71c031SAndreas Gohr 756c71c031SAndreas Gohr $this->opt['value'] = $value; 766c71c031SAndreas Gohr return !$this->error; 773ad9c1eaSAndreas Gohr } 783ad9c1eaSAndreas Gohr 793ad9c1eaSAndreas Gohr /** 803ad9c1eaSAndreas Gohr * Creates the HTML for the field 813ad9c1eaSAndreas Gohr * 823ad9c1eaSAndreas Gohr * @param array $params 833ad9c1eaSAndreas Gohr * @param Doku_Form $form 843ad9c1eaSAndreas Gohr * @param int $formid 853ad9c1eaSAndreas Gohr */ 86d6d97f60SAnna Dabrowska public function renderfield($params, Doku_Form $form, $formid) 87d6d97f60SAnna Dabrowska { 883ad9c1eaSAndreas Gohr if (!$this->column) return; 893ad9c1eaSAndreas Gohr 903ad9c1eaSAndreas Gohr // this is what parent does 913ad9c1eaSAndreas Gohr $this->_handlePreload(); 923ad9c1eaSAndreas Gohr if (!$form->_infieldset) { 933ad9c1eaSAndreas Gohr $form->startFieldset(''); 943ad9c1eaSAndreas Gohr } 953ad9c1eaSAndreas Gohr if ($this->error) { 963ad9c1eaSAndreas Gohr $params['class'] = 'bureaucracy_error'; 973ad9c1eaSAndreas Gohr } 983ad9c1eaSAndreas Gohr 993ad9c1eaSAndreas Gohr // output the field 100d1482d40SAnna Dabrowska $value = $this->createValue(); 10195838d50SAndreas Gohr $field = $this->makeField($value, $params['name']); 1023ad9c1eaSAndreas Gohr $form->addElement($field); 1033ad9c1eaSAndreas Gohr } 1043ad9c1eaSAndreas Gohr 10595838d50SAndreas Gohr /** 106b360e3b5SAnna Dabrowska * Adds replacement for type user to the parent method 107b360e3b5SAnna Dabrowska * 108b360e3b5SAnna Dabrowska * @return array|mixed|string 109b360e3b5SAnna Dabrowska */ 11064480a7bSAnna Dabrowska public function getReplacementValue() 11164480a7bSAnna Dabrowska { 112b360e3b5SAnna Dabrowska $value = $this->getParam('value'); 113b360e3b5SAnna Dabrowska 114b360e3b5SAnna Dabrowska if (is_array($value)) { 115*7234bfb1Ssplitbrain return [$this, 'replacementMultiValueCallback']; 116b360e3b5SAnna Dabrowska } 117b360e3b5SAnna Dabrowska 118b360e3b5SAnna Dabrowska if (!empty($value) && $this->column->getType() instanceof User) { 119b360e3b5SAnna Dabrowska return userlink($value, true); 120b360e3b5SAnna Dabrowska } 121b360e3b5SAnna Dabrowska 122b360e3b5SAnna Dabrowska return parent::getReplacementValue(); 123b360e3b5SAnna Dabrowska } 124b360e3b5SAnna Dabrowska 125b360e3b5SAnna Dabrowska /** 126b360e3b5SAnna Dabrowska * Adds handling of type user to the parent method 127b360e3b5SAnna Dabrowska * 128b360e3b5SAnna Dabrowska * @param $matches 129b360e3b5SAnna Dabrowska * @return string 130b360e3b5SAnna Dabrowska */ 13164480a7bSAnna Dabrowska public function replacementMultiValueCallback($matches) 13264480a7bSAnna Dabrowska { 133b360e3b5SAnna Dabrowska $value = $this->opt['value']; 134b360e3b5SAnna Dabrowska 135b360e3b5SAnna Dabrowska //default value 136b360e3b5SAnna Dabrowska if (is_null($value) || $value === false) { 137b360e3b5SAnna Dabrowska if (isset($matches['default']) && $matches['default'] != '') { 138b360e3b5SAnna Dabrowska return $matches['default']; 139b360e3b5SAnna Dabrowska } 140b360e3b5SAnna Dabrowska return $matches[0]; 141b360e3b5SAnna Dabrowska } 142b360e3b5SAnna Dabrowska 143b360e3b5SAnna Dabrowska if (!empty($value) && $this->column->getType() instanceof User) { 144b360e3b5SAnna Dabrowska $value = array_map(function ($user) { 145b360e3b5SAnna Dabrowska return userlink($user, true); 146b360e3b5SAnna Dabrowska }, $value); 147b360e3b5SAnna Dabrowska } 148b360e3b5SAnna Dabrowska 149b360e3b5SAnna Dabrowska //check if matched string containts a pair of brackets 150b360e3b5SAnna Dabrowska $delimiter = preg_match('/\(.*\)/s', $matches[0]) ? $matches['delimiter'] : ', '; 151b360e3b5SAnna Dabrowska 152b360e3b5SAnna Dabrowska return implode($delimiter, $value); 153b360e3b5SAnna Dabrowska } 154b360e3b5SAnna Dabrowska 155b360e3b5SAnna Dabrowska /** 156d1482d40SAnna Dabrowska * Returns a Value object for the current column. 157d1482d40SAnna Dabrowska * Special handling for Page and Lookup literal form values. 158d1482d40SAnna Dabrowska * 159d1482d40SAnna Dabrowska * @return Value 160d1482d40SAnna Dabrowska */ 161d1482d40SAnna Dabrowska protected function createValue() 162d1482d40SAnna Dabrowska { 1633a41f427SAnna Dabrowska $preparedValue = $this->opt['value'] ?? ''; 164d1482d40SAnna Dabrowska 165d1482d40SAnna Dabrowska // page fields might need to be JSON encoded depending on usetitles config 166d1482d40SAnna Dabrowska if ( 167d1482d40SAnna Dabrowska $this->column->getType() instanceof Page 168d1482d40SAnna Dabrowska && $this->column->getType()->getConfig()['usetitles'] 169d1482d40SAnna Dabrowska ) { 1703a41f427SAnna Dabrowska $preparedValue = json_encode([$preparedValue, null]); 171d1482d40SAnna Dabrowska } 172d1482d40SAnna Dabrowska 173d1482d40SAnna Dabrowska $value = new Value($this->column, $preparedValue); 174d1482d40SAnna Dabrowska 175d1482d40SAnna Dabrowska // no way to pass $israw parameter to constructor, so re-set the Lookup value 176d1482d40SAnna Dabrowska if ($this->column->getType() instanceof Lookup) { 177d1482d40SAnna Dabrowska $value->setValue($preparedValue, true); 178d1482d40SAnna Dabrowska } 179d1482d40SAnna Dabrowska 180d1482d40SAnna Dabrowska return $value; 181d1482d40SAnna Dabrowska } 182d1482d40SAnna Dabrowska 183d1482d40SAnna Dabrowska /** 18495838d50SAndreas Gohr * Create the input field 18595838d50SAndreas Gohr * 18695838d50SAndreas Gohr * @param Value $field 18795838d50SAndreas Gohr * @param String $name field's name 18895838d50SAndreas Gohr * @return string 18995838d50SAndreas Gohr */ 190d6d97f60SAnna Dabrowska protected function makeField(Value $field, $name) 191d6d97f60SAnna Dabrowska { 19295838d50SAndreas Gohr $trans = hsc($field->getColumn()->getTranslatedLabel()); 19395838d50SAndreas Gohr $hint = hsc($field->getColumn()->getTranslatedHint()); 19495838d50SAndreas Gohr $class = $hint ? 'hashint' : ''; 19595838d50SAndreas Gohr $lclass = $this->error ? 'bureaucracy_error' : ''; 19695838d50SAndreas Gohr $colname = $field->getColumn()->getFullQualifiedLabel(); 197*7234bfb1Ssplitbrain $required = empty($this->opt['optional']) ? ' <sup>*</sup>' : ''; 19895838d50SAndreas Gohr 1995275870bSAnna Dabrowska $id = uniqid('struct__', true); 200ee983135SMichael Große $input = $field->getValueEditor($name, $id); 20195838d50SAndreas Gohr 202ee983135SMichael Große $html = '<div class="field">'; 203ee983135SMichael Große $html .= "<label class=\"$lclass\" data-column=\"$colname\" for=\"$id\">"; 20495838d50SAndreas Gohr $html .= "<span class=\"label $class\" title=\"$hint\">$trans$required</span>"; 20595838d50SAndreas Gohr $html .= '</label>'; 206ee983135SMichael Große $html .= "<span class=\"input\">$input</span>"; 207ee983135SMichael Große $html .= '</div>'; 20895838d50SAndreas Gohr 20995838d50SAndreas Gohr return $html; 21095838d50SAndreas Gohr } 21195838d50SAndreas Gohr 2123ad9c1eaSAndreas Gohr /** 2133ad9c1eaSAndreas Gohr * Tries to find the correct column and schema 2143ad9c1eaSAndreas Gohr * 2153ad9c1eaSAndreas Gohr * @param string $colname 216*7234bfb1Ssplitbrain * @return Column 2170549dcc5SAndreas Gohr * @throws StructException 2183ad9c1eaSAndreas Gohr */ 219d6d97f60SAnna Dabrowska protected function findColumn($colname) 220d6d97f60SAnna Dabrowska { 221*7234bfb1Ssplitbrain [$table, $label] = explode('.', $colname, 2); 2223ad9c1eaSAndreas Gohr if (!$table || !$label) { 2233ad9c1eaSAndreas Gohr throw new StructException('Field \'%s\' not given in schema.field form', $colname); 2243ad9c1eaSAndreas Gohr } 2253ad9c1eaSAndreas Gohr $schema = new Schema($table); 2263ad9c1eaSAndreas Gohr return $schema->findColumn($label); 2273ad9c1eaSAndreas Gohr } 2283ad9c1eaSAndreas Gohr 2293ad9c1eaSAndreas Gohr /** 2303ad9c1eaSAndreas Gohr * This ensures all language strings are still working 2313ad9c1eaSAndreas Gohr * 2323ad9c1eaSAndreas Gohr * @return string always 'bureaucracy' 2333ad9c1eaSAndreas Gohr */ 234d6d97f60SAnna Dabrowska public function getPluginName() 235d6d97f60SAnna Dabrowska { 2363ad9c1eaSAndreas Gohr return 'bureaucracy'; 2373ad9c1eaSAndreas Gohr } 238ed3de3d6SAndreas Gohr} 239