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

ArticleWebsiteSubscriber::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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