Completed
Push — master ( 5c0675...554793 )
by Helmut
03:37
created

Form::validator()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
crap 2
1
<?php 
2
3
namespace Helmut\Forms;
4
5
use Helmut\Forms\Utility\Str;
6
use Helmut\Forms\Utility\Reflect;
7
8
abstract class Form {
9
10
    /**
11
     * The request implementation used by the form.
12
     *
13
     * @var \Helmut\Forms\Request
14
     */
15
    protected $request;
16
    
17
    /**
18
     * The renderer used by the form.
19
     *
20
     * @var \Helmut\Forms\Renderer
21
     */
22
    protected $renderer;
23
24
    /**
25
     * The unique id of the form.
26
     *
27
     * @var string
28
     */
29
    public $id; 
30
31
    /**
32
     * The action for the form.
33
     *
34
     * @var string
35
     */
36
    public $action = '';    
37
38
    /**
39
     * Array containing all the form fields.
40
     *
41
     * @var array
42
     */
43
    protected $fields = [];
44
45
    /**
46
     * Array of button keys.
47
     *
48
     * @var array
49
     */
50
    protected $buttons = [];    
51
52
    /**
53
     * Array of models.
54
     *
55
     * @var array
56
     */
57
    protected $models = []; 
58
59
    /**
60
     * The active template package.
61
     *
62
     * @var string
63
     */
64
    protected $template;
65
66
    /**
67
     * The active language used.
68
     *
69
     * @var string
70
     */
71
    protected $lang = 'en'; 
72
73
    /**
74
     * A cache of language translations.
75
     *
76
     * @var array
77
     */
78
    protected $translations = [];   
79
80
    /**
81
     * An array of plugins.
82
     *
83
     * @var array
84
     */
85
    protected $plugins = [];    
86
87
    /**
88
     * An array of namespaces for class loading.
89
     *
90
     * @var array
91
     */
92
    protected $namespaces = [];
93
94
    /**
95
     * An array of paths for autoloading.
96
     *
97
     * @var array
98
     */
99
    protected $paths = [];  
100
101
    /**
102
     * The static instantiation counter. Used
103
     * to make sure each form implementation can
104
     * have a unique id.
105
     *
106
     * @var integer
107
     */
108
    protected static $count = 0;
109
  
110
    /**
111
     * Create a new form.
112
     *
113
     * @param  \Helmut\Forms\Request  $request
114
     * @param  \Helmut\Forms\Renderer  $renderer
115
     */
116
    public function __construct(Request $request = null, Renderer $renderer = null)
117
    {
118
        $this->request = $request ?: new Requests\Globals;
119
        $this->renderer = $renderer ?: new Renderer;
120 134
121
        $this->loadNamespaces();
122 134
    
123 134
        $this->setId();
124
        $this->loadDefaults();
125 134
        $this->triggerDefinition();
126
    }
127 134
128 134
    /**
129 134
     * Load namespaces.
130 134
     *
131
     * @return void
132
     */
133
    public function loadNamespaces()
134
    {
135
        $class = get_class($this);
136
137 134
        $classes = [$class];
138
139 134
        while ($class = get_parent_class($class)) {
140
            $classes[] = $class;
141 134
        }
142
143 134
        $classes = array_reverse($classes);
144 134
145
        foreach ($classes as $class) {
146
            $this->addNamespaceForClass($class);
147 134
        }
148
    }
149 134
150 134
    /**
151
     * Set a unique id.
152 134
     *
153
     * @return void
154
     */
155
    public function setId()
156
    {
157
        self::$count++;
158
        $id = substr(md5(self::$count), 0, 5);
159 134
        $this->id = 'form_'.$id;
160
    }
161 134
162 134
    /**
163 134
     * Load form defaults
164 134
     *
165
     * @return void
166
     */
167
    public function loadDefaults()
168
    {
169
        if (is_null($this->template)) {
170
            $this->setTemplate('bootstrap');
171 134
        }
172
    }
173 134
174 134
    /**
175
     * Trigger the definition.
176 134
     *
177
     * @return void
178
     */
179
    public function triggerDefinition()
180
    {
181
        if (method_exists($this, 'define')) {
182
            call_user_func_array([$this, 'define'], []);
183 134
        }
184
185 134
        $this->broadcast('define');
186 1
    }    
187
188
    /**
189 134
     * Add a new field.
190 134
     *
191
     * @param  string  $type
192
     * @param  string  $name
193
     * @return \Helmut\Forms\Fields\Field
194
     */
195
    public function addField($type, $name)
196
    {
197
        if ( ! isset($this->fields[$name])) { 
198
            $class = $this->typeToClass($type);
199 118
            $field = new $class($this, $type, $name);
200
            foreach ($field->buttons() as $button) {
201 118
                $this->addButton($button);
202 118
            }
203 118
            $this->fields[$name] = $field;
204 118
        }
205 19
        return $this->fields[$name];
206
    }
207 118
208
    /**
209 118
     * Set all the field values.
210
     *
211
     * @return void
212
     */
213
    public function setValues()
214
    {
215
        foreach ($this->fields as $field)
216
        {
217 113
            // Set values from defaults
218
            $field->setFromDefaults();
219 113
220
            // Then load values from models
221
            foreach ($this->models as $model) {
222 111
                $field->setFromModel($model);
223
            }
224
225 111
            // Then from the current request if submitted
226 9
            if ($this->submitted()) {
227
                $field->setFromRequest($this->request);
228
            }
229
        }
230 111
    }
231 111
232
    /**
233
     * Add default models to the form.
234 113
     *
235
     * @return void
236
     */
237
    public function defaults() 
238
    {
239
        $models = func_get_args();
240
        
241
        foreach ($models as $model) {
242 9
            $this->models[] = (object) $model;
243
        }
244 9
245
    }
246 9
247 9
    /**
248
     * Fetch all fields or just those matching
249
     * the names provided.
250 9
     *
251
     * @param  array  $names
252
     * @return array
253
     */
254
    public function fields($names = null)
255
    {
256
        if (is_null($names)) return $this->fields;
257
258
        return array_filter($this->fields, function($field) use ($names) {
259 15
            return array_key_exists($field->name, $names);
260
        });
261 15
    }   
262
263
    /**
264
     * Get a field matching name.
265
     *
266
     * @param  string  $name
267
     * @return \Helmut\Forms\Field
268
     */
269
    public function field($name)
270
    {
271
        if (isset($this->fields[$name])) {
272
            return $this->fields[$name];
273
        }
274 26
    }   
275
276 26
    /**
277 26
     * Fetch all of the field keys.
278
     *
279
     * @return array
280
     */
281
    public function keys()
282
    {
283
        $keys = [];
284
285
        foreach ($this->fields as $field) {
286 1
            $keys = array_merge($keys, $field->keys());
287
        }
288 1
        
289
        return $keys;
290 1
    }
291 1
292
    /**
293
     * Fetch all of the field values.
294 1
     *
295
     * @return array
296
     */
297
    public function all()
298
    {
299
        $this->setValues();
300
301
        $values = [];
302 1
303
        foreach ($this->fields as $field) {
304 1
            $values = array_merge($values, $field->values());
305
        }
306 1
307
        return $values;
308 1
    }
309 1
    
310
    /**
311
     * Fetch the value of a field.
312 1
     *
313
     * @param  string  $name
314
     * @param  string  $key
315
     * @return array
316
     */
317
    public function get($name, $key = null)
318
    {
319
        $this->setValues();
320
321
        $field = $this->field($name);
322 25
323
        if ( ! is_null($field)) {
324 25
            return $field->getValue($key);
325
        }
326 25
    }
327
328 25
    /**
329 25
     * Fill a model with values.
330
     *
331
     * @param  object  $model
332
     * @param  array  $names
333
     */
334
    public function fill($model, $names = null)
335
    {
336
        $this->setValues();
337
338
        $fields = $this->fields($names);
339 13
340
        foreach ($fields as $field) {
341 13
            $field->fillModel($model);
342
        }
343 13
    }
344
345 13
    /**
346 13
     * Check if a form has been submitted and valid in one
347
     * quick and easy step.
348 13
     *
349
     * @param  string  $name
350
     * @return bool
351
     */
352
    public function completed($name = null)
353
    {
354
        if($this->submitted($name) && $this->valid()) {
355
            $this->broadcast('completed');
356
            return true;
357
        }
358
        return false;
359
    }
360
361
    /**
362
     * Check if a form has been submitted. If no specific name
363
     * is requested check for any button.
364
     *
365
     * @param  string  $name
366
     * @return bool
367
     */
368
    public function submitted($name = null) 
369
    {
370
        $buttons = is_null($name) ? $this->buttons : [$name];
371
372
        foreach ($buttons as $button) {
373 116
            if ($this->request->get($button) == true) {
374
                $this->broadcast('submitted');
375 116
                return true;
376
            }
377 116
        }
378 116
379 9
        return false;
380 116
    }
381
382
    /**
383
     * Add a button.
384 108
     *
385
     * @param  string  $name
386
     * @return void
387
     */
388
    public function addButton($name)
389
    {
390
        $this->buttons[] = $name;
391
    }
392
393 134
    /**
394
     * Add a new namespace.
395 134
     *
396 134
     * @param  string  $namespace
397
     * @return void
398
     */
399
    public function addNamespace($namespace)
400
    {
401
        if ( ! in_array($namespace, $this->namespaces)) {
402
            array_unshift($this->namespaces, $namespace);
403
        }
404 134
    }
405
406 134
    /**
407 134
     * Get namespaces.
408
     *
409 134
     * @return array
410
     */
411
    public function namespaces()
412
    {
413
        return $this->namespaces;
414
    }
415
416 2
    /**
417
     * Add a new autoload path.
418 2
     *
419
     * @param  string  $path
420
     * @return void
421
     */
422
    public function addPath($path)
423
    {
424
        $path = rtrim($path, '/').'/';
425
426
        if ( ! in_array($path, $this->paths) && is_dir($path)) {
427 134
            array_unshift($this->paths, $path);
428
        }
429 134
    }
430
431 134
    /**
432 134
     * Find and add a new namespace using a class.
433
     *
434 134
     * @param  string  $class
435
     * @return void
436
     */
437
    public function addNamespaceForClass($class)
438
    {
439
        $namespace = Reflect::getNamespace($class);
440
441
        if ( ! is_null($namespace)) {
442 134
            $this->addNamespace($namespace);
443
        }
444 134
445
        $directory = Reflect::getDirectory($class);
446 134
  
447
        if ( ! is_null($directory) && is_dir($directory)) {
448 134
            $this->addPath($directory);
449 134
        }
450
    }   
451
452 134
    /**
453 134
     * Check if a type exists.
454
     *
455
     * @param  string  $type
456
     * @return string
457
     */
458
    public function typeExists($type)
459
    {
460
        return ! is_null($this->typeToClass($type));
461 118
    }
462
463 118
    /**
464
     * Convert a string type to full class name.
465
     *
466
     * @param  string  $type
467
     * @return string
468
     */
469
    public function typeToClass($type)
470
    {
471
        $class = Str::studly($type);
472 118
473
        $class = '\\Fields\\'.ucwords($class).'\\'.ucwords($class);
474 118
475
        foreach ($this->namespaces as $namespace) {
476 118
            if (class_exists($namespace.$class)) return $namespace.$class;
477
        }
478 118
    }
479 118
480
    /**
481 10
     * Get the validation errors. With option to
482
     * get only for a specific field.
483
     *
484
     * @param  string  $name
485
     * @return array     
486
     */
487
    public function errors($name = null)
488
    {
489
        if ($this->submitted()) $this->validate();
490
491
        if ( ! is_null($name)) return $this->field($name)->errors();
492
493
        $errors = [];
494
495
        foreach ($this->fields as $field) {
496
            foreach($field->errors() as $error) {
497
                $errors[] = $error;
498
            }
499
        }
500
501
        return $errors;
502
    }
503
504
    /**
505
     * Perform validation on the form. 
506
     *
507
     * @return void
508
     */
509
    public function validate()
510
    {
511
        $this->setValues();
512 28
513
        $this->broadcast('validate');
514 28
515
        foreach ($this->fields as $field) {
516 28
            $field->runValidations();
517
        }
518 28
519 28
        $this->broadcast('validated');
520
    }
521
522 28
    /**
523 28
     * Perform validation on the form. With option
524
     * to check if a particular field is valid.
525
     *
526
     * @param  string  $name
527
     * @return bool
528
     */
529
    public function valid($name = null)
530
    {
531
        $this->validate();
532 27
533
        $fields = is_null($name) ? $this->fields : [$this->field($name)];
534 27
535
        foreach ($fields as $field) {
536 27
537
            if ($field->isInvalid()) {
538 27
                $this->broadcast('invalid');
539
                return false;
540 27
            }
541 26
        }
542 27
543
        $this->broadcast('valid');
544
        return true;
545
    }
546 27
547 27
    /**
548
     * The opposite of valid.
549
     *
550
     * @param  string  $name
551
     * @return bool
552
     */
553
    public function invalid($name = null)
554
    {
555
        return ! $this->valid($name);
556
    }   
557
558
    /**
559
     * Set the active language.
560
     *
561
     * @param  string  $lang
562
     * @return void
563
     */
564
    public function setLanguage($lang)
565
    {
566
        $this->lang = $lang;
567 1
    }
568
569 1
    /**
570 1
     * Set the template package.
571
     *
572
     * @param  string  $template
573
     * @return void
574
     */
575
    public function setTemplate($template)
576
    {
577
        if ( ! is_null($this->template)) {
578 134
            $this->uninstallTemplate($this->template);
579
        }
580 134
581 4
        $this->installTemplate($template);
582
        
583
        $this->template = $template;
584 134
    }
585
586 134
    /**
587 134
     * Get template configuration.
588
     *
589
     * @param  string  $template
590
     * @return array
591
     */
592
    public function templateConfig($template)
593
    {
594
        $paths = $this->paths(null, 'templates/'.$template);
595 134
596
        foreach ($paths as $path) {
597 134
            
598
            $config = $path.'config.php';
599 134
            
600
            if (file_exists($config)) {
601 134
                return include($config);
602
            }
603 134
        }
604 134
605
        return [];
606
    }   
607
608 4
    /**
609
     * Install template configuration.
610
     *
611
     * @param  string  $template
612
     * @return void
613
     */
614 View Code Duplication
    public function installTemplate($template)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
615
    {
616
        $config = $this->templateConfig($template);
617 134
618
        if ( isset($config['plugins']) && is_array($config['plugins'])) {
619 134
            foreach($config['plugins'] as $plugin) {
620
                $this->addPlugin($plugin);
621 134
            }
622 134
        }
623 134
    }
624
625
    /**
626 134
     * Uninstall template configuration.
627
     *
628
     * @param  string  $template
629
     * @return void
630
     */
631 View Code Duplication
    public function uninstallTemplate($template)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
632
    {
633
        $config = $this->templateConfig($template);
634 4
635
        if ( isset($config['plugins']) && is_array($config['plugins'])) {
636 4
            foreach($config['plugins'] as $plugin) {
637
                $this->removePlugin($plugin);
638 4
            }
639 4
        }
640 4
    }
641
642
    /**
643 4
     * Fetch a fields properties.
644
     *
645
     * @param  \Helmut\Forms\Field  $field
646
     * @return string
647
     */
648
    public function fieldProperties($field) 
649
    {   
650
        $properties = [ 
651 45
            'id' => $field->id, 
652
            'form_id' => $this->id, 
653
            'type' => $field->type, 
654 45
            'name' => $field->name, 
655 45
            'label' => $field->label,
656 45
            'required' => $field->isRequired(),
657 45
            'valid' => $field->isValid(),
658 45
            'invalid' => $field->isInvalid(),
659 45
            'errors' => [],
660 45
            'keys' => [],
661 45
        ];
662
663
        $properties = array_merge($properties, $field->properties());
664
665
        foreach ($field->keys() as $key) {
666 45
            $properties['keys'][] = $key;
667
        }
668 45
669 44
        if ($field->isInvalid()) {
670
            foreach ($field->errors() as $error => $parameters) {
671
672 45
                if ($error == 'userDefined') {
673 1
                    foreach($parameters as $message) {
674
                        $properties['errors'][] = ['error' => $message];
675 1
                    }
676
                } else {
677
678
                    $parameters['field'] = str_replace('_', ' ', $field->name);
679
680
                    $message = $this->translate($error, $field);
681 1
682
                    foreach($parameters as $key => $value) {
683 1
                        if (is_object($value) && method_exists($value, '__toString')) $value = (string) $value;
684
                        if (is_array($value)) $value = implode(', ', $value);
685 1
                        $message = str_replace('['.$key.']', $value, $message);
686 1
                    }
687 1
                    $properties['errors'][] = ['error' => $message];
688 1
                }
689
            }
690 1
        }
691
692
        return $properties;
693
    }
694
695 45
    /**
696
     * Render the field using templates.
697
     *
698
     * @param  \Helmut\Forms\Field  $field
699
     * @param  array  $properties
700
     * @return string
701
     */
702
    public function renderField($field, $properties = null) 
703
    {   
704
        if (is_null($properties)) $properties = $this->fieldProperties($field);
705 45
706
        return $this->renderTemplate($field->type, $properties, $field);
707 45
    }
708
709 45
    /**
710
     * Render the field using templates.
711
     *
712
     * @param  \Helmut\Forms\Field  $field
713
     * @param  array  $properties
714
     * @return string
715
     */
716
    public function renderFieldErrors($field, $properties = null) 
717
    {   
718
        if (is_null($properties)) $properties = $this->fieldProperties($field);
719 45
720
        return $this->renderTemplate('errors', $properties, $field);
721 45
    }   
722
723 45
    /**
724
     * Render the form using templates.
725
     *
726
     * @param  string  $template
727
     * @return string
728
     */
729
    public function render($template = null)
730
    {
731
        $this->broadcast('render');
732 47
733
        $this->setValues();
734 47
735
        if ($this->submitted()) $this->validate();
736 47
737
        if ( ! is_null($template)) $this->setTemplate($template);
738 47
739
        $properties = [];
740 47
        $properties['id'] = $this->id;
741
        $properties['action'] = $this->action;
742 47
        $properties['csrf'] = $this->request->csrf();
743 47
        $properties['fields'] = [];     
744 47
745 47
        $renderered_form = $this->renderTemplate('csrf', $this->request->csrf());
746 47
747
        foreach ($this->fields as $field) {
748 47
749
            $field_properties = $this->fieldProperties($field);
750 47
751
            $properties['fields'][] = $field_properties;
752 45
753
            $rendered_field = $this->renderField($field, $field_properties);
754 45
            $rendered_field .= $this->renderFieldErrors($field, $field_properties);
755
756 45
            $field_properties['field'] = $rendered_field;
757 45
758
            $renderered_form .= $this->renderTemplate('field', $field_properties, $field);
759 45
        }
760
761 45
        $properties['form'] = $renderered_form;
762
763
        $renderered_template = $this->renderTemplate('form', $properties);
764 47
765
        return $renderered_template;
766 47
    }
767
768 47
    /**
769
     * Render a template.
770
     *
771
     * @param  string  $template
772
     * @param  array  $properties
773
     * @param  \Helmut\Forms\Field  $field
774
     * @return string
775
     */
776
    public function renderTemplate($template, $properties = [], $field = null)
777
    {
778
        $paths = $this->templatePaths($field);
779 47
780
        $properties['lang'] = $this->translations($field);
781 47
782
        $rendered_template = $this->renderer->render($template, $properties, $paths);
783 47
784
        $properties[$template] = $rendered_template;
785 47
786
        foreach ($this->plugins as $plugin) {
787 47
            if ($this->renderer->has($template, $plugin->templatePaths())) {
788
                $rendered_template = $this->renderer->render($template, $properties, $plugin->templatePaths());
789 47
            }
790
        }
791
792
        return $rendered_template;
793
    }
794
795 47
    /**
796
     * Translate a specific key.
797
     *
798
     * @param  string  $key
799
     * @param  \Helmut\Forms\Field  $field
800
     * @return string
801
     */
802
    public function translate($key, $field = null) 
803
    {
804
        $translations = $this->translations($field);
805 1
806
        if (isset($translations[$key])) {
807 1
            return $translations[$key];
808
        }
809 1
810 1
        throw new \Exception('No translation found for '.$key);
811
    }
812
813
    /**
814
     * Get translations and cache them if necessary.
815
     *
816
     * @param  \Helmut\Forms\Field  $field
817
     * @return array
818
     */
819
    public function translations($field = null) 
820
    {
821
        $lang = $this->lang;
822 47
823
        if ( ! isset($this->translations[$lang])) {
824 47
            $paths = $this->langPaths();
825
            $this->translations[$lang] = $this->loadTranslations($lang, $paths);
826 47
        }
827 47
828 47
        $translations = $this->translations[$lang];
829
830
        if ( ! is_null($field)) {
831 47
832
            if ( ! isset($this->translations[$field->type][$lang])) {
833 47
834
                if ( ! isset($this->translations[$field->type])) {
835 45
                    $this->translations[$field->type] = [];
836
                }
837 45
838 45
                $paths = $this->langPaths($field);
839
840
                $this->translations[$field->type][$lang] = $this->loadTranslations($lang, $paths);
841 45
            }
842
843 45
            $translations = array_merge($this->translations[$field->type][$lang], $translations);
844
        } 
845
846 45
        return $translations;
847
    }
848
849 47
    /**
850
     * Load the translations from paths.
851
     *
852
     * @param  string  $lang
853
     * @param  array  $paths
854
     * @return array
855
     */
856
    public function loadTranslations($lang, $paths) 
857
    {
858
        $translations = [];
859 47
860
        foreach ($paths as $path) {
861 47
            $file = $path.$lang.'.php';
862
            if (file_exists($file)) {
863 47
                $translations = array_merge($translations, include($file));
864 47
            }
865 47
        }
866 47
867
        return $translations;
868
    }
869
870 47
    /**
871
     * Add a plugin to a form.
872
     *
873
     * @param  string  $name
874
     * @return void
875
     */
876
    public function addPlugin($name)
877
    {
878
        $class = Str::studly($name);
879 134
880
        $class = '\\Plugins\\'.ucwords($class).'\\'.ucwords($class);
881 134
882
        foreach ($this->namespaces as $namespace) {
883 134
            
884
            $plugin = $namespace.$class;
885 134
            
886
            if (class_exists($plugin)) {
887 134
                $this->plugins[$name] = new $plugin;
888
                $this->plugins[$name]->event($this, 'load');
889 134
890 134
                return;
891 134
            }
892
        }
893 134
    }
894
895
    /**
896
     * Remove a plugin.
897
     *
898
     * @param  string  $name
899
     * @return void
900
     */
901
    public function removePlugin($name)
902
    {
903
        if (array_key_exists($name, $this->plugins)) {
904 134
            unset($this->plugins[$name]);
905
        }
906 134
    }
907 134
908
    /**
909 134
     * Remove all plugins.
910
     *
911
     * @return void
912
     */
913
    public function removeAllPlugins()
914
    {
915
        foreach ($this->plugins as $name => $plugin) {
916 134
            $this->removePlugin($name);
917
        }
918 134
    }   
919 134
920
    /**
921 134
     * Broadcast an event.
922
     *
923
     * @param  string  $event
924
     * @param  array  $params
925
     * @return void
926
     */
927
    private function broadcast($event, $params = []) 
928
    {
929
        foreach($this->plugins as $plugin) {
930 134
            $plugin->event($this, $event, $params);
931
        }
932 134
    }
933 134
934
    /**
935 134
     * Get all paths to the language files or just to those
936
     * for a specific field. 
937
     *
938
     * @param  \Helmut\Forms\Field  $field
939
     * @return array
940
     */
941
    public function langPaths($field = null) 
942
    {
943
        return $this->paths($field, 'lang');
944 47
    }
945
946 47
    /**
947
     * Get all paths to template packages or just to the 
948
     * packages for a specific field.
949
     *
950
     * @param  \Helmut\Forms\Field  $field
951
     * @return array
952
     */
953
    public function templatePaths($field = null) 
954
    {
955
        return $this->paths($field, 'templates/'.$this->template);
956 53
    }
957
958 53
    /**
959
     * Get all autoload paths or just the path 
960
     * of a specific resource.
961
     *
962
     * @param  \Helmut\Forms\Field  $field
963
     * @param  string  $append
964
     * @return array
965
     */
966
    public function paths($field = null, $append = null) 
967
    {
968
        $paths = $this->paths;
969 134
970
        if ( ! is_null($field)) {
971 134
            array_unshift($paths, $this->pathForClass($field));
972
        }
973 134
974 45
        if ( ! is_null($append)) {
975
            $paths = array_map(function($path) use($append) {
976
                return $path .= ltrim(rtrim($append, '/'), '/').'/';
977 134
            }, $paths);
978 134
        }
979 134
980 134
        return array_filter($paths, 'is_dir');
981
    }
982
983 134
    /**
984
     * Get autoload path for a class.
985
     *
986
     * @param  string|object  $class
987
     * @return string
988
     */
989
    public function pathForClass($class)
990
    {
991
        $path = Reflect::getDirectory($class);
992 45
993
        return rtrim($path, '/').'/';
994 45
    }
995
996 45
997 45
    /**
998
     * Set the form action.
999 45
     *
1000
     * @param  string  $action     
1001
     * @return void
1002
     */
1003
    public function setAction($action)
1004
    {
1005
        $this->action = $action;
1006
    }
1007
1008
    /**
1009
     * Get the active template package.
1010
     *
1011
     * @return string
1012
     */
1013
    public function getTemplate()
1014
    {
1015
        return $this->template;
1016
    }
1017
1018
    /**
1019
     * Get the request implementation.
1020
     *
1021
     * @return \Helmut\Forms\Request
1022
     */
1023
    public function getRequest()
1024
    {
1025
        return $this->request;
1026
    }   
1027
1028
    /**
1029 1
     * Get the renderer implementation.
1030
     *
1031 1
     * @return \Helmut\Forms\Renderer
1032
     */
1033
    public function getRenderer()
1034
    {
1035
        return $this->renderer;
1036
    } 
1037
1038
    /**
1039
     * Get all of the plugins
1040
     *
1041
     * @return array
1042
     */
1043
    public function getPlugins()
1044
    {
1045
        return $this->plugins;
1046
    }   
1047
1048
    /**
1049 134
     * Requests directly on the object could be trying to
1050
     * create a field so check if type exists.
1051 134
     *
1052 134
     * @param  string  $method
1053
     * @param  array  $parameters
1054
     * @return mixed
1055 134
     */
1056
    public function __call($method, $parameters)
1057
    {
1058
        if ( ! method_exists($this, $method))
1059
        {
1060
            if ( $this->typeExists($method)) {
1061
                return $this->addField($method, array_shift($parameters));
1062
            }
1063
        }
1064
    }
1065
1066
    /**
1067
     * Render the form.
1068
     *
1069
     * @return string
1070
     */
1071
    public function __toString()
1072
    {
1073
        return $this->render();
1074
    }   
1075
1076
}
1077