Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Arkanii opened this issue Feb 1, 2024 · 11 comments
Open

Comments

@Arkanii
Copy link

Arkanii commented Feb 1, 2024

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 : gediminas.morkevicius@gmail.com
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 <gediminas.morkevicius@gmail.com> 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 <gediminas.morkevicius@gmail.com>
 */
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 <gediminas.morkevicius@gmail.com> 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 <gediminas.morkevicius@gmail.com>
 */
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 ! 😄

@Arkanii Arkanii changed the title Timestampable don't work with DBAL 4.0.0-RC2 Timestampable (and maybe more extensions) don't work with DBAL 4.0.0-RC2 Feb 1, 2024
@mbabker
Copy link
Contributor

mbabker commented Feb 2, 2024

DBAL 4.0 isn't supported right now and probably won't be for a while (IIRC ORM 2.x isn't getting support for it, so ORM 3.x compat has to be sorted out first).

@stof
Copy link
Contributor

stof commented Feb 12, 2024

The solution is actually to use the high-level API to access the platform (which has not change between 3.x and 4.x) instead of reaching for the low-level driver.

@conradfr
Copy link

It seems the Symfony 7 generator uses DBAL 4.0, this "bug" will annoy many people (I'm one of them ;)).

@stof
Copy link
Contributor

stof commented Feb 16, 2024

Note that the Symfony generator should be forcing DBAL 3.x for now since a few days.

@joshmurrayeu
Copy link

Hi folks, I've installed Doctrine manually into a Laravel application and I'm experiencing the same problem.

DBAL 4.0 isn't supported right now and probably won't be for a while....

@mbabker is there a roadmap I could look at? Failing that, do you have any idea when DBAL 4.x will be implemented?

I'll build a workaround for my particular scenario.

@mbabker
Copy link
Contributor

mbabker commented Apr 9, 2024

@mbabker is there a roadmap I could look at? Failing that, do you have any idea when DBAL 4.x will be implemented?

As this package is entirely supported by volunteers, there's no roadmap or timeline. But, the gist of what's required is basically to finish ORM 3 compat (as ORM 2 and DBAL 4 are not usable together, so there's nothing that can really be done to test this at the moment) then start working on DBAL 4 compatibility.

The fix noted in #2752 (comment) (basically changing any calls similar to $this->getObjectManager()->getConnection()->getDriver()->getDatabasePlatform() to $this->getObjectManager()->getConnection()->getDatabasePlatform()) could be sent as a PR at any time to fix this specific issue, but issues like #2502 are pretty big blockers to allowing DBAL 4 (and if I'm being honest, my gut feeling says that might not come without a major release of this package considering what would be involved to resolve that one).

@nbennett25
Copy link

nbennett25 commented Jun 4, 2024

I also just ran into this issue - it would be helpful to make a note what the extension is and is not compatible with in the README.md so people don't get started with the extension only to run into the same error (especially if the incompatibility issue 2502 is almost 2 years old)

fwiw @Arkanii I was able to get the Timestampable annotation working with your change and one other - here's a composer patch file, maybe it'll help somebody out.
gedmo-doctrine-extenstions-timestampable.patch

@mbabker
Copy link
Contributor

mbabker commented Jun 4, 2024

I also just ran into this issue - it would be helpful to make a note what the extension is and is not compatible with in the README.md so people don't get started with the extension only to run into the same error

The best place to look at compatibility is going to be the composer.json file because that's what Composer is going to use to figure out what to install. Putting compatibility info in README files or other docs files ends up in info being outdated pretty easily (like I just learned that there's a table that tries to convey what versions of doctrine/orm and doctrine/common some things are compatible with, and that table's massively out-of-date and honestly not well presented (the two libraries have different versioning schemes, so trying to say it's compatible with both like the header implies isn't great).

especially if the incompatibility issue 2502 is almost 2 years old

And as that issue shows, there's actually a patch that can help fix that particular compatibility issue from a pure code perspective. Except it's not easy to ship it because the changes require data migrations for downstream users (the DBAL's object and array types store data using PHP's serialize() function, whereas the JSON type uses native JSON support, so it's not just a matter applying that patch and shipping the change but figuring out how to deal with any existing data as well).

I was able to get the Timestampable extension working with your change and one other - here's a composer patch file, maybe it'll help somebody out.

A pull request for the first change in that patch would be hugely appreciated instead of just patching your local app. As for the second change, a proper fix has already landed in this repository, so it's not necessary with the latest release.

@jgwiazdowski
Copy link

@nbennett25
patch works, thanks

but still, it needs fixing :|

@michaelukolovrus
Copy link

Is it planned to update dbal > 4.0.0 in the upcoming release?

@mbabker
Copy link
Contributor

mbabker commented Jun 27, 2024

Is it planned to update dbal > 4.0.0 in the upcoming release?

Eventually, yes. Unfortunately, there is a huge task involved in that (see #2502 and #2825).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants