Passed
Pull Request — 1.2 (#405)
by
unknown
08:49
created

HandleBlocks::getChildBlocks()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 4.944

Importance

Changes 0
Metric Value
cc 3
eloc 9
c 0
b 0
f 0
nc 3
nop 2
dl 0
loc 16
ccs 4
cts 10
cp 0.4
crap 4.944
rs 9.9666
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 Illuminate\Support\Collection;
8
use Schema;
9
10
trait HandleBlocks
11
{
12
    /**
13
     * @param \A17\Twill\Models\Model $object
14
     * @param array $fields
15
     * @return \A17\Twill\Models\Model|void
16
     */
17 2
    public function hydrateHandleBlocks($object, $fields)
18
    {
19 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

19
        if ($this->/** @scrutinizer ignore-call */ shouldIgnoreFieldBeforeSave('blocks')) {
Loading history...
20
            return;
21
        }
22
23 2
        $blocksCollection = Collection::make();
24 2
        $blocksFromFields = $this->getBlocks($object, $fields);
25 2
        $blockRepository = app(BlockRepository::class);
26
27 2
        $fakeBlockId = 1;
28
29 2
        foreach ($blocksFromFields as $block) {
30 1
            $newBlock = $blockRepository->createForPreview($block);
31
32 1
            $newBlock->id = $fakeBlockId;
33 1
            $fakeBlockId++;
34
35 1
            $childBlocksCollection = Collection::make();
36
37 1
            foreach ($block['blocks'] as $childBlock) {
38
                $childBlock['parent_id'] = $newBlock->id;
39
40
                $newChildBlock = $blockRepository->createForPreview($childBlock);
41
42
                $newChildBlock->id = $fakeBlockId;
43
                $fakeBlockId++;
44
45
                $blocksCollection->push($newChildBlock);
46
                $childBlocksCollection->push($newChildBlock);
47
            }
48
49 1
            $newBlock->setRelation('children', $childBlocksCollection);
50
51 1
            $blocksCollection->push($newBlock);
52
        }
53
54 2
        $object->setRelation('blocks', $blocksCollection);
55
56 2
        return $object;
57
    }
58
59
    /**
60
     * @param \A17\Twill\Models\Model $object
61
     * @param array $fields
62
     * @return void
63
     */
64 17
    public function afterSaveHandleBlocks($object, $fields)
65
    {
66 17
        if ($this->shouldIgnoreFieldBeforeSave('blocks')) {
67
            return;
68
        }
69
70 17
        $blockRepository = app(BlockRepository::class);
71
72 17
        $blockRepository->bulkDelete($object->blocks()->pluck('id')->toArray());
73
        $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...
74 2
            $this->createBlock($blockRepository, $block);
75 17
        });
76 17
    }
77
78
    /**
79
     * Create a block from formFields, and recursively create it's child blocks
80
     *
81
     * @param  \A17\Twill\Repositories\BlockRepository $blockRepository
82
     * @param  array $blockFields
83
     *
84
     * @return \A17\Twill\Models\Block $blockCreated
85
     */
86 2
    private function createBlock(BlockRepository $blockRepository, $blockFields)
87
    {
88 2
        $blockCreated = $blockRepository->create($blockFields);
89
90
        // Handle child blocks
91
        $blockFields['blocks']->each(function ($childBlock) use ($blockCreated, $blockRepository) {
92
            $childBlock['parent_id'] = $blockCreated->id;
93
            $this->createBlock($blockRepository, $childBlock);
94 2
        });
95
96 2
        return $blockCreated;
97
    }
98
99
    /**
100
     * @param \A17\Twill\Models\Model $object
101
     * @param array $fields
102
     * @return \Illuminate\Support\Collection
103
     */
104 17
    private function getBlocks($object, $fields)
105
    {
106 17
        $blocks = Collection::make();
107 17
        if (isset($fields['blocks']) && is_array($fields['blocks'])) {
108
109 2
            foreach ($fields['blocks'] as $index => $block) {
110 2
                $block = $this->buildBlock($block, $object);
111 2
                $block['position'] = $index + 1;
112 2
                $block['blocks'] = $this->getChildBlocks($object, $block);
113
114 2
                $blocks->push($block);
115
            }
116
        }
117
118 17
        return $blocks;
119
    }
