DateTimeValueResolver.php 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  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\Controller\ArgumentResolver;
  11. use Psr\Clock\ClockInterface;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpKernel\Attribute\MapDateTime;
  14. use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
  15. use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
  16. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  17. /**
  18. * Convert DateTime instances from request attribute variable.
  19. *
  20. * @author Benjamin Eberlei <kontakt@beberlei.de>
  21. * @author Tim Goudriaan <tim@codedmonkey.com>
  22. */
  23. final class DateTimeValueResolver implements ValueResolverInterface
  24. {
  25. public function __construct(
  26. private readonly ?ClockInterface $clock = null,
  27. ) {
  28. }
  29. public function resolve(Request $request, ArgumentMetadata $argument): array
  30. {
  31. if (!is_a($argument->getType(), \DateTimeInterface::class, true) || !$request->attributes->has($argument->getName())) {
  32. return [];
  33. }
  34. $value = $request->attributes->get($argument->getName());
  35. $class = \DateTimeInterface::class === $argument->getType() ? \DateTimeImmutable::class : $argument->getType();
  36. if (!$value) {
  37. if ($argument->isNullable()) {
  38. return [null];
  39. }
  40. if (!$this->clock) {
  41. return [new $class()];
  42. }
  43. $value = $this->clock->now();
  44. }
  45. if ($value instanceof \DateTimeInterface) {
  46. return [$value instanceof $class ? $value : $class::createFromInterface($value)];
  47. }
  48. $format = null;
  49. if ($attributes = $argument->getAttributes(MapDateTime::class, ArgumentMetadata::IS_INSTANCEOF)) {
  50. $attribute = $attributes[0];
  51. $format = $attribute->format;
  52. }
  53. if (null !== $format) {
  54. $date = $class::createFromFormat($format, $value, $this->clock?->now()->getTimeZone());
  55. if (($class::getLastErrors() ?: ['warning_count' => 0])['warning_count']) {
  56. $date = false;
  57. }
  58. } else {
  59. if (false !== filter_var($value, \FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]])) {
  60. $value = '@'.$value;
  61. }
  62. try {
  63. $date = new $class($value, $this->clock?->now()->getTimeZone());
  64. } catch (\Exception) {
  65. $date = false;
  66. }
  67. }
  68. if (!$date) {
  69. throw new NotFoundHttpException(\sprintf('Invalid date given for parameter "%s".', $argument->getName()));
  70. }
  71. return [$date];
  72. }
  73. }