1 | <?php declare(strict_types = 1); |
||
2 | namespace Templado\Engine; |
||
3 | |||
4 | use DOMElement; |
||
5 | use DOMXPath; |
||
6 | |||
7 | class FormDataRenderer { |
||
8 | |||
9 | /** |
||
10 | * @throws FormDataRendererException |
||
11 | */ |
||
12 | 45 | public function render(DOMElement $context, FormData $form): void { |
|
13 | try { |
||
14 | 45 | $formElement = $this->findFormElement($context, $form->getIdentifier()); |
|
15 | |||
16 | 39 | $this->processInputElements($form, $formElement); |
|
17 | 36 | $this->processSelectElements($form, $formElement); |
|
18 | 36 | $this->processTextareaElement($form, $formElement); |
|
19 | 9 | } catch (FormDataException $e) { |
|
20 | 3 | throw new FormDataRendererException( |
|
21 | 3 | $e->getMessage() |
|
22 | ); |
||
23 | } |
||
24 | 36 | } |
|
25 | |||
26 | 21 | private function setInputValue(DOMElement $input, string $value): void { |
|
27 | 21 | $type = $input->getAttribute('type'); |
|
28 | |||
29 | 21 | switch ($type) { |
|
30 | 21 | case 'file': |
|
31 | 18 | case 'password': |
|
32 | 6 | return; |
|
33 | 15 | case 'radio': |
|
34 | 12 | case 'checkbox': |
|
35 | 6 | $this->toggleInput($input, $value); |
|
36 | |||
37 | 6 | return; |
|
38 | default: |
||
39 | 9 | $input->setAttribute('value', $value); |
|
40 | } |
||
41 | 9 | } |
|
42 | |||
43 | 6 | private function toggleInput(DOMElement $input, string $value): void { |
|
44 | 6 | $actualValue = $input->getAttribute('value'); |
|
45 | |||
46 | 6 | if ($actualValue === $value) { |
|
47 | 6 | $input->setAttribute('checked', 'checked'); |
|
48 | |||
49 | 6 | return; |
|
50 | } |
||
51 | 3 | $input->removeAttribute('checked'); |
|
52 | 3 | } |
|
53 | |||
54 | 3 | private function setSelectValue(DOMElement $select, string $value): void { |
|
55 | 3 | foreach ($select->getElementsByTagName('option') as $option) { |
|
56 | /** @var DOMElement $option */ |
||
57 | 3 | if ($option->getAttribute('value') === $value) { |
|
58 | 3 | $option->setAttribute('selected', 'selected'); |
|
59 | |||
60 | 3 | continue; |
|
61 | } |
||
62 | 3 | $option->removeAttribute('selected'); |
|
63 | } |
||
64 | 3 | } |
|
65 | |||
66 | /** |
||
67 | * @throws FormDataRendererException |
||
68 | */ |
||
69 | 45 | private function findFormElement(DOMElement $context, string $identifier): DOMElement { |
|
70 | 45 | $xp = new DOMXPath($context->ownerDocument); |
|
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
71 | 45 | $result = $xp->query( |
|
72 | 45 | \sprintf('.//*[local-name() = "form" and (@id = "%1$s" or @name = "%1$s")]', $identifier), |
|
73 | 15 | $context |
|
74 | ); |
||
75 | |||
76 | 45 | switch ($result->length) { |
|
77 | 45 | case 1: { |
|
78 | /** @psalm-var DOMElement */ |
||
79 | 39 | return $result->item(0); |
|
80 | } |
||
81 | 6 | case 0: { |
|
82 | 3 | throw new FormDataRendererException( |
|
83 | 3 | \sprintf('No form with name or id "%s" found', $identifier) |
|
84 | ); |
||
85 | } |
||
86 | default: { |
||
87 | 3 | throw new FormDataRendererException( |
|
88 | 3 | \sprintf('Multiple forms found with name or id "%s"', $identifier) |
|
89 | ); |
||
90 | |||
91 | } |
||
92 | } |
||
93 | } |
||
94 | |||
95 | /** |
||
96 | * @throws FormDataException |
||
97 | */ |
||
98 | 39 | private function processInputElements(FormData $form, DOMElement $formElement): void { |
|
99 | 39 | foreach ($formElement->getElementsByTagName('input') as $input) { |
|
100 | /** @var DOMElement $input */ |
||
101 | 27 | $name = $input->getAttribute('name'); |
|
102 | |||
103 | 27 | if (!$form->hasKey($name)) { |
|
104 | 3 | continue; |
|
105 | } |
||
106 | 24 | $this->setInputValue( |
|
107 | 24 | $input, |
|
108 | 24 | $form->getValue( |
|
109 | 24 | $name |
|
110 | ) |
||
111 | ); |
||
112 | } |
||
113 | 36 | } |
|
114 | |||
115 | /** |
||
116 | * @throws FormDataException |
||
117 | */ |
||
118 | 36 | private function processSelectElements(FormData $form, DOMElement $formElement): void { |
|
119 | 36 | foreach ($formElement->getElementsByTagName('select') as $select) { |
|
120 | /** @var DOMElement $select */ |
||
121 | 6 | $name = $select->getAttribute('name'); |
|
122 | |||
123 | 6 | if (!$form->hasKey($name)) { |
|
124 | 3 | continue; |
|
125 | } |
||
126 | 3 | $this->setSelectValue( |
|
127 | 3 | $select, |
|
128 | 3 | $form->getValue( |
|
129 | 3 | $select->getAttribute('name') |
|
130 | ) |
||
131 | ); |
||
132 | } |
||
133 | 36 | } |
|
134 | |||
135 | /** |
||
136 | * @throws FormDataException |
||
137 | */ |
||
138 | 36 | private function processTextareaElement(FormData $form, DOMElement $formElement): void { |
|
139 | 36 | foreach ($formElement->getElementsByTagName('textarea') as $textarea) { |
|
140 | /** @var DOMElement $textarea */ |
||
141 | 6 | $name = $textarea->getAttribute('name'); |
|
142 | |||
143 | 6 | if (!$form->hasKey($name)) { |
|
144 | 3 | continue; |
|
145 | } |
||
146 | 3 | $textarea->nodeValue = ''; |
|
147 | 3 | $textarea->appendChild( |
|
148 | 3 | $textarea->ownerDocument->createTextNode( |
|
149 | 3 | $form->getValue( |
|
150 | 3 | $textarea->getAttribute('name') |
|
151 | ) |
||
152 | ) |
||
153 | ); |
||
154 | } |
||
155 | 36 | } |
|
156 | } |
||
157 |