FormRenderer   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 168
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 85
dl 0
loc 168
rs 10
c 1
b 0
f 1
wmc 21

11 Methods

Rating   Name   Duplication   Size   Complexity  
A render() 0 10 2
A __construct() 0 6 1
A groupFields() 0 11 3
A setFields() 0 3 1
A renderField() 0 33 4
A getFieldTemplate() 0 10 1
A renderGroup() 0 13 1
A generateLabelHtml() 0 21 4
A renderAttributes() 0 7 2
A renderFieldset() 0 9 1
A getGroupTemplate() 0 8 1
1
<?php
2
3
namespace Jidaikobo\Kontiki\Renderers;
4
5
use Jidaikobo\Kontiki\Utils\FormUtils;
6
use Slim\Views\PhpRenderer;
7
8
class FormRenderer
9
{
10
    private array $fields;
11
    private FormUtils $formUtils;
12
    private PhpRenderer $view;
13
14
    public function __construct(
15
        PhpRenderer $view,
16
        FormUtils $formUtils
17
    ) {
18
        $this->view = $view;
19
        $this->formUtils = $formUtils;
20
    }
21
22
    public function setFields(array $fields): void
23
    {
24
        $this->fields = $fields;
25
    }
26
27
    public function render(): string
28
    {
29
        $groupedFields = $this->groupFields();
30
31
        $html = '';
32
        foreach ($groupedFields as $group => $fields) {
33
            $html .= $this->renderGroup($group, $fields);
34
        }
35
36
        return $html;
37
    }
38
39
    protected function groupFields(): array
40
    {
41
        $grouped = [];
42
        foreach ($this->fields as $name => $config) {
43
            if (!isset($config['type'])) {
44
                continue;
45
            }
46
            $group = $config['group'] ?? 'default';
47
            $grouped[$group][$name] = $config;
48
        }
49
        return $grouped;
50
    }
51
52
    protected function renderGroup(string $group, array $fields): string
53
    {
54
        $groupTemplate = $this->getGroupTemplate($group);
55
56
        $fieldHtml = array_map(function ($name, $config) {
57
            return $this->renderFieldset($name, $config);
58
        }, array_keys($fields), $fields);
59
60
        return $this->view->fetch(
61
            $groupTemplate,
62
            [
63
                'fields_html' => implode("\n", $fieldHtml),
64
                'buttonPosition' => $this->view->getAttributes()['buttonPosition'] ?? 'main'
65
            ]
66
        );
67
    }
68
69
    protected function renderFieldset(string $name, array $config): string
70
    {
71
        $labelText = $this->generateLabelHtml($name, $config);
72
        $fieldHtml = $this->renderField($name, $config);
73
        $fieldsetTemplate = $config['fieldset_template'] ?? 'forms/fieldset/flat.php';
74
75
        return $this->view->fetch($fieldsetTemplate, [
76
            'label' => $labelText,
77
            'field' => $fieldHtml,
78
        ]);
79
    }
80
81
    private function generateLabelHtml(string $name, array $config): string
82
    {
83
        if ($config['type'] === 'hidden') {
84
            return ''; // Hidden fields do not need labels
85
        }
86
87
        $id = $this->formUtils->nameToId($name);
88
        $labelAttributes = $this->renderAttributes(array_merge(
89
            $config['label_attributes'] ?? [],
90
            ['for' => $id]
91
        ));
92
93
        $labelText = e($config['label']);
94
        if (!empty($config['rules']) && in_array('required', $config['rules'], true)) {
95
            $labelText .= ' (' . __('required') . ')';
96
        }
97
98
        return sprintf(
99
            '<label %s>%s</label>',
100
            $labelAttributes,
101
            e($labelText)
102
        );
103
    }
104
105
    protected function renderField(string $name, array $config): string
106
    {
107
        $id = $this->formUtils->nameToId($name);
108
109
        $attributes = $config['attributes'] ?? [];
110
111
        if (isset($config['rules']) && in_array('required', $config['rules'], true)) {
112
            $attributes['required'] = 'required';
113
        }
114
115
        $renderedAttributes = $this->renderAttributes($attributes);
116
117
        $fieldTemplate = $this->getFieldTemplate($config['type']);
118
119
        $ariaDescribedby = '';
120
        $ariaDescribedbyAttribute = '';
121
        $description = $config['description'] ?? '';
122
        if (!empty($description)) {
123
            $ariaDescribedby = 'ariaDesc_' . $id;
124
            $ariaDescribedbyAttribute = ' aria-describedby="' . $ariaDescribedby . '"';
125
            $description = '<div class="form-text" id="' . $ariaDescribedby . '">' . $description . '</div>';
126
        }
127
128
        return $this->view->fetch($fieldTemplate, [
129
            'id' => $id,
130
            'name' => $name,
131
            'type' => $config['type'],
132
            'value' => e($config['default'] ?? ''),
133
            'options' => $config['options'] ?? [],
134
            'attributes' => $renderedAttributes,
135
            'ariaDescribedby' => $ariaDescribedby,
136
            'ariaDescribedbyAttribute' => $ariaDescribedbyAttribute,
137
            'description' => $description,
138
        ]);
139
    }
140
141
    /**
142
     * Render HTML attributes from an associative array.
143
     *
144
     * @param array $attributes Associative array of attributes.
145
     * @return string Rendered attributes as a string.
146
     */
147
    protected function renderAttributes(array $attributes): string
148
    {
149
        $result = [];
150
        foreach ($attributes as $key => $value) {
151
            $result[] = sprintf('%s="%s"', e($key), e($value));
152
        }
153
        return implode(' ', $result);
154
    }
155
156
    protected function getFieldTemplate(string $type): string
157
    {
158
        $templates = [
159
            'text' => 'forms/fields/text.php',
160
            'textarea' => 'forms/fields/textarea.php',
161
            'checkbox' => 'forms/fields/checkbox.php',
162
            'radio' => 'forms/fields/radio.php',
163
            'select' => 'forms/fields/select.php',
164
        ];
165
        return $templates[$type] ?? 'forms/fields/text.php';
166
    }
167
168
    protected function getGroupTemplate(string $group): string
169
    {
170
        $templates = [
171
            'header' => 'forms/groups/header.php',
172
            'main' => 'forms/groups/main.php',
173
            'meta' => 'forms/groups/meta.php',
174
        ];
175
        return $templates[$group] ?? 'forms/groups/default.php';
176
    }
177
}
178