vendor/excelwebzone/symfony-admin-bundle/src/EventSubscriber/TimezoneSubscriber.php line 92

Open in your IDE?
  1. <?php
  2. namespace EWZ\SymfonyAdminBundle\EventSubscriber;
  3. use Doctrine\DBAL\DBALException;
  4. use Doctrine\DBAL\Types\Type;
  5. use EWZ\SymfonyAdminBundle\Doctrine\DBAL\Types\DateTimeType;
  6. use EWZ\SymfonyAdminBundle\Util\DateTimeKernel;
  7. use Symfony\Component\Console\ConsoleEvents;
  8. use Symfony\Component\Console\Event\ConsoleCommandEvent;
  9. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  10. use Symfony\Component\HttpFoundation\RequestStack;
  11. use Symfony\Component\HttpKernel\Event\RequestEvent;
  12. use Symfony\Component\HttpKernel\KernelEvents;
  13. use Symfony\Component\HttpKernel\KernelInterface;
  14. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  15. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  16. use Twig\Environment;
  17. use Twig\Extension\CoreExtension;
  18. /**
  19.  * Timezone management and additional \DateTime methods.
  20.  */
  21. class TimezoneSubscriber implements EventSubscriberInterface
  22. {
  23.     /** @var KernelInterface */
  24.     private $kernel;
  25.     /** @var TokenStorageInterface */
  26.     private $tokenStorage;
  27.     /** @var RequestStack */
  28.     private $requestStack;
  29.     /** @var Environment */
  30.     private $twig;
  31.     /** @var string */
  32.     private $timeZoneDatabase null;
  33.     /** @var string */
  34.     private $timeZoneClient null;
  35.     /**
  36.      * @param KernelInterface       $kernel
  37.      * @param TokenStorageInterface $tokenStorage
  38.      * @param RequestStack          $requestStack
  39.      * @param Environment           $twig
  40.      * @param string|null           $timeZoneDatabase
  41.      * @param string|null           $timeZoneClient
  42.      */
  43.     public function __construct(
  44.         KernelInterface $kernel,
  45.         TokenStorageInterface $tokenStorage,
  46.         RequestStack $requestStack,
  47.         Environment $twig,
  48.         string $timeZoneDatabase null,
  49.         string $timeZoneClient null
  50.     ) {
  51.         $this->kernel $kernel;
  52.         $this->tokenStorage $tokenStorage;
  53.         $this->requestStack $requestStack;
  54.         $this->twig $twig;
  55.         $this->timeZoneDatabase $timeZoneDatabase;
  56.         $this->timeZoneClient $timeZoneClient;
  57.         $this->initializeTypeOverrides();
  58.     }
  59.     /**
  60.      * {@inheritdoc}
  61.      */
  62.     public static function getSubscribedEvents(): array
  63.     {
  64.         return [
  65.             ConsoleEvents::COMMAND => 'onConsoleCommand',
  66.             KernelEvents::REQUEST => 'onKernelRequest',
  67.         ];
  68.     }
  69.     /**
  70.      * @param ConsoleCommandEvent $event
  71.      */
  72.     public function onConsoleCommand(ConsoleCommandEvent $event): void
  73.     {
  74.         $this->updateDateTimeKernel();
  75.     }
  76.     /**
  77.      * @param RequestEvent $event
  78.      */
  79.     public function onKernelRequest(RequestEvent $event): void
  80.     {
  81.         $this->updateDateTimeKernel();
  82.     }
  83.     /**
  84.      * @throws DBALException
  85.      */
  86.     private function initializeTypeOverrides(): void
  87.     {
  88.         // save all datetime objects in the configured time zone,
  89.         // see {@link http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/working-with-datetime.html}
  90.         Type::overrideType('datetime'DateTimeType::class);
  91.         Type::overrideType('datetimetz'DateTimeType::class);
  92.     }
  93.     /**
  94.      * Method called:.
  95.      *
  96.      * - before controller action and
  97.      * - before console command.
  98.      */
  99.     private function updateDateTimeKernel(): void
  100.     {
  101.         $this->updateKernelTimeZones();
  102.         if (!$this->updateKernelDateTime()) {
  103.             throw new \RuntimeException('Unable to initialize the DateTimeKernel object.');
  104.         }
  105.     }
  106.     /**
  107.      * Updates the timezones.
  108.      */
  109.     private function updateKernelTimeZones(): void
  110.     {
  111.         DateTimeKernel::setTimeZoneDatabase(new \DateTimeZone($this->timeZoneDatabase ?: date_default_timezone_get()));
  112.         DateTimeKernel::setTimeZoneClient(new \DateTimeZone($this->timeZoneClient ?: date_default_timezone_get()));
  113.         /** @var TokenInterface $token */
  114.         if ($token $this->tokenStorage->getToken()) {
  115.             $user $token->getUser();
  116.             if (method_exists($user'getTimezone')) {
  117.                 DateTimeKernel::setTimeZoneClient(new \DateTimeZone($user->getTimezone()));
  118.             }
  119.         }
  120.         // set PHP server timezone
  121.         date_default_timezone_set(DateTimeKernel::getTimeZoneClient()->getName());
  122.         // set Twig default timezone
  123.         $this->twig->getExtension(CoreExtension::class)
  124.             ->setTimezone(DateTimeKernel::getTimeZoneClient());
  125.     }
  126.     /**
  127.      * Prerequisites: Method {@see self::updateKernelTimeZones()} must be called before.
  128.      *
  129.      * @return bool
  130.      */
  131.     private function updateKernelDateTime(): bool
  132.     {
  133.         return $this->updateKernelDateTimeByRequestTime()
  134.             || $this->updateKernelDateTimeByKernelStartTime()
  135.             || $this->updateKernelDateTimeByCurrentServerTime();
  136.     }
  137.     /**
  138.      * @return bool
  139.      */
  140.     private function updateKernelDateTimeByRequestTime(): bool
  141.     {
  142.         if (null === $this->requestStack || null === $this->requestStack->getMainRequest()) {
  143.             return false;
  144.         }
  145.         $request $this->requestStack->getMainRequest();
  146.         if (is_numeric($request->server->get('REQUEST_TIME_FLOAT'))) {
  147.             $datetime = \DateTimeImmutable::createFromFormat('U.u'$request->server->get('REQUEST_TIME_FLOAT'));
  148.         } elseif (is_numeric($request->server->get('REQUEST_TIME'))) {
  149.             $datetime = new \DateTimeImmutable(sprintf('@%d'$request->server->get('REQUEST_TIME')));
  150.         }
  151.         if ($datetime ?? null) {
  152.             DateTimeKernel::setDateTimeServer($datetime);
  153.         }
  154.         return true;
  155.     }
  156.     /**
  157.      * @return bool
  158.      */
  159.     private function updateKernelDateTimeByKernelStartTime(): bool
  160.     {
  161.         if (null === $this->kernel || !is_numeric($this->kernel->getStartTime())) {
  162.             return false;
  163.         }
  164.         DateTimeKernel::setDateTimeServer(
  165.             new \DateTimeImmutable(sprintf('@%d'$this->kernel->getStartTime()))
  166.         );
  167.         return true;
  168.     }
  169.     /**
  170.      * @return bool
  171.      */
  172.     private function updateKernelDateTimeByCurrentServerTime(): bool
  173.     {
  174.         DateTimeKernel::setDateTimeServer(
  175.             new \DateTimeImmutable('now', new \DateTimeZone('+00:00'))
  176.         );
  177.         return true;
  178.     }
  179. }