120
121
    /**
122
     * Recursively generate child blocks from the fields of a block
123
     *
124
     * @param  \A17\Twill\Models\Model $object
125
     * @param  array $parentBlockFields
126
     *
127
     * @return \Illuminate\Support\Collection
128
     */
129 2
    private function getChildBlocks($object, $parentBlockFields)
130
    {
131 2
        $childBlocksList = Collection::make();
132
133 2
        foreach ($parentBlockFields['blocks'] as $childKey => $childBlocks) {
134
            foreach ($childBlocks as $index => $childBlock) {
135
                $childBlock = $this->buildBlock($childBlock, $object, true);
136
                $childBlock['child_key'] = $childKey;
137
                $childBlock['position'] = $index + 1;
138
                $childBlock['blocks'] = $this->getChildBlocks($object, $childBlock);
139
140
                $childBlocksList->push($childBlock);
141
            }
142
        }
143
144 2
        return $childBlocksList;
145
    }
146
147
    /**
148
     * @param array $block
149
     * @param \A17\Twill\Models\Model $object
150
     * @param bool $repeater
151
     * @return array
152
     */
153 2
    private function buildBlock($block, $object, $repeater = false)
154
    {
155 2
        $block['blockable_id'] = $object->id;
156 2
        $block['blockable_type'] = $object->getMorphClass();
157
158 2
        return app(BlockRepository::class)->buildFromCmsArray($block, $repeater);
159
    }
160
161
    /**
162
     * @param \A17\Twill\Models\Model $object
163
     * @param array $fields
164
     * @return array
165
     */
166 4
    public function getFormFieldsHandleBlocks($object, $fields)
167
    {
168 4
        $fields['blocks'] = null;
169
170 4
        if ($object->has('blocks')) {
171
172 4
            $blocksConfig = config('twill.block_editor');
173
174 4
            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...
175
176 1
                $isInRepeater = isset($block->parent_id);
177 1
                $configKey = $isInRepeater ? 'repeaters' : 'blocks';
178 1
                $blockTypeConfig = $blocksConfig[$configKey][$block->type] ?? null;
179
180 1
                if (is_null($blockTypeConfig)) {
181
                    continue;
182
                }
183
184
                $blockItem = [
185 1
                    'id' => $block->id,
186 1
                    'type' => $blockTypeConfig['component'],
187 1
                    'title' => $blockTypeConfig['title'],
188 1
                    'attributes' => $blockTypeConfig['attributes'] ?? [],
189
                ];
190
191 1
                if ($isInRepeater) {
192
                    $fields['blocksRepeaters']["blocks-{$block->parent_id}_{$block->child_key}"][] = $blockItem + [
193
                        'trigger' => $blockTypeConfig['trigger'],
194
                    ] + (isset($blockTypeConfig['max']) ? [
195
                        'max' => $blockTypeConfig['max'],
196
                    ] : []);
197
                } else {
198 1
                    $fields['blocks'][] = $blockItem + [
199 1
                        'icon' => $blockTypeConfig['icon'],
200
                    ];
201
                }
202
203
                $fields['blocksFields'][] = Collection::make($block['content'])->filter(function ($value, $key) {
204 1
                    return $key !== "browsers";
205
                })->map(function ($value, $key) use ($block) {
206
                    return [
207 1
                        'name' => "blocks[$block->id][$key]",
208 1
                        'value' => $value,
209
                    ];
210 1
                })->filter()->values()->toArray();
211
212 1
                $blockFormFields = app(BlockRepository::class)->getFormFields($block);
213
214 1
                $medias = $blockFormFields['medias'];
215
216 1
                if ($medias) {
217
                    if (config('twill.media_library.translated_form_fields', false)) {
218
                        $fields['blocksMedias'][] = Collection::make($medias)->mapWithKeys(function ($mediasByLocale, $locale) use ($block) {
219
                            return Collection::make($mediasByLocale)->mapWithKeys(function ($value, $key) use ($block, $locale) {
220
                                return [
221
                                    "blocks[$block->id][$key][$locale]" => $value,
222
                                ];
223
                            });
224
                        })->filter()->toArray();
225
                    } else {
226
                        $fields['blocksMedias'][] = Collection::make($medias)->mapWithKeys(function ($value, $key) use ($block) {
227
                            return [
228
                                "blocks[$block->id][$key]" => $value,
229
                            ];
230
                        })->filter()->toArray();
231
                    }
232
                }
233
234 1
                $files = $blockFormFields['files'];
235
236 1
                if ($files) {
237
                    Collection::make($files)->each(function ($rolesWithFiles, $locale) use (&$fields, $block) {
238
                        $fields['blocksFiles'][] = Collection::make($rolesWithFiles)->mapWithKeys(function ($files, $role) use ($locale, $block) {
239
                            return [
240
                                "blocks[$block->id][$role][$locale]" => $files,
241
                            ];
242
                        })->toArray();
243
                    });
244
                }
245
246 1
                if (isset($block['content']['browsers'])) {
247
                    $fields['blocksBrowsers'][] = $this->getBlockBrowsers($block);
248
                }
249
            }
250
251 4
            if ($fields['blocksFields'] ?? false) {
252 1
                $fields['blocksFields'] = call_user_func_array('array_merge', $fields['blocksFields'] ?? []);
253
            }
254
255 4
            if ($fields['blocksMedias'] ?? false) {
256
                $fields['blocksMedias'] = call_user_func_array('array_merge', $fields['blocksMedias'] ?? []);
257
            }
258
259 4
            if ($fields['blocksFiles'] ?? false) {
260
                $fields['blocksFiles'] = call_user_func_array('array_merge', $fields['blocksFiles'] ?? []);
261
            }
262
263 4
            if ($fields['blocksBrowsers'] ?? false) {
264
                $fields['blocksBrowsers'] = call_user_func_array('array_merge', $fields['blocksBrowsers'] ?? []);
265
            }
266
        }
