Completed
Push — master ( e7cb1a...50f9b8 )
by Helmut
02:52
created

Form::fieldProperties()   C

Complexity

Conditions 10
Paths 4

Size

Total Lines 51
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 10.0862

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 51
rs 6
ccs 19
cts 21
cp 0.9048
cc 10
eloc 31
nc 4
nop 1
crap 10.0862

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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->setFromDefault();
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)) {
257
            return $this->fields;
258
        }
259 15
260
        return array_filter($this->fields, function($field) use ($names) {
261 15
            return array_key_exists($field->name, $names);
262
        });
263
    }   
264
265
    /**
266
     * Get a field matching name.
267
     *
268
     * @param  string  $name
269
     * @return \Helmut\Forms\Field
270
     */
271
    public function field($name)
272
    {
273
        if (isset($this->fields[$name])) {
274 26
            return $this->fields[$name];
275
        }
276 26
    }   
277 26
278
    /**
279
     * Fetch all of the field keys.
280
     *
281
     * @return array
282
     */
283
    public function keys()
284
    {
285
        $keys = [];
286 1
287
        foreach ($this->fields as $field) {
288 1
            $keys = array_merge($keys, $field->keys());
289
        }
290 1
        
291 1
        return $keys;
292
    }
293
294 1
    /**
295
     * Fetch all of the field values.
296
     *
297
     * @return array
298
     */
299
    public function all()
300
    {
301
        $this->setValues();
302 1
303
        $values = [];
304 1
305
        foreach ($this->fields as $field) {
306 1
            $values = array_merge($values, $field->values());
307
        }
308 1
309 1
        return $values;
310
    }
311
    
312 1
    /**
313
     * Fetch the value of a field.
314
     *
315
     * @param  string  $name
316
     * @param  string  $key
317
     * @return array
318
     */
319
    public function get($name, $key = null)
320
    {
321
        $this->setValues();
322 25
323
        $field = $this->field($name);
324 25
325
        if ( ! is_null($field)) {
326 25
            return $field->value($key);
327
        }
328 25
    }
329 25
330
    /**
331
     * Fill a model with values.
332
     *
333
     * @param  object  $model
334
     * @param  array  $names
335
     */
336
    public function fill($model, $names = null)
337
    {
338
        $this->setValues();
339 13
340
        $fields = $this->fields($names);
341 13
342
        foreach ($fields as $field) {
343 13
            $field->fillModel($model);
344
        }
345 13
    }
346 13
347
    /**
348 13
     * Check if a form has been submitted and valid in one
349
     * quick and easy step.
350
     *
351
     * @param  string  $name
352
     * @return bool
353
     */
354
    public function completed($name = null)
355
    {
356
        if($this->submitted($name) && $this->valid()) {
357
            $this->broadcast('completed');
358
            return true;
359
        }
360
        return false;
361
    }
362
363
    /**
364
     * Check if a form has been submitted. If no specific name
365
     * is requested check for any button.
366
     *
367
     * @param  string  $name
368
     * @return bool
369
     */
370
    public function submitted($name = null) 
371
    {
372
        $buttons = is_null($name) ? $this->buttons : [$name];
373 116
374
        foreach ($buttons as $button) {
375 116
            if ($this->request->get($button) == true) {
376
                $this->broadcast('submitted');
377 116
                return true;
378 116
            }
379 9
        }
380 116
381
        return false;
382
    }
383
384 108
    /**
385
     * Add a button.
386
     *
387
     * @param  string  $name
388
     * @return void
389
     */
390
    public function addButton($name)
391
    {
392
        $this->buttons[] = $name;
393 134
    }
394
395 134
    /**
396 134
     * Add a new namespace.
397
     *
398
     * @param  string  $namespace
399
     * @return void
400
     */
401
    public function addNamespace($namespace)
402
    {
403
        if ( ! in_array($namespace, $this->namespaces)) {
404 134
            array_unshift($this->namespaces, $namespace);
405
        }
406 134
    }
