Completed
Pull Request — master (#56)
by Daniel
09:02
created

AutoNameSubscriber::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 1 Features 1
Metric Value
c 6
b 1
f 1
dl 0
loc 14
rs 9.4286
cc 1
eloc 11
nc 1
nop 5
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
    {
77
        $this->registry = $registry;
78
        $this->slugifier = $slugifier;
79
        $this->resolver = $resolver;
80
        $this->nodeManager = $nodeManager;
81
        $this->documentStrategy = $documentStrategy;
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87
    public static function getSubscribedEvents()
88
    {
89
        return [
90
            Events::CONFIGURE_OPTIONS => 'configureOptions',
91
            Events::PERSIST => ['handlePersist', 480],
92
            Events::MOVE => ['handleMove', 480],
93
            Events::COPY => ['handleCopy', 480],
94
        ];
95
    }
96
97
    public function configureOptions(ConfigureOptionsEvent $event)
98
    {
99
        $event->getOptions()->setDefaults(
100
            [
101
                'auto_name' => true,
102
            ]
103
        );
104
    }
105
106
    /**
107
     * @param MoveEvent $event
108
     */
109
    public function handleMove(MoveEvent $event)
110
    {
111
        $this->handleMoveCopy($event);
112
    }
113
114
    /**
115
     * @param CopyEvent $event
116
     */
117
    public function handleCopy(CopyEvent $event)
118
    {
119
        $this->handleMoveCopy($event);
120
    }
121
122
    /**
123
     * @param PersistEvent $event
124
     *
125
     * @throws DocumentManagerException
126
     */
127
    public function handlePersist(PersistEvent $event)
128
    {
129
        if (!$event->getOption('auto_name')) {
130
            return;
131
        }
132
133
        $document = $event->getDocument();
134
135
        if (!$document instanceof AutoNameBehavior) {
136
            return;
137
        }
138
139
        $title = $document->getTitle();
140
141
        if (!$title) {
142
            throw new DocumentManagerException(
143
                sprintf(
144
                    'Document has no title (title is required for auto name behavior): %s)',
145
                    DocumentHelper::getDebugTitle($document)
146
                )
147
            );
148
        }
149
150
        $name = $this->slugifier->slugify($title);
151
152
        $parentNode = $event->getParentNode();
153
154
        $node = $event->hasNode() ? $event->getNode() : null;
155
        $name = $this->resolver->resolveName($parentNode, $name, $node);
156
157
        if (null === $node) {
158
            $node = $this->documentStrategy->createNodeForDocument($document, $parentNode, $name);
159
            $event->setNode($node);
160
161
            return;
162
        }
163
164
        if ($name === $node->getName()) {
165
            return;
166
        }
167
168
        $node = $event->getNode();
169
        $defaultLocale = $this->registry->getDefaultLocale();
170
171
        if ($defaultLocale != $event->getLocale()) {
172
            return;
173
        }
174
175
        $this->rename($node, $name);
176
    }
177
178
    /**
179
     * TODO: This is a workaround for a bug in Jackalope which will be fixed in the next
180
     *       release 1.2: https://github.com/jackalope/jackalope/pull/262.
181
     */
182
    private function rename(NodeInterface $node, $name)
183
    {
184
        $names = (array)$node->getParent()->getNodeNames();
185
        $pos = array_search($node->getName(), $names);
186
        $next = isset($names[$pos + 1]) ? $names[$pos + 1] : null;
187
188
        $node->rename($name);
189
190
        if ($next) {
191
            $node->getParent()->orderBefore($name, $next);
192
        }
193
    }
194
195
    /**
196
     * Resolve the destination name on move and copy events.
197
     *
198
     * @param MoveEvent $event
199
     */
200
    private function handleMoveCopy(MoveEvent $event)
201
    {
202
        $document = $event->getDocument();
203
204
        if (!$document instanceof AutoNameBehavior) {
205
            return;
206
        }
207
208
        $destId = $event->getDestId();
209
        $node = $this->registry->getNodeForDocument($document);
210
        $destNode = $this->nodeManager->find($destId);
211
        $nodeName = $this->resolver->resolveName($destNode, $node->getName());
212
213
        $event->setDestName($nodeName);
214
    }
215
}
216