Completed
Push — develop ( e326d5...b2cbdf )
by Daniel
09:21
created

AbstractComponent::getParentContent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
ccs 0
cts 6
cp 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Silverback\ApiComponentBundle\Entity\Component;
6
7
use ApiPlatform\Core\Annotation\ApiProperty;
8
use Doctrine\Common\Collections\ArrayCollection;
9
use Doctrine\Common\Collections\Collection;
10
use Doctrine\ORM\Mapping as ORM;
11
use Ramsey\Uuid\Uuid;
12
use Silverback\ApiComponentBundle\Entity\Content\AbstractContent;
13
use Silverback\ApiComponentBundle\Entity\Content\ComponentGroup\ComponentGroup;
14
use Silverback\ApiComponentBundle\Entity\DeleteCascadeInterface;
15
use Silverback\ApiComponentBundle\Entity\ValidComponentTrait;
16
use Symfony\Component\Serializer\Annotation\Groups;
17
18
/**
19
 * Class AbstractComponent
20
 * @package Silverback\ApiComponentBundle\Entity\Component
21
 * @author Daniel West <[email protected]>
22
 * @ORM\Entity()
23
 * @ORM\Table(name="component")
24
 * @ORM\InheritanceType("SINGLE_TABLE")
25
 * @ORM\DiscriminatorColumn(name="type", type="string")
26
 * @ORM\DiscriminatorMap({
27
 *     "content" = "Silverback\ApiComponentBundle\Entity\Component\Content\Content",
28
 *     "form" = "Silverback\ApiComponentBundle\Entity\Component\Form\Form",
29
 *     "gallery" = "Silverback\ApiComponentBundle\Entity\Component\Gallery\Gallery",
30
 *     "gallery_item" = "Silverback\ApiComponentBundle\Entity\Component\Gallery\GalleryItem",
31
 *     "hero" = "Silverback\ApiComponentBundle\Entity\Component\Hero\Hero",
32
 *     "feature_columns" = "Silverback\ApiComponentBundle\Entity\Component\Feature\Columns\FeatureColumns",
33
 *     "feature_columns_item" = "Silverback\ApiComponentBundle\Entity\Component\Feature\Columns\FeatureColumnsItem",
34
 *     "feature_stacked" = "Silverback\ApiComponentBundle\Entity\Component\Feature\Stacked\FeatureStacked",
35
 *     "feature_stacked_item" = "Silverback\ApiComponentBundle\Entity\Component\Feature\Stacked\FeatureStackedItem",
36
 *     "feature_text_list" = "Silverback\ApiComponentBundle\Entity\Component\Feature\TextList\FeatureTextList",
37
 *     "feature_text_list_item" = "Silverback\ApiComponentBundle\Entity\Component\Feature\TextList\FeatureTextListItem",
38
 *     "nav_bar" = "Silverback\ApiComponentBundle\Entity\Component\Navigation\NavBar\NavBar",
39
 *     "nav_bar_item" = "Silverback\ApiComponentBundle\Entity\Component\Navigation\NavBar\NavBarItem",
40
 *     "tabs" = "Silverback\ApiComponentBundle\Entity\Component\Navigation\Tabs\Tabs",
41
 *     "tabs_item" = "Silverback\ApiComponentBundle\Entity\Component\Navigation\Tabs\TabsItem",
42
 *     "menu" = "Silverback\ApiComponentBundle\Entity\Component\Navigation\Menu\Menu",
43
 *     "menu_item" = "Silverback\ApiComponentBundle\Entity\Component\Navigation\Menu\MenuItem",
44
 *     "collection" = "Silverback\ApiComponentBundle\Entity\Component\Collection\Collection",
45
 *     "layout_side_column" = "Silverback\ApiComponentBundle\Entity\Component\Layout\SideColumn",
46
 *     "simple_image" = "Silverback\ApiComponentBundle\Entity\Component\Image\SimpleImage"
47
 * })
48
 * @ORM\EntityListeners({"Silverback\ApiComponentBundle\EntityListener\ComponentListener"})
49
 */