407 134
408
    /**
409 134
     * Get namespaces.
410
     *
411
     * @return array
412
     */
413
    public function namespaces()
414
    {
415
        return $this->namespaces;
416 2
    }
417
418 2
    /**
419
     * Add a new autoload path.
420
     *
421
     * @param  string  $path
422
     * @return void
423
     */
424
    public function addPath($path)
425
    {
426
        $path = rtrim($path, '/').'/';
427 134
428
        if ( ! in_array($path, $this->paths) && is_dir($path)) {
429 134
            array_unshift($this->paths, $path);
430
        }
431 134
    }
432 134
433
    /**
434 134
     * Find and add a new namespace using a class.
435
     *
436
     * @param  string  $class
437
     * @return void
438
     */
439
    public function addNamespaceForClass($class)
440
    {
441
        $namespace = Reflect::getNamespace($class);
442 134
443
        if ( ! is_null($namespace)) {
444 134
            $this->addNamespace($namespace);
445
        }
446 134
447
        $directory = Reflect::getDirectory($class);
448 134
  
449 134
        if ( ! is_null($directory) && is_dir($directory)) {
450
            $this->addPath($directory);
451
        }
452 134
    }   
453 134
454
    /**
455
     * Check if a type exists.
456
     *
457
     * @param  string  $type
458
     * @return string
459
     */
460
    public function typeExists($type)
461 118
    {
462
        return ! is_null($this->typeToClass($type));
463 118
    }
464
465
    /**
466
     * Convert a string type to full class name.
467
     *
468
     * @param  string  $type
469
     * @return string
470
     */
471
    public function typeToClass($type)
472 118
    {
473
        $class = Str::studly($type);
474 118
475
        $class = '\\Fields\\'.ucwords($class).'\\'.ucwords($class);
476 118
477
        foreach ($this->namespaces as $namespace) {
478 118
            if (class_exists($namespace.$class)) {
479 118
                return $namespace.$class;
480
            }
481 10
        }
482
    }
483
484
    /**
485
     * Get the validation errors. With option to
486
     * get only for a specific field.
487
     *
488
     * @param  string  $name
489
     * @return array     
490
     */
491
    public function errors($name = null)
492
    {
493
        if ($this->submitted()) {
494
            $this->validate();
495
        }
496
497
        if ( ! is_null($name)) {
498
            return $this->field($name)->errors();
499
        }
500
501
        $errors = [];
502
503
        foreach ($this->fields as $field) {
504
            foreach($field->errors() as $error) {
505
                $errors[] = $error;
506
            }
507
        }
508
509
        return $errors;
510
    }
511
512 28
    /**
513
     * Perform validation on the form. 
514 28
     *
515
     * @return void
516 28
     */
517
    public function validate()
518 28
    {
519 28
        $this->setValues();
520
521
        $this->broadcast('validate');
522 28
523 28
        foreach ($this->fields as $field) {
524
            $field->runValidations();
525
        }
526
527
        $this->broadcast('validated');
528
    }
529
530
    /**
531
     * Perform validation on the form. With option
532 27
     * to check if a particular field is valid.
533
     *
534 27
     * @param  string  $name
535
     * @return bool
536 27
     */
537
    public function valid($name = null)
538 27
    {
539
        $this->validate();
540 27
541 26
        $fields = is_null($name) ? $this->fields : [$this->field($name)];
542 27
543
        foreach ($fields as $field) {
544
545
            if ($field->isInvalid()) {
546 27
                $this->broadcast('invalid');
547 27
                return false;
548
            }
549
        }
550
551
        $this->broadcast('valid');
552
        return true;
553
    }
554
555
    /**
556
     * The opposite of valid.
557
     *
558
     * @param  string  $name
559
     * @return bool
560
     */
561
    public function invalid($name = null)
562
    {
563
        return ! $this->valid($name);
564
    }   
