Field::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 4
rs 10
1
<?php
2
3
namespace GeminiLabs\Castor\Forms;
4
5
use Exception;
6
use ReflectionException;
7
8
class Field
9
{
10
    /**
11
     * @var array
12
     */
13
    protected $args;
14
15
    /**
16
     * @var array
17
     */
18
    protected $dependencies;
19
20
    public function __construct()
21
    {
22
        $this->args = [];
23
        $this->dependencies = [];
24
    }
25
26
    /**
27
     * @param string $property
28
     *
29
     * @return mixed
30
     * @throws Exception
31
     */
32
    public function __get($property)
33
    {
34
        switch ($property) {
35
            case 'args':
36
            case 'dependencies':
37
                return $this->$property;
38
        }
39
        throw new Exception(sprintf('Invalid %s property: %s', __CLASS__, $property));
40
    }
41
42
    /**
43
     * Get a specific Field.
44
     *
45
     * @return mixed GeminiLabs\SiteReviews\Html\Fields\*
46
     */
47
    public function getField(array $args = [])
48
    {
49
        if (empty($args)) {
50
            $args = $this->args;
51
        }
52
53
        $className = sprintf('GeminiLabs\Castor\Forms\Fields\%s', ucfirst($args['type']));
54
55
        if (!class_exists($className)) {
56
            throw new ReflectionException("Class does not exist: {$className}");
57
        }
58
59
        return new $className($args);
60
    }
61
62
    /**
63
     * Normalize the field arguments.
64
     *
65
     * @return $this
66
     */
67
    public function normalize(array $args = [])
68
    {
69
        $defaults = [
70
            'after' => '',
71
            'attributes' => '',
72
            'before' => '',
73
            'class' => '',
74
            'default' => null,
75
            'depends' => null,
76
            'desc' => '',
77
            'errors' => [],
78
            'inline' => false,
79
            'label' => '',
80
            'name' => '',
81
            'options' => [],
82
            'path' => '',
83
            'placeholder' => '',
84
            'prefix' => '',
85
            'render' => true,
86
            'suffix' => null,
87
            'type' => 'text',
88
            'value' => '',
89
        ];
90
91
        $args = $atts = wp_parse_args($args, $defaults);
92
93
        $args['attributes'] = $this->parseAttributes($atts);
94
        $args['id'] = $this->parseId($atts);
95
        $args['inline'] = $this->parseInline($atts);
96
        $args['type'] = $this->parseType($atts);
97
        $args['name'] = $this->parseName($atts);
98
        $args['options'] = (array) $atts['options']; // make sure this is always an array
99
        $args['path'] = $atts['name'];
100
        $args['prefix'] = $this->parsePrefix($atts);
101
        $args['value'] = $this->parseValue($atts);
102
103
        $this->args = $args;
104
        $this->dependencies = $this->getField($args)->dependencies;
105
106
        $this->setDataDepends();
107
        $this->checkForErrors($atts);
108
109
        return $this;
110
    }
111
112
    /**
113
     * Render the field.
114
     *
115
     * @param mixed $print
116
     *
117
     * @return string|void
118
     */
119
    public function render($print = true)
120
    {
121
        if (false === $this->args['render']) {
122
            return;
123
        }
124
125
        $field = $this->getField();
126
127
        $class = 'glsr-field';
128
        $class .= $this->args['errors'] ? ' glsr-has-error' : '';
129
130
        $renderedString = '%s';
131
132
        if ((isset($field->args['required']) && $field->args['required'])
133
            || (isset($field->args['attributes']['required']) || in_array('required', $field->args['attributes']))) {
134
            $class .= ' glsr-required';
135
        }
136
137
        if ('hidden' !== $field->args['type']) {
138
            $renderedString = sprintf('<div class="%s">%%s</div>', $class);
139
        }
140
141
        $rendered = sprintf($renderedString,
142
            $this->args['before'].
143
            $field->generateLabel().
144
            $field->render().
145
            $this->args['after'].
146
            $this->args['errors']
147
        );
148
149
        $rendered = apply_filters('castor/rendered/field', $rendered, $field->args['type']);
150
151
        if ((bool) $print && 'return' !== $print) {
152
            echo $rendered;
153
        }
154
155
        return $rendered;
156
    }
157
158
    /**
159
     * Reset the Field.
160
     *
161
     * @return self
162
     */
163
    public function reset()
164
    {
165
        $this->args = [];
166
167
        return $this;
168
    }
169
170
    /**
171
     * Check for form submission field errors.
172
     *
173
     * @return void
174
     */
175
    protected function checkForErrors(array $atts)
176
    {
177
        $args = $this->args;
178
179
        if (!array_key_exists($atts['name'], $args['errors'])) {
180
            $this->args['errors'] = ''; // set to an empty string
181
            return;
182
        }
183
184
        $field_errors = $args['errors'][$atts['name']];
185
186
        $errors = array_reduce($field_errors['errors'], function ($carry, $error) {
187
            return $carry.sprintf('<span>%s</span> ', $error);
188
        });
189
190
        $this->args['errors'] = sprintf('<span class="glsr-field-errors">%s</span>', $errors);
191
    }
192
193
    /**
194
     * Parse the field attributes and convert to an array if needed.
195
     *
196
     * @return array
197
     */
198
    protected function parseAttributes(array $args)
199
    {
200
        if (empty($args['attributes'])) {
201
            return [];
202
        }
203
204
        $attributes = (array) $args['attributes'];
205
206
        foreach ($attributes as $key => $value) {
207
            if (is_string($key)) {
208
                continue;
209
            }
210
            unset($attributes[$key]);
211
            if (!isset($attributes[$value])) {
212
                $attributes[$value] = '';
213
            }
214
        }
215
216
        return $attributes;
217
    }
218
219
    /**
220
     * Parse the field ID from the field path.
221
     *
222
     * @return string|null
223
     */
224
    protected function parseId(array $args)
225
    {
226
        if (isset($args['id']) && !$args['id']) {
227
            return;
228
        }
229
230
        !$args['suffix'] ?: $args['suffix'] = "-{$args['suffix']}";
231
232
        return str_replace(['[]', '[', ']', '.'], ['', '-', '', '-'], $this->parseName($args).$args['suffix']);
233
    }
234
235
    /**
236
     * Parse the field inline.
237
     *
238
     * @return bool
239
     */
240
    protected function parseInline(array $args)
241
    {
242
        return false !== stripos($args['type'], '_inline')
243
            ? true
244
            : $args['inline'];
245
    }
246
247
    /**
248
     * Parse the field name.
249
     *
250
     * @return string
251
     */
252
    protected function parseName(array $args)
253
    {
254
        $name = $args['name'];
255
        $prefix = $this->parsePrefix($args);
256
257
        if (false === $prefix) {
258
            return $name;
259
        }
260
261
        $paths = explode('.', $name);
262
263
        return array_reduce($paths, function ($result, $value) {
264
            return $result .= "[$value]";
265
        }, $prefix);
266
    }
267
268
    /**
269
     * Parse the field prefix.
270
     *
271
     * @return string|false
272
     */
273
    protected function parsePrefix(array $args)
274
    {
275
        return $args['prefix'];
276
    }
277
278
    /**
279
     * Parse the field type.
280
     *
281
     * @return string
282
     */
283
    protected function parseType(array $args)
284
    {
285
        $type = $args['type'];
286
287
        return false !== stripos($type, '_inline')
288
            ? str_replace('_inline', '', $type)
289
            : $type;
290
    }
291
292
    /**
293
     * Parse the field value.
294
     *
295
     * @return string
296
     */
297
    protected function parseValue(array $args)
298
    {
299
        $default = $args['default'];
300
        $name = $args['name'];
301
        $prefix = $args['prefix'];
302
        $value = $args['value'];
303
304
        if (':placeholder' == $default) {
305
            $default = '';
306
        }
307
308
        return (!empty($value) || !$name || false === $prefix)
309
            ? $value
310
            : $default;
311
    }
312
313
    /**
314
     * Get the [data-depends] attribute.
315
     *
316
     * @return array|null
317
     */
318
    public function getDataDepends()
319
    {
320
        return $this->setDataDepends();
321
    }
322
323
    /**
324
     * Set the field value.
325
     *
326
     * @return self
327
     */
328
    public function setValue()
329
    {
330
        return $this;
331
    }
332
333
    /**
334
     * Set the [data-depends] attribute.
335
     *
336
     * @return array|null
337
     */
338
    protected function setDataDepends()
339
    {
340
        if (!($depends = $this->args['depends'])) {
341
            return;
342
        }
343
344
        $name = $depends;
345
        $value = true;
346
347
        if (is_array($depends)) {
348
            reset($depends);
349
            $name = key($depends);
350
            $value = $depends[$name];
351
        }
352
353
        $name = $this->parseName([
354
            'name' => $name,
355
            'prefix' => $this->args['prefix'],
356
        ]);
357
358
        return $this->args['attributes']['data-depends'] = [
359
            'name' => $name,
360
            'value' => $value,
361
        ];
362
    }
363
}
364