Skip to content

Timestampable (and maybe more extensions) don't work with DBAL 4.0.0-RC2ย #2752

@Arkanii

Description

@Arkanii

Environment

Package

show

$ composer show --latest gedmo/doctrine-extensions
name     : gedmo/doctrine-extensions
descrip. : Doctrine behavioral extensions
keywords : Blameable, behaviors, doctrine, extensions, gedmo, loggable, nestedset, odm, orm, sluggable, sortable, timestampable, translatable, tree, uploadable
versions : * v3.14.0
latest   : v3.14.0
type     : library
license  : MIT License (MIT) (OSI approved) https://spdx.org/licenses/MIT.html#licenseText
homepage : http://gediminasm.org/
source   : [git] https://github.com/doctrine-extensions/DoctrineExtensions.git 3b5b5cba476b4ae32a55ef69ef2e59d64d5893cf
dist     : [zip] https://api.github.com/repos/doctrine-extensions/DoctrineExtensions/zipball/3b5b5cba476b4ae32a55ef69ef2e59d64d5893cf 3b5b5cba476b4ae32a55ef69ef2e59d64d5893cf
path     : /app/vendor/gedmo/doctrine-extensions
names    : gedmo/doctrine-extensions

support
email : [email protected]
issues : https://github.com/doctrine-extensions/DoctrineExtensions/issues
source : https://github.com/doctrine-extensions/DoctrineExtensions/tree/v3.14.0
wiki : https://github.com/Atlantic18/DoctrineExtensions/tree/main/doc

autoload
psr-4
Gedmo\ => src/

requires
behat/transliterator ^1.2
doctrine/annotations ^1.13 || ^2.0
doctrine/collections ^1.2 || ^2.0
doctrine/common ^2.13 || ^3.0
doctrine/event-manager ^1.2 || ^2.0
doctrine/persistence ^2.2 || ^3.0
php ^7.4 || ^8.0
psr/cache ^1 || ^2 || ^3
symfony/cache ^5.4 || ^6.0 || ^7.0
symfony/deprecation-contracts ^2.1 || ^3.0

requires (dev)
doctrine/cache ^1.11 || ^2.0
doctrine/dbal ^3.2
doctrine/doctrine-bundle ^2.3
doctrine/mongodb-odm ^2.3
doctrine/orm ^2.14.0
friendsofphp/php-cs-fixer ^3.14.0
nesbot/carbon ^2.71 || 3.x-dev as 3.0
phpstan/phpstan ^1.10.2
phpstan/phpstan-doctrine ^1.0
phpstan/phpstan-phpunit ^1.0
phpunit/phpunit ^9.6
rector/rector ^0.18
symfony/console ^5.4 || ^6.0 || ^7.0
symfony/phpunit-bridge ^6.0 || ^7.0
symfony/yaml ^5.4 || ^6.0 || ^7.0

suggests
doctrine/mongodb-odm to use the extensions with the MongoDB ODM
doctrine/orm to use the extensions with the ORM

conflicts
doctrine/dbal <3.2
doctrine/mongodb-odm <2.3
doctrine/orm <2.14.0 || 2.16.0 || 2.16.1
sebastian/comparator <2.0

Doctrine packages

show

$ composer show --latest 'doctrine/*'
Color legend:
- patch or minor release available - update recommended
- major release available - update possible
- up to date version

Direct dependencies required in composer.json:
doctrine/dbal                       4.0.0-RC2 4.0.0-RC2 Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.
doctrine/doctrine-bundle            2.11.1    2.11.1    Symfony DoctrineBundle
doctrine/doctrine-migrations-bundle 3.3.0     3.3.0     Symfony DoctrineMigrationsBundle
doctrine/orm                        3.0.0-RC1 3.0.0-RC1 Object-Relational-Mapper for PHP

Transitive dependencies not required in composer.json:
doctrine/annotations                2.0.1     2.0.1     Docblock Annotations Parser
doctrine/cache                      2.2.0     2.2.0     PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.
doctrine/collections                2.1.4     2.1.4     PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.
doctrine/common                     3.4.3     3.4.3     PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, proxies and mu...
doctrine/deprecations               1.1.3     1.1.3     A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.
doctrine/event-manager              2.0.0     2.0.0     The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.
doctrine/inflector                  2.0.9     2.0.9     PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.
doctrine/instantiator               2.0.0     2.0.0     A small, lightweight utility to instantiate objects in PHP without invoking their constructors
doctrine/lexer                      3.0.0     3.0.0     PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.
doctrine/migrations                 3.7.2     3.7.2     PHP Doctrine Migrations project offer additional functionality on top of the database abstraction layer (DBAL) for versioning your database schema and easily deploying ...
doctrine/persistence                3.2.0     3.2.0     The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.
doctrine/sql-formatter              1.1.3     1.1.3     a PHP SQL highlighting library

PHP version

$ php -v
PHP 8.3.2 (cli) (built: Jan 27 2024 04:34:00) (ZTS)
Copyright (c) The PHP Group
Zend Engine v4.3.2, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.2, Copyright (c), by Zend Technologies
    with Xdebug v3.3.1, Copyright (c) 2002-2023, by Derick Rethans