267
268 4
        return $fields;
269
    }
270
271
    /**
272
     * @param \A17\Twill\Models\Block $block
273
     * @return array
274
     */
275
    protected function getBlockBrowsers($block)
276
    {
277
        return Collection::make($block['content']['browsers'])->mapWithKeys(function ($ids, $relation) use ($block) {
278
            if (Schema::hasTable(config('twill.related_table', 'twill_related')) && $block->getRelated($relation)->isNotEmpty()) {
279
                $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

279
                /** @scrutinizer ignore-call */ 
280
                $items = $this->getFormFieldsForRelatedBrowser($block, $relation);;
Loading history...
280
            } else {
281
                $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

281
                /** @scrutinizer ignore-call */ 
282
                $relationRepository = $this->getModelRepository($relation);
Loading history...
282
                $relatedItems = $relationRepository->get([], ['id' => $ids], [], -1);
283
                $sortedRelatedItems = array_flip($ids);
284
285
                foreach ($relatedItems as $item) {
286
                    $sortedRelatedItems[$item->id] = $item;
287
                }
288
289
                $items = Collection::make(array_values($sortedRelatedItems))->filter(function ($value) {
290
                    return is_object($value);
291
                })->map(function ($relatedElement) use ($relation) {
292
                    return [
293
                        'id' => $relatedElement->id,
294
                        'name' => $relatedElement->titleInBrowser ?? $relatedElement->title,
295
                        'edit' => moduleRoute($relation, config('twill.block_editor.browser_route_prefixes.' . $relation), 'edit', $relatedElement->id),
296
                    ] + (classHasTrait($relatedElement, HasMedias::class) ? [
297
                        'thumbnail' => $relatedElement->defaultCmsImage(['w' => 100, 'h' => 100]),
298
                    ] : []);
299
                })->toArray();
300
            }
301
            return [
302
                "blocks[$block->id][$relation]" => $items,
303
            ];
304
        })->filter()->toArray();
305
    }
306
}
307