565
566
    /**
567 1
     * Set the active language.
568
     *
569 1
     * @param  string  $lang
570 1
     * @return void
571
     */
572
    public function setLanguage($lang)
573
    {
574
        $this->lang = $lang;
575
    }
576
577
    /**
578 134
     * Set the template package.
579
     *
580 134
     * @param  string  $template
581 4
     * @return void
582
     */
583
    public function setTemplate($template)
584 134
    {
585
        if ( ! is_null($this->template)) {
586 134
            $this->uninstallTemplate($this->template);
587 134
        }
588
589
        $this->installTemplate($template);
590
        
591
        $this->template = $template;
592
    }
593
594
    /**
595 134
     * Get template configuration.
596
     *
597 134
     * @param  string  $template
598
     * @return array
599 134
     */
600
    public function templateConfig($template)
601 134
    {
602
        $paths = $this->paths(null, 'templates/'.$template);
603 134
604 134
        foreach ($paths as $path) {
605
            
606
            $config = $path.'config.php';
607
            
608 4
            if (file_exists($config)) {
609
                return include($config);
610
            }
611
        }
612
613
        return [];
614
    }   
615
616
    /**
617 134
     * Install template configuration.
618
     *
619 134
     * @param  string  $template
620
     * @return void
621 134
     */
622 134
    public function installTemplate($template)
623 134
    {
624
        $config = $this->templateConfig($template);
625
626 134
        if ( isset($config['plugins']) && is_array($config['plugins'])) {
627
            foreach($config['plugins'] as $key => $plugin) {
628
                if (is_array($plugin)) {
629
                    $this->addPlugin($key, $plugin);
630
                } else {
631
                    $this->addPlugin($plugin);
632
                }
633
            }
634 4
        }
635
    }
636 4
637
    /**
638 4
     * Uninstall template configuration.
639 4
     *
640 4
     * @param  string  $template
641
     * @return void
642
     */
643 4
    public function uninstallTemplate($template)
644
    {
645
        $config = $this->templateConfig($template);
646
647
        if ( isset($config['plugins']) && is_array($config['plugins'])) {
648
            foreach($config['plugins'] as $plugin) {
649
                $this->removePlugin($plugin);
650
            }
651 45
        }
652
    }
653
654 45
    /**
655 45
     * Fetch a fields properties.
656 45
     *
657 45
     * @param  \Helmut\Forms\Field  $field
658 45
     * @return string
659 45
     */
660 45
    public function fieldProperties($field) 
661 45
    {   
662
        $properties = [ 
663
            'id' => $field->id, 
664
            'form_id' => $this->id, 
665
            'type' => $field->type, 
666 45
            'name' => $field->name, 
667
            'label' => $field->label,
668 45
            'required' => $field->isRequired(),
669 44
            'valid' => $field->isValid(),
670
            'invalid' => $field->isInvalid(),
671
            'errors' => [],
672 45
            'keys' => [],
673 1
        ];
674
675 1
        $properties = array_merge($properties, $field->properties());
676
677
        foreach ($field->keys() as $key) {
678
            $properties['keys'][] = $key;
679
        }
680
681 1
        if ($field->isInvalid()) {
682
            foreach ($field->errors() as $error => $parameters) {
683 1
684
                if ($error == 'userDefined') {
685 1
                    foreach($parameters as $message) {
686 1
                        $properties['errors'][] = ['error' => $message];
687 1
                    }
688 1
                } else {
689
690 1
                    $parameters['field'] = str_replace('_', ' ', $field->name);
691
692
                    $message = $this->translate($error, $field);
693
694
                    foreach($parameters as $key => $value) {
695 45
                        if (is_object($value) && method_exists($value, '__toString')) {
696
                            $value = (string) $value;
697
                        }
698
                        if (is_array($value)) {
699
                            $value = implode(', ', $value);
700
                        }
701
                        $message = str_replace('['.$key.']', $value, $message);
702
                    }
703
704
                    $properties['errors'][] = ['error' => $message];
705 45
                }
706
            }
707 45
        }
708
709 45
        return $properties;
710
    }
