Сохранить даты в UTC - PullRequest
       6

Сохранить даты в UTC

1 голос
/ 09 марта 2020

Я сейчас пытаюсь сохранить свои даты в базе данных с часовым поясом UT C.

Чтобы получить часовой пояс пользователя, у меня есть функция JS, которая делает запрос AJAX на мой back-end как это:

import $ from 'jquery';
import jstz from 'jstz';

export default function setSessionTimezone(route)
{
    var timezone = jstz.determine();
    $.ajax({
        type:'POST', async:true, cache:false, url:route, data:"timezone="+timezone.name(),
        success:function(data) { if (data.reloadPage) location.reload(); }
    });
}

Этот метод вызывается, только если часовой пояс еще не находится в сеансе Итак, пока у меня есть пользовательский часовой пояс в моем бэкэнде, это был первый шаг.

Я хочу сохранить его в базе данных. В этом сообщении я нашел кое-что интересное: Symfony buildForm конвертирует дату и время в локальную и обратно в ut c

Они рекомендуют использовать "model_timezone" и "view_timezone" для формы, я тоже:

use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TimeType;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class UtcTypeExtension extends AbstractTypeExtension
{
    /**
     * @var SessionInterface
     */
    private $session;

    public function __construct(SessionInterface $session)
    {
        $this->session = $session;
    }

    /**
     * Return the class of the type being extended.
     */
    public static function getExtendedTypes(): iterable
    {
        return [TimeType::class, DateType::class];
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        parent::configureOptions($resolver);

        $resolver->setDefaults([
            'model_timezone' => 'UTC',
            "view_timezone" => $this->session->get('tools_timezone')
        ]);
    }
}

И уууу, это работает. Но только в формах.

Если я хочу отобразить даты с помощью Twig или из PHP, мне нужно получить часовой пояс из сеанса и изменить часовой пояс DateTime.

Поэтому я искал другой вариант. Я нашел это на Doctrine сайте , чтобы изменить часовой пояс напрямую с Doctrine.

Это звучит интересно, но я, вероятно, упускаю точку, потому что кажется, что работать, даже после того, как я добавил следующую конфигурацию:

doctrine:
    dbal:
        types:
            datetime: SomeNamespace\DoctrineExtensions\DBAL\Types\UTCDateTimeType

Так что я хотел бы знать , возможно ли то, что я хочу сделать ? Или если я вынужден переопределить фильтр даты «Twig», чтобы использовать мой часовой пояс? И если я хочу отобразить дату с PHP, я также вынужден использовать часовой пояс из сеанса?

1 Ответ

0 голосов
/ 10 марта 2020

Я нашел что-то, что, кажется, отвечает на мой вопрос.

Я добавил слушателя к событию doctrine "postLoad".

Для информации, TimezoneProvider просто возвращает DateTimezone объект из сеанса или UT C, если он не был определен.

use DateTime;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\ORM\Mapping\Column;
use SomeNamespace\Provider\TimezoneProvider;
use ReflectionClass;
use ReflectionException;
use Symfony\Component\PropertyAccess\PropertyAccess;

class DateTimeConverterListener
{
    /**
     * @var AnnotationReader
     */
    private $reader;

    /**
     * @var TimezoneProvider
     */
    private $timezoneProvider;

    public function __construct(AnnotationReader $reader, TimezoneProvider $timezoneProvider)
    {
        $this->reader = $reader;
        $this->timezoneProvider = $timezoneProvider;
    }

    public function postLoad(LifecycleEventArgs $args)
    {
        $entity = $args->getObject();
        $propertyAccessor = PropertyAccess::createPropertyAccessor();

        try {
            $reflection = new ReflectionClass(get_class($entity));

            //We search the properties where we need to update the Timezone.
            foreach ($reflection->getProperties() as $property) {
                $annotation = $this->reader->getPropertyAnnotation($property, Column::class);
                if (!$annotation instanceof Column)
                    continue;

                switch ($annotation->type) {
                    case "time":
                    case "date":
                    case "datetime":
                        /** @var DateTime|null $attribute */
                        $attribute = $propertyAccessor->getValue($entity, $property->getName());

                        if (null === $attribute)
                            continue 2;

                        //The getTimezone function returns UTC in case of no session information. And because it's a
                        // DateTime object, we don't need to set the value after the modification
                        $attribute->setTimezone($this->timezoneProvider->getTimezone());
                        break;
                }
            }
        } catch (ReflectionException $e) {
            //Abort the transformation
        }
    }
}

Для правильного отображения даты с помощью фильтра веток «| date» я также обновляю Twig с помощью события:

use SomeNamespace\Provider\TimezoneProvider;
use Twig\Environment;
use Twig\Extension\CoreExtension;

class SetupTwigTimezoneListener
{
    /**
     * @var TimezoneProvider
     */
    private $timezoneProvider;
    /**
     * @var Environment
     */
    private $twig;

    public function __construct(TimezoneProvider $timezoneProvider, Environment $twig)
    {
        $this->timezoneProvider = $timezoneProvider;
        $this->twig = $twig;
    }

    public function onKernelRequest()
    {
        //Define the timezone of the application based of the timezone of the user
        $this->twig->getExtension(CoreExtension::class)->setTimezone($this->timezoneProvider->getTimezone()->getName());
    }
}

Я не совсем уверен, что это идеальное решение, но, похоже, оно работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...