Completed
Push — master ( c02fab...ffc04d )
by Kristijan
06:15
created

RulesParser::min()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 12
ccs 4
cts 5
cp 0.8
rs 9.4285
cc 2
eloc 6
nc 2
nop 1
crap 2.032
1
<?php namespace Kris\LaravelFormBuilder;
2
3
use Illuminate\Support\Arr;
4
use Illuminate\Support\Str;
5
use Kris\LaravelFormBuilder\Fields\FormField;
6
7
/**
8
 * Laravel Validator rules to HTML5 attributes parser.
9
 *
10
 * Based on Laravel Validator and Former LiveValidation
11
 * @see https://github.com/laravel/framework
12
 * @see https://github.com/formers/former
13
 */
14
class RulesParser
15
{
16
    /**
17
     * @var FormField
18
     */
19
    protected $field;
20
21
    /**
22
     * @var FormHelper
23
     */
24
    protected $formHelper;
25
26
    /**
27
     * @param FormField $field
28
     */
29 71
    public function __construct(FormField $field)
30
    {
31 71
        $this->field = $field;
32 71
        $this->formHelper = $this->field->getParent()->getFormHelper();
33 71
    }
34
35
    /**
36
     * Parse a rule for an input into an array of attributes.
37
     *
38
     * @param  string|array $rules
39
     * @return array
40
     */
41 5
    public function parse($rules)
42
    {
43 5
        $attributes = array();
44 5
        $rules = $rule = (is_string($rules)) ? explode('|', $rules) : $rules;
45
46 5
        foreach ($rules as $rule) {
47 5
            list($rule, $parameters) = $this->parseRule($rule);
48
49 5
            if ($rule && method_exists($this, $rule)) {
50 5
                $attributes += $this->$rule($parameters);
51
            }
52
        }
53
54 5
        return $attributes;
55
    }
56
57
    /**
58
     * Check that a checkbox is accepted. Needs yes, on, 1, or true as value.
59
     *
60
     *   accepted  -> required="required"
61
     *
62
     * @return array
63
     *
64
     * @see http://laravel.com/docs/5.1/validation#rule-accepted
65
     */
66 1
    protected function accepted()
67
    {
68
        return [
69 1
            'required' => 'required',
70 1
            'title' => $this->getTitle('accepted'),
71
        ];
72
    }
73
74
    /**
75
     * Check that the field is required.
76
     *
77
     *   required  -->  required="required"
78
     *
79
     * @return array
80
     *
81
     * @see http://laravel.com/docs/5.1/validation#rule-required
82
     */
83 3
    protected function required()
84
    {
85 3
        return ['required' => 'required'];
86
    }
87
88
    /**
89
     * Check that the input only contains alpha.
90
     *
91
     *   alpha  --> pattern="[a-zA-Z]+"
92
     *
93
     * @return array
94
     */
95 1
    protected function alpha()
96
    {
97
        return [
98 1
            'pattern' => '[a-zA-Z]+',
99 1
            'title' => $this->getTitle('alpha'),
100
        ];
101
    }
102
103
    /**
104
     * Check if the input contains only alpha and num.
105
     *
106
     *   alpha_num  --> pattern="[a-zA-Z0-9]+"
107
     *
108
     * @return array
109
     *
110
     * @see http://laravel.com/docs/5.1/validation#rule-alpha-num
111
     */
112 1
    protected function alphaNum()
113
    {
114
        return [
115 1
            'pattern' => '[a-zA-Z0-9]+',
116 1
            'title' => $this->getTitle('alpha_num'),
117
        ];
118
    }
119
120
    /**
121
     * Check if the input contains only alpha, num and dash.
122
     *
123
     *   alpha_dash  --> pattern="[a-zA-Z0-9_\-]+"
124
     *
125
     * @return array
126
     *
127
     * @see http://laravel.com/docs/5.1/validation#rule-alpha-dash
128
     */
129
    protected function alphaDash()
130
    {
131
        return [
132
            'pattern' => '[a-zA-Z0-9_\-]+',
133
            'title' => $this->getTitle('alpha_dash'),
134
        ];
135
    }
136
137
    /**
138
     * Check if the field is an integer value. Cannot contain decimals.
139
     *
140
     *   integer  --> step="1" (number)
141
     *   integer  --> pattern="\d+" (text)
142
     *
143
     * @return array
144
     *
145
     * @see http://laravel.com/docs/5.1/validation#rule-integer
146
     */
147
    protected function integer()
148
    {
149
        if ($this->isNumeric()) {
150
            return ['step' => 1];
151
        }
152
153
        return [
154
            'pattern' => '\d+',
155
            'title' => $this->getTitle('integer'),
156
        ];
157
    }
158
159
    /**
160
     * Check that a field is numeric. It may contain decimals.
161
     *
162
     *   numeric  --> step="any" (number)
163
     *   numeric  --> pattern="[-+]?[0-9]*[.,]?[0-9]+" (text)
164
     *
165
     * @return array
166
     *
167
     * @see http://laravel.com/docs/5.1/validation#rule-numeric
168
     */
169
    protected function numeric()
170
    {
171
        if ($this->isNumeric()) {
172
            return ['step' => 'any'];
173
        }
174
175
        return [
176
            'pattern' => '[-+]?[0-9]*[.,]?[0-9]+',
177
            'title' => $this->getTitle('numeric'),
178
        ];
179
    }
180
181
    /**
182
     * Check that a value is either 0 or 1, so it can be parsed as bool.
183
     *
184
     *   boolean  --> pattern="0|1"
185
     *
186
     * @return array
187
     *
188
     * @see http://laravel.com/docs/5.1/validation#rule-boolean
189
     */
190
    protected function boolean()
191
    {
192
        return [
193
            'pattern' => '0|1',
194
            'title' => $this->getTitle('boolean'),
195
        ];
196
    }
197
198
    /**
199
     * Check that the value is numeric and contains exactly the given digits.
200
     *
201
     *   digits:3  --> min="100" max="999"
202
     *   digits:3  --> pattern="\d{3,5}"  (text)
203
     *
204
     * @param $param
205
     * @return array
206
     *
207
     * @see http://laravel.com/docs/5.1/validation#rule-digits
208
     */
209
    protected function digits($param)
210
    {
211
        $digits = $param[0];
212
213
        if ($this->isNumeric()) {
214
            return [
215
                'min' => pow(10, $digits - 1),
216
                'max' => pow(10, $digits) - 1,
217
            ];
218
        }
219
220
        return [
221
            'pattern' => '\d{'.$digits.'}',
222
            'title' => $this->getTitle('digits', compact('digits')),
223
        ];
224
    }
225
226
    /**
227
     * Check that the value is numeric and contains between min/max digits.
228
     *
229
     *   digits_between:3,5  --> min="100" max="99999"
230
     *   digits_between:3,5  --> pattern="\d{3,5}"  (text)
231
     *
232
     * @param $param
233
     * @return array
234
     *
235
     * @see http://laravel.com/docs/5.1/validation#rule-digits-between
236
     */
237
    protected function digitsBetween($param)
238
    {
239
        list($min, $max) = $param;
240
241
        if ($this->isNumeric()) {
242
            return [
243
                'min' => pow(10, $min - 1),
244
                'max' => pow(10, $max) - 1,
245
            ];
246
        }
247
248
        return [
249
            'pattern' => '\d{'.$min.','.$max.'}',
250
            'title' => $this->getTitle('digits_between', compact('min', 'max')),
251
        ];
252
    }
253
254
    /**
255
     * For numbers, set the minimum value.
256
     * For strings, set the minimum number of characters.
257
     *
258
     *   min:5  --> min="5"       (number)
259
     *   min:5  --> minlength="5" (text)
260
     *
261
     * @param $param
262
     * @return array
263
     *
264
     * @see http://laravel.com/docs/5.1/validation#rule-min
265
     */
266 2
    protected function min($param)
267
    {
268 2
        $min = $param[0];
269
270 2
        if ($this->isNumeric()) {
271
            return ['min' => $min];
272
        }
273
274
        return [
275 2
            'minlength' => $min,
276
        ];
277
    }
278
279
    /**
280
     * For numbers, set the max value.
281
     * For strings, set the max number of characters.
282
     *
283
     *   max:5  --> max="5"       (number)
284
     *   max:5  --> maxlength="5" (text)
285
     *
286
     * @param $param
287
     * @return array
288
     *
289
     * @see http://laravel.com/docs/5.1/validation#rule-max
290
     */
291
    protected function max($param)
292
    {
293
        $max = $param[0];
294
295
        if ($this->isNumeric()) {
296
            return ['max' => $max];
297
        }
298
299
        return ['maxlength' => $max];
300
    }
301
302
    /**
303
     * For number/range inputs, check if the number is between the values.
304
     * For strings, check the length of the string.
305
     *
306
     *   between:3,5  --> min="3" max="5"             (number)
307
     *   between:3,5  --> minlength="3" maxlength="5" (text)
308
     *
309
     * @param $param
310
     * @return array
311
     *
312
     * @see http://laravel.com/docs/5.1/validation#rule-between
313
     */
314
    protected function between($param)
315
    {
316
        list ($min, $max) = $param;
317
318
        if ($this->isNumeric()) {
319
            return [
320
                'min' => $min,
321
                'max' => $max,
322
            ];
323
        }
324
325
        return [
326
            'minlength' => $min,
327
            'maxlength' => $max,
328
        ];
329
    }
330
331
    /**
332
     * For numbers: Check an exact value
333
     * For strings: Check the length of the string
334
     *
335
     *   size:5 --> min="5" max="5" (number)
336
     *   size:5 --> pattern=".{5}"  (text)
337
     *
338
     * @param $param
339
     * @return array
340
     *
341
     * @see http://laravel.com/docs/5.1/validation#rule-size
342
     */
343
    protected function size($param)
344
    {
345
        $size = $param[0];
346
347
        if ($this->isNumeric()) {
348
            return [
349
                'min' => $size,
350
                'max' => $size,
351
                'title' => $this->getTitle('size.numeric', compact('size')),
352
            ];
353
        }
354
355
        return [
356
            'pattern' =>  '.{'.$size.'}',
357
            'title' => $this->getTitle('size.string', compact('size')),
358
        ];
359
    }
360
361
    /**
362
     * Check if the value is one of the give 'in' rule values
363
     * by creating a matching pattern.
364
     *
365
     *   in:foo,bar  --> pattern="foo|bar"
366
     *
367
     * @param $params
368
     * @return array
369
     *
370
     * @see http://laravel.com/docs/5.1/validation#rule-in
371
     */
372
    protected function in($params)
373
    {
374
        return [
375
            'pattern' => implode('|', $params),
376
            'title' => $this->getTitle('in'),
377
        ];
378
    }
379
380
    /**
381
     * Check if the value is not one of the 'not_in' rule values
382
     * by creating a pattern value.
383
     *
384
     *   not_in:foo,bar  --> pattern="(?:(?!^foo$|^bar$).)*"
385
     *
386
     * @param $params
387
     * @return array
388
     *
389
     * @see http://laravel.com/docs/5.1/validation#rule-not-in
390
     */
391
    protected function notIn($params)
392
    {
393
        return [
394
            'pattern' => '(?:(?!^' . join('$|^', $params) . '$).)*',
395
            'title' => $this->getTitle('not_in'),
396
        ];
397
    }
398
399
    /**
400
     * Set the 'min' attribute on a date/datetime/datetime-local field,
401
     * based on the 'before' validation.
402
     *
403
     *   after:01-12-2015 -> min="2015-12-01"
404
     *
405
     * @param  $params
406
     * @return array
407
     *
408
     * @see http://laravel.com/docs/5.1/validation#rule-after
409
     */
410
    protected function after($params)
411
    {
412
        if ($date = $this->getDateAttribute($params[0])) {
413
            return ['min' => $date];
414
        }
415
416
        return [];
417
    }
418
419
    /**
420
     * Set the 'min' attribute on a date/datetime/datetime-local field,
421
     * based on the 'before' validation.
422
     *
423
     *   before:01-12-2015 -> max="2015-12-01"
424
     *
425
     * @param  $params
426
     * @return array
427
     *
428
     * @see http://laravel.com/docs/5.1/validation#rule-before
429
     */
430
    protected function before($params)
431
    {
432
        if ($date = $this->getDateAttribute($params[0])) {
433
            return ['max' => $date];
434
        }
435
436
        return [];
437
    }
438
439
    /**
440
     * Add the image mime-type to a file input.
441
     *
442
     * @return array
443
     *
444
     * @see http://laravel.com/docs/5.1/validation#rule-image
445
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-accept
446
     */
447
    protected function image()
448
    {
449
        return ['accept' => 'image/*'];
450
    }
451
452
    /**
453
     * Add the mime types to the accept attribute.
454
     *
455
     *  mimes:xls,xlsx  --> accept=".xls, .xlsx"
456
     *
457
     * @param  array
458
     * @return array
459
     *
460
     * @see http://laravel.com/docs/5.1/validation#rule-mimes
461
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-accept
462
     */
463
    protected function mimes($param)
464
    {
465
        $mimes = '.' . implode(', .', $param);
466
467
        return ['accept'  => $mimes];
468
    }
469
470
    /**
471
     * Get the title, used for validating a rule
472
     *
473
     * @param  string $rule
474
     * @param  array  $params
475
     * @return string
476
     */
477 3
    protected function getTitle($rule, $params = array())
478
    {
479 3
        $params['attribute'] = $this->field->getOption('label');
480
481 3
        return $this->formHelper->getTranslator()->trans('validation.' . $rule, $params);
482
    }
483
484
    /**
485
     * Check if the field is one of certain types.
486
     *
487
     * @param  string|array  $types
488
     * @return bool
489
     */
490 2
    protected function isType($types)
491
    {
492 2
        return in_array($this->field->getType(), (array) $types);
493
    }
494
495 2
    protected function isNumeric()
496
    {
497 2
        return $this->isType(['number', 'range']);
498
    }
499
500
    /**
501
     * Format a date to the correct format, based on the current field.
502
     *
503
     * @param $dateStr
504
     * @return bool|string
505
     */
506
    protected function getDateAttribute($dateStr)
507
    {
508
        $format = "Y-m-d";
509
        if ($this->isType(['datetime', 'datetime-local'])) {
510
            $format .= '\TH:i:s';
511
        }
512
513
        return date($format, strtotime($dateStr));
514
    }
515
516
    /**
517
     * Methods below are copied from \Illuminate\Validation\Validator
518
     * @see https://github.com/laravel/framework/blob/5.1/src/Illuminate/Validation/Validator.php
519
     * @copyright Taylor Otwell
520
     */
521
522
    /**
523
     * Extract the rule name and parameters from a rule.
524
     *
525
     * @param  array|string $rules
526
     * @return array
527
     */
528 5
    protected function parseRule($rules)
529
    {
530 5
        if (is_array($rules)) {
531
            return $this->parseArrayRule($rules);
532
        }
533 5
        return $this->parseStringRule($rules);
534
    }
535
536
    /**
537
     * Parse an array based rule.
538
     *
539
     * @param  array $rules
540
     * @return array
541
     */
542
    protected function parseArrayRule(array $rules)
543
    {
544
        return [Str::studly(trim(Arr::get($rules, 0))), array_slice($rules, 1)];
545
    }
546
547
    /**
548
     * Parse a string based rule.
549
     *
550
     * @param  string $rules
551
     * @return array
552
     */
553 5
    protected function parseStringRule($rules)
554
    {
555 5
        $parameters = [];
556
        // The format for specifying validation rules and parameters follows an
557
        // easy {rule}:{parameters} formatting convention. For instance the
558
        // rule "Max:3" states that the value may only be three letters.
559 5
        if (strpos($rules, ':') !== false) {
560 2
            list($rules, $parameter) = explode(':', $rules, 2);
561 2
            $parameters = $this->parseParameters($rules, $parameter);
562
        }
563 5
        return [Str::studly(trim($rules)), $parameters];
564
    }
565
566
    /**
567
     * Parse a parameter list.
568
     *
569
     * @param  string $rule
570
     * @param  string $parameter
571
     * @return array
572
     */
573 2
    protected function parseParameters($rule, $parameter)
574
    {
575 2
        if (strtolower($rule) == 'regex') {
576
            return [$parameter];
577
        }
578 2
        return str_getcsv($parameter);
579
    }
580
}
581