Skip to content

Commit 25f4e4a

Browse files
authored
EZP-31851: Added Twig helpers that abstracts content rendering (#115)
1 parent d1b8505 commit 25f4e4a

19 files changed

+972
-0
lines changed

eZ/Bundle/EzPublishCoreBundle/Resources/config/templating.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,75 @@ services:
155155
tags:
156156
- { name: twig.extension }
157157

158+
eZ\Publish\Core\MVC\Symfony\Templating\Twig\Extension\RenderExtension:
159+
arguments:
160+
$renderStrategy: '@eZ\Publish\SPI\MVC\Templating\RenderStrategy'
161+
$eventDispatcher: '@event_dispatcher'
162+
tags:
163+
- { name: twig.extension }
164+
165+
eZ\Publish\Core\MVC\Symfony\Templating\Twig\Extension\RenderContentExtension:
166+
arguments:
167+
$renderContentStrategy: '@eZ\Publish\Core\MVC\Symfony\Templating\RenderContentStrategy'
168+
$eventDispatcher: '@event_dispatcher'
169+
tags:
170+
- { name: twig.extension }
171+
172+
eZ\Publish\Core\MVC\Symfony\Templating\Twig\Extension\RenderLocationExtension:
173+
arguments:
174+
$renderLocationStrategy: '@eZ\Publish\Core\MVC\Symfony\Templating\RenderLocationStrategy'
175+
$eventDispatcher: '@event_dispatcher'
176+
tags:
177+
- { name: twig.extension }
178+
179+
eZ\Publish\Core\MVC\Symfony\Templating\RenderStrategy:
180+
arguments:
181+
$strategies: !tagged_iterator ibexa.platform.render.strategy
182+
183+
eZ\Publish\SPI\MVC\Templating\RenderStrategy: '@eZ\Publish\Core\MVC\Symfony\Templating\RenderStrategy'
184+
185+
eZ\Publish\Core\MVC\Symfony\Templating\RenderContentStrategy:
186+
arguments:
187+
$defaultMethod: 'inline'
188+
$renderMethods: !tagged_iterator ibexa.platform.render.method
189+
$siteAccess: '@ezpublish.siteaccess'
190+
$requestStack: '@request_stack'
191+
tags:
192+
- { name: ibexa.platform.render.strategy }
193+
194+
eZ\Publish\Core\MVC\Symfony\Templating\RenderLocationStrategy:
195+
arguments:
196+
$defaultMethod: 'inline'
197+
$renderMethods: !tagged_iterator ibexa.platform.render.method
198+
$siteAccess: '@ezpublish.siteaccess'
199+
$requestStack: '@request_stack'
200+
tags:
201+
- { name: ibexa.platform.render.strategy }
202+
203+
eZ\Publish\Core\MVC\Symfony\Templating\RenderMethod\RenderInline:
204+
arguments:
205+
$kernel: '@kernel'
206+
$controllerListener: '@ezpublish.view_controller_listener'
207+
$controllerResolver: '@controller_resolver'
208+
$argumentMetadataFactory: '@argument_metadata_factory'
209+
$argumentValueResolver: '@argument_resolver.request_attribute'
210+
$viewTemplateRenderer: '@ezpublish.view.template_renderer'
211+
tags:
212+
- { name: ibexa.platform.render.method }
213+
214+
eZ\Publish\Core\MVC\Symfony\Templating\RenderMethod\RenderSubRequest:
215+
arguments:
216+
$kernel: '@kernel'
217+
tags:
218+
- { name: ibexa.platform.render.method }
219+
220+
eZ\Publish\Core\MVC\Symfony\Templating\RenderMethod\RenderEdgeSideInclude:
221+
arguments:
222+
$fragmentRenderer: '@fragment.renderer.esi'
223+
$router: '@router'
224+
tags:
225+
- { name: ibexa.platform.render.method }
226+
158227
ezpublish.twig.extension.image:
159228
class: eZ\Publish\Core\MVC\Symfony\Templating\Twig\Extension\ImageExtension
160229
arguments:
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace eZ\Publish\Core\MVC\Symfony\Event;
10+
11+
use eZ\Publish\Core\MVC\Symfony\Templating\RenderOptions;
12+
use Symfony\Contracts\EventDispatcher\Event;
13+
14+
final class ResolveRenderOptionsEvent extends Event
15+
{
16+
/** @var \eZ\Publish\Core\MVC\Symfony\Templating\RenderOptions */
17+
private $renderOptions;
18+
19+
public function __construct(
20+
RenderOptions $renderOptions
21+
) {
22+
$this->renderOptions = $renderOptions;
23+
}
24+
25+
public function getRenderOptions(): RenderOptions
26+
{
27+
return $this->renderOptions;
28+
}
29+
30+
public function setRenderOptions(RenderOptions $renderOptions): void
31+
{
32+
$this->renderOptions = $renderOptions;
33+
}
34+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace eZ\Publish\Core\MVC\Symfony\Templating\Exception;
10+
11+
use eZ\Publish\Core\Base\Exceptions\ForbiddenException;
12+
use eZ\Publish\Core\Base\Translatable;
13+
use eZ\Publish\Core\Base\TranslatableBase;
14+
15+
class InvalidResponseException extends ForbiddenException implements Translatable
16+
{
17+
use TranslatableBase;
18+
19+
public function __construct(string $whatIsWrong)
20+
{
21+
parent::__construct(
22+
'Response is invalid: %whatIsWrong%',
23+
[
24+
'%whatIsWrong%' => $whatIsWrong,
25+
]
26+
);
27+
}
28+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace eZ\Publish\Core\MVC\Symfony\Templating;
10+
11+
use eZ\Publish\API\Repository\Values\Content\Content;
12+
use eZ\Publish\API\Repository\Values\ValueObject;
13+
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;
14+
use eZ\Publish\SPI\MVC\Templating\BaseRenderStrategy;
15+
use eZ\Publish\SPI\MVC\Templating\RenderStrategy;
16+
use Symfony\Component\HttpFoundation\Request;
17+
18+
final class RenderContentStrategy extends BaseRenderStrategy implements RenderStrategy
19+
{
20+
private const DEFAULT_VIEW_TYPE = 'embed';
21+
22+
public function supports(ValueObject $valueObject): bool
23+
{
24+
return $valueObject instanceof Content;
25+
}
26+
27+
public function render(ValueObject $valueObject, RenderOptions $options): string
28+
{
29+
if (!$this->supports($valueObject)) {
30+
throw new InvalidArgumentException(
31+
'valueObject',
32+
'Must be a type of ' . Content::class
33+
);
34+
}
35+
36+
/** @var \eZ\Publish\API\Repository\Values\Content\Content $content */
37+
$content = $valueObject;
38+
39+
$currentRequest = $this->requestStack->getCurrentRequest();
40+
$surrogateCapability = $currentRequest->get('Surrogate-Capability');
41+
42+
$request = new Request();
43+
$request->headers->set('siteaccess', $this->siteAccess->name);
44+
$request->headers->set('Surrogate-Capability', $surrogateCapability);
45+
46+
$request->attributes->add([
47+
'_route' => '_ez_content_view',
48+
'_controller' => 'ez_content::viewAction',
49+
'siteaccess' => $this->siteAccess,
50+
'contentId' => $content->id,
51+
'viewType' => $options->get('viewType', self::DEFAULT_VIEW_TYPE),
52+
]);
53+
54+
$renderMethod = $this->getRenderMethod($options, $content);
55+
56+
return $renderMethod->render($request);
57+
}
58+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace eZ\Publish\Core\MVC\Symfony\Templating;
10+
11+
use eZ\Publish\API\Repository\Values\Content\Location;
12+
use eZ\Publish\API\Repository\Values\ValueObject;
13+
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;
14+
use eZ\Publish\SPI\MVC\Templating\BaseRenderStrategy;
15+
use eZ\Publish\SPI\MVC\Templating\RenderStrategy;
16+
use Symfony\Component\HttpFoundation\Request;
17+
18+
final class RenderLocationStrategy extends BaseRenderStrategy implements RenderStrategy
19+
{
20+
private const DEFAULT_VIEW_TYPE = 'embed';
21+
22+
public function supports(ValueObject $valueObject): bool
23+
{
24+
return $valueObject instanceof Location;
25+
}
26+
27+
public function render(ValueObject $valueObject, RenderOptions $options): string
28+
{
29+
if (!$this->supports($valueObject)) {
30+
throw new InvalidArgumentException(
31+
'valueObject',
32+
'Must be a type of ' . Location::class
33+
);
34+
}
35+
36+
/** @var \eZ\Publish\API\Repository\Values\Content\Location $location */
37+
$location = $valueObject;
38+
$content = $location->getContent();
39+
40+
$currentRequest = $this->requestStack->getCurrentRequest();
41+
$surrogateCapability = $currentRequest->get('Surrogate-Capability');
42+
43+
$request = new Request();
44+
$request->headers->set('siteaccess', $this->siteAccess->name);
45+
$request->headers->set('Surrogate-Capability', $surrogateCapability);
46+
47+
$request->attributes->add([
48+
'_route' => '_ez_content_view',
49+
'_controller' => 'ez_content::viewAction',
50+
'siteaccess' => $this->siteAccess,
51+
'locationId' => $location->id,
52+
'contentId' => $content->id,
53+
'viewType' => $options->get('viewType', self::DEFAULT_VIEW_TYPE),
54+
]);
55+
56+
$renderMethod = $this->getRenderMethod($options, $content);
57+
58+
return $renderMethod->render($request);
59+
}
60+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace eZ\Publish\Core\MVC\Symfony\Templating\RenderMethod;
10+
11+
use eZ\Publish\SPI\MVC\Templating\RenderMethod;
12+
use Symfony\Component\HttpFoundation\Request;
13+
use Symfony\Component\HttpKernel\Controller\ControllerReference;
14+
use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
15+
use Symfony\Component\Routing\RouteCompiler;
16+
use Symfony\Component\Routing\RouterInterface;
17+
18+
/**
19+
* @internal
20+
*/
21+
final class RenderEdgeSideInclude implements RenderMethod
22+
{
23+
public const IDENTIFIER = 'esi';
24+
25+
/** @var \Symfony\Component\HttpKernel\Fragment\AbstractSurrogateFragmentRenderer */
26+
private $fragmentRenderer;
27+
28+
/** @var \Symfony\Component\Routing\RouterInterface */
29+
private $router;
30+
31+
public function __construct(
32+
FragmentRendererInterface $fragmentRenderer,
33+
RouterInterface $router
34+
) {
35+
$this->fragmentRenderer = $fragmentRenderer;
36+
$this->router = $router;
37+
}
38+
39+
public function getIdentifier(): string
40+
{
41+
return self::IDENTIFIER;
42+
}
43+
44+
public function render(Request $request): string
45+
{
46+
$controllerReference = new ControllerReference(
47+
$request->get('_controller'),
48+
$this->getRouteAttributes($request)
49+
);
50+
51+
$esiFragmentResponse = $this->fragmentRenderer->render($controllerReference, $request);
52+
53+
return $esiFragmentResponse->getContent();
54+
}
55+
56+
private function getRouteAttributes(Request $request): array
57+
{
58+
$route = $this->router->getRouteCollection()->get($request->get('_route'));
59+
$variables = RouteCompiler::compile($route)->getVariables();
60+
61+
$routeAttributes = [
62+
'siteaccess' => $request->headers->get('siteaccess'),
63+
];
64+
65+
foreach ($variables as $variable) {
66+
$routeAttributes[$variable] = $request->attributes->get($variable);
67+
}
68+
69+
return $routeAttributes;
70+
}
71+
}

0 commit comments

Comments
 (0)