Completed
Pull Request — master (#220)
by
unknown
09:41
created

FormHelper::prepareAttributes()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 5

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 18
ccs 9
cts 9
cp 1
rs 8.8571
cc 5
eloc 9
nc 5
nop 1
crap 5
1
<?php  namespace Kris\LaravelFormBuilder;
2
3
use Illuminate\Support\Collection;
4
use Illuminate\Translation\Translator;
5
use Illuminate\Database\Eloquent\Model;
6
use Kris\LaravelFormBuilder\Fields\FormField;
7
use Illuminate\Contracts\View\Factory as View;
8
9
class FormHelper
10
{
11
12
    /**
13
     * @var View
14
     */
15
    protected $view;
16
17
    /**
18
     * @var Translator
19
     */
20
    protected $translator;
21
22
    /**
23
     * @var array
24
     */
25
    protected $config;
26
27
    /**
28
     * @var FormBuilder
29
     */
30
    protected $formBuilder;
31
32
    /**
33
     * All available field types
34
     *
35
     * @var array
36
     */
37
    protected static $availableFieldTypes = [
38
        'text'           => 'InputType',
39
        'email'          => 'InputType',
40
        'url'            => 'InputType',
41
        'tel'            => 'InputType',
42
        'search'         => 'InputType',
43
        'password'       => 'InputType',
44
        'hidden'         => 'InputType',
45
        'number'         => 'InputType',
46
        'date'           => 'InputType',
47
        'file'           => 'InputType',
48
        'image'          => 'InputType',
49
        'color'          => 'InputType',
50
        'datetime-local' => 'InputType',
51
        'month'          => 'InputType',
52
        'range'          => 'InputType',
53
        'time'           => 'InputType',
54
        'week'           => 'InputType',
55
        'select'         => 'SelectType',
56
        'textarea'       => 'TextareaType',
57
        'button'         => 'ButtonType',
58
        'submit'         => 'ButtonType',
59
        'reset'          => 'ButtonType',
60
        'radio'          => 'CheckableType',
61
        'checkbox'       => 'CheckableType',
62
        'choice'         => 'ChoiceType',
63
        'form'           => 'ChildFormType',
64
        'entity'         => 'EntityType',
65
        'collection'     => 'CollectionType',
66
        'repeated'       => 'RepeatedType',
67
        'static'         => 'StaticType'
68
    ];
69
70
    /**
71
     * Custom types
72
     *
73
     * @var array
74
     */
75
    private $customTypes = [];
76
77
    /**
78
     * @param View    $view
79
     * @param Translator $translator
80
     * @param array   $config
81
     */
82 88
    public function __construct(View $view, Translator $translator, array $config = [])
83
    {
84 88
        $this->view = $view;
85 88
        $this->translator = $translator;
86 88
        $this->config = $config;
87 88
        $this->loadCustomTypes();
88 88
    }
89
90
    /**
91
     * @param string $key
92
     * @param string $default
93
     * @return mixed
94
     */
95 88
    public function getConfig($key, $default = null)
96
    {
97 88
        return array_get($this->config, $key, $default);
98
    }
99
100
    /**
101
     * @return View
102
     */
103 29
    public function getView()
104
    {
105 29
        return $this->view;
106
    }
107
108
    /**
109
     * Merge options array
110
     *
111
     * @param array $first
112
     * @param array $second
113
     * @return array
114
     */
115
    public function mergeOptions(array $first, array $second)
116
    {
117 88
        $merge_options = function($first, $second, $concat_classes = FALSE) use(&$merge_options) {
118 88
            $arr = array();
119 88
            foreach (array_unique(array_merge(array_keys($first), array_keys($second))) as $key) {
120 88
                $new_value = NULL;
121
122
                // Element exists in both arrays.
123 88
                if (array_key_exists($key, $first) && array_key_exists($key, $second)) {
124
                    // Recurse.
125 73
                    if (is_array($first[$key]) && is_array($second[$key])) {
126 70
                        $new_value = $merge_options($first[$key], $second[$key], in_array($key, array('wrapper', 'label_attr', 'attr')));
127
                    }
128
                    // Merge classes.
129 73
                    elseif ($concat_classes && $key == 'class') {
130 70
                        if (!str_contains($first[$key], $second[$key]) && !str_contains($second[$key], $first[$key])) {
131 70
                            $new_value = trim($first[$key] . ' ' . $second[$key]);
132
                        }
133
                    }
134
                }
135
136
                // Take (in this order) new value, second value, first value.
137 88
                $arr[$key] = $new_value ?: (array_key_exists($key, $second) ? $second[$key] : $first[$key]);
138
            }
139 88
            return $arr;
140 88
        };
141
142 88
        return $merge_options($first, $second);
143
    }
144
145
    /**
146
     * Get proper class for field type
147
     *
148
     * @param $type
149
     * @return string
150
     */
151 59
    public function getFieldType($type)
152
    {
153 59
        $types = array_keys(static::$availableFieldTypes);
154
155 59
        if (!$type || trim($type) == '') {
156 1
            throw new \InvalidArgumentException('Field type must be provided.');
157
        }
158
159 58
        if (array_key_exists($type, $this->customTypes)) {
160 2
            return $this->customTypes[$type];
161
        }
162
163 56
        if (!in_array($type, $types)) {
164 2
            throw new \InvalidArgumentException(
165
                sprintf(
166 2
                    'Unsupported field type [%s]. Available types are: %s',
167
                    $type,
168 2
                    join(', ', array_merge($types, array_keys($this->customTypes)))
169
                )
170
            );
171
        }
172
173 54
        $namespace = __NAMESPACE__.'\\Fields\\';
174
175 54
        return $namespace . static::$availableFieldTypes[$type];
176
    }
177
178
    /**
179
     * Convert array of attributes to html attributes
180
     *
181
     * @param $options
182
     * @return string
183
     */
184 70
    public function prepareAttributes($options)
185
    {
186 70
        if (!$options) {
187 2
            return null;
188
        }
189
190 70
        $attributes = [];
191
192 70
        foreach ($options as $name => $option) {
193 70
            if ($option !== null) {
194 70
                $name = is_numeric($name) ? $option : $name;
195
196 70
                $attributes[] = $name.'="'.$option.'" ';
197
            }
198
        }
199
200 70
        return join('', $attributes);
201
    }
202
203
    /**
204
     * Add custom field
205
     *
206
     * @param $name
207
     * @param $class
208
     */
209 3
    public function addCustomField($name, $class)
210
    {
211 3
        if (!array_key_exists($name, $this->customTypes)) {
212 3
            return $this->customTypes[$name] = $class;
213
        }
214
215 1
        throw new \InvalidArgumentException('Custom field ['.$name.'] already exists on this form object.');
216
    }
217
218
    /**
219
     * Load custom field types from config file
220
     */
221 88
    private function loadCustomTypes()
222
    {
223 88
        $customFields = (array) $this->getConfig('custom_fields');
224
225 88
        if (!empty($customFields)) {
226 1
            foreach ($customFields as $fieldName => $fieldClass) {
227 1
                $this->addCustomField($fieldName, $fieldClass);
228
            }
229
        }
230 88
    }
231
232 5
    public function convertModelToArray($model)
233
    {
234 5
        if (!$model) {
235 1
            return null;
236
        }
237
238 5
        if ($model instanceof Model) {
239 1
            return $model->toArray();
240
        }
241
242 5
        if ($model instanceof Collection) {
243 2
            return $model->all();
244
        }
245
246 5
        return $model;
247
    }
248
249
    /**
250
     * Format the label to the proper format
251
     *
252
     * @param $name
253
     * @return string
254
     */
255 69
    public function formatLabel($name)
256
    {
257 69
        if (!$name) {
258 1
            return null;
259
        }
260
261 69
        if ($this->translator->has($name)) {
262 1
            $translatedName = $this->translator->get($name);
263
264 1
            if (is_string($translatedName)) {
265 1
                return $translatedName;
266
            }
267
        }
268
269 68
        return ucfirst(str_replace('_', ' ', $name));
270
    }
271
272
    /**
273
     * @param FormField[] $fields
274
     * @return array
275
     */
276 3
    public function mergeFieldsRules($fields)
277
    {
278 3
        $rules = [];
279 3
        $attributes = [];
280
281 3
        foreach ($fields as $field) {
282 3
            if ($fieldRules = $field->getValidationRules()) {
283 3
                $rules = array_merge($rules, $fieldRules['rules']);
284 3
                $attributes = array_merge($attributes, $fieldRules['attributes']);
285
            }
286
        }
287
288
        return [
289 3
            'rules' => $rules,
290 3
            'attributes' => $attributes
291
        ];
292
    }
293
294
    /**
295
     * @param string $string
296
     * @return string
297
     */
298 69
    public function transformToDotSyntax($string)
299
    {
300 69
        return str_replace(['.', '[]', '[', ']'], ['_', '', '.', ''], $string);
301
    }
302
303
    /**
304
     * @return Translator
305
     */
306 3
    public function getTranslator()
307
    {
308 3
        return $this->translator;
309
    }
310
}
311