vendor/symfony/form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php line 111

Open in your IDE?
  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\Form\Extension\Core\DataTransformer;
  11. use Symfony\Component\Form\Exception\TransformationFailedException;
  12. /**
  13. * Transforms between a date string and a DateTime object.
  14. *
  15. * @author Bernhard Schussek <bschussek@gmail.com>
  16. * @author Florian Eckerstorfer <florian@eckerstorfer.org>
  17. */
  18. class DateTimeToStringTransformer extends BaseDateTimeTransformer
  19. {
  20. /**
  21. * Format used for generating strings.
  22. *
  23. * @var string
  24. */
  25. private $generateFormat;
  26. /**
  27. * Format used for parsing strings.
  28. *
  29. * Different than the {@link $generateFormat} because formats for parsing
  30. * support additional characters in PHP that are not supported for
  31. * generating strings.
  32. *
  33. * @var string
  34. */
  35. private $parseFormat;
  36. /**
  37. * Transforms a \DateTime instance to a string.
  38. *
  39. * @see \DateTime::format() for supported formats
  40. *
  41. * @param string|null $inputTimezone The name of the input timezone
  42. * @param string|null $outputTimezone The name of the output timezone
  43. * @param string $format The date format
  44. * @param string|null $parseFormat The parse format when different from $format
  45. */
  46. public function __construct(?string $inputTimezone = null, ?string $outputTimezone = null, string $format = 'Y-m-d H:i:s', ?string $parseFormat = null)
  47. {
  48. parent::__construct($inputTimezone, $outputTimezone);
  49. $this->generateFormat = $format;
  50. $this->parseFormat = $parseFormat ?? $format;
  51. // See https://php.net/datetime.createfromformat
  52. // The character "|" in the format makes sure that the parts of a date
  53. // that are *not* specified in the format are reset to the corresponding
  54. // values from 1970-01-01 00:00:00 instead of the current time.
  55. // Without "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 12:32:47",
  56. // where the time corresponds to the current server time.
  57. // With "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 00:00:00",
  58. // which is at least deterministic and thus used here.
  59. if (!str_contains($this->parseFormat, '|')) {
  60. $this->parseFormat .= '|';
  61. }
  62. }
  63. /**
  64. * Transforms a DateTime object into a date string with the configured format
  65. * and timezone.
  66. *
  67. * @param \DateTimeInterface $dateTime A DateTimeInterface object
  68. *
  69. * @return string
  70. *
  71. * @throws TransformationFailedException If the given value is not a \DateTimeInterface
  72. */
  73. public function transform($dateTime)
  74. {
  75. if (null === $dateTime) {
  76. return '';
  77. }
  78. if (!$dateTime instanceof \DateTimeInterface) {
  79. throw new TransformationFailedException('Expected a \DateTimeInterface.');
  80. }
  81. if (!$dateTime instanceof \DateTimeImmutable) {
  82. $dateTime = clone $dateTime;
  83. }
  84. $dateTime = $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
  85. return $dateTime->format($this->generateFormat);
  86. }
  87. /**
  88. * Transforms a date string in the configured timezone into a DateTime object.
  89. *
  90. * @param string $value A value as produced by PHP's date() function
  91. *
  92. * @return \DateTime|null
  93. *
  94. * @throws TransformationFailedException If the given value is not a string,
  95. * or could not be transformed
  96. */
  97. public function reverseTransform($value)
  98. {
  99. if (empty($value)) {
  100. return null;
  101. }
  102. if (!\is_string($value)) {
  103. throw new TransformationFailedException('Expected a string.');
  104. }
  105. if (str_contains($value, "\0")) {
  106. throw new TransformationFailedException('Null bytes not allowed');
  107. }
  108. $outputTz = new \DateTimeZone($this->outputTimezone);
  109. $dateTime = \DateTime::createFromFormat($this->parseFormat, $value, $outputTz);
  110. $lastErrors = \DateTime::getLastErrors() ?: ['error_count' => 0, 'warning_count' => 0];
  111. if (0 < $lastErrors['warning_count'] || 0 < $lastErrors['error_count']) {
  112. throw new TransformationFailedException(implode(', ', array_merge(array_values($lastErrors['warnings']), array_values($lastErrors['errors']))));
  113. }
  114. try {
  115. if ($this->inputTimezone !== $this->outputTimezone) {
  116. $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
  117. }
  118. } catch (\Exception $e) {
  119. throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
  120. }
  121. return $dateTime;
  122. }
  123. }