Passed
Push — develop ( 9af182...91a680 )
by Daniel
05:16 queued 26s
created

AbstractComponent::removeComponentGroup()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

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