Completed
Pull Request — develop (#453)
by Luca
21:47 queued 06:50
created

WebsiteArticleController::indexAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 6
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of Sulu.
5
 *
6
 * (c) Sulu 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\Controller;
13
14
use Sulu\Bundle\ArticleBundle\Document\ArticleDocument;
15
use Sulu\Bundle\ArticleBundle\Document\ArticleInterface;
16
use Sulu\Bundle\ArticleBundle\Document\ArticlePageDocument;
17
use Sulu\Bundle\ArticleBundle\Resolver\ArticleContentResolverInterface;
18
use Sulu\Bundle\HttpCacheBundle\Cache\SuluHttpCache;
19
use Sulu\Bundle\PreviewBundle\Preview\Preview;
20
use Sulu\Bundle\WebsiteBundle\Resolver\TemplateAttributeResolverInterface;
21
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
22
use Symfony\Component\HttpFoundation\Request;
23
use Symfony\Component\HttpFoundation\Response;
24
use Symfony\Component\HttpKernel\Exception\HttpException;
25
use Twig\Environment;
26
27
/**
28
 * Handles articles.
29
 */
30
class WebsiteArticleController extends AbstractController
31
{
32
    /**
33
     * @var TemplateAttributeResolverInterface
34
     */
35
    private $templateAttributeResolver;
36
37
    /**
38
     * @var ArticleContentResolverInterface
39
     */
40
    private $articleContentResolver;
41
42
    public function __construct(
43
        TemplateAttributeResolverInterface $templateAttributeResolver,
44
        ArticleContentResolverInterface $articleContentResolver
45
    ) {
46
        $this->templateAttributeResolver = $templateAttributeResolver;
47
        $this->articleContentResolver = $articleContentResolver;
48
    }
49
50
    /**
51
     * Article index action.
52
     *
53
     * @param string $view
54
     * @param int $pageNumber
55
     *
56
     * @return Response
57
     */
58
    public function indexAction(Request $request, ArticleInterface $object, $view, $pageNumber = 1, $preview = false, $partial = false)
59
    {
60
        return $this->renderArticle($request, $object, $view, $pageNumber, $preview, $partial);
61
    }
62
63
    /**
64
     * Render article with given view.
65
     *
66
     * @param string $view
67
     * @param int $pageNumber
68
     * @param array $attributes
69
     *
70
     * @return Response
71
     */
72
    protected function renderArticle(Request $request, ArticleInterface $object, $view, $pageNumber, $preview, $partial, $attributes = [])
73
    {
74
        $object = $this->normalizeArticle($object);
75
76
        $requestFormat = $request->getRequestFormat();
77
        $viewTemplate = $view . '.' . $requestFormat . '.twig';
78
79
        $content = $this->resolveArticle($object, $pageNumber);
80
81
        $data = $this->templateAttributeResolver->resolve(array_merge($content, $attributes));
82
83
        try {
84
            if ($partial) {
85
                $response = $this->createResponse($request);
86
                $response->setContent(
87
                    $this->renderBlock(
88
                        $viewTemplate,
89
                        'content',
90
                        $data
91
                    )
92
                );
93
94
                return $response;
95
            } elseif ($preview) {
96
                $parameters = [
97
                    'previewParentTemplate' => $viewTemplate,
98
                    'previewContentReplacer' => Preview::CONTENT_REPLACER,
99
                ];
100
101
                return $this->render(
102
                    '@SuluWebsite/Preview/preview.html.twig',
103
                    array_merge($data, $parameters),
104
                    $this->createResponse($request)
105
                );
106
            } else {
107
                return $this->render(
108
                    $viewTemplate,
109
                    $data,
110
                    $this->createResponse($request)
111
                );
112
            }
113
        } catch (\InvalidArgumentException $exception) {
114
            // template not found
115
            throw new HttpException(406, 'Error encountered when rendering content', $exception);
116
        }
117
    }
118
119
    /**
120
     * Returns all the times the article-document.
121
     * This is necessary because the preview system passes an article-page here.
122
     *
123
     * @return ArticleDocument
124
     */
125
    protected function normalizeArticle(ArticleInterface $object)
126
    {
127
        if ($object instanceof ArticlePageDocument) {
128
            return $object->getParent();
129
        }
130
131
        return $object;
132
    }
133
134
    /**
135
     * Serialize given article with page-number.
136
     *
137
     * @param int $pageNumber
138
     *
139
     * @return array
140
     */
141
    protected function resolveArticle(ArticleInterface $object, $pageNumber)
142
    {
143
        return $this->articleContentResolver->resolve($object, $pageNumber);
144
    }
145
146
    /**
147
     * Create response.
148
     *
149
     * @return Response
150
     */
151
    private function createResponse(Request $request)
152
    {
153
        $response = new Response();
154
        $cacheLifetime = $request->attributes->get('_cacheLifetime');
155
156
        if ($cacheLifetime) {
157
            $response->setPublic();
158
            $response->headers->set(
159
                SuluHttpCache::HEADER_REVERSE_PROXY_TTL,
160
                $cacheLifetime
161
            );
162
            $response->setMaxAge($this->getParameter('sulu_http_cache.cache.max_age'));
163
            $response->setSharedMaxAge($this->getParameter('sulu_http_cache.cache.shared_max_age'));
164
        }
165
166
        // we need to set the content type ourselves here
167
        // else symfony will use the accept header of the client and the page could be cached with false content-type
168
        // see following symfony issue: https://github.com/symfony/symfony/issues/35694
169
        $mimeType = $request->getMimeType($request->getRequestFormat());
170
171
        if ($mimeType) {
172
            $response->headers->set('Content-Type', $mimeType);
173
        }
174
175
        return $response;
176
    }
177
178
    protected function renderBlock($template, $block, $attributes = [])
179
    {
180
        /** @var Environment $twig */
181
        $twig = $this->container->get('twig');
182
        $attributes = $twig->mergeGlobals($attributes);
183
184
        $template = $twig->loadTemplate($template);
185
186
        $level = ob_get_level();
187
        ob_start();
188
189
        try {
190
            $rendered = $template->renderBlock($block, $attributes);
191
            ob_end_clean();
192
193
            return $rendered;
194
        } catch (\Exception $e) {
195
            while (ob_get_level() > $level) {
196
                ob_end_clean();
197
            }
198
199
            throw $e;
200
        }
201
    }
202
203
    public static function getSubscribedServices()
204
    {
205
        return array_merge(parent::getSubscribedServices(), [
206
            'twig' => Environment::class,
207
        ]);
208
    }
209
}
210