Completed
Pull Request — develop (#147)
by Wachter
14:07
created

ArticleSubscriber::handleScheduleIndexLive()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 16
Ratio 100 %

Code Coverage

Tests 6
CRAP Score 3.0261

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 16
loc 16
rs 9.4285
ccs 6
cts 7
cp 0.8571
cc 3
eloc 9
nc 3
nop 1
crap 3.0261
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 PHPCR\NodeInterface;
15
use Sulu\Bundle\ArticleBundle\Document\ArticleDocument;
16
use Sulu\Bundle\ArticleBundle\Document\ArticlePageDocument;
17
use Sulu\Bundle\ArticleBundle\Document\Index\IndexerInterface;
18
use Sulu\Bundle\DocumentManagerBundle\Bridge\DocumentInspector;
19
use Sulu\Bundle\DocumentManagerBundle\Bridge\PropertyEncoder;
20
use Sulu\Component\Content\Document\LocalizationState;
21
use Sulu\Component\DocumentManager\DocumentManagerInterface;
22
use Sulu\Component\DocumentManager\Event\AbstractMappingEvent;
23
use Sulu\Component\DocumentManager\Event\FlushEvent;
24
use Sulu\Component\DocumentManager\Event\HydrateEvent;
25
use Sulu\Component\DocumentManager\Event\PersistEvent;
26
use Sulu\Component\DocumentManager\Event\PublishEvent;
27
use Sulu\Component\DocumentManager\Event\RemoveDraftEvent;
28
use Sulu\Component\DocumentManager\Event\RemoveEvent;
29
use Sulu\Component\DocumentManager\Event\UnpublishEvent;
30
use Sulu\Component\DocumentManager\Events;
31
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
32
33
/**
34
 * Indexes article and generate route on persist and removes it from index and routing on delete.
35
 */
36
class ArticleSubscriber implements EventSubscriberInterface
37
{
38
    const PAGES_PROPERTY = 'suluPages';
39
40
    /**
41
     * @var IndexerInterface
42
     */
43
    private $indexer;
44
45
    /**
46
     * @var IndexerInterface
47
     */
48
    private $liveIndexer;
49
50
    /**
51
     * @var DocumentManagerInterface
52
     */
53
    private $documentManager;
54
55
    /**
56
     * @var DocumentInspector
57
     */
58
    private $documentInspector;
59 36
60
    /**
61
     * @var PropertyEncoder
62
     */
63
    private $propertyEncoder;
64 36
65 36
    /**
66 36
     * @var array
67 36
     */
68
    private $documents = [];
69
70
    /**
71
     * @var array
72 31
     */
73
    private $liveDocuments = [];
74
75 31
    /**
76 31
     * @param IndexerInterface $indexer
77 31
     * @param IndexerInterface $liveIndexer
78 31
     * @param DocumentManagerInterface $documentManager
79 31
     * @param DocumentInspector $documentInspector
80 31
     * @param PropertyEncoder $propertyEncoder
81
     */
82
    public function __construct(
83
        IndexerInterface $indexer,
84
        IndexerInterface $liveIndexer,
85
        DocumentManagerInterface $documentManager,
86
        DocumentInspector $documentInspector,
87
        PropertyEncoder $propertyEncoder
88
    ) {
89 32
        $this->indexer = $indexer;
90
        $this->liveIndexer = $liveIndexer;
91 32
        $this->documentManager = $documentManager;
92 32
        $this->documentInspector = $documentInspector;
93 1
        $this->propertyEncoder = $propertyEncoder;
94
    }
95
96 32
    /**
97 32
     * {@inheritdoc}
98 32
     */
99
    public static function getSubscribedEvents()
100 32
    {
101
        return [
102
            Events::HYDRATE => [
103
                ['hydratePageData', -2000],
104
            ],
105
            Events::PERSIST => [
106
                ['handleScheduleIndex', -500],
107 13
                ['setChildrenStructureType', 0],
108
                ['persistPageData', -2000],
109 13
            ],
110 13
            Events::REMOVE => [
111 1
                ['handleRemove', -500],
112
                ['handleRemoveLive', -500],
113
                ['handleRemovePage', -500],
114 13
                ['handleRemovePageLive', -500],
115 13
            ],
116 13
            Events::PUBLISH => [
117
                ['handleScheduleIndexLive', 0],
118 13
                ['handleScheduleIndex', 0],
119
                ['synchronizeChildren', 0],
120
                ['publishChildren', 0],
121
                ['persistPageData', -2000],
122
            ],
123
            Events::UNPUBLISH => 'handleUnpublish',
124
            Events::REMOVE_DRAFT => [['handleScheduleIndex', -1024], ['removeDraftChildren', 0]],
125 31
            Events::FLUSH => [['handleFlush', -2048], ['handleFlushLive', -2048]],
126
        ];
127 31
    }
128 3
129
    /**
130
     * Schedule article document for index.
131 31
     *
132 31
     * @param AbstractMappingEvent $event
133 31
     */
134 31 View Code Duplication
    public function handleScheduleIndex(AbstractMappingEvent $event)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
135 31
    {
136
        $document = $event->getDocument();
137
        if (!$document instanceof ArticleDocument) {
138
            if (!$document instanceof ArticlePageDocument) {
139 31
                return;
140 31
            }
141 31
142
            $document = $document->getParent();
143
        }
144
145
        $this->documents[$document->getUuid()] = [
146
            'uuid' => $document->getUuid(),
147
            'locale' => $document->getLocale(),
148 31
        ];
149
    }
150 31
151 20
    /**
152
     * Schedule article document for live index.
153
     *
154 12
     * @param AbstractMappingEvent $event
155 12
     */
156 12 View Code Duplication
    public function handleScheduleIndexLive(AbstractMappingEvent $event)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
157 12
    {
158 12
        $document = $event->getDocument();
159
        if (!$document instanceof ArticleDocument) {
160
            if (!$document instanceof ArticlePageDocument) {
161
                return;
162 12
            }
163 12
164 12
            $document = $document->getParent();
165
        }
166
167
        $this->liveDocuments[$document->getUuid()] = [
168
            'uuid' => $document->getUuid(),
169
            'locale' => $document->getLocale(),
170
        ];
171
    }
172
173
    /**
174
     * Syncs children between live and draft.
175
     *
176
     * @param PublishEvent $event
177
     */
178
    public function synchronizeChildren(PublishEvent $event)
179
    {
180
        $document = $event->getDocument();
181
        if (!$document instanceof ArticleDocument) {
182
            return;
183
        }
184
185
        $liveNode = $event->getNode();
186
        $draftNode = $this->documentInspector->getNode($document);
187
188
        $liveChildren = $this->getChildren($liveNode);
189
        $draftChildren = $this->getChildren($draftNode);
190
        $removedChildrenIds = array_diff(array_keys($liveChildren), array_keys($draftChildren));
191
192
        foreach ($removedChildrenIds as $removedChildrenId) {
193
            $liveChildren[$removedChildrenId]->remove();
194
        }
195
    }
196
197
    /**
198
     * Returns children of given node.
199
     *
200
     * @param NodeInterface $node
201
     *
202
     * @return NodeInterface[]
203
     */
204
    private function getChildren(NodeInterface $node)
205 3
    {
206
        $result = [];
207 3
        foreach ($node->getNodes() as $child) {
208 3
            $result[$child->getIdentifier()] = $child;
209
        }
210
211
        return $result;
212 3
    }
213 3
214 3
    /**
215
     * Publish pages when article will be published.
216
     *
217
     * @param PublishEvent $event
218
     */
219 View Code Duplication
    public function publishChildren(PublishEvent $event)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
220
    {
221 3
        $document = $event->getDocument();
222
        if (!$document instanceof ArticleDocument) {
223 3
            return;
224 3
        }
225
226
        $children = iterator_to_array($document->getChildren());
227
        foreach ($children as $child) {
228 3
            if ($this->documentInspector->getLocalizationState($child) !== LocalizationState::GHOST) {
229 3
                $this->documentManager->publish($child, $event->getLocale());
230 3
            }
231
        }
232
    }
233
234
    /**
235
     * Persist page-data.
236
     *
237
     * @param PersistEvent|PublishEvent $event
238
     */
239
    public function persistPageData($event)
240
    {
241
        $document = $event->getDocument();
242
        if (!$document instanceof ArticleDocument) {
243
            return;
244
        }
245
246
        $pages = [
247
            [
248
                'uuid' => $document->getUuid(),
249
                'title' => $document->getPageTitle() ?: $document->getTitle(),
250
                'routePath' => $document->getRoutePath(),
251
                'pageNumber' => $document->getPageNumber(),
252
            ],
253
        ];
254
255
        foreach ($document->getChildren() as $child) {
256
            if ($child instanceof ArticlePageDocument
257
                && $this->documentInspector->getLocalizationState($child) !== LocalizationState::GHOST
258
            ) {
259
                $pages[] = [
260
                    'uuid' => $child->getUuid(),
261
                    'title' => $child->getPageTitle(),
262
                    'routePath' => $child->getRoutePath(),
263
                    'pageNumber' => $child->getPageNumber(),
264
                ];
265
            }
266
        }
267
268
        $document->setPages($pages);
269
        $event->getNode()->setProperty(
270
            $this->propertyEncoder->localizedSystemName(self::PAGES_PROPERTY, $event->getLocale()),
271
            json_encode($pages)
272
        );
273
    }
274
275
    /**
276
     * Hydrate page-data.
277
     *
278
     * @param HydrateEvent $event
279
     */
280
    public function hydratePageData(HydrateEvent $event)
281
    {
282
        $document = $event->getDocument();
283
        if (!$document instanceof ArticleDocument) {
284
            return;
285
        }
286
287
        $pages = $event->getNode()->getPropertyValueWithDefault(
288
            $this->propertyEncoder->localizedSystemName(self::PAGES_PROPERTY, $event->getLocale()),
289
            json_encode([])
290
        );
291
        $document->setPages(json_decode($pages, true));
292
    }
293
294
    /**
295
     * Remove draft from children.
296
     *
297
     * @param RemoveDraftEvent $event
298
     */
299 View Code Duplication
    public function removeDraftChildren(RemoveDraftEvent $event)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
300
    {
301
        $document = $event->getDocument();
302
        if (!$document instanceof ArticleDocument) {
303
            return;
304
        }
305
306
        foreach ($document->getChildren() as $child) {
307
            if ($this->documentInspector->getLocalizationState($child) !== LocalizationState::GHOST) {
308
                $this->documentManager->removeDraft($child, $event->getLocale());
309
            }
310
        }
311
    }
312
313
    /**
314
     * Index all scheduled article documents with default indexer.
315
     *
316
     * @param FlushEvent $event
317
     */
318 View Code Duplication
    public function handleFlush(FlushEvent $event)
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
319
    {
320
        if (count($this->documents) < 1) {
321
            return;
322
        }
323
324
        foreach ($this->documents as $documentData) {
325
            $document = $this->documentManager->find($documentData['uuid'], $documentData['locale']);
326
            $this->documentManager->refresh($document, $documentData['locale']);
0 ignored issues
show
Unused Code introduced by
The call to DocumentManagerInterface::refresh() has too many arguments starting with $documentData['locale'].

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
327
328
            $this->indexer->index($document);
329
        }
330
        $this->indexer->flush();
331
        $this->documents = [];
332
    }
333
334
    /**
335
     * Index all scheduled article documents with live indexer.
336
     *
337
     * @param FlushEvent $event
338
     */
339 View Code Duplication
    public function handleFlushLive(FlushEvent $event)
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
340
    {
341
        if (count($this->liveDocuments) < 1) {
342
            return;
343
        }
344
345
        foreach ($this->liveDocuments as $documentData) {
346
            $document = $this->documentManager->find($documentData['uuid'], $documentData['locale']);
347
            $this->documentManager->refresh($document, $documentData['locale']);
0 ignored issues
show
Unused Code introduced by
The call to DocumentManagerInterface::refresh() has too many arguments starting with $documentData['locale'].

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
348
349
            $this->liveIndexer->index($document);
350
        }
351
        $this->liveIndexer->flush();
352
        $this->liveDocuments = [];
353
    }
354
355
    /**
356
     * Removes document from live index and unpublish document in default index.
357
     *
358
     * @param UnpublishEvent $event
359
     */
360
    public function handleUnpublish(UnpublishEvent $event)
361
    {
362
        $document = $event->getDocument();
363
        if (!$document instanceof ArticleDocument) {
364
            return;
365
        }
366
367
        $this->liveIndexer->remove($document);
368
        $this->liveIndexer->flush();
369
370
        $this->indexer->setUnpublished($document->getUuid());
371
    }
372
373
    /**
374
     * Reindex article if a page was removed.
375
     *
376
     * @param RemoveEvent $event
377
     */
378
    public function handleRemovePage(RemoveEvent $event)
379
    {
380
        $document = $event->getDocument();
381
        if (!$document instanceof ArticlePageDocument) {
382
            return;
383
        }
384
385
        $document = $document->getParent();
386
        $this->documents[$document->getUuid()] = [
387
            'uuid' => $document->getUuid(),
388
            'locale' => $document->getLocale(),
389
        ];
390
    }
391
392
    /**
393
     * Reindex article live if a page was removed.
394
     *
395
     * @param RemoveEvent $event
396
     */
397
    public function handleRemovePageLive(RemoveEvent $event)
398
    {
399
        $document = $event->getDocument();
400
        if (!$document instanceof ArticlePageDocument) {
401
            return;
402
        }
403
404
        $document = $document->getParent();
405
        $this->liveDocuments[$document->getUuid()] = [
406
            'uuid' => $document->getUuid(),
407
            'locale' => $document->getLocale(),
408
        ];
409
    }
410
411
    /**
412
     * Removes article-document.
413
     *
414
     * @param RemoveEvent $event
415
     */
416
    public function handleRemove(RemoveEvent $event)
417
    {
418
        $document = $event->getDocument();
419
        if (!$document instanceof ArticleDocument) {
420
            return;
421
        }
422
423
        $this->indexer->remove($document);
424
        $this->indexer->flush();
425
    }
426
427
    /**
428
     * Removes article-document.
429
     *
430
     * @param RemoveEvent|UnpublishEvent $event
431
     */
432
    public function handleRemoveLive($event)
433
    {
434
        $document = $event->getDocument();
435
        if (!$document instanceof ArticleDocument) {
436
            return;
437
        }
438
439
        $this->liveIndexer->remove($document);
440
        $this->liveIndexer->flush();
441
    }
442
443
    /**
444
     * Set structure-type to pages.
445
     *
446
     * @param PersistEvent $event
447
     */
448
    public function setChildrenStructureType(PersistEvent $event)
449
    {
450
        $document = $event->getDocument();
451
        if (!$document instanceof ArticleDocument) {
452
            return;
453
        }
454
455
        foreach ($document->getChildren() as $child) {
456
            if ($this->documentInspector->getLocalizationState($child) !== LocalizationState::GHOST
457
                && $document->getStructureType() !== $child->getStructureType()
458
            ) {
459
                $child->setStructureType($document->getStructureType());
460
                $this->documentManager->persist($child, $event->getLocale(), $event->getOptions());
0 ignored issues
show
Documentation introduced by
$event->getOptions() is of type object<Symfony\Component...solver\OptionsResolver>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
461
            }
462
        }
463
    }
464
}
465