Completed
Push — develop ( 292cbe...631186 )
by Alexander
15:04
created

RoutableSubscriber::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 8
cts 8
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 13
nc 1
nop 6
crap 1
1
<?php
2
3
/*
4
 * This file is part of Sulu.
5
 *
6
 * (c) MASSIVE ART WebServices GmbH
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Sulu\Bundle\ArticleBundle\Document\Subscriber;
13
14
use Doctrine\ORM\EntityManagerInterface;
15
use Sulu\Bundle\ArticleBundle\Document\ArticleDocument;
16
use Sulu\Bundle\ArticleBundle\Document\Behavior\RoutableBehavior;
17
use Sulu\Bundle\DocumentManagerBundle\Bridge\DocumentInspector;
18
use Sulu\Bundle\DocumentManagerBundle\Bridge\PropertyEncoder;
19
use Sulu\Bundle\RouteBundle\Entity\RouteRepositoryInterface;
20
use Sulu\Bundle\RouteBundle\Manager\RouteManagerInterface;
21
use Sulu\Component\DocumentManager\DocumentManagerInterface;
22
use Sulu\Component\DocumentManager\Event\AbstractMappingEvent;
23
use Sulu\Component\DocumentManager\Event\ConfigureOptionsEvent;
24
use Sulu\Component\DocumentManager\Event\CopyEvent;
25
use Sulu\Component\DocumentManager\Event\MetadataLoadEvent;
26
use Sulu\Component\DocumentManager\Event\RemoveEvent;
27
use Sulu\Component\DocumentManager\Events;
28
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
29
30
/**
31
 * Handles document-manager events to create/update/remove routes.
32
 */
33
class RoutableSubscriber implements EventSubscriberInterface
34
{
35
    const ROUTE_FIELD = 'routePath';
36
37
    /**
38
     * @var RouteManagerInterface
39
     */
40
    private $routeManager;
41
42
    /**
43
     * @var RouteRepositoryInterface
44
     */
45
    private $routeRepository;
46
47
    /**
48
     * @var EntityManagerInterface
49
     */
50
    private $entityManager;
51
52
    /**
53
     * @var DocumentManagerInterface
54
     */
55
    private $documentManager;
56
57
    /**
58
     * @var DocumentInspector
59
     */
60
    private $documentInspector;
61
62
    /**
63
     * @var PropertyEncoder
64
     */
65
    private $propertyEncoder;
66
67
    /**
68
     * @param RouteManagerInterface $routeManager
69
     * @param RouteRepositoryInterface $routeRepository
70
     * @param EntityManagerInterface $entityManager
71
     * @param DocumentManagerInterface $documentManager
72
     * @param DocumentInspector $documentInspector
73
     * @param PropertyEncoder $propertyEncoder
74
     */
75 36
    public function __construct(
76
        RouteManagerInterface $routeManager,
77
        RouteRepositoryInterface $routeRepository,
78
        EntityManagerInterface $entityManager,
79
        DocumentManagerInterface $documentManager,
80
        DocumentInspector $documentInspector,
81
        PropertyEncoder $propertyEncoder
82
    ) {
83 36
        $this->routeManager = $routeManager;
84 36
        $this->routeRepository = $routeRepository;
85 36
        $this->entityManager = $entityManager;
86 36
        $this->documentManager = $documentManager;
87 36
        $this->documentInspector = $documentInspector;
88 36
        $this->propertyEncoder = $propertyEncoder;
89 36
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94 31
    public static function getSubscribedEvents()
95
    {
96
        return [
97 31
            Events::HYDRATE => [['handleHydrate', -500]],
98 31
            Events::PERSIST => [['handleRouteUpdate', 1], ['handleRoute', 0]],
99 31
            Events::REMOVE => [['handleRemove', -500]],
100 31
            Events::COPY => ['handleCopy', -2000],
101 31
            Events::METADATA_LOAD => 'handleMetadataLoad',
102 31
            Events::CONFIGURE_OPTIONS => 'configureOptions',
103
        ];
104
    }
105
106
    /**
107
     * Load route.
108
     *
109
     * @param AbstractMappingEvent $event
110
     */
111 31
    public function handleHydrate(AbstractMappingEvent $event)
112
    {
113 31
        $document = $event->getDocument();
114 31
        if (!$document instanceof RoutableBehavior || null === $document->getRoutePath()) {
115 29
            return;
116
        }
117
118 31
        $route = $this->routeRepository->findByPath($document->getRoutePath(), $document->getOriginalLocale());
119 31
        if (!$route) {
120 30
            return;
121
        }
122
123 31
        $document->setRoute($route);
124 31
    }
125
126
    /**
127
     * Generate route.
128
     *
129
     * @param AbstractMappingEvent $event
130
     */
131 32
    public function handleRoute(AbstractMappingEvent $event)
132
    {
133 32
        $document = $event->getDocument();
134 32
        if (!$document instanceof RoutableBehavior || null !== $document->getRoutePath()) {
135 9
            return;
136
        }
137
138 32
        $document->setUuid($event->getNode()->getIdentifier());
139
140 32
        $route = $this->routeManager->create($document, $event->getOption('route_path'));
141 32
        $this->entityManager->persist($route);
142 32
        $this->entityManager->flush();
143 32
    }
144
145
    /**
146
     * Update route if route-path was changed.
147
     *
148
     * @param AbstractMappingEvent $event
149
     */
150 31
    public function handleRouteUpdate(AbstractMappingEvent $event)
151
    {
152 31
        $document = $event->getDocument();
153 31
        if (!$document instanceof RoutableBehavior
154 31
            || null === $document->getRoute()
155 31
            || null === ($routePath = $event->getOption('route_path'))
156
        ) {
157 30
            return;
158
        }
159
160 1
        $route = $this->routeManager->update($document, $routePath);
161 1
        $document->setRoutePath($route->getPath());
162 1
        $this->entityManager->persist($route);
0 ignored issues
show
Bug introduced by
It seems like $route defined by $this->routeManager->upd...($document, $routePath) on line 160 can be null; however, Doctrine\Common\Persiste...bjectManager::persist() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
163 1
        $this->entityManager->flush();
164 1
    }
165
166
    /**
167
     * Removes route.
168
     *
169
     * @param RemoveEvent $event
170
     */
171 3
    public function handleRemove(RemoveEvent $event)
172
    {
173 3
        $document = $event->getDocument();
174 3
        if (!$document instanceof RoutableBehavior) {
175
            return;
176
        }
177
178 3
        $route = $this->routeRepository->findByPath($document->getRoutePath(), $document->getOriginalLocale());
179 3
        if (!$route) {
180 2
            return;
181
        }
182
183 1
        $this->entityManager->remove($route);
184 1
        $this->entityManager->flush();
185 1
    }
186
187
    /**
188
     * Update routes for copied article.
189
     *
190
     * @param CopyEvent $event
191
     */
192 1
    public function handleCopy(CopyEvent $event)
193
    {
194 1
        $document = $event->getDocument();
195 1
        if (!$document instanceof RoutableBehavior) {
196
            return;
197
        }
198
199 1
        $locales = $this->documentInspector->getLocales($document);
200 1
        foreach ($locales as $locale) {
201
            /** @var ArticleDocument $localizedDocument */
202 1
            $localizedDocument = $this->documentManager->find($event->getCopiedPath(), $locale);
203
204 1
            $localizedDocument->removeRoute();
205 1
            $route = $this->routeManager->create($localizedDocument);
206 1
            $document->setRoutePath($route->getPath());
207 1
            $this->entityManager->persist($route);
208
209 1
            $event->getCopiedNode()->setProperty(
210 1
                $this->propertyEncoder->localizedSystemName(self::ROUTE_FIELD, $locale),
211 1
                $route->getPath()
212
            );
213
        }
214
215 1
        $this->entityManager->flush();
216 1
    }
217
218
    /**
219
     * Add route to metadata.
220
     *
221
     * @param MetadataLoadEvent $event
222
     */
223 30
    public function handleMetadataLoad(MetadataLoadEvent $event)
224
    {
225 30
        if (!$event->getMetadata()->getReflectionClass()->implementsInterface(RoutableBehavior::class)) {
226 1
            return;
227
        }
228
229 30
        $metadata = $event->getMetadata();
230 30
        $metadata->addFieldMapping(
231 30
            self::ROUTE_FIELD,
232
            [
233 30
                'encoding' => 'system_localized',
234 30
                'property' => self::ROUTE_FIELD,
235
            ]
236
        );
237 30
    }
238
239
    /**
240
     * Add route-path to options.
241
     *
242
     * @param ConfigureOptionsEvent $event
243
     */
244 30
    public function configureOptions(ConfigureOptionsEvent $event)
245
    {
246 30
        $options = $event->getOptions();
247 30
        $options->setDefaults(['route_path' => null]);
248 30
    }
249
}
250