HandleBlocks::getFormFieldsHandleBlocks()   C
last analyzed

Complexity

Conditions 15
Paths 17

Size

Total Lines 104
Code Lines 64

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 33.6997

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 15
eloc 64
c 2
b 0
f 0
nc 17
nop 2
dl 0
loc 104
ccs 31
cts 55
cp 0.5636
crap 33.6997
rs 5.9166

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 A17\Twill\Repositories\Behaviors;
4
5
use A17\Twill\Models\Behaviors\HasMedias;
6
use A17\Twill\Repositories\BlockRepository;
7
use A17\Twill\Services\Blocks\BlockCollection;
8
use Illuminate\Support\Collection;
9
use Log;
10
use Schema;
11
use Symfony\Component\Routing\Exception\RouteNotFoundException;
12
13
trait HandleBlocks
14
{
15
    /**
16
     * @param \A17\Twill\Models\Model $object
17
     * @param array $fields
18 2
     * @param int $fakeBlockId
19
     * @param int|null $parentId
20 2
     * @param \Illuminate\Support\Collection|null $blocksFromFields
21
     * @param \Illuminate\Support\Collection|null $mainCollection
22
     * @param int|null $mainCollection|void
23
     * @return \A17\Twill\Models\Model
24 2
     */
25 2
    public function hydrateHandleBlocks($object, $fields, &$fakeBlockId = 0, $parentId = null, $blocksFromFields = null, $mainCollection = null)
26 2
    {
27 2
        if ($this->shouldIgnoreFieldBeforeSave('blocks')) {
0 ignored issues
show
Bug introduced by
It seems like shouldIgnoreFieldBeforeSave() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

27
        if ($this->/** @scrutinizer ignore-call */ shouldIgnoreFieldBeforeSave('blocks')) {
Loading history...
28 2
            return;
29
        }
30 2
31 2
        $firstItem = false;
32
        $blocksCollection = Collection::make();
0 ignored issues
show
Unused Code introduced by
The assignment to $blocksCollection is dead and can be removed.
Loading history...
33
        if ($mainCollection === null) {
34 2
            $firstItem = true;
35 2
            $mainCollection = Collection::make();
36 2
        }
37 2
        if ($blocksFromFields === null) {
38
            $blocksFromFields = $this->getBlocks($object, $fields);
39
        }
40 2
41
        $blockRepository = app(BlockRepository::class);
42 2
        $blocksCollection = $this->getChildrenBlocks($blocksFromFields, $blockRepository, $parentId, $fakeBlockId, $mainCollection);
43
        $object->setRelation('blocks', $firstItem ? $mainCollection : $blocksCollection);
44 2
        return $object;
45 1
    }
46
47
    protected function getChildrenBlocks($blocks, $blockRepository, $parentId, &$fakeBlockId, $mainCollection)
48 1
    {
49
        $childBlocksCollection = Collection::make();
50 1
51 1
        foreach ($blocks as $childBlock) {
52 1
            if ($parentId) {
53 1
                $childBlock['parent_id'] = $parentId;
54 1
            }
55
            $newChildBlock = $blockRepository->createForPreview($childBlock);
56
57 1
            $fakeBlockId++;
58 1
            $newChildBlock->id = $fakeBlockId;
59
            if (!empty($childBlock['blocks'])) {
60 2
                $childBlockHydrated = $this->hydrateHandleBlocks($newChildBlock, $childBlock, $fakeBlockId, $newChildBlock->id, $childBlock['blocks'], $mainCollection);
61
                $newChildBlock->setRelation('children', $childBlockHydrated->blocks);
0 ignored issues
show
Bug introduced by
The property blocks does not seem to exist on A17\Twill\Models\Model. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
62
            }
63
64
            $mainCollection->push($newChildBlock);
65
            $childBlocksCollection->push($newChildBlock);
66
        }
67
        return $childBlocksCollection;
68 21
    }
69
70 21
    /**
71
     * @param \A17\Twill\Models\Model $object
72
     * @param array $fields
73
     * @return void
74 21
     */
75
    public function afterSaveHandleBlocks($object, $fields)
76 21
    {
77 21
        if ($this->shouldIgnoreFieldBeforeSave('blocks')) {
78 2
            return;
79 21
        }
80 21
81
        $blockRepository = app(BlockRepository::class);
82
83
        $blockRepository->bulkDelete($object->blocks()->pluck('id')->toArray());
84
        $this->getBlocks($object, $fields)->each(function ($block) use ($object, $blockRepository) {
0 ignored issues
show
Unused Code introduced by
The import $object is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
85
            $this->createBlock($blockRepository, $block);
86
        });
87
    }
88
89
    /**
90 2
     * Create a block from formFields, and recursively create it's child blocks
91
     *
92 2
     * @param  \A17\Twill\Repositories\BlockRepository $blockRepository
93
     * @param  array $blockFields
94
     * @return \A17\Twill\Models\Block $blockCreated
95 2
     */
96
    private function createBlock(BlockRepository $blockRepository, $blockFields)
97
    {
98 2
        $blockCreated = $blockRepository->create($blockFields);
99
100 2
        // Handle child blocks
101
        $blockFields['blocks']->each(function ($childBlock) use ($blockCreated, $blockRepository) {
102
            $childBlock['parent_id'] = $blockCreated->id;
103
            $this->createBlock($blockRepository, $childBlock);
104
        });
105
106
        return $blockCreated;
107
    }
108 21
109
    /**
110 21
     * @param \A17\Twill\Models\Model $object
111 21
     * @param array $fields
112
     * @return \Illuminate\Support\Collection
113 2
     */
114 2
    private function getBlocks($object, $fields)
115 2
    {
116 2
        $blocks = Collection::make();
117
        if (isset($fields['blocks']) && is_array($fields['blocks'])) {
118 2
            foreach ($fields['blocks'] as $index => $block) {
119
                $block = $this->buildBlock($block, $object);
120
                $block['position'] = $index + 1;
121 21
                $block['blocks'] = $this->getChildBlocks($object, $block);
122
123
                $blocks->push($block);
124
            }
125
        }
126
        return $blocks;
127
    }
128
129
    /**
130
     * Recursively generate child blocks from the fields of a block
131
     *
132 2
     * @param  \A17\Twill\Models\Model $object
133
     * @param  array $parentBlockFields
134 2
     * @return \Illuminate\Support\Collection
135
     */
136 2
    private function getChildBlocks($object, $parentBlockFields)
137
    {
138
        $childBlocksList = Collection::make();
139
140
        foreach ($parentBlockFields['blocks'] as $childKey => $childBlocks) {
141
            foreach ($childBlocks as $index => $childBlock) {
142
                $childBlock = $this->buildBlock($childBlock, $object, true);
143
                $childBlock['child_key'] = $childKey;
144
                $childBlock['position'] = $index + 1;
145
                $childBlock['editor_name'] = $parentBlockFields['editor_name'] ?? 'default';
146
                $childBlock['blocks'] = $this->getChildBlocks($object, $childBlock);
147 2
148
                $childBlocksList->push($childBlock);
149
            }
150
        }
151
152
        return $childBlocksList;
153
    }
154
155
    /**
156 2
     * @param array $block
157
     * @param \A17\Twill\Models\Model $object
158 2
     * @param bool $repeater
159 2
     * @return array
160
     */
161 2
    private function buildBlock($block, $object, $repeater = false)
162
    {
163
        $block['blockable_id'] = $object->id;
164
        $block['blockable_type'] = $object->getMorphClass();
165
166
        return app(BlockRepository::class)->buildFromCmsArray($block, $repeater);
167
    }
168
169 5
    /**
170
     * @param \A17\Twill\Models\Model $object
171 5
     * @param array $fields
172
     * @return array
173 5
     */
174
    public function getFormFieldsHandleBlocks($object, $fields)
175 5
    {
176
        $fields['blocks'] = null;
177 5
178
        if ($object->has('blocks')) {
179 1
            $blocksList = app(BlockCollection::class)->list()->keyBy('name');
180 1
181 1
            foreach ($object->blocks as $block) {
0 ignored issues
show
Bug introduced by
The property blocks does not seem to exist on A17\Twill\Models\Model. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
182
                $isInRepeater = isset($block->parent_id);
183 1
                $configKey = $isInRepeater ? 'repeaters' : 'blocks';
0 ignored issues
show
Unused Code introduced by
The assignment to $configKey is dead and can be removed.
Loading history...
184
                $blockTypeConfig = $blocksList[$block->type] ?? null;
185
186
                if (is_null($blockTypeConfig)) {
187
                    continue;
188 1
                }
189 1
190 1
                $blockItem = [
191 1
                    'id' => $block->id,
192
                    'type' => $blockTypeConfig['component'],
193
                    'title' => $blockTypeConfig['title'],
194 1
                    'name' => $block->editor_name ?? 'default',
195
                    'titleField' => $blockTypeConfig['titleField'],
196
                    'hideTitlePrefix' => $blockTypeConfig['hideTitlePrefix'],
197
                    'attributes' => $blockTypeConfig['attributes'] ?? [],
198
                ];
199
200
                if ($isInRepeater) {
201 1
                    $fields['blocksRepeaters']["blocks-{$block->parent_id}_{$block->child_key}"][] = $blockItem + [
202 1
                        'trigger' => $blockTypeConfig['trigger'],
203
                    ] + (isset($blockTypeConfig['max']) ? [
204
                        'max' => $blockTypeConfig['max'],
205
                    ] : []);
206 1
                } else {
207 1
                    $fields['blocks'][$blockItem['name']][] = $blockItem + [
208 1
                        'icon' => $blockTypeConfig['icon'],
209
                    ];
210 1
                }
211 1
212
                $fields['blocksFields'][] = Collection::make($block['content'])->filter(function ($value, $key) {
213 1
                    return $key !== "browsers";
214
                })->map(function ($value, $key) use ($block) {
215 1
                    return [
216
                        'name' => "blocks[$block->id][$key]",
217 1
                        'value' => $value,
218
                    ];
219 1
                })->filter()->values()->toArray();
220
221
                $blockFormFields = app(BlockRepository::class)->getFormFields($block);
222
223
                $medias = $blockFormFields['medias'];
224
225
                if ($medias) {
226
                    if (config('twill.media_library.translated_form_fields', false)) {
227
                        $fields['blocksMedias'][] = Collection::make($medias)->mapWithKeys(function ($mediasByLocale, $locale) use ($block) {
228
                            return Collection::make($mediasByLocale)->mapWithKeys(function ($value, $key) use ($block, $locale) {
229
                                return [
230
                                    "blocks[$block->id][$key][$locale]" => $value,
231
                                ];
232
                            });
233
                        })->filter()->toArray();
234
                    } else {
235
                        $fields['blocksMedias'][] = Collection::make($medias)->mapWithKeys(function ($value, $key) use ($block) {
236
                            return [
237 1
                                "blocks[$block->id][$key]" => $value,
238
                            ];
239 1
                        })->filter()->toArray();
240
                    }
241
                }
242
243
                $files = $blockFormFields['files'];
244
245
                if ($files) {
246
                    Collection::make($files)->each(function ($rolesWithFiles, $locale) use (&$fields, $block) {
247
                        $fields['blocksFiles'][] = Collection::make($rolesWithFiles)->mapWithKeys(function ($files, $role) use ($locale, $block) {
248
                            return [
249 1
                                "blocks[$block->id][$role][$locale]" => $files,
250
                            ];
251
                        })->toArray();
252
                    });
253
                }
254 5
255 1
                if (isset($block['content']['browsers'])) {
256
                    $fields['blocksBrowsers'][] = $this->getBlockBrowsers($block);
257
                }
258 5
            }
259
260
            if ($fields['blocksFields'] ?? false) {
261
                $fields['blocksFields'] = call_user_func_array('array_merge', $fields['blocksFields'] ?? []);
262 5
            }
263
264
            if ($fields['blocksMedias'] ?? false) {
265
                $fields['blocksMedias'] = call_user_func_array('array_merge', $fields['blocksMedias'] ?? []);
266 5
            }
267
268
            if ($fields['blocksFiles'] ?? false) {
269
                $fields['blocksFiles'] = call_user_func_array('array_merge', $fields['blocksFiles'] ?? []);
270
            }
271 5
272
            if ($fields['blocksBrowsers'] ?? false) {
273
                $fields['blocksBrowsers'] = call_user_func_array('array_merge', $fields['blocksBrowsers'] ?? []);
274
            }
275
        }
276
277
        return $fields;
278
    }
279
280
    /**
281
     * @param \A17\Twill\Models\Block $block
282
     * @return array
283
     */
284
    protected function getBlockBrowsers($block)
285
    {
286
        return Collection::make($block['content']['browsers'])->mapWithKeys(function ($ids, $relation) use ($block) {
287
            if (Schema::hasTable(config('twill.related_table', 'twill_related')) && $block->getRelated($relation)->isNotEmpty()) {
288
                $items = $this->getFormFieldsForRelatedBrowser($block, $relation);
0 ignored issues
show
Bug introduced by
It seems like getFormFieldsForRelatedBrowser() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

288
                /** @scrutinizer ignore-call */ 
289
                $items = $this->getFormFieldsForRelatedBrowser($block, $relation);
Loading history...
289
                foreach ($items as &$item) {
290
                    if (!isset($item['edit'])) {
291
                        try {
292
                            $item['edit'] = moduleRoute(
293
                                $relation,
294
                                config('twill.block_editor.browser_route_prefixes.' . $relation),
295
                                'edit',
296
                                $item['id']
297
                            );
298
                        } catch (RouteNotFoundException $e) {
299
                            report($e);
300
                            Log::notice(
301
                                "Twill warning: The url for the \"{$relation}\" browser items can't " .
302
                                "be resolved. You might be missing a {$relation} key in your " .
303
                                "twill.block_editor.browser_route_prefixes configuration."
304
                            );
305
                        }
306
                    }
307
                }
308
            } else {
309
                $relationRepository = $this->getModelRepository($relation);
0 ignored issues
show
Bug introduced by
It seems like getModelRepository() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

309
                /** @scrutinizer ignore-call */ 
310
                $relationRepository = $this->getModelRepository($relation);
Loading history...
310
                $relatedItems = $relationRepository->get([], ['id' => $ids], [], -1);
311
                $sortedRelatedItems = array_flip($ids);
312
313
                foreach ($relatedItems as $item) {
314
                    $sortedRelatedItems[$item->id] = $item;
315
                }
316
317
                $items = Collection::make(array_values($sortedRelatedItems))->filter(function ($value) {
318
                    return is_object($value);
319
                })->map(function ($relatedElement) use ($relation) {
320
                    return [
321
                        'id' => $relatedElement->id,
322
                        'name' => $relatedElement->titleInBrowser ?? $relatedElement->title,
323
                        'edit' => moduleRoute($relation, config('twill.block_editor.browser_route_prefixes.' . $relation), 'edit', $relatedElement->id),
324
                    ] + (classHasTrait($relatedElement, HasMedias::class) ? [
325
                        'thumbnail' => $relatedElement->defaultCmsImage(['w' => 100, 'h' => 100]),
326
                    ] : []);
327
                })->toArray();
328
            }
329
            return [
330
                "blocks[$block->id][$relation]" => $items,
331
            ];
332
        })->filter()->toArray();
333
    }
334
}
335