123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- <?php
- /*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace Symfony\Component\HttpKernel\Fragment;
- use Symfony\Component\HttpFoundation\Request;
- use Symfony\Component\HttpFoundation\Response;
- use Symfony\Component\HttpKernel\Controller\ControllerReference;
- use Symfony\Component\HttpKernel\UriSigner;
- use Symfony\Component\Templating\EngineInterface;
- use Twig\Environment;
- use Twig\Error\LoaderError;
- use Twig\Loader\ExistsLoaderInterface;
- use Twig\Loader\SourceContextLoaderInterface;
- /**
- * Implements the Hinclude rendering strategy.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- */
- class HIncludeFragmentRenderer extends RoutableFragmentRenderer
- {
- private $globalDefaultTemplate;
- private $signer;
- private $templating;
- private $charset;
- /**
- * @param EngineInterface|Environment $templating An EngineInterface or a Twig instance
- * @param string $globalDefaultTemplate The global default content (it can be a template name or the content)
- */
- public function __construct($templating = null, UriSigner $signer = null, string $globalDefaultTemplate = null, string $charset = 'utf-8')
- {
- $this->setTemplating($templating);
- $this->globalDefaultTemplate = $globalDefaultTemplate;
- $this->signer = $signer;
- $this->charset = $charset;
- }
- /**
- * Sets the templating engine to use to render the default content.
- *
- * @param EngineInterface|Environment|null $templating An EngineInterface or an Environment instance
- *
- * @throws \InvalidArgumentException
- *
- * @internal
- */
- public function setTemplating($templating)
- {
- if (null !== $templating && !$templating instanceof EngineInterface && !$templating instanceof Environment) {
- throw new \InvalidArgumentException('The hinclude rendering strategy needs an instance of Twig\Environment or Symfony\Component\Templating\EngineInterface.');
- }
- if ($templating instanceof EngineInterface) {
- @trigger_error(sprintf('Using a "%s" instance for "%s" is deprecated since version 4.3; use a \Twig\Environment instance instead.', EngineInterface::class, __CLASS__), \E_USER_DEPRECATED);
- }
- $this->templating = $templating;
- }
- /**
- * Checks if a templating engine has been set.
- *
- * @return bool true if the templating engine has been set, false otherwise
- */
- public function hasTemplating()
- {
- return null !== $this->templating;
- }
- /**
- * {@inheritdoc}
- *
- * Additional available options:
- *
- * * default: The default content (it can be a template name or the content)
- * * id: An optional hx:include tag id attribute
- * * attributes: An optional array of hx:include tag attributes
- */
- public function render($uri, Request $request, array $options = [])
- {
- if ($uri instanceof ControllerReference) {
- if (null === $this->signer) {
- throw new \LogicException('You must use a proper URI when using the Hinclude rendering strategy or set a URL signer.');
- }
- // we need to sign the absolute URI, but want to return the path only.
- $uri = substr($this->signer->sign($this->generateFragmentUri($uri, $request, true)), \strlen($request->getSchemeAndHttpHost()));
- }
- // We need to replace ampersands in the URI with the encoded form in order to return valid html/xml content.
- $uri = str_replace('&', '&', $uri);
- $template = $options['default'] ?? $this->globalDefaultTemplate;
- if (null !== $this->templating && $template && $this->templateExists($template)) {
- $content = $this->templating->render($template);
- } else {
- $content = $template;
- }
- $attributes = isset($options['attributes']) && \is_array($options['attributes']) ? $options['attributes'] : [];
- if (isset($options['id']) && $options['id']) {
- $attributes['id'] = $options['id'];
- }
- $renderedAttributes = '';
- if (\count($attributes) > 0) {
- $flags = \ENT_QUOTES | \ENT_SUBSTITUTE;
- foreach ($attributes as $attribute => $value) {
- $renderedAttributes .= sprintf(
- ' %s="%s"',
- htmlspecialchars($attribute, $flags, $this->charset, false),
- htmlspecialchars($value, $flags, $this->charset, false)
- );
- }
- }
- return new Response(sprintf('<hx:include src="%s"%s>%s</hx:include>', $uri, $renderedAttributes, $content));
- }
- private function templateExists(string $template): bool
- {
- if ($this->templating instanceof EngineInterface) {
- try {
- return $this->templating->exists($template);
- } catch (\Exception $e) {
- return false;
- }
- }
- $loader = $this->templating->getLoader();
- if (1 === Environment::MAJOR_VERSION && !$loader instanceof ExistsLoaderInterface) {
- try {
- if ($loader instanceof SourceContextLoaderInterface) {
- $loader->getSourceContext($template);
- } else {
- $loader->getSource($template);
- }
- return true;
- } catch (LoaderError $e) {
- }
- return false;
- }
- return $loader->exists($template);
- }
- /**
- * {@inheritdoc}
- */
- public function getName()
- {
- return 'hinclude';
- }
- }
|