Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[PropertyInfo] DoctrineExtractor incompatible type resolution with DBAL 4 or ORM 2.19 #54418

Copy link
Copy link
Closed
@llupa

Description

@llupa
Issue body actions

Symfony version(s) affected

7.0.3

Description

Preface

With the recent release of Doctrine ORM 3 and DBAL 4 there has been a major change in at least one column type.

bigint now reads:

Maps and converts 8-byte integer values.
...

Values retrieved from the database are always converted to PHP's integer type if they are within PHP's integer range
or string if they aren't.

Additionally, if you did not yet make the jump to ORM 3/DBAL 4 and are using ORM 2.19 which acts like Sf .4 and the
next major .0 you can use int typehints in your PHP code with a bigint column type if you go for a string|int
union. You can read more about it in this issue: Invalid field error reported for bigint DBAL type.

Another case would be if you know that your project's tech will always rely on int within your PHP_INT_MAX you could
also override the default bigint type and bind it to int.

This is also dependent of your DB engine too, but generally speaking, all of the above are true for pgsql. How one goes about handling this Doctrine hiccup is up to developer's choice and from my POV any of the solutions that can be used for Doctrine is fine.

Symfony

Let's assume that you are using one of the methods to have Doctrine happy but without jeopardising your project. If your project is in any capacity in need of denormalizing request data into PHP objects this is the next step that breaks.

At one point, for objects, the AbstractObjectNormalizer::getTypes() is called, which in turn makes use of
PropertyInfoExtractor to resolve the Type of a bigint property that is in some way type-hinted as int and request data will use int values too.

DoctrineExtractor::getTypes() will internally try to get the PHP type of bigint which for now is always going to map
it to string.

// at about line ~250
return match ($doctrineType) {
    Types::SMALLINT,
    Types::INTEGER => Type::BUILTIN_TYPE_INT,
    Types::FLOAT => Type::BUILTIN_TYPE_FLOAT,
    Types::BIGINT, // <- here
    Types::STRING,
    Types::TEXT,
    Types::GUID,
    Types::DECIMAL => Type::BUILTIN_TYPE_STRING, // <- mapped to string
    // ...

This causes a gate-keeping effect with the following exception message:

The type of the "bigint" attribute for class "IHaveNumbers" must be one of "string" ("int" given).

For this there are some possible ways to go about it.

A) You can use DISABLE_TYPE_ENFORCEMENT on your context and the value is used as is, letting it be handled on code level
which may result in \Error issues.
B) Switch your property to string only and add more cast juggling.
C) Switch your property to string and also reflect this in your general API so that request data is now only string.
D) Update / Decorate DoctrineExtractor with the following hack solution:

// new block
if (Types::BIGINT === $typeOfField) {
    return [
        new Type(Type::BUILTIN_TYPE_INT, $nullable),
        new Type(Type::BUILTIN_TYPE_STRING, $nullable),
    ];
}
// continue how it used to be
if (!$builtinType = $this->getPhpType($typeOfField)) {
    return null;
}

I went for option D because I really want to have bigint typed to int and not to string as I have a project that
only delivers an API with API Platform. So keeping my JSON Schema consistent is top priority.

It works, but I am not sure if it is a) a solution and b) a preferred solution.

How to reproduce

I can create a simple project if the description above is not enough. The easiest way would be to:

  • use API Platform with one resource and pgsql for storage.
  • use orm 3 and dbal 4
  • add 1 property with bigint
  • send a JSON body with int values in your property
  • The type of the "bigint" attribute for class "IHaveNumbers" must be one of "string" ("int" given).

Possible Solution

In case DoctrineExtractor cannot be updated one can also play around with attributes. Below I have my example in my project:

#[ORM\Column(type: Types::BIGINT)]
#[ApiProperty(
    jsonSchemaContext: ['type' => 'integer'],
    extraProperties: [SchemaPropertyMetadataFactory::JSON_SCHEMA_USER_DEFINED => true]
)]
#[Context(denormalizationContext: [AbstractObjectNormalizer::DISABLE_TYPE_ENFORCEMENT => true])]
#[Assert\Type(type: 'int')]
#[Assert\Positive]
#[Assert\Range(max: 12_345_678_901)]
private $bigInt;

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.