ReorderSubscriber::resolveSiblingName()   B
last analyzed

Complexity

Conditions 6
Paths 7

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 24
rs 8.5126
cc 6
eloc 13
nc 7
nop 3
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\Component\DocumentManager\Subscriber\Phpcr;
13
14
use PHPCR\NodeInterface;
15
use PHPCR\Util\PathHelper;
16
use PHPCR\Util\UUIDHelper;
17
use Sulu\Component\DocumentManager\DocumentRegistry;
18
use Sulu\Component\DocumentManager\Event\ReorderEvent;
19
use Sulu\Component\DocumentManager\Events;
20
use Sulu\Component\DocumentManager\Exception\DocumentManagerException;
21
use Sulu\Component\DocumentManager\NodeManager;
22
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
23
24
/**
25
 * Handles the document reorder operation.
26
 */
27
class ReorderSubscriber implements EventSubscriberInterface
28
{
29
    /**
30
     * @var NodeManager
31
     */
32
    private $nodeManager;
33
34
    /**
35
     * @var DocumentRegistry
36
     */
37
    private $documentRegistry;
38
39
    /**
40
     * @param NodeManager $nodeManager
41
     * @param DocumentRegistry $documentRegistry
42
     */
43
    public function __construct(NodeManager $nodeManager, DocumentRegistry $documentRegistry)
44
    {
45
        $this->nodeManager = $nodeManager;
46
        $this->documentRegistry = $documentRegistry;
47
    }
48
49
    /**
50
     * {@inheritdoc}
51
     */
52
    public static function getSubscribedEvents()
53
    {
54
        return [
55
            Events::REORDER => ['handleReorder', 500],
56
        ];
57
    }
58
59
    /**
60
     * Handle the reorder operation.
61
     *
62
     * @param ReorderEvent $event
63
     *
64
     * @throws DocumentManagerException
65
     */
66
    public function handleReorder(ReorderEvent $event)
67
    {
68
        $document = $event->getDocument();
69
        $siblingId = $event->getDestId();
70
        $after = $event->getAfter();
71
72
        $node = $this->documentRegistry->getNodeForDocument($document);
73
        $parentNode = $node->getParent();
74
75
        $nodeName = $node->getName();
76
        $siblingName = $this->resolveSiblingName($siblingId, $parentNode, $node);
77
        if (true === $after) {
78
            $siblingName = $this->resolveAfterSiblingName($parentNode, $siblingName);
79
        }
80
81
        $parentNode->orderBefore($nodeName, $siblingName);
82
    }
83
84
    private function resolveSiblingName($siblingId, NodeInterface $parentNode, NodeInterface $node)
85
    {
86
        if (null === $siblingId) {
87
            return;
88
        }
89
90
        $siblingPath = $siblingId;
91
        if (UUIDHelper::isUUID($siblingId)) {
92
            $siblingPath = $this->nodeManager->find($siblingId)->getPath();
93
        }
94
95
        if ($siblingPath !== null && PathHelper::getParentPath($siblingPath) !== $parentNode->getPath()) {
96
            throw new DocumentManagerException(sprintf(
97
                'Cannot reorder documents which are not siblings. Trying to reorder "%s" to "%s"',
98
                $node->getPath(), $siblingPath
99
            ));
100
        }
101
102
        if (null !== $siblingPath) {
103
            return PathHelper::getNodeName($siblingPath);
104
        }
105
106
        return $node->getName();
107
    }
108
109
    /**
110
     * If the node should be ordered after the target then we need to order the
111
     * node before the sibling after the target sibling. If the node should be the
112
     * last sibling, then the target sibling should be NULL.
113
     *
114
     * @param NodeInterface $parentNode
115
     * @param string $siblingName
116
     *
117
     * @return string
118
     */
119
    private function resolveAfterSiblingName(NodeInterface $parentNode, $siblingName)
120
    {
121
        $targetName = null;
122
        $found = false;
123
124
        foreach (array_keys($parentNode->getNodes()) as $name) {
125
            if ($name === $siblingName) {
126
                $found = true;
127
                continue;
128
            } elseif ($found) {
129
                $targetName = $name;
130
                break;
131
            }
132
        }
133
134
        return $targetName;
135
    }
136
}
137