Passed
Push — develop ( 69ffd6...9486de )
by Daniel
08:05
created

AbstractComponent::getParentComponents()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2.032

Importance

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