Symfony 6, Doctrine, DateTime and microseconds
Fabian Blechschmidt
Not tested in production
This is not tested on a stage or production environment yet – and I’m sure I forget to remove this warning, once it is properly tested. Feel free to write a comment, so we can update this post 🙂
Doctrine isn’t yet able to handle microseconds , if I understand correctly, especially because they are not sure how to handle the on the difference database management systems.
But thankfully it is relatively simple to implement our own type (or overwrite the datetime type).
Implement your own type
Thanks to flauschi , I was able to adapt his code for our purpose (especially without using Carbon)
<?php
declare(strict_types=1);
namespace Winkelwagen\Dbal;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\Type;
class DateTimeWithMicroseconds extends Type
{
private const TYPENAME = 'datetime';
public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
{
if (isset($column['version']) && $column['version'] === true) {
return 'TIMESTAMP';
}
if ($platform instanceof PostgreSqlPlatform) {
return 'TIMESTAMP(6) WITHOUT TIME ZONE';
}
return 'DATETIME(6)';
}
public function convertToPHPValue($value, AbstractPlatform $platform): mixed
{
if ($value === null || $value instanceof \DateTimeInterface) {
return $value;
}
if (str_contains($value, '.')) {
return \DateTimeImmutable::createFromFormat('Y-m-d H:i:s.u', $value);
}
return \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $value);
}
public function convertToDatabaseValue($value, AbstractPlatform $platform): mixed
{
if (null === $value) {
return null;
}
if ($value instanceof \DateTimeInterface) {
return $value->format('Y-m-d H:i:s.u');
}
throw ConversionException::conversionFailedInvalidType(
$value,
$this->getName(),
['null', 'DateTime']
);
}
public function getName(): string
{
return self::TYPENAME;
}
public function requiresSQLCommentHint(AbstractPlatform $platform): bool
{
return true;
}
}
With this class and the following configuration, you are set:
# config/packages/doctrine.yaml
doctrine:
dbal:
types:
datetime: \Paddox\Dbal\DateTimeWithMicroseconds
To change the name of the type, you need to change the YAML key and the PHP constant.
gist with everything
https://gist.github.com/Schrank/d1f3243e47e52bc20809a3c20cd0441a
Other articles from this category
ENABLE_SERVICES: the Shopware env var that quietly installs apps on your shop
I was grepping through vendor/shopware/core for the hidden-gems series and stumbled over Shopware\Core\Service\AllServiceInstaller. Two-argument constructor, twelve lines of logic, @internal. Nothing dramatic — until I read what it actually does: it installs apps on your shop. By itself. In production. Once a day. Unless you told it not to. So this one isn’t going to […]
Shopware 6 Hidden Gems #24: Lightning round — ten small gems that didn’t need their own post
Twenty-three parts into this series, my research folder still has a stack of finds that are real, useful, undocumented — and about two paragraphs big. Instead of stretching each into a full post, here’s the lightning round. One problem, one gem, one file reference. Go. 1. rawUrl() — URLs for mail templates that actually work […]
Shopware 6 Hidden Gems #23: Why your sitemap silently stopped updating (and sitemap:generate –force)
A slow-burn bug report, verbatim from memory: „Google Search Console shows our sitemap is three months old. New categories aren’t in it.“ Three months. No errors in the log worth noticing, the scheduled task looks healthy, and regenerating „worked“ — or seemed to. The cause turned out to be a mechanism that’s completely reasonable and […]