You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
3.5 KiB

3 years ago
  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\HttpKernel\Controller\ControllerReference;
  14. use Symfony\Component\HttpKernel\UriSigner;
  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 $fragmentPath;
  24. private $signer;
  25. private $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. /**
  33. * {@inheritDoc}
  34. */
  35. public function generate(ControllerReference $controller, Request $request = null, bool $absolute = false, bool $strict = true, bool $sign = true): string
  36. {
  37. if (null === $request && (null === $this->requestStack || null === $request = $this->requestStack->getCurrentRequest())) {
  38. throw new \LogicException('Generating a fragment URL can only be done when handling a Request.');
  39. }
  40. if ($sign && null === $this->signer) {
  41. throw new \LogicException('You must use a URI when using the ESI rendering strategy or set a URL signer.');
  42. }
  43. if ($strict) {
  44. $this->checkNonScalar($controller->attributes);
  45. }
  46. // We need to forward the current _format and _locale values as we don't have
  47. // a proper routing pattern to do the job for us.
  48. // This makes things inconsistent if you switch from rendering a controller
  49. // to rendering a route if the route pattern does not contain the special
  50. // _format and _locale placeholders.
  51. if (!isset($controller->attributes['_format'])) {
  52. $controller->attributes['_format'] = $request->getRequestFormat();
  53. }
  54. if (!isset($controller->attributes['_locale'])) {
  55. $controller->attributes['_locale'] = $request->getLocale();
  56. }
  57. $controller->attributes['_controller'] = $controller->controller;
  58. $controller->query['_path'] = http_build_query($controller->attributes, '', '&');
  59. $path = $this->fragmentPath.'?'.http_build_query($controller->query, '', '&');
  60. // we need to sign the absolute URI, but want to return the path only.
  61. $fragmentUri = $sign || $absolute ? $request->getUriForPath($path) : $request->getBaseUrl().$path;
  62. if (!$sign) {
  63. return $fragmentUri;
  64. }
  65. $fragmentUri = $this->signer->sign($fragmentUri);
  66. return $absolute ? $fragmentUri : substr($fragmentUri, \strlen($request->getSchemeAndHttpHost()));
  67. }
  68. private function checkNonScalar(array $values): void
  69. {
  70. foreach ($values as $key => $value) {
  71. if (\is_array($value)) {
  72. $this->checkNonScalar($value);
  73. } elseif (!is_scalar($value) && null !== $value) {
  74. throw new \LogicException(sprintf('Controller attributes cannot contain non-scalar/non-null values (value for key "%s" is not a scalar or null).', $key));
  75. }
  76. }
  77. }
  78. }