Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.50% covered (success)
97.50%
39 / 40
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ViewRenderer
97.50% covered (success)
97.50%
39 / 40
80.00% covered (warning)
80.00%
4 / 5
6
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 renderPage
93.33% covered (success)
93.33%
14 / 15
0.00% covered (danger)
0.00%
0 / 1
2.00
 renderNode
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 resolveRenderer
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 doRender
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Node;
6
7use Celemas\Container\Container;
8use Celemas\Core\Factory\Factory;
9use Celemas\Core\Request;
10use Celemas\Core\Response;
11use Cosray\Cms;
12use Cosray\Config;
13use Cosray\Field\FieldHydrator;
14use Cosray\Node\Contract\ProvidesRenderContext;
15use Cosray\Renderer;
16
17class ViewRenderer
18{
19    public function __construct(
20        private readonly Container $container,
21        private readonly Factory $factory,
22        private readonly FieldHydrator $hydrator,
23        private readonly Types $types,
24    ) {}
25
26    /**
27     * Render a page node to an HTML response.
28     *
29     * The node is wrapped in a Node and passed to the template as
30     * '$page'. If the node implements ProvidesRenderContext, its
31     * extra context is merged in.
32     */
33    public function renderPage(
34        object $node,
35        array $fieldNames,
36        Cms $cms,
37        Request $request,
38        Config $config,
39        array $context = [],
40    ): Response {
41        $proxy = new Node($node, $fieldNames, $this->hydrator, $this->types, $request);
42
43        $baseContext = [
44            'page' => $proxy,
45            'cms' => $cms,
46            'locale' => $request->get('locale'),
47            'locales' => $request->get('locales'),
48            'request' => $request,
49            'container' => $this->container,
50            'debug' => $config->debug(),
51            'env' => $config->env(),
52        ];
53
54        if ($node instanceof ProvidesRenderContext) {
55            $baseContext = array_merge($baseContext, $node->renderContext());
56        }
57
58        $baseContext = array_merge($baseContext, $context);
59
60        return $this->doRender($node, $baseContext);
61    }
62
63    /**
64     * Render a node to an HTML string.
65     *
66     * The node is wrapped in a Node and passed to the template as
67     * '$node'.
68     */
69    public function renderNode(
70        object $node,
71        array $fieldNames,
72        Cms $cms,
73        Request $request,
74        Config $config,
75        array $context = [],
76    ): string {
77        $proxy = new Node($node, $fieldNames, $this->hydrator, $this->types, $request);
78
79        $baseContext = array_merge([
80            'node' => $proxy,
81            'cms' => $cms,
82            'locale' => $request->get('locale'),
83            'locales' => $request->get('locales'),
84            'request' => $request,
85            'container' => $this->container,
86            'debug' => $config->debug(),
87            'env' => $config->env(),
88        ], $context);
89
90        [$type, $id] = $this->resolveRenderer($node);
91        $renderer = $this->container->tag(Renderer::class)->get($type);
92
93        return $renderer->render($id, $baseContext);
94    }
95
96    /**
97     * Resolve the renderer type and template ID for a node.
98     *
99     * @return array{0: string, 1: string} [rendererType, templateId]
100     */
101    public function resolveRenderer(object $node): array
102    {
103        return ['view', $this->types->schemaOf($node::class)->renderer];
104    }
105
106    private function doRender(object $node, array $context): Response
107    {
108        [$type, $id] = $this->resolveRenderer($node);
109        $renderer = $this->container->tag(Renderer::class)->get($type);
110
111        return new Response(
112            $this->factory
113                ->response()
114                ->withHeader('Content-Type', 'text/html; charset=utf-8'),
115        )->body(
116            $renderer->render($id, $context),
117        );
118    }
119}