Passed
Push — master ( ca4e2d...533f2e )
by Derek Stephen
13:15 queued 11:23
created

FormFactory::createFromEntity()   B

Complexity

Conditions 8
Paths 26

Size

Total Lines 46
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 8.1373

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 31
c 2
b 0
f 0
dl 0
loc 46
rs 8.1795
ccs 27
cts 31
cp 0.871
cc 8
nc 26
nop 2
crap 8.1373
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Del\Form\Factory;
6
7
use DateTimeInterface;
8
use Del\Form\Field\Attributes\Field;
9
use Del\Form\Field\CheckBox;
10
use Del\Form\Field\FieldInterface;
11
use Del\Form\Field\FileUpload;
12
use Del\Form\Field\Hidden;
13
use Del\Form\Field\MultiSelect;
14
use Del\Form\Field\Radio;
15
use Del\Form\Field\Select;
16
use Del\Form\Field\Submit;
17
use Del\Form\Field\Text;
18
use Del\Form\Field\Text\EmailAddress;
19
use Del\Form\Field\Text\FloatingPoint;
20
use Del\Form\Field\Text\Integer;
21
use Del\Form\Field\Text\Password;
22
use Del\Form\Field\TextArea;
23
use Del\Form\Form;
24
use Del\Form\FormInterface;
25
use Del\Form\Validator\FileExtensionValidator;
26
use Del\Form\Validator\MaxLength;
27
use Del\Form\Validator\MimeTypeValidator;
28
use Del\Form\Validator\MinLength;
29
use ReflectionClass;
30
use function array_shift;
31
use function count;
32
use function explode;
33
use function strpos;
34
35
class FormFactory
36
{
37
    private Form $form;
38
39 1
    public function createFromEntity(string $name, object $entity): FormInterface
40
    {
41 1
        $this->form = new Form($name);
42 1
        $mirror = new ReflectionClass($entity);
43 1
        $properties = $mirror->getProperties();
44
45 1
        foreach ($properties as $property) {
46 1
            $fieldName = $property->getName();
47 1
            $attributes = $property->getAttributes(Field::class);
48
49 1
            if (count($attributes) > 0) {
50 1
                $instance = $attributes[0]->newInstance();
51 1
                $rules = $instance->rules;
52 1
                $fieldClass = $instance->fieldClass;
53
54 1
                if (strpos($rules, '|') !== false) {
55 1
                    $rules = explode('|', $rules);
56 1
                    $fieldType = array_shift($rules);
57
                } else {
58 1
                    $fieldType = $rules;
59 1
                    $rules = [];
60
                }
61
62 1
                if (strpos($fieldType, 'date_format') !== false) {
63
                    $fieldType = strpos($fieldType, 'H:i') !== false
64
                        ? 'datetime'
65
                        : 'date';
66
                }
67
68 1
                $field = $this->createField($fieldName, $fieldType, $fieldClass);
69 1
                $this->addValidators($field, $rules);
70 1
                $value = $property->isInitialized($entity)
71 1
                    ? $property->getValue($entity)
72
                    : null;
73 1
                $this->setValue($field, $value);
74 1
                $this->form->addField($field);
75
76 1
                if ($field instanceof FileUpload) {
77 1
                    $this->form->setEncType(Form::ENC_TYPE_MULTIPART_FORM_DATA);
78
                }
79
            }
80
        }
81
82 1
        $this->form->addField(new Submit('submit'));
83
84 1
        return $this->form;
85
    }
86
87 1
    private function createField(string $fieldName, string $fieldType, string $fieldClass = null): FieldInterface
88
    {
89
        switch ($fieldType) {
90 1
            case 'bool':
91 1
            case 'boolean':
92 1
            case 'checkbox':
93 1
                $field = new CheckBox($fieldName);
94 1
                break;
95 1
            case 'custom':
96
                if ($fieldClass === null) {
97
                    throw new \Exception('You must set a field class for a custom type');
98
                }
99
100
                $field = new $fieldClass($fieldName);
101
                break;
102 1
            case 'date':
103
                $field = new Text\Date($fieldName);
104
                break;
105 1
            case 'datetime':
106 1
                $field = new Text\DateTime($fieldName);
107 1
                break;
108 1
            case 'email':
109 1
                $field = new EmailAddress($fieldName);
110 1
                break;
111 1
            case 'file':
112 1
                $field = new FileUpload($fieldName);
113 1
                break;
114 1
            case 'float':
115 1
                $field = new FloatingPoint($fieldName);
116 1
                break;
117 1
            case 'hidden':
118 1
                $field = new Hidden($fieldName);
119 1
                break;
120 1
            case 'integer':
121 1
                $field = new Integer($fieldName);
122 1
                break;
123 1
            case 'multiselect':
124 1
                $field = new MultiSelect($fieldName);
125 1
                break;
126 1
            case 'password':
127 1
                $field = new Password($fieldName);
128 1
                break;
129 1
            case 'radio':
130 1
                $field = new Radio($fieldName);
131 1
                break;
132 1
            case 'select':
133 1
                $field = new Select($fieldName);
134 1
                break;
135 1
            case 'textarea':
136 1
                $field = new TextArea($fieldName);
137 1
                break;
138
            case 'string':
139
            case 'text':
140
            default:
141
                $field = new Text($fieldName);
142
                break;
143
        }
144
145 1
        $field->setLabel($fieldName);
146
147 1
        if ($field->getAttribute('placeholder') === null) {
148 1
            $field->setAttribute('placeholder', 'Enter ' . $fieldName . '...');
149
        }
150
151 1
        return $field;
152
    }
153
154 1
    private function addValidators(FieldInterface $field, array $rules): void
155
    {
156 1
        foreach ($rules as $rule) {
157 1
            $arg = null;
158
159 1
            if (strpos($rule, ':') !== false) {
160 1
                $debris = explode(':', $rule);
161 1
                $rule = $debris[0];
162 1
                $arg = $debris[1];
163
            }
164
165
            switch ($rule) {
166 1
                case 'file_ext':
167 1
                    $extensions = explode(',', $arg);
168 1
                    $field->addValidator(new FileExtensionValidator($extensions));
169 1
                    break;
170 1
                case 'max':
171 1
                    $field->addValidator(new MaxLength((int) $arg));
172 1
                    break;
173 1
                case 'mime':
174 1
                    $mimeTypes = explode(',', $arg);
175 1
                    $field->addValidator(new MimeTypeValidator($mimeTypes, $field->getName()));
176 1
                    break;
177 1
                case 'min':
178 1
                    $field->addValidator(new MinLength((int) $arg));
179 1
                    break;
180 1
                case 'required':
181 1
                    $field->setRequired(true);
182 1
                    break;
183 1
                case 'upload':
184 1
                    if ($field instanceof FileUpload) {
185 1
                        $field->setUploadDirectory($arg);
186
                    }
187 1
                    break;
188
            }
189
        }
190
    }
191
192 1
    private function setValue(FieldInterface $field, mixed $value): void
193
    {
194 1
        if ($value instanceof DateTimeInterface) {
195
//            die(var_dump($field));
196 1
            $value = $value->format('');
197
        }
198
199 1
        if ($value !== null) {
200 1
            $field->setValue($value);
201
        }
202
    }
203
}
204