Completed
Push — master ( 976295...cf57a5 )
by Kristijan
03:22
created

CollectionType::createChildren()   C

Complexity

Conditions 14
Paths 81

Size

Total Lines 57

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 14.0072

Importance

Changes 0
Metric Value
cc 14
nc 81
nop 0
dl 0
loc 57
rs 6.2666
c 0
b 0
f 0
ccs 29
cts 30
cp 0.9667
crap 14.0072

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 Kris\LaravelFormBuilder\Fields;
4
5
use Illuminate\Support\Collection;
6
7
class CollectionType extends ParentType
8
{
9
    /**
10
     * Contains template for a collection element.
11
     *
12
     * @var FormField
13
     */
14
    protected $proto;
15
16
    /**
17
     * @inheritdoc
18
     */
19
    protected $valueProperty = 'data';
20
21
    /**
22
     * @return string
23
     */
24 12
    protected function getTemplate()
25
    {
26 12
        return 'collection';
27
    }
28
29
    /**
30
     * @inheritdoc
31
     */
32 12
    protected function getDefaults()
33
    {
34
        return [
35 12
            'type' => null,
36
            'options' => ['is_child' => true],
37
            'prototype' => true,
38
            'data' => null,
39
            'property' => 'id',
40
            'prototype_name' => '__NAME__',
41
            'empty_row' => true
42
        ];
43
    }
44
45
    /**
46
     * Get the prototype object.
47
     *
48
     * @return FormField
49
     * @throws \Exception
50
     */
51 4
    public function prototype()
52
    {
53
54 4
        if ($this->getOption('prototype') === false) {
55 1
            throw new \Exception(
56 1
                'Prototype for collection field [' . $this->name .'] is disabled.'
57
            );
58
        }
59
60 3
        return $this->proto;
61
    }
62
63
    /**
64
     * @inheritdoc
65
     */
66
    public function getAllAttributes()
67
    {
68
        // Collect all children's attributes.
69
        return $this->parent->getFormHelper()->mergeAttributes($this->children);
70
    }
71
72
    /**
73
     * @inheritdoc
74
     */
75 12
    protected function createChildren()
76
    {
77 12
        $this->children = [];
78 12
        $type = $this->getOption('type');
79 12
        $oldInput = $this->parent->getRequest()->old($this->getNameKey());
80 12
        $currentInput = $this->parent->getRequest()->input($this->getNameKey());
81
82
        try {
83 12
            $fieldType = $this->formHelper->getFieldType($type);
84 1
        } catch (\Exception $e) {
85 1
            throw new \Exception(
86 1
                'Collection field ['.$this->name.'] requires [type] option'. "\n\n".
87 1
                $e->getMessage()
88
            );
89
        }
90
91 11
        $data = $this->getOption($this->valueProperty, []);
92
93
        // If no value is provided, get values from current request.
94 11
        if (!is_null($data) && count($data) === 0) {
95
            $data = $currentInput;
96
        }
97
98
        // Needs to have more than 1 item because 1 is rendered by default.
99
        // This overrides current request in situations when validation fails.
100 11
        if ($oldInput && count($oldInput) > 1) {
101 1
            $data = $oldInput;
102
        }
103
104 11
        if ($data instanceof Collection) {
105 2
            $data = $data->all();
106
        }
107
108 11
        $field = new $fieldType($this->name, $type, $this->parent, $this->getOption('options'));
109
110 11
        if ($this->getOption('prototype')) {
111 10
            $this->generatePrototype(clone $field);
112
        }
113
114 11
        if (!$data || empty($data)) {
115 4
            if ($this->getOption('empty_row')) {
116 3
                return $this->children[] = $this->setupChild(clone $field, '[0]');
117
            }
118
119 1
            return $this->children = [];
120
        }
121
122 7
        if (!is_array($data) && !$data instanceof \Traversable) {
123 1
            throw new \Exception(
124 1
                'Data for collection field ['.$this->name.'] must be iterable.'
125
            );
126
        }
127
128 6
        foreach ($data as $key => $val) {
129 6
            $this->children[] = $this->setupChild(clone $field, '['.$key.']', $val);
130
        }
131 6
    }
132
133
    /**
134
     * Set up a single child element for a collection.
135
     *
136
     * @param FormField $field
137
     * @param           $name
138
     * @param null      $value
139
     * @return FormField
140
     */
141 11
    protected function setupChild(FormField $field, $name, $value = null)
142
    {
143 11
        $newFieldName = $field->getName().$name;
144
145 11
        $firstFieldOptions = $this->formHelper->mergeOptions(
146 11
            $this->getOption('options'),
147 11
            ['attr' => ['id' => $newFieldName]]
148
        );
149
150 11
        $field->setName($newFieldName);
151 11
        $field->setOptions($firstFieldOptions);
152
153 11
        if ($value && !$field instanceof ChildFormType) {
154 2
            $value = $this->getModelValueAttribute(
155 2
                $value,
156 2
                $this->getOption('property')
157
            );
158
        }
159
160 11
        $field->setValue($value);
161
162
163 11
        return $field;
164
    }
165
166
    /**
167
     * Generate prototype for regular form field.
168
     *
169
     * @param FormField $field
170
     * @return void
171
     */
172 10
    protected function generatePrototype(FormField $field)
173
    {
174 10
        $value = $field instanceof ChildFormType ? false : null;
175 10
        $field->setOption('is_prototype', true);
176 10
        $field = $this->setupChild($field, $this->getPrototypeName(), $value);
177
178 10
        if ($field instanceof ChildFormType) {
179 5
            foreach ($field->getChildren() as $child) {
180 4
                if ($child instanceof CollectionType) {
181 4
                    $child->preparePrototype($child->prototype());
182
                }
183
            }
184
        }
185
186 10
        $this->proto = $field;
187 10
    }
188
189
    /**
190
     * Generate array like prototype name.
191
     *
192
     * @return string
193
     */
194 10
    protected function getPrototypeName()
195
    {
196 10
        return '[' . $this->getOption('prototype_name') . ']';
197
    }
198
199
    /**
200
     * Prepare collection for prototype by adding prototype as child.
201
     *
202
     * @param FormField $field
203
     * @return void
204
     */
205
    public function preparePrototype(FormField $field)
206
    {
207
        if (!$field->getOption('is_prototype')) {
208
            throw new \InvalidArgumentException(
209
                'Field ['.$field->getRealName().'] is not a valid prototype object.'
210
            );
211
        }
212
213
        $this->children = [];
214
        $this->children[] = $field;
215
    }
216
}
217