7e957d4c95f71ea579a537598fcc458c20953fc7
[yaffs-website] / vendor / symfony / http-kernel / Fragment / HIncludeFragmentRenderer.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\HttpKernel\Fragment;
13
14 use Symfony\Component\HttpFoundation\Request;
15 use Symfony\Component\HttpFoundation\Response;
16 use Symfony\Component\Templating\EngineInterface;
17 use Symfony\Component\HttpKernel\Controller\ControllerReference;
18 use Symfony\Component\HttpKernel\UriSigner;
19 use Twig\Environment;
20 use Twig\Error\LoaderError;
21 use Twig\Loader\ExistsLoaderInterface;
22
23 /**
24  * Implements the Hinclude rendering strategy.
25  *
26  * @author Fabien Potencier <fabien@symfony.com>
27  */
28 class HIncludeFragmentRenderer extends RoutableFragmentRenderer
29 {
30     private $globalDefaultTemplate;
31     private $signer;
32     private $templating;
33     private $charset;
34
35     /**
36      * @param EngineInterface|Environment $templating            An EngineInterface or a Twig instance
37      * @param UriSigner                   $signer                A UriSigner instance
38      * @param string                      $globalDefaultTemplate The global default content (it can be a template name or the content)
39      * @param string                      $charset
40      */
41     public function __construct($templating = null, UriSigner $signer = null, $globalDefaultTemplate = null, $charset = 'utf-8')
42     {
43         $this->setTemplating($templating);
44         $this->globalDefaultTemplate = $globalDefaultTemplate;
45         $this->signer = $signer;
46         $this->charset = $charset;
47     }
48
49     /**
50      * Sets the templating engine to use to render the default content.
51      *
52      * @param EngineInterface|Environment|null $templating An EngineInterface or an Environment instance
53      *
54      * @throws \InvalidArgumentException
55      */
56     public function setTemplating($templating)
57     {
58         if (null !== $templating && !$templating instanceof EngineInterface && !$templating instanceof Environment) {
59             throw new \InvalidArgumentException('The hinclude rendering strategy needs an instance of Twig\Environment or Symfony\Component\Templating\EngineInterface');
60         }
61
62         $this->templating = $templating;
63     }
64
65     /**
66      * Checks if a templating engine has been set.
67      *
68      * @return bool true if the templating engine has been set, false otherwise
69      */
70     public function hasTemplating()
71     {
72         return null !== $this->templating;
73     }
74
75     /**
76      * {@inheritdoc}
77      *
78      * Additional available options:
79      *
80      *  * default:    The default content (it can be a template name or the content)
81      *  * id:         An optional hx:include tag id attribute
82      *  * attributes: An optional array of hx:include tag attributes
83      */
84     public function render($uri, Request $request, array $options = array())
85     {
86         if ($uri instanceof ControllerReference) {
87             if (null === $this->signer) {
88                 throw new \LogicException('You must use a proper URI when using the Hinclude rendering strategy or set a URL signer.');
89             }
90
91             // we need to sign the absolute URI, but want to return the path only.
92             $uri = substr($this->signer->sign($this->generateFragmentUri($uri, $request, true)), strlen($request->getSchemeAndHttpHost()));
93         }
94
95         // We need to replace ampersands in the URI with the encoded form in order to return valid html/xml content.
96         $uri = str_replace('&', '&amp;', $uri);
97
98         $template = isset($options['default']) ? $options['default'] : $this->globalDefaultTemplate;
99         if (null !== $this->templating && $template && $this->templateExists($template)) {
100             $content = $this->templating->render($template);
101         } else {
102             $content = $template;
103         }
104
105         $attributes = isset($options['attributes']) && is_array($options['attributes']) ? $options['attributes'] : array();
106         if (isset($options['id']) && $options['id']) {
107             $attributes['id'] = $options['id'];
108         }
109         $renderedAttributes = '';
110         if (count($attributes) > 0) {
111             $flags = ENT_QUOTES | ENT_SUBSTITUTE;
112             foreach ($attributes as $attribute => $value) {
113                 $renderedAttributes .= sprintf(
114                     ' %s="%s"',
115                     htmlspecialchars($attribute, $flags, $this->charset, false),
116                     htmlspecialchars($value, $flags, $this->charset, false)
117                 );
118             }
119         }
120
121         return new Response(sprintf('<hx:include src="%s"%s>%s</hx:include>', $uri, $renderedAttributes, $content));
122     }
123
124     /**
125      * @param string $template
126      *
127      * @return bool
128      */
129     private function templateExists($template)
130     {
131         if ($this->templating instanceof EngineInterface) {
132             try {
133                 return $this->templating->exists($template);
134             } catch (\InvalidArgumentException $e) {
135                 return false;
136             }
137         }
138
139         $loader = $this->templating->getLoader();
140         if ($loader instanceof ExistsLoaderInterface || method_exists($loader, 'exists')) {
141             return $loader->exists($template);
142         }
143
144         try {
145             if (method_exists($loader, 'getSourceContext')) {
146                 $loader->getSourceContext($template);
147             } else {
148                 $loader->getSource($template);
149             }
150
151             return true;
152         } catch (LoaderError $e) {
153         }
154
155         return false;
156     }
157
158     /**
159      * {@inheritdoc}
160      */
161     public function getName()
162     {
163         return 'hinclude';
164     }
165 }