Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\HttpKernel\Fragment; Chris@0: Chris@0: use Symfony\Component\HttpFoundation\Request; Chris@0: use Symfony\Component\HttpFoundation\Response; Chris@0: use Symfony\Component\HttpKernel\Controller\ControllerReference; Chris@0: use Symfony\Component\HttpKernel\HttpCache\SurrogateInterface; Chris@0: use Symfony\Component\HttpKernel\UriSigner; Chris@0: Chris@0: /** Chris@0: * Implements Surrogate rendering strategy. Chris@0: * Chris@0: * @author Fabien Potencier Chris@0: */ Chris@0: abstract class AbstractSurrogateFragmentRenderer extends RoutableFragmentRenderer Chris@0: { Chris@0: private $surrogate; Chris@0: private $inlineStrategy; Chris@0: private $signer; Chris@0: Chris@0: /** Chris@0: * The "fallback" strategy when surrogate is not available should always be an Chris@0: * instance of InlineFragmentRenderer. Chris@0: * Chris@0: * @param SurrogateInterface $surrogate An Surrogate instance Chris@0: * @param FragmentRendererInterface $inlineStrategy The inline strategy to use when the surrogate is not supported Chris@0: * @param UriSigner $signer Chris@0: */ Chris@0: public function __construct(SurrogateInterface $surrogate = null, FragmentRendererInterface $inlineStrategy, UriSigner $signer = null) Chris@0: { Chris@0: $this->surrogate = $surrogate; Chris@0: $this->inlineStrategy = $inlineStrategy; Chris@0: $this->signer = $signer; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: * Chris@0: * Note that if the current Request has no surrogate capability, this method Chris@0: * falls back to use the inline rendering strategy. Chris@0: * Chris@0: * Additional available options: Chris@0: * Chris@0: * * alt: an alternative URI to render in case of an error Chris@0: * * comment: a comment to add when returning the surrogate tag Chris@0: * Chris@0: * Note, that not all surrogate strategies support all options. For now Chris@0: * 'alt' and 'comment' are only supported by ESI. Chris@0: * Chris@0: * @see Symfony\Component\HttpKernel\HttpCache\SurrogateInterface Chris@0: */ Chris@17: public function render($uri, Request $request, array $options = []) Chris@0: { Chris@0: if (!$this->surrogate || !$this->surrogate->hasSurrogateCapability($request)) { Chris@0: if ($uri instanceof ControllerReference && $this->containsNonScalars($uri->attributes)) { Chris@14: @trigger_error('Passing non-scalar values as part of URI attributes to the ESI and SSI rendering strategies is deprecated since Symfony 3.1, and will be removed in 4.0. Use a different rendering strategy or pass scalar values.', E_USER_DEPRECATED); Chris@0: } Chris@0: Chris@0: return $this->inlineStrategy->render($uri, $request, $options); Chris@0: } Chris@0: Chris@0: if ($uri instanceof ControllerReference) { Chris@0: $uri = $this->generateSignedFragmentUri($uri, $request); Chris@0: } Chris@0: Chris@0: $alt = isset($options['alt']) ? $options['alt'] : null; Chris@0: if ($alt instanceof ControllerReference) { Chris@0: $alt = $this->generateSignedFragmentUri($alt, $request); Chris@0: } Chris@0: Chris@0: $tag = $this->surrogate->renderIncludeTag($uri, $alt, isset($options['ignore_errors']) ? $options['ignore_errors'] : false, isset($options['comment']) ? $options['comment'] : ''); Chris@0: Chris@0: return new Response($tag); Chris@0: } Chris@0: Chris@0: private function generateSignedFragmentUri($uri, Request $request) Chris@0: { Chris@0: if (null === $this->signer) { Chris@0: throw new \LogicException('You must use a URI when using the ESI rendering strategy or set a URL signer.'); Chris@0: } Chris@0: Chris@0: // we need to sign the absolute URI, but want to return the path only. Chris@0: $fragmentUri = $this->signer->sign($this->generateFragmentUri($uri, $request, true)); Chris@0: Chris@17: return substr($fragmentUri, \strlen($request->getSchemeAndHttpHost())); Chris@0: } Chris@0: Chris@0: private function containsNonScalars(array $values) Chris@0: { Chris@0: foreach ($values as $value) { Chris@17: if (\is_array($value)) { Chris@14: return $this->containsNonScalars($value); Chris@0: } elseif (!is_scalar($value) && null !== $value) { Chris@0: return true; Chris@0: } Chris@0: } Chris@0: Chris@0: return false; Chris@0: } Chris@0: }