Completed
Push — develop ( 1624d7...c0f09c )
by Daniel
10:18 queued 04:42
created

AbstractComponent::addLocation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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