50
abstract class AbstractComponent implements ComponentInterface, DeleteCascadeInterface
51
{
52
    use ValidComponentTrait;
53
54
    /**
55
     * @ORM\Id()
56
     * @ORM\Column(type="string")
57
     * @var string
58
     */
59
    private $id;
60
61
    /**
62
     * @ORM\Column(nullable=true)
63
     * @Groups({"component", "content"})
64
     * @var null|string
65
     */
66
    private $className;
67
68
    /**
69
     * @ORM\OneToMany(targetEntity="Silverback\ApiComponentBundle\Entity\Component\ComponentLocation", mappedBy="component")
70
     * @var Collection|ComponentLocation[]
71
     */
72
    protected $locations;
73
74
    /**
75
     * @ORM\OneToMany(targetEntity="Silverback\ApiComponentBundle\Entity\Content\ComponentGroup\ComponentGroup", mappedBy="parent", cascade={"persist"})
76
     * @ORM\OrderBy({"sort"="ASC"})
77
     * @ApiProperty(attributes={"fetchEager": false})
78
     * @Groups({"layout", "route", "content", "component"})
79
     * @var Collection|ComponentGroup[]
80
     */
81
    protected $componentGroups;
82
83
    /**
84
     * @ORM\Column(nullable=true)
85
     * @Groups({"route", "content", "component"})
86
     * @var string|null
87
     */
88
    protected $componentName;
89
90
    /**
91 10
     * AbstractComponent constructor.
92
     */
93 10
    public function __construct()
94 10
    {
95 10
        $this->id = Uuid::uuid4()->getHex();
96 10
        $this->locations = new ArrayCollection;
97 10
        $this->componentGroups = new ArrayCollection;
98
        $this->validComponents = new ArrayCollection;
99
    }
100
101
    /**
102
     * @return string
103
     */
104
    public function getId(): string
105
    {
106
        return $this->id;
107
    }
108
109
    /**
110
     * @return null|string
111
     */
112
    public function getClassName(): ?string
113
    {
114
        return $this->className;
115
    }
116
117
    /**
118
     * @param null|string $className
119
     * @return self
120
     */
121
    public function setClassName(?string $className): self
122
    {
123
        $this->className = $className;
124
        return $this;
125
    }
126
127
    /**
128
     * @return Collection|ComponentLocation[]
129
     */
130
    public function getLocations()
131
    {
132
        return $this->locations;
133
    }
134
135
    /**
136
     * @param ComponentLocation $componentLocation
137
     * @return self
138
     */
139
    public function addLocation(ComponentLocation $componentLocation): self
140
    {
141
        if (!$this->locations->contains($componentLocation)) {
142
            $componentLocation->setComponent($this);
143
            $this->locations->add($componentLocation);
144
        }
145
        return $this;
146
    }
147
148
    /**
149
     * @param ComponentLocation $componentLocation
150
     * @return self
151
     */
152
    public function removeLocation(ComponentLocation $componentLocation): self
153
    {
154
        if ($this->locations->contains($componentLocation)) {
155
            $this->locations->removeElement($componentLocation);
156
        }
157
        return $this;
158
    }
159
160
    /**
161
     * @param array $componentGroups
162
     * @return self
163
     */
164
    public function setComponentGroups(array $componentGroups): self
165
    {
166
        $this->componentGroups = new ArrayCollection;
167
        foreach ($componentGroups as $componentGroup) {
168
            $this->addComponentGroup($componentGroup);
169
        }
170
        return $this;
171
    }
172
173
    /**
174
     * @param ComponentGroup $componentGroup
175 3
     * @return self
176
     */
177 3
    public function addComponentGroup(ComponentGroup $componentGroup): self
178 3
    {
179 3
        if (!$this->componentGroups->contains($componentGroup)) {
180
            $this->componentGroups->add($componentGroup);
181 3
            $componentGroup->setParent($this);
182
        }
183
        return $this;
184
    }
185
186
    /**
187
     * @param ComponentGroup $componentGroup
188
     * @return self
189
     */
190
    public function removeComponentGroup(ComponentGroup $componentGroup): self
191
    {
192
        if ($this->componentGroups->contains($componentGroup)) {
193
            $this->componentGroups->removeElement($componentGroup);
194
        }
195
        return $this;
196
    }
197
198
    /**
199 3
     * @return Collection|\Silverback\ApiComponentBundle\Entity\Content\ComponentGroup\ComponentGroup[]
200
     */
201 3
    public function getComponentGroups(): Collection
202
    {
203
        return $this->componentGroups;
204
    }
205
206
    /**
207
     * @param null|string $componentName
208
     * @return self
209
     */
210
    public function setComponentName(?string $componentName): self
211
    {
212
        $this->componentName = $componentName;
213
        return $this;
214
    }
215
216
    /**
217
     * Return the component name for front-end to decipher
218
     * @return string
219
     */
220
    public function getComponentName(): string
221
    {
222
        if ($this->componentName) {
223
            return $this->componentName;
224
        }
225
        $explodedClass = explode('\\', static::class);
226
        return array_pop($explodedClass);
227
    }
228
229
    /**
230
     * @return bool
231
     */
232
    public function onDeleteCascade(): bool
233
    {
234
        return false;
235
    }
236
237
    /**
238
     * @Groups({"component_write"})
239
     * @param AbstractComponent $parent
240
     * @param int $componentGroupOffset
241
     * @return self
242
     */
243
    public function setParentComponent(AbstractComponent $parent, int $componentGroupOffset = 0): self
244
    {
245
        if (!\in_array($parent, $this->getParentComponents(), true)) {
246
            $componentGroup = $this->getComponentComponentGroup($parent, $componentGroupOffset);
247
            if (!$componentGroup->hasComponent($this)) {
248
                $componentGroup->addComponentLocation(new ComponentLocation($componentGroup, $this));
249
            }
250
        }
251
        return $this;
252
    }
253
254
    /**
255
     * @Groups({"component_write"})
256
     * @param ComponentGroup $componentGroup
257
     * @return self
258
     */
259
    public function setParentComponentGroup(ComponentGroup $componentGroup): self
260
    {
261
        if (!$componentGroup->hasComponent($this)) {
262
            $componentGroup->addComponentLocation(new ComponentLocation($componentGroup, $this));
263
        }
264
        return $this;
265
    }
266
267
    /**
268
     * @param AbstractContent $content
269
     * @return bool
270
     */
271
    public function hasParentContent(AbstractContent $content): bool
272
    {
273
        foreach ($this->locations as $location) {
274
            if ($location->getContent() === $content) {
275
                return true;
276
            }
277
        }
278
        return false;
279
    }
280
281
    /**
282
     * @param AbstractComponent $component
283
     * @param int $componentGroupOffset
284
     * @return ComponentGroup
285
     */
286
    private function getComponentComponentGroup(AbstractComponent $component, int $componentGroupOffset = 0): ComponentGroup
287
    {
288
        /** @var ComponentGroup $componentGroup */
289
        $componentGroup = $component->getComponentGroups()->get($componentGroupOffset);
290
        if (null === $componentGroup) {
291
            throw new \InvalidArgumentException(sprintf('There is no component group child of this component with the offset %d', $componentGroupOffset));
292
        }
293
        return $componentGroup;
294
    }
295
296
    /**
297
     * @return AbstractComponent[]
298
     */
299
    private function getParentComponents(): array
300
    {
301
        $parentContent = $this->getParentContent();
302
        return array_unique(
303
            array_filter(
304
                array_map(
305
                    function ($content) {
306
                        if ($content instanceof ComponentGroup) {
307
                            return $content->getParent();
308
                        }
309
                    },
310
                    $parentContent
311
                )
312
            )
313
        );
314
    }
315
316
    /**
317
     * @return AbstractContent[]
318
     */
319
    private function getParentContent(): array
320
    {
321
        return array_unique(
322
            array_filter(
323
                array_map(
324
                    function (ComponentLocation $loc) {
325
                        return $loc->getContent();
326
                    },
327
                    $this->locations->toArray()
328
                )
329
            )
330
        );
331
    }
332
}
333