AutoNameSubscriber::handlePersist()   C
last analyzed

Complexity

Conditions 8
Paths 11

Size

Total Lines 50
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 7
Bugs 1 Features 1
Metric Value
c 7
b 1
f 1
dl 0
loc 50
rs 6.3636
cc 8
eloc 27
nc 11
nop 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\Component\DocumentManager\Subscriber\Behavior\Path;
13
14
use PHPCR\NodeInterface;
15
use Sulu\Component\DocumentManager\Behavior\Path\AutoNameBehavior;
16
use Sulu\Component\DocumentManager\DocumentHelper;
17
use Sulu\Component\DocumentManager\DocumentRegistry;
18
use Sulu\Component\DocumentManager\DocumentStrategyInterface;
19
use Sulu\Component\DocumentManager\Event\ConfigureOptionsEvent;
20
use Sulu\Component\DocumentManager\Event\CopyEvent;
21
use Sulu\Component\DocumentManager\Event\MoveEvent;
22
use Sulu\Component\DocumentManager\Event\PersistEvent;
23
use Sulu\Component\DocumentManager\Events;
24
use Sulu\Component\DocumentManager\Exception\DocumentManagerException;
25
use Sulu\Component\DocumentManager\NameResolver;
26
use Sulu\Component\DocumentManager\NodeManager;
27
use Symfony\Cmf\Bundle\CoreBundle\Slugifier\SlugifierInterface;
28
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
29
30
/**
31
 * Automatically assign a name to the document based on its title.
32
 *
33
 * TODO: Refactor MOVE auto-name handling somehow.
34
 */
35
class AutoNameSubscriber implements EventSubscriberInterface
36
{
37
    /**
38
     * @var DocumentRegistry
39
     */
40
    private $registry;
41
42
    /**
43
     * @var SlugifierInterface
44
     */
45
    private $slugifier;
46
47
    /**
48
     * @var NameResolver
49
     */
50
    private $resolver;
51
52
    /**
53
     * @var NodeManager
54
     */
55
    private $nodeManager;
56
57
    /**
58
     * @var DocumentStrategyInterface
59
     */
60
    private $documentStrategy;
61
62
    /**
63
     * @param DocumentRegistry $registry
64
     * @param SlugifierInterface $slugifier
65
     * @param NameResolver $resolver
66
     * @param NodeManager $nodeManager
67
     * @param DocumentStrategyInterface $documentStrategy
68
     */
69
    public function __construct(
70
        DocumentRegistry $registry,
71
        SlugifierInterface $slugifier,
72
        NameResolver $resolver,
73
        NodeManager $nodeManager,
74
        DocumentStrategyInterface $documentStrategy
75
    ) {
76
        $this->registry = $registry;
77
        $this->slugifier = $slugifier;
78
        $this->resolver = $resolver;
79
        $this->nodeManager = $nodeManager;
80
        $this->documentStrategy = $documentStrategy;
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86
    public static function getSubscribedEvents()
87
    {
88
        return [
89
            Events::CONFIGURE_OPTIONS => 'configureOptions',
90
            Events::PERSIST => ['handlePersist', 480],
91
            Events::MOVE => ['handleMove', 480],
92
            Events::COPY => ['handleCopy', 480],
93
        ];
94
    }
95
96
    public function configureOptions(ConfigureOptionsEvent $event)
97
    {
98
        $event->getOptions()->setDefaults(
99
            [
100
                'auto_name' => true,
101
            ]
102
        );
103
    }
104
105
    /**
106
     * @param MoveEvent $event
107
     */
108
    public function handleMove(MoveEvent $event)
109
    {
110
        $this->handleMoveCopy($event);
111
    }
112
113
    /**
114
     * @param CopyEvent $event
115
     */
116
    public function handleCopy(CopyEvent $event)
117
    {
118
        $this->handleMoveCopy($event);
119
    }
120
121
    /**
122
     * @param PersistEvent $event
123
     *
124
     * @throws DocumentManagerException
125
     */
126
    public function handlePersist(PersistEvent $event)
127
    {
128
        if (!$event->getOption('auto_name')) {
129
            return;
130
        }
131
132
        $document = $event->getDocument();
133
134
        if (!$document instanceof AutoNameBehavior) {
135
            return;
136
        }
137
138
        $title = $document->getTitle();
139
140
        if (!$title) {
141
            throw new DocumentManagerException(
142
                sprintf(
143
                    'Document has no title (title is required for auto name behavior): %s)',
144
                    DocumentHelper::getDebugTitle($document)
145
                )
146
            );
147
        }
148
149
        $name = $this->slugifier->slugify($title);
150
151
        $parentNode = $event->getParentNode();
152
153
        $node = $event->hasNode() ? $event->getNode() : null;
154
        $name = $this->resolver->resolveName($parentNode, $name, $node);
155
156
        if (null === $node) {
157
            $node = $this->documentStrategy->createNodeForDocument($document, $parentNode, $name);
158
            $event->setNode($node);
159
160
            return;
161
        }
162
163
        if ($name === $node->getName()) {
164
            return;
165
        }
166
167
        $node = $event->getNode();
168
        $defaultLocale = $this->registry->getDefaultLocale();
169
170
        if ($defaultLocale != $event->getLocale()) {
171
            return;
172
        }
173
174
        $this->rename($node, $name);
175
    }
176
177
    /**
178
     * TODO: This is a workaround for a bug in Jackalope which will be fixed in the next
179
     *       release 1.2: https://github.com/jackalope/jackalope/pull/262.
180
     */
181
    private function rename(NodeInterface $node, $name)
182
    {
183
        $names = (array) $node->getParent()->getNodeNames();
184
        $pos = array_search($node->getName(), $names);
185
        $next = isset($names[$pos + 1]) ? $names[$pos + 1] : null;
186
187
        $node->rename($name);
188
189
        if ($next) {
190
            $node->getParent()->orderBefore($name, $next);
191
        }
192
    }
193
194
    /**
195
     * Resolve the destination name on move and copy events.
196
     *
197
     * @param MoveEvent $event
198
     */
199
    private function handleMoveCopy(MoveEvent $event)
200
    {
201
        $document = $event->getDocument();
202
203
        if (!$document instanceof AutoNameBehavior) {
204
            return;
205
        }
206
207
        $destId = $event->getDestId();
208
        $node = $this->registry->getNodeForDocument($document);
209
        $destNode = $this->nodeManager->find($destId);
210
        $nodeName = $this->resolver->resolveName($destNode, $node->getName());
211
212
        $event->setDestName($nodeName);
213
    }
214
}
215