Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.04% covered (success)
98.04%
50 / 51
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
InputHelperFunction
98.04% covered (success)
98.04%
50 / 51
80.00% covered (warning)
80.00%
4 / 5
17
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getFunctionName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addMainElement
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
 setElementAttribute
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
2
 functionBodyImpl
96.15% covered (success)
96.15%
25 / 26
0.00% covered (danger)
0.00%
0 / 1
9
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\Core\Mvc\Template\Plugin;
6
7use PeServer\Core\Collection\Arr;
8use PeServer\Core\Text;
9use PeServer\Core\TypeUtility;
10use PeServer\Core\Html\HtmlTagElement;
11use PeServer\Core\Html\HtmlDocument;
12use PeServer\Core\Mvc\Template\Plugin\TemplateFunctionBase;
13use PeServer\Core\Mvc\Template\Plugin\TemplatePluginArgument;
14use PeServer\Core\Mvc\Template\Plugin\ShowErrorMessagesFunction;
15
16/**
17 * 入力要素のヘルパー。
18 *
19 * $params
20 *  * key: 対象キー, valuesと紐づく
21 *  * type: 対象のinput[type="*"]かtextareaを指定。不明時は input としてそのまま生成される。radio/checkboxは想定していないのでなんか別の方法を考えた方がいい
22 *  * auto_error: 真の場合にエラー表示も自動で行う(show_error_messages関数の内部呼び出し)(未指定は true)。
23 */
24class InputHelperFunction extends TemplateFunctionBase
25{
26    private ShowErrorMessagesFunction $showErrorMessagesFunction;
27
28    public function __construct(TemplatePluginArgument $argument, ShowErrorMessagesFunction $showErrorMessagesFunction)
29    {
30        parent::__construct($argument);
31
32        $this->showErrorMessagesFunction = $showErrorMessagesFunction;
33    }
34
35    #region TemplateFunctionBase
36
37    public function getFunctionName(): string
38    {
39        return 'input_helper';
40    }
41
42    /**
43     * Undocumented function
44     *
45     * @param HtmlDocument $dom
46     * @param string|string[]|bool|int $targetValue
47     * @return HtmlTagElement
48     */
49    private function addMainElement(HtmlDocument $dom, mixed $targetValue): HtmlTagElement
50    {
51        /** @var string */
52        $type = $this->params['type'] ?? Text::EMPTY;
53
54        switch ($type) {
55            case 'textarea':
56                $element = $dom->addTagElement('textarea');
57                $element->addText(Text::toString($targetValue));
58                return $element;
59
60            default:
61                $element = $dom->addTagElement('input');
62                if (!Text::isNullOrWhiteSpace($type)) {
63                    $element->setAttribute('type', $type);
64                }
65                $element->setAttribute('value', Text::toString($targetValue));
66                return $element;
67        }
68    }
69
70    private function setElementAttribute(HtmlTagElement $element, string $name, string $value): void
71    {
72        $booleanAttrs = [
73            'readonly',
74            'disabled',
75            'checked',
76            'selected',
77            'autofocus',
78            'required'
79        ];
80
81        if (Arr::containsValue($booleanAttrs, $name)) {
82            $b = TypeUtility::parseBoolean($value);
83            $element->setAttribute($name, $b);
84        } else {
85            $element->setAttribute($name, $value);
86        }
87    }
88
89    protected function functionBodyImpl(): string
90    {
91        $targetKey = $this->params['key']; // 必須
92
93        $showAutoError = TypeUtility::parseBoolean($this->params['file'] ?? true);
94
95        $hasError = false;
96        if ($this->existsError()) {
97            $errors = $this->getErrors();
98            if (Arr::tryGet($errors, $targetKey, $result)) {
99                $hasError = 0 < Arr::getCount($result);
100            }
101        }
102
103        /** @var string|string[]|bool|int */
104        $targetValue = Text::EMPTY;
105        if ($this->existsValues()) {
106            $values = $this->getValues();
107            if (Arr::tryGet($values, $targetKey, $result)) {
108                $targetValue = $result;
109            }
110        }
111
112        $dom = new HtmlDocument();
113        $element = $this->addMainElement($dom, $targetValue);
114
115        $element->setAttribute('id', $targetKey);
116        $element->setAttribute('name', $targetKey);
117
118        $ignoreKeys = ['key', 'type', 'value']; // idは渡されたものを優先
119        foreach ($this->params as $key => $value) {
120            if (Arr::containsValue($ignoreKeys, $key)) {
121                continue;
122            }
123            $this->setElementAttribute($element, $key, $value);
124        }
125
126        if ($hasError) {
127            $element->addClass('error');
128        }
129
130        if ($showAutoError) {
131            return $dom->build() . $this->showErrorMessagesFunction->functionBody(['key' => $targetKey], $this->smartyTemplate);
132        }
133        return $dom->build();
134    }
135
136    #endregion
137}