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

BackedEnum primary key fails to convert for association using proxy classes #10788

Open
wmouwen opened this issue Jun 22, 2023 · 7 comments
Open

Comments

@wmouwen
Copy link

wmouwen commented Jun 22, 2023

Bug Report

Q A
BC Break unsure
Version 2.15.3

Summary

For a while BackedEnums were allowed as primary keys, where Doctrine would happily convert them to their scalar value. There has been some back and forth about this in previous issues/PRs where the functionality was repaired and broken again.

#10334
#10471
#10508

Most recent events:
#10745
#10758

Current behavior

Setting a BackedEnum as primary key on an entity, using that entity in an association and trying to save it with a proxy class, will throw an error as the BackedEnum is no longer converted to a scalar value.

Uncaught Error: Object of class Enum\LocaleCode could not be converted to string in /app/vendor/doctrine/dbal/src/Driver/PDO/Statement.php:43
Stack trace:
#0 /app/vendor/doctrine/dbal/src/Driver/PDO/Statement.php(43): PDOStatement->bindValue(1, Object(Enum\LocaleCode), 2)
#1 /app/vendor/doctrine/dbal/src/Statement.php(115): Doctrine\DBAL\Driver\PDO\Statement->bindValue(1, Object(Enum\LocaleCode), 2)
#2 /app/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php(276): Doctrine\DBAL\Statement->bindValue(1, Object(Enum\LocaleCode), Object(Doctrine\DBAL\Types\StringType))
#3 /app/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php(1172): Doctrine\ORM\Persisters\Entity\BasicEntityPersister->executeInserts()
#4 /app/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php(441): Doctrine\ORM\UnitOfWork->executeInserts(Object(Doctrine\ORM\Mapping\ClassMetadata))
#5 /app/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php(403): Doctrine\ORM\UnitOfWork->commit(NULL)
#6 /app/trigger_error.php(23): Doctrine\ORM\EntityManager->flush()
#7 {main}
  thrown in /app/vendor/doctrine/dbal/src/Driver/PDO/Statement.php on line 43

How to reproduce

See https://github.com/wmouwen/doctrine-orm-10788 for a minimal setup throwing the error.

Code snippet copy 👇
<?php

enum LocaleCode: string
{
    case Dutch = 'nl_NL';
}

#[ORM\Entity, ORM\Table]
class Locale
{
    #[ORM\Id]
    #[ORM\Column(name: 'code', type: Types::STRING, enumType: LocaleCode::class)]
    public LocaleCode $code;
}

#[ORM\Entity, ORM\Table]
class CategoryLocale
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(name: 'id', type: Types::INTEGER)]
    public int $id;

    #[ORM\ManyToOne(targetEntity: \Entity\Locale::class, cascade: ['persist'])]
    #[ORM\JoinColumn(name: 'locale_code', referencedColumnName: 'code', nullable: false)]
    public Locale $locale;
}
global $entityManager;

// Create entity with BackedEnum as primary key.
$locale = new \Entity\Locale();
$locale->code = \Enum\LocaleCode::Dutch;

// Persist entity, clear manager.
$entityManager->persist($locale);
$entityManager->flush();
$entityManager->clear();

// Create entity with an association to the entity with BackedEnum key.
// Note that the use of a proxy class is required for the error to show.
$categoryLocale = new \Entity\CategoryLocale();
$categoryLocale->locale = $entityManager->getReference(\Entity\Locale::class, \Enum\LocaleCode::Dutch);

// Attempt to persist, throws an error.
$entityManager->persist($categoryLocale);
$entityManager->flush();

Expected behavior

The BackedEnum is converted and the save succeeds, as it did in version 2.15.2.

-edit- Added the stack trace, made the code snippet collapse, added reference to repository with minimal setup.

@wmouwen
Copy link
Author

wmouwen commented Jun 22, 2023

@Gwemox Allow me to tag you in this issue as you were the author of the initial pull requests.

@Gwemox
Copy link
Contributor

Gwemox commented Jun 22, 2023

@wmouwen Do you have the stack trace?

@wmouwen
Copy link
Author

wmouwen commented Jun 22, 2023

@Gwemox I've created a repository with minimal code which triggers the error. Important to the case is the use of a proxy class. Stack trace is included in the README in the repository.

https://github.com/wmouwen/doctrine-orm-10788

@wmouwen wmouwen changed the title BackedEnum primary key failed to convert for association BackedEnum primary key fails to convert for association using proxy classes Jun 22, 2023
@Gwemox
Copy link
Contributor

Gwemox commented Jun 23, 2023

@wmouwen you can convert your backed enum to string with a doctrine custom type : https://www.doctrine-project.org/projects/doctrine-orm/en/2.15/cookbook/custom-mapping-types.html

@greg0ire @sips-richard We should think about the desired solution for 2.6 or 3.0 ?

Currently StringType does nothing.

    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        return $value;
    }

$value is a backed enum.

@greg0ire
Copy link
Member

Well if it's a bug, for 2.15

@Gwemox
Copy link
Contributor

Gwemox commented Jun 23, 2023

We reverted because of this issue #10745

We could modify the StringType to make a ->value if it is an enum ? Or create EnumType ?

@wmouwen
Copy link
Author

wmouwen commented Jun 23, 2023

After having fiddled with custom types for backed enumerations, I would argue having dedicated types isn't the way to go. You would have to differ between the (kinds of) string and integers that there are default mappings for: EnumStringType, EnumIntegerType, optionally EnumSmallintType, etc.

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

3 participants