711
712
    /**
713
     * Render the field using templates.
714
     *
715
     * @param  \Helmut\Forms\Field  $field
716
     * @param  array  $properties
717
     * @return string
718
     */
719 45 View Code Duplication
    public function renderField($field, $properties = null) 
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...
720
    {   
721 45
        if (is_null($properties)) {
722
            $properties = $this->fieldProperties($field);
723 45
        }
724
725
        return $this->renderTemplate($field->type, $properties, $field);
726
    }
727
728
    /**
729
     * Render the field using templates.
730
     *
731
     * @param  \Helmut\Forms\Field  $field
732 47
     * @param  array  $properties
733
     * @return string
734 47
     */
735 View Code Duplication
    public function renderFieldErrors($field, $properties = null) 
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...
736 47
    {   
737
        if (is_null($properties)) {
738 47
            $properties = $this->fieldProperties($field);
739
        }
740 47
741
        return $this->renderTemplate('errors', $properties, $field);
742 47
    }   
743 47
744 47
    /**
745 47
     * Render the form using templates.
746 47
     *
747
     * @param  string  $template
748 47
     * @return string
749
     */
750 47
    public function render($template = null)
751
    {
752 45
        $this->broadcast('render');
753
754 45
        $this->setValues();
755
756 45
        if ($this->submitted()) {
757 45
            $this->validate();
758
        }
759 45
760
        if ( ! is_null($template)) {
761 45
            $this->setTemplate($template);
762
        }
763
764 47
        $properties = [];
765
        $properties['id'] = $this->id;
766 47
        $properties['action'] = $this->action;
767
        $properties['csrf'] = $this->request->csrf();
768 47
        $properties['fields'] = [];     
769
770
        $renderered_form = $this->renderTemplate('csrf', $this->request->csrf());
771
772
        foreach ($this->fields as $field) {
773
774
            $field_properties = $this->fieldProperties($field);
775
776
            $properties['fields'][] = $field_properties;
777
778
            $rendered_field = $this->renderField($field, $field_properties);
779 47
            $rendered_field .= $this->renderFieldErrors($field, $field_properties);
780
781 47
            $field_properties['field'] = $rendered_field;
782
783 47
            $renderered_form .= $this->renderTemplate('field', $field_properties, $field);
784
        }
785 47
786
        $properties['form'] = $renderered_form;
787 47
788
        $renderered_template = $this->renderTemplate('form', $properties);
789 47
790
        return $renderered_template;
791
    }
792
793
    /**
794
     * Render a template.
795 47
     *
796
     * @param  string  $template
797
     * @param  array  $properties
798
     * @param  \Helmut\Forms\Field  $field
799
     * @return string
800
     */
801
    public function renderTemplate($template, $properties = [], $field = null)
802
    {
803
        $paths = $this->templatePaths($field);
804
805 1
        $properties['lang'] = $this->translations($field);
806
807 1
        $rendered_template = $this->renderer->render($template, $properties, $paths);
808
809 1
        if (count($this->plugins)) {
810 1
811
            $properties[$template] = $rendered_template;
812
813
            foreach ($this->plugins as $key=>$plugin) {
814
                if ($this->renderer->has($template, $plugin->templatePaths())) {
815
                    $rendered_template = $this->renderer->render($template, $properties, $plugin->templatePaths());
816
                    $properties[$template] = $rendered_template;
817
                }
818
            }
819
        }
820
821
        return $rendered_template;
822 47
    }
823
824 47
    /**
825
     * Translate a specific key.
826 47
     *
827 47
     * @param  string  $key
828 47
     * @param  \Helmut\Forms\Field  $field
829
     * @return string
830
     */
831 47
    public function translate($key, $field = null) 
