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

Bug: Generated proxy method getId() casts to int and breaks when used with enums #1006

Open
pauljura opened this issue Sep 13, 2023 · 0 comments

Comments

@pauljura
Copy link

The bug

The generated proxy class for an entity has the following code for the getId() method:

    /**
     * {@inheritDoc}
     */
    public function getId(): ?ExampleEnum
    {
        if ($this->__isInitialized__ === false) {
            return (int)  parent::getId();
        }


        $this->__initializer__ && $this->__initializer__->__invoke($this, 'getId', []);

        return parent::getId();
    }

The problem is the line with return (int) parent::getId(); because it's casting the return value to int, even though the method is expected to return ?ExampleEnum.

Current behavior

An error is thrown:

Proxies\\__CG__\\App\\Entity\\ExampleEntity::getId(): Return value must be of type ?ExampleEnum, int returned

How to reproduce

To reproduce this, you need:

  1. an entity with a PHP enum class as the primary key
  2. a second entity that has a ManyToOne relationship with the first
  3. load an instance of the second entity, and then try to fetch the id of the related entity (the one with the enum PK)
  4. since the related entity is not yet loaded, the proxy method will be used
  5. error occurs
enum ExampleEnum: int
{
  Case A = 1;
  Case B = 2;
}

class ExampleEntity
{
  #[ORM\Column(name: 'id', type: Types::INTEGER, nullable: false, enumType: ExampleEnum::class)]
  #[ORM\Id]
  #[ORM\GeneratedValue(strategy: 'IDENTITY')]
  private ?ExampleEnum $id = null;

  public function getId(): ?ExampleEnum
  {
    return $this->id;
  }
}

class AnotherEntity
{
  #[ORM\Column(name: 'id', type: Types::INTEGER, nullable: false)]
  #[ORM\Id]
  #[ORM\GeneratedValue(strategy: 'IDENTITY')]
  private ?int $id = null;

  public function getId(): ?int
  {
    return $this->id;
  }

  #[ORM\ManyToOne(targetEntity: ExampleEntity::class)]
  #[ORM\JoinColumn(name: 'entityId', referencedColumnName: 'id', nullable: false)]
  private ExampleEntity $relatedEntity;

  public function getRelatedEntity: ExampleEntity
  {
    return $this->relatedEntity;
  }
}


$foo = $em->getRepository(AnotherEntity::class)->find(1);

$enum = $foo->getRelatedEntity()->getId(); // fails here

Expected behavior

The getId() method should return the correct enum class instead of an int.

Workaround

Avoid using the proxy by using eager loading, or fetching some other property to initialize the object.

Potential solution

I can see the offending code is here:

$methods .= $name . '(' . $this->buildParametersString($method->getParameters()) . ')';
$methods .= $this->getMethodReturnType($method);
$methods .= "\n" . ' {' . "\n";
if ($this->isShortIdentifierGetter($method, $class)) {
$identifier = lcfirst(substr($name, 3));
$fieldType = $class->getTypeOfField($identifier);
$cast = in_array($fieldType, ['integer', 'smallint'], true) ? '(int) ' : '';
$methods .= ' if ($this->__isInitialized__ === false) {' . "\n";
$methods .= ' ';
$methods .= $this->shouldProxiedMethodReturn($method) ? 'return ' : '';
$methods .= $cast . ' parent::' . $method->getName() . "();\n";
$methods .= ' }' . "\n\n";
}

You could simply remove the $cast variable, it's not necessary in my opinion, since you already declare the return type thanks to:

$this->getMethodReturnType($method)

Thanks!

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

1 participant