Completed
Pull Request — develop (#179)
by Wachter
14:46
created

ArticleWebsiteSubscriber::appendPageData()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 0
cts 13
cp 0
rs 8.6737
c 0
b 0
f 0
cc 5
eloc 13
nc 6
nop 1
crap 30
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\Serializer;
13
14
use JMS\Serializer\EventDispatcher\Events;
15
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
16
use JMS\Serializer\EventDispatcher\ObjectEvent;
17
use ProxyManager\Factory\LazyLoadingValueHolderFactory;
18
use ProxyManager\Proxy\LazyLoadingInterface;
19
use ProxyManager\Proxy\VirtualProxyInterface;
20
use Sulu\Bundle\ArticleBundle\Document\ArticleDocument;
21
use Sulu\Bundle\ArticleBundle\Document\ArticleInterface;
22
use Sulu\Bundle\ArticleBundle\Document\ArticlePageDocument;
23
use Sulu\Component\Content\Compat\StructureInterface;
24
use Sulu\Component\Content\Compat\StructureManagerInterface;
25
use Sulu\Component\Content\ContentTypeManagerInterface;
26
use Sulu\Component\Util\SortUtils;
27
28
/**
29
 * Extends serializer with addtional functionallity to prepare article(-page) data.
30
 */
31
class ArticleWebsiteSubscriber implements EventSubscriberInterface
32
{
33
    /**
34
     * @var StructureManagerInterface
35
     */
36
    private $structureManager;
37
38
    /**
39
     * @var ContentTypeManagerInterface
40
     */
41
    private $contentTypeManager;
42
43
    /**
44
     * @var LazyLoadingValueHolderFactory
45
     */
46
    private $proxyFactory;
47
48
    /**
49
     * @param StructureManagerInterface $structureManager
50
     * @param ContentTypeManagerInterface $contentTypeManager
51
     * @param LazyLoadingValueHolderFactory $proxyFactory
52
     */
53
    public function __construct(
54
        StructureManagerInterface $structureManager,
55
        ContentTypeManagerInterface $contentTypeManager,
56
        LazyLoadingValueHolderFactory $proxyFactory
57
    ) {
58
        $this->structureManager = $structureManager;
59
        $this->contentTypeManager = $contentTypeManager;
60
        $this->proxyFactory = $proxyFactory;
61
    }
62
63
    /**
64
     * {@inheritdoc}
65 1
     */
66
    public static function getSubscribedEvents()
67
    {
68
        return [
69 1
            [
70 1
                'event' => Events::POST_SERIALIZE,
71 1
                'format' => 'array',
72
                'method' => 'resolveContentOnPostSerialize',
73
            ],
74 1
            [
75 1
                'event' => Events::POST_SERIALIZE,
76 1
                'format' => 'array',
77
                'method' => 'resolveContentForArticleOnPostSerialize',
78
            ],
79 1
            [
80 1
                'event' => Events::POST_SERIALIZE,
81 1
                'format' => 'array',
82
                'method' => 'resolveContentForArticlePageOnPostSerialize',
83
            ],
84 1
            [
85 1
                'event' => Events::POST_SERIALIZE,
86 1
                'format' => 'array',
87
                'method' => 'appendPageData',
88
            ],
89
        ];
90
    }
91
92
    /**
93
     * Resolve content on serialization.
94
     *
95
     * @param ObjectEvent $event
96
     */
97
    public function resolveContentOnPostSerialize(ObjectEvent $event)
98
    {
99
        $article = $event->getObject();
100
        $visitor = $event->getVisitor();
101
        $context = $event->getContext();
102
103
        if (!$article instanceof ArticleInterface || !$context->attributes->containsKey('website')) {
104
            return;
105
        }
106
107
        $visitor->addData('uuid', $context->accept($article->getArticleUuid()));
108
        $visitor->addData('pageUuid', $context->accept($article->getPageUuid()));
109
        $visitor->addData('extension', $context->accept($article->getExtensionsData()->toArray()));
110
    }
111
112
    /**
113
     * Append page data.
114
     *
115
     * @param ObjectEvent $event
116
     */
117
    public function appendPageData(ObjectEvent $event)
118
    {
119
        $article = $event->getObject();
120
        $visitor = $event->getVisitor();
121
        $context = $event->getContext();
122
123
        if ($article instanceof ArticlePageDocument) {
124
            $article = $article->getParent();
125
        }
126
127
        if (!$article instanceof ArticleDocument || !$context->attributes->containsKey('website')) {
128
            return;
129
        }
130
131
        $pageNumber = 1;
132
        if ($context->attributes->containsKey('pageNumber')) {
133
            $pageNumber = $context->attributes->get('pageNumber')->get();
134
        }
135
136
        $visitor->addData('page', $pageNumber);
137
        $visitor->addData('pages', $context->accept($article->getPages()));
138
    }
139
140
    /**
141
     * Resolve content on serialization.
142
     *
143
     * @param ObjectEvent $event
144
     */
145
    public function resolveContentForArticleOnPostSerialize(ObjectEvent $event)
146
    {
147
        $article = $event->getObject();
148
        $visitor = $event->getVisitor();
149
        $context = $event->getContext();
150
151
        if (!$article instanceof ArticleDocument || !$context->attributes->containsKey('website')) {
152
            return;
153
        }
154
155
        $children = $article->getChildren();
156
157
        if (null !== $children && $context->attributes->containsKey('pageNumber')) {
158
            $pages = array_values(is_array($children) ? $children : iterator_to_array($children));
159
            $pages = SortUtils::multisort($pages, 'pageNumber');
160
161
            $pageNumber = $context->attributes->get('pageNumber')->get();
162
            if ($pageNumber !== 1) {
163
                $article = $pages[$pageNumber - 2];
164
            }
165
        }
166
167
        $content = $this->resolve($article);
168
        foreach ($content as $name => $value) {
169
            $visitor->addData($name, $value);
170
        }
171
    }
172
173
    /**
174
     * Resolve content on serialization.
175
     *
176
     * @param ObjectEvent $event
177
     */
178
    public function resolveContentForArticlePageOnPostSerialize(ObjectEvent $event)
179
    {
180
        $article = $event->getObject();
181
        $visitor = $event->getVisitor();
182
        $context = $event->getContext();
183
184
        if (!$article instanceof ArticlePageDocument || !$context->attributes->containsKey('website')) {
185
            return;
186
        }
187
188
        $content = $this->resolve($article);
189
        foreach ($content as $name => $value) {
190
            $visitor->addData($name, $value);
191
        }
192
    }
193
194
    /**
195
     * Returns content and view of article.
196
     *
197
     * @param ArticleInterface $article
198
     *
199
     * @return array
200
     */
201
    private function resolve(ArticleInterface $article)
202
    {
203
        $structure = $this->structureManager->getStructure($article->getStructureType(), 'article');
204
        $structure->setDocument($article);
205
206
        $data = $article->getStructure()->toArray();
207
208
        return [
209
            'content' => $this->createContentProxy($structure, $data),
210
            'view' => $this->createViewProxy($structure, $data),
211
        ];
212
    }
213
214
    /**
215
     * Create content-proxy for given structure.
216
     *
217
     * @param StructureInterface $structure
218
     * @param array $data
219
     *
220
     * @return VirtualProxyInterface
221
     */
222 View Code Duplication
    private function createContentProxy($structure, $data)
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...
223
    {
224
        return $this->proxyFactory->createProxy(
225
            \ArrayObject::class,
226
            function (
227
                &$wrappedObject,
228
                LazyLoadingInterface $proxy,
229
                $method,
230
                array $parameters,
231
                &$initializer
232
            ) use ($structure, $data) {
233
                $content = [];
234
                foreach ($structure->getProperties(true) as $child) {
235
                    if (array_key_exists($child->getName(), $data)) {
236
                        $child->setValue($data[$child->getName()]);
237
                    }
238
239
                    $contentType = $this->contentTypeManager->get($child->getContentTypeName());
240
                    $content[$child->getName()] = $contentType->getContentData($child);
241
                }
242
243
                $initializer = null;
244
                $wrappedObject = new \ArrayObject($content);
245
246
                return true;
247
            }
248
        );
249
    }
250
251
    /**
252
     * Create view-proxy for given structure.
253
     *
254
     * @param StructureInterface $structure
255
     * @param array $data
256
     *
257
     * @return VirtualProxyInterface
258
     */
259 View Code Duplication
    private function createViewProxy($structure, array $data)
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...
260
    {
261
        return $this->proxyFactory->createProxy(
262
            \ArrayObject::class,
263
            function (
264
                &$wrappedObject,
265
                LazyLoadingInterface $proxy,
266
                $method,
267
                array $parameters,
268
                &$initializer
269
            ) use ($structure, $data) {
270
                $view = [];
271
                foreach ($structure->getProperties(true) as $child) {
272
                    if (array_key_exists($child->getName(), $data)) {
273
                        $child->setValue($data[$child->getName()]);
274
                    }
275
276
                    $contentType = $this->contentTypeManager->get($child->getContentTypeName());
277
                    $view[$child->getName()] = $contentType->getViewData($child);
278
                }
279
280
                $initializer = null;
281
                $wrappedObject = new \ArrayObject($view);
282
283
                return true;
284
            }
285
        );
286
    }
287
}
288