Form::normalize()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 13
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 20
rs 9.8333
1
<?php
2
3
namespace GeminiLabs\Castor\Forms;
4
5
use Exception;
6
use GeminiLabs\Castor\Services\Normalizer;
7
8
class Form
9
{
10
    /**
11
     * @var array
12
     */
13
    protected $args;
14
15
    /**
16
     * @var array
17
     */
18
    protected $dependencies;
19
20
    /**
21
     * @var Field
22
     */
23
    protected $field;
24
25
    /**
26
     * @var array
27
     */
28
    protected $fields;
29
30
    /**
31
     * @var Normalizer
32
     */
33
    protected $normalize;
34
35
    public function __construct(Field $field, Normalizer $normalize)
36
    {
37
        $this->args = [];
38
        $this->dependencies = [];
39
        $this->field = $field;
40
        $this->fields = [];
41
        $this->normalize = $normalize;
42
    }
43
44
    /**
45
     * @param string $property
46
     *
47
     * @return mixed
48
     * @throws Exception
49
     */
50
    public function __get($property)
51
    {
52
        switch ($property) {
53
            case 'args':
54
            case 'dependencies':
55
            case 'fields':
56
                return $this->$property;
57
        }
58
        throw new Exception(sprintf('Invalid %s property: %s', __CLASS__, $property));
59
    }
60
61
    /**
62
     * @param string $property
63
     * @param string $value
64
     *
65
     * @return void
66
     * @throws Exception
67
     */
68
    public function __set($property, $value)
69
    {
70
        switch ($property) {
71
            case 'args':
72
            case 'dependencies':
73
            case 'fields':
74
                $this->$property = $value;
75
                break;
76
            default:
77
                throw new Exception(sprintf('Invalid %s property: %s', __CLASS__, $property));
78
        }
79
    }
80
81
    /**
82
     * Add a field to the form.
83
     *
84
     * @return Form
85
     */
86
    public function addField(array $args = [])
87
    {
88
        $field = $this->field->normalize($args);
89
90
        if (false !== $field->args['render']) {
91
            $this->dependencies = array_unique(
92
                array_merge($field->dependencies, $this->dependencies)
93
            );
94
            $this->fields[] = $field;
95
        }
96
97
        return $this;
98
    }
99
100
    /**
101
     * Normalize the form arguments.
102
     *
103
     * @return Form
104
     */
105
    public function normalize(array $args = [])
106
    {
107
        $defaults = [
108
            'action' => '',
109
            'attributes' => '',
110
            'id' => '',
111
            'class' => '',
112
            'enctype' => 'multipart/form-data',
113
            'method' => 'post',
114
            'nonce' => '',
115
            'submit' => __('Submit', 'site-reviews'),
116
        ];
117
118
        $this->args = array_merge($defaults, $args);
119
120
        $attributes = $this->normalize->form($this->args, 'implode');
121
122
        $this->args['attributes'] = $attributes;
123
124
        return $this;
125
    }
126
127
    /**
128
     * Render the form.
129
     *
130
     * @param mixed $print
131
     *
132
     * @return string|void
133
     */
134
    public function render($print = true)
135
    {
136
        $rendered = sprintf('<form %s>%s%s</form>',
137
            $this->args['attributes'],
138
            $this->generateFields(),
139
            $this->generateSubmitButton()
140
        );
141
142
        if ((bool) $print && 'return' !== $print) {
143
            echo $rendered;
144
        }
145
146
        return $rendered;
147
    }
148
149
    /**
150
     * Reset the Form.
151
     *
152
     * @return Form
153
     */
154
    public function reset()
155
    {
156
        $this->args = [];
157
        $this->dependencies = [];
158
        $this->fields = [];
159
        return $this;
160
    }
161
162
    /**
163
     * Generate the form fields.
164
     *
165
     * @return string
166
     */
167
    protected function generateFields()
168
    {
169
        $hiddenFields = '';
170
171
        $fields = array_reduce($this->fields, function ($carry, $formField) use (&$hiddenFields) {
172
            $stringLegend = '<legend class="screen-reader-text"><span>%s</span></legend>';
173
            $stringFieldset = '<fieldset%s>%s%s</fieldset>';
174
            $stringRendered = '<tr class="glsr-field %s"><th scope="row">%s</th><td>%s</td></tr>';
175
            $outsideRendered = '</tbody></table>%s<table class="form-table"><tbody>';
176
177
            // set field value only when rendering because we need to check the default setting
178
            // against the database
179
            $field = $formField->setValue()->getField();
180
181
            $multi = true === $field->multi;
182
            $label = $field->generateLabel();
183
            $rendered = $field->render();
184
185
            // render hidden inputs outside the table
186
            if ('hidden' === $field->args['type']) {
187
                $hiddenFields .= $rendered;
188
                return $carry;
189
            }
190
191
            $hiddenClass = $this->isFieldHidden($formField) ? 'hidden' : '';
192
193
            if ($multi) {
194
                if ($depends = $formField->getDataDepends()) {
195
                    $depends = sprintf(' data-depends=\'%s\'', json_encode($depends));
196
                }
197
198
                $legend = $label ? sprintf($stringLegend, $label) : '';
199
                $rendered = sprintf($stringFieldset, $depends, $legend, $rendered);
200
            }
201
202
            $renderedField = $field->outside
203
                ? sprintf($outsideRendered, $rendered)
204
                : sprintf($stringRendered, $hiddenClass, $label, $rendered);
205
206
            return $carry.$renderedField;
207
        });
208
209
        return sprintf('<table class="form-table"><tbody>%s</tbody></table>%s', $fields, $hiddenFields);
210
    }
211
212
    /**
213
     * Generate the form submit button.
214
     *
215
     * @return string|null
216
     */
217
    protected function generateSubmitButton()
218
    {
219
        $args = $this->args['submit'];
220
221
        is_array($args) ?: $args = ['text' => $args];
222
223
        $args = shortcode_atts([
224
            'text' => __('Save Changes', 'site-reviews'),
225
            'type' => 'primary',
226
            'name' => 'submit',
227
            'wrap' => true,
228
            'other_attributes' => null,
229
        ], $args);
230
231
        if (is_admin()) {
232
            ob_start();
233
            submit_button($args['text'], $args['type'], $args['name'], $args['wrap'], $args['other_attributes']);
234
            return ob_get_clean();
235
        }
236
    }
237
238
    /**
239
     * @param object $field GeminiLabs\Castor\Form\Fields\*
240
     *
241
     * @return bool|null
242
     */
243
    protected function isFieldHidden($field)
244
    {
245
        if (!($dependsOn = $field->getDataDepends())) {
246
            return;
247
        }
248
249
        foreach ($this->fields as $formField) {
250
            if ($dependsOn['name'] !== $formField->args['name']) {
251
                continue;
252
            }
253
254
            if (is_array($dependsOn['value'])) {
255
                return !in_array($formField->args['value'], $dependsOn['value']);
256
            }
257
258
            return $dependsOn['value'] != $formField->args['value'];
259
        }
260
    }
261
}
262