832
    {
833 47
        $translations = $this->translations($field);
834
835 45
        if (isset($translations[$key])) {
836
            return $translations[$key];
837 45
        }
838 45
839
        throw new \Exception('No translation found for '.$key);
840
    }
841 45
842
    /**
843 45
     * Get translations and cache them if necessary.
844
     *
845
     * @param  \Helmut\Forms\Field  $field
846 45
     * @return array
847
     */
848
    public function translations($field = null) 
849 47
    {
850
        $lang = $this->lang;
851
852
        if ( ! isset($this->translations[$lang])) {
853
            $paths = $this->langPaths();
854
            $this->translations[$lang] = $this->loadTranslations($lang, $paths);
855
        }
856
857
        $translations = $this->translations[$lang];
858
859 47
        if ( ! is_null($field)) {
860
861 47
            if ( ! isset($this->translations[$field->type][$lang])) {
862
863 47
                if ( ! isset($this->translations[$field->type])) {
864 47
                    $this->translations[$field->type] = [];
865 47
                }
866 47
867
                $paths = $this->langPaths($field);
868
869
                $paths = array_reverse($paths);
870 47
871
                $this->translations[$field->type][$lang] = $this->loadTranslations($lang, $paths);
872
            }
873
874
            $translations = array_merge($translations, $this->translations[$field->type][$lang]);
875
876
        } 
877
878
        return $translations;
879 134
    }
880
881 134
    /**
882
     * Load the translations from paths.
883 134
     *
884
     * @param  string  $lang
885 134
     * @param  array  $paths
886
     * @return array
887 134
     */
888
    public function loadTranslations($lang, $paths) 
889 134
    {
890 134
        $translations = [];
891 134
892
        foreach ($paths as $path) {
893 134
            $file = $path.$lang.'.php';
894
            if (file_exists($file)) {
895
                $translations = array_merge($translations, include($file));
896
            }
897
        }
898
899
        return $translations;
900
    }
901
902
    /**
903
     * Add a plugin to a form.
904 134
     *
905
     * @param  string  $name
906 134
     * @param  array  $config
907 134
     * @return \Helmut\Forms\Plugin
908
     */
909 134
    public function addPlugin($name, $config = [])
910
    {
911
        $class = Str::studly($name);
912
913
        $class = '\\Plugins\\'.ucwords($class).'\\'.ucwords($class);
914
915
        foreach ($this->namespaces as $namespace) {
916 134
            
917
            $plugin = $namespace.$class;
918 134
            
919 134
            if (class_exists($plugin)) {
920
                $this->plugins[$name] = new $plugin($config);
921 134
                $this->plugins[$name]->event($this, 'load');
922
923
                return $this->plugins[$name];
924
            }
925
        }
926
    }
927
928
    /**
929
     * Remove a plugin.
930 134
     *
931
     * @param  string  $name
932 134
     * @return void
933 134
     */
934
    public function removePlugin($name)
935 134
    {
936
        if (array_key_exists($name, $this->plugins)) {
937
            unset($this->plugins[$name]);
938
        }
939
    }
940
941
    /**
942
     * Get a plugin instance.
943
     *
944 47
     * @param  string  $name
945
     * @return \Helmut\Forms\Plugin
946 47
     */
947
    public function getPlugin($name)
948
    {
949
        return $this->plugins[$name];
950
    }
951
952
    /**
953
     * Remove all plugins.
954
     *
955
     * @return void
956 53
     */
957
    public function removeAllPlugins()
958 53
    {
959
        foreach ($this->plugins as $name => $plugin) {
960
            $this->removePlugin($name);
961
        }
962
    }   
963
964
    /**
965
     * Broadcast an event.
966
     *
967
     * @param  string  $event
968
     * @param  array  $params
969 134
     * @return void
970
     */
971 134
    private function broadcast($event, $params = []) 
972
    {
973 134
        foreach($this->plugins as $plugin) {
974 45
            $plugin->event($this, $event, $params);
975
        }
976
    }
977 134
978 134
    /**
979 134
     * Get all paths to the language files or just to those
980 134
     * for a specific field. 
981
     *
982
     * @param  \Helmut\Forms\Field  $field
983 134
     * @return array
984
     */
985
    public function langPaths($field = null) 
986
    {
987
        return $this->paths($field, 'lang');
988
    }
989
990
    /**
991
     * Get all paths to template packages or just to the 
992 45
     * packages for a specific field.
993
     *
994 45
     * @param  \Helmut\Forms\Field  $field
995
     * @return array
996 45
     */
997 45
    public function templatePaths($field = null) 
998
    {
999 45
        return $this->paths($field, 'templates/'.$this->template);
1000
    }
1001
1002
    /**
1003
     * Get all autoload paths or just the path 
1004
     * of a specific resource.
1005
     *
1006
     * @param  \Helmut\Forms\Field  $field
1007
     * @param  string  $append
1008
     * @return array
1009
     */
1010
    public function paths($field = null, $append = null) 
1011
    {
1012
        $paths = $this->paths;
1013
1014
        if ( ! is_null($field)) {
1015
            array_unshift($paths, $this->pathForClass($field));
1016
        }
1017
1018
        if ( ! is_null($append)) {
1019
            $paths = array_map(function($path) use($append) {
1020
                return $path .= ltrim(rtrim($append, '/'), '/').'/';
1021
            }, $paths);
1022
        }
1023
1024
        return array_filter($paths, 'is_dir');
1025
    }
1026
1027
    /**
1028
     * Get autoload path for a class.
1029 1
     *
1030
     * @param  string|object  $class
1031 1
     * @return string
1032
     */
1033
    public function pathForClass($class)
1034
    {
1035
        $path = Reflect::getDirectory($class);
1036
1037
        return rtrim($path, '/').'/';
1038
    }
1039
1040
1041
    /**
1042
     * Set the form action.
1043
     *
1044
     * @param  string  $action     
1045
     * @return void
1046
     */
1047
    public function setAction($action)
1048
    {
1049 134
        $this->action = $action;
1050
    }
1051 134
1052 134
    /**
1053
     * Get the active template package.
1054
     *
1055 134
     * @return string
1056
     */
1057
    public function getTemplate()
1058
    {
1059
        return $this->template;
1060
    }
1061
1062
    /**
1063
     * Get the request implementation.
1064
     *
1065
     * @return \Helmut\Forms\Request
1066
     */
1067
    public function getRequest()
1068
    {
1069
        return $this->request;
1070
    }   
1071
1072
    /**
1073
     * Get the renderer implementation.
1074
     *
1075
     * @return \Helmut\Forms\Renderer
1076 118
     */
1077
    public function getRenderer()
1078 118
    {
1079
        return $this->renderer;
1080 118
    } 
1081 118
1082
    /**
1083
     * Get all of the plugins
1084 10
     *
1085
     * @return array
1086
     */
1087
    public function getPlugins()
1088
    {
1089
        return $this->plugins;
1090
    }
1091
1092
    /**
1093
     * Get all of the namespaces
1094
     *
1095
     * @return array
1096
     */
1097
    public function getNamespaces()
1098
    {
1099
        return $this->namespaces;
1100
    }       
1101
1102
    /**
1103
     * Requests directly on the object could be trying to
1104
     * create a field so check if type exists.
1105
     *
1106
     * @param  string  $method
1107
     * @param  array  $parameters
1108
     * @return mixed
1109
     */
1110
    public function __call($method, $parameters)
1111
    {
1112
        if ( ! method_exists($this, $method))
1113
        {
1114
            if ( $this->typeExists($method)) {
1115
                return $this->addField($method, array_shift($parameters));
1116
            }
1117
        }
1118
    }
1119
1120
    /**
1121
     * Render the form.
1122
     *
1123
     * @return string
1124
     */
1125
    public function __toString()
1126
    {
1127
        return $this->render();
1128
    }   
1129
1130
}
1131