Subject

With DBAL 4.0.0-RC2, there is a bug with Timestampable.
I found why and I can provide a fix, but I think this bug can be on other extensions... That's why I only create a bug issue.

In DBAL 4.0.0-RC2, the method $this->getObjectManager()->getConnection()->getDriver()->getDatabasePlatform() now wait an argument, which is not provided for the moment, and the getFieldMapping function return an object instead of an array.

I found the bug in the src/Timestampable/Mapping/Event/Adapter/ORM.php file.

Actual version :

show

<?php

/*
 * This file is part of the Doctrine Behavioral Extensions package.
 * (c) Gediminas Morkevicius <[email protected]> http://www.gediminasm.org
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Gedmo\Timestampable\Mapping\Event\Adapter;

use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping\ClassMetadata;
use Gedmo\Mapping\Event\Adapter\ORM as BaseAdapterORM;
use Gedmo\Timestampable\Mapping\Event\TimestampableAdapter;

/**
 * Doctrine event adapter for ORM adapted
 * for Timestampable behavior
 *
 * @author Gediminas Morkevicius <[email protected]>
 */
final class ORM extends BaseAdapterORM implements TimestampableAdapter
{
    /**
     * @param ClassMetadata $meta
     */
    public function getDateValue($meta, $field)
    {
        $mapping = $meta->getFieldMapping($field);
        $converter = Type::getType($mapping['type'] ?? Types::DATETIME_MUTABLE);
        $platform = $this->getObjectManager()->getConnection()->getDriver()->getDatabasePlatform();

        return $converter->convertToPHPValue($this->getRawDateValue($mapping), $platform);
    }

    /**
     * Generates current timestamp for the specified mapping
     *
     * @param array<string, mixed> $mapping
     *
     * @return \DateTimeInterface|int
     */
    private function getRawDateValue(array $mapping)
    {
        $datetime = new \DateTime();
        $type = $mapping['type'] ?? null;

        if ('integer' === $type) {
            return (int) $datetime->format('U');
        }

        if (in_array($type, ['date_immutable', 'time_immutable', 'datetime_immutable', 'datetimetz_immutable'], true)) {
            return \DateTimeImmutable::createFromMutable($datetime);
        }

        return $datetime;
    }
}

Fixed version :

show

<?php

/*
 * This file is part of the Doctrine Behavioral Extensions package.
 * (c) Gediminas Morkevicius <[email protected]> http://www.gediminasm.org
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Gedmo\Timestampable\Mapping\Event\Adapter;

use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\FieldMapping;
use Gedmo\Mapping\Event\Adapter\ORM as BaseAdapterORM;
use Gedmo\Timestampable\Mapping\Event\TimestampableAdapter;

/**
 * Doctrine event adapter for ORM adapted
 * for Timestampable behavior
 *
 * @author Gediminas Morkevicius <[email protected]>
 */
final class ORM extends BaseAdapterORM implements TimestampableAdapter
{
    /**
     * @param ClassMetadata $meta
     */
    public function getDateValue($meta, $field)
    {
        $mapping = $meta->getFieldMapping($field);
        $converter = Type::getType($mapping['type'] ?? Types::DATETIME_MUTABLE);
        $platform = $this->getObjectManager()->getConnection()->getDriver()->getDatabasePlatform($this->getObjectManager()->getConnection());

        return $converter->convertToPHPValue($this->getRawDateValue($mapping), $platform);
    }

    /**
     * Generates current timestamp for the specified mapping
     *
     * @param FieldMapping $mapping
     *
     * @return \DateTimeInterface|int
     */
    private function getRawDateValue(FieldMapping $mapping)
    {
        $datetime = new \DateTime();
        $type = $mapping->type ?? null;

        if ('integer' === $type) {
            return (int) $datetime->format('U');
        }

        if (in_array($type, ['date_immutable', 'time_immutable', 'datetime_immutable', 'datetimetz_immutable'], true)) {
            return \DateTimeImmutable::createFromMutable($datetime);
        }

        return $datetime;
    }
}

This fix work on my side.

I'll be happy to help if needed !

Minimal repository with the bug

I'll do it if I have some free time, I apologize to haven't created it for now.

Steps to reproduce

Just create a project that use DBAL 4.0.0-RC2 instead of 3.x.x and use Timestampable on a updated_at property and try to save a entity.

Expected results

{"@context":"\/api\/contexts\/Todo","@id":"\/api\/todos\/10","@type":"Todo","id":10,"name":"Test","done":false,"createdAt":"2024-02-01T18:07:54+00:00","updatedAt":"2024-02-01T18:07:54+00:00"}

Actual results

"Too few arguments to function Doctrine\\DBAL\\Driver\\Middleware\\AbstractDriverMiddleware::getDatabasePlatform(), 0 passed in /app/vendor/gedmo/doctrine-extensions/src/Timestampable/Mapping/Event/Adapter/ORM.php on line 33 and exactly 1 expected"

Thanks ! ๐Ÿ˜„

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions