FragmentUriGenerator.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\HttpKernel\Fragment;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpFoundation\RequestStack;
  13. use Symfony\Component\HttpFoundation\UriSigner;
  14. use Symfony\Component\HttpKernel\Controller\ControllerReference;
  15. /**
  16. * Generates a fragment URI.
  17. *
  18. * @author Kévin Dunglas <kevin@dunglas.fr>
  19. * @author Fabien Potencier <fabien@symfony.com>
  20. */
  21. final class FragmentUriGenerator implements FragmentUriGeneratorInterface
  22. {
  23. private string $fragmentPath;
  24. private ?UriSigner $signer;
  25. private ?RequestStack $requestStack;
  26. public function __construct(string $fragmentPath, ?UriSigner $signer = null, ?RequestStack $requestStack = null)
  27. {
  28. $this->fragmentPath = $fragmentPath;
  29. $this->signer = $signer;
  30. $this->requestStack = $requestStack;
  31. }
  32. public function generate(ControllerReference $controller, ?Request $request = null, bool $absolute = false, bool $strict = true, bool $sign = true): string
  33. {
  34. if (null === $request && (null === $this->requestStack || null === $request = $this->requestStack->getCurrentRequest())) {
  35. throw new \LogicException('Generating a fragment URL can only be done when handling a Request.');
  36. }
  37. if ($sign && null === $this->signer) {
  38. throw new \LogicException('You must use a URI when using the ESI rendering strategy or set a URL signer.');
  39. }
  40. if ($strict) {
  41. $this->checkNonScalar($controller->attributes);
  42. }
  43. // We need to forward the current _format and _locale values as we don't have
  44. // a proper routing pattern to do the job for us.
  45. // This makes things inconsistent if you switch from rendering a controller
  46. // to rendering a route if the route pattern does not contain the special
  47. // _format and _locale placeholders.
  48. if (!isset($controller->attributes['_format'])) {
  49. $controller->attributes['_format'] = $request->getRequestFormat();
  50. }
  51. if (!isset($controller->attributes['_locale'])) {
  52. $controller->attributes['_locale'] = $request->getLocale();
  53. }
  54. $controller->attributes['_controller'] = $controller->controller;
  55. $controller->query['_path'] = http_build_query($controller->attributes, '', '&');
  56. $path = $this->fragmentPath.'?'.http_build_query($controller->query, '', '&');
  57. // we need to sign the absolute URI, but want to return the path only.
  58. $fragmentUri = $sign || $absolute ? $request->getUriForPath($path) : $request->getBaseUrl().$path;
  59. if (!$sign) {
  60. return $fragmentUri;
  61. }
  62. $fragmentUri = $this->signer->sign($fragmentUri);
  63. return $absolute ? $fragmentUri : substr($fragmentUri, \strlen($request->getSchemeAndHttpHost()));
  64. }
  65. private function checkNonScalar(array $values): void
  66. {
  67. foreach ($values as $key => $value) {
  68. if (\is_array($value)) {
  69. $this->checkNonScalar($value);
  70. } elseif (!\is_scalar($value) && null !== $value) {
  71. throw new \LogicException(\sprintf('Controller attributes cannot contain non-scalar/non-null values (value for key "%s" is not a scalar or null).', $key));
  72. }
  73. }
  74. }
  75. }