Repository: doctrine/orm (php)

Issue:
Error in ProxyFactory using cloned proxy entity with Enum field
### Bug Report

<!-- Fill in the relevant information below to help triage your issue. -->

|    Q        |   A
|------------ | ------
| BC Break    | no
| Version     | 3.1.0

#### Summary

<!-- Provide a summary describing the problem you are experiencing. -->
I'll use simulated example. We have 2 entities (Cart, Customer) with OneToOne join. Customer entity has PHP Enum field. I fetch Cart from database, get Customer (receive proxy object), make copy with clone. When I try to access data of cloned entity - there is fatal error:
`Typed property ReflectionProperty::$name must not be accessed before initialization` in Doctrine\ORM\Proxy\ProxyFactory line 237.
```
foreach ($class->getReflectionProperties() as $property) {
    if (! $property || ! $class->hasField($property->name) && ! $class->hasAssociation($property->name)) {
        continue;
    }
```
In that cycle $property is a Doctrine\Persistence\Reflection\EnumReflectionProperty object and $name variable is not initialized.
EnumReflectionProperty has method getName() - using this method in ProxyFactory solves the problem.
```
public function getName(): string
{
    return $this->originalReflectionProperty->getName();
}
```
Possible fix:
```
foreach ($class->getReflectionProperties() as $property) {
    if (! $property || ! $class->hasField($property->getName()) && ! $class->hasAssociation($property->getName())) {
        continue;
```


#### Current behavior

<!-- What is the current (buggy) behavior? -->
Fatal error

#### How to reproduce

<!--
Provide steps to reproduce the bug.
If possible, also add a code snippet with relevant configuration, entity mappings, DQL etc.
Adding a failing Unit or Functional Test would help us a lot - you can submit one in a Pull Request separately, referencing this bug report.
-->
2 entities, enum object and example to reproduce:
```
<?php

namespace App\Entity;

use App\Repository\CartRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: CartRepository::class)]
class Cart
{
    #[ORM\Id, ORM\GeneratedValue, ORM\Column]
    private ?int $id = null;

    #[ORM\Column]
    private ?int $amount = null;

    #[ORM\OneToOne(inversedBy: 'cart', cascade: ['persist', 'remove'])]
    private ?Customer $customer = null;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getAmount(): ?int
    {
        return $this->amount;
    }

    public function setAmount(int $amount): static
    {
        $this->amount = $amount;

        return $this;
    }

    public function getCustomer(): ?Customer
    {
        return $this->customer;
    }

    public function setCustomer(?Customer $customer): self
    {
        $this->customer = $customer;

        return $this;
    }
}
```

```
<?php

namespace App\Entity;

use App\Enum\Type;
use App\Repository\CustomerRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: CustomerRepository::class)]
class Customer
{
    #[ORM\Id, ORM\GeneratedValue, ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private ?string $name = null;

    #[ORM\Column(type: Types::SMALLINT, nullable: true, enumType: Type::class, options: ['unsigned' => true])]
    private ?Type $type = null;

    #[ORM\OneToOne(mappedBy: 'customer')]
    private ?Cart $cart = null;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): static
    {
        $this->name = $name;

        return $this;
    }

    public function getType(): ?Type
    {
        return $this->type;
    }

    public function setType(Type $type): static
    {
        $this->type = $type;

        return $this;
    }

    public function getCart(): ?Cart
    {
        return $this->cart;
    }

    public function setCart(?Cart $cart): self
    {
        // unset the owning side of the relation if necessary
        if (null === $cart && null !== $this->cart) {
            $this->cart->setCustomer(null);
        }

        // set the owning side of the relation if necessary
        if (null !== $cart && $cart->getCustomer() !== $this) {
            $cart->setCustomer($this);
        }

        $this->cart = $cart;

        return $this;
    }
}
```

```
<?php

namespace App\Enum;

enum Type: int
{
    case MALE = 1;
    case FEMALE = 2;
}
```

```
$cart = $repo->find(1);
$customer = clone $cart->getCustomer();
echo $customer->getName();
```


#### Expected behavior

<!-- What was the expected (correct) behavior? -->
No errors


Pull request:
Fixed proxy initialization for EnumReflectionProperty
Closes #11386

Patch:
diff --git a/.doctrine-project.json b/.doctrine-project.json
index 0eeb48f58..e76154929 100644
--- a/.doctrine-project.json
+++ b/.doctrine-project.json
@@ -94,6 +94,42 @@
             "branchName": "2.10.x",
             "slug": "2.10",
             "maintained": false
+        },
+        {
+            "name": "2.9",
+            "branchName": "2.9.x",
+            "slug": "2.9",
+            "maintained": false
+        },
+        {
+            "name": "2.8",
+            "branchName": "2.8.x",
+            "slug": "2.8",
+            "maintained": false
+        },
+        {
+            "name": "2.7",
+            "branchName": "2.7",
+            "slug": "2.7",
+            "maintained": false
+        },
+        {
+            "name": "2.6",
+            "branchName": "2.6",
+            "slug": "2.6",
+            "maintained": false
+        },
+        {
+            "name": "2.5",
+            "branchName": "2.5",
+            "slug": "2.5",
+            "maintained": false
+        },
+        {
+            "name": "2.4",
+            "branchName": "2.4",
+            "slug": "2.4",
+            "maintained": false
         }
     ]
 }
diff --git a/src/Proxy/ProxyFactory.php b/src/Proxy/ProxyFactory.php
index f784cefa6..8dd39ddd8 100644
--- a/src/Proxy/ProxyFactory.php
+++ b/src/Proxy/ProxyFactory.php
@@ -234,7 +234,7 @@ EOPHP;
             $class = $entityPersister->getClassMetadata();
 
             foreach ($class->getReflectionProperties() as $property) {
-                if (! $property || ! $class->hasField($property->name) && ! $class->hasAssociation($property->name)) {
+                if (! $property || ! $class->hasField($property->getName()) && ! $class->hasAssociation($property->getName())) {
                     continue;
                 }
 


Test patch:
diff --git a/tests/Tests/ORM/Functional/Ticket/GH11386/GH11386EntityCart.php b/tests/Tests/ORM/Functional/Ticket/GH11386/GH11386EntityCart.php
new file mode 100644
index 000000000..032171aac
--- /dev/null
+++ b/tests/Tests/ORM/Functional/Ticket/GH11386/GH11386EntityCart.php
@@ -0,0 +1,55 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Doctrine\Tests\ORM\Functional\Ticket\GH11386;
+
+use Doctrine\ORM\Mapping\Column;
+use Doctrine\ORM\Mapping\Entity;
+use Doctrine\ORM\Mapping\GeneratedValue;
+use Doctrine\ORM\Mapping\Id;
+use Doctrine\ORM\Mapping\OneToOne;
+
+#[Entity]
+class GH11386EntityCart
+{
+    #[Id]
+    #[GeneratedValue]
+    #[Column]
+    private int|null $id = null;
+
+    #[Column]
+    private int|null $amount = null;
+
+    #[OneToOne(inversedBy: 'cart', cascade: ['persist', 'remove'], orphanRemoval: true)]
+    private GH11386EntityCustomer|null $customer = null;
+
+    public function getId(): int|null
+    {
+        return $this->id;
+    }
+
+    public function getAmount(): int|null
+    {
+        return $this->amount;
+    }
+
+    public function setAmount(int $amount): static
+    {
+        $this->amount = $amount;
+
+        return $this;
+    }
+
+    public function getCustomer(): GH11386EntityCustomer|null
+    {
+        return $this->customer;
+    }
+
+    public function setCustomer(GH11386EntityCustomer|null $customer): self
+    {
+        $this->customer = $customer;
+
+        return $this;
+    }
+}
diff --git a/tests/Tests/ORM/Functional/Ticket/GH11386/GH11386EntityCustomer.php b/tests/Tests/ORM/Functional/Ticket/GH11386/GH11386EntityCustomer.php
new file mode 100644
index 000000000..3290a6f99
--- /dev/null
+++ b/tests/Tests/ORM/Functional/Ticket/GH11386/GH11386EntityCustomer.php
@@ -0,0 +1,80 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Doctrine\Tests\ORM\Functional\Ticket\GH11386;
+
+use Doctrine\ORM\Mapping\Column;
+use Doctrine\ORM\Mapping\Entity;
+use Doctrine\ORM\Mapping\GeneratedValue;
+use Doctrine\ORM\Mapping\Id;
+use Doctrine\ORM\Mapping\OneToOne;
+
+#[Entity]
+class GH11386EntityCustomer
+{
+    #[Id]
+    #[GeneratedValue]
+    #[Column]
+    private int|null $id = null;
+
+    #[Column]
+    private string|null $name = null;
+
+    #[Column(type: 'smallint', nullable: true, enumType: GH11386EnumType::class, options: ['unsigned' => true])]
+    private GH11386EnumType|null $type = null;
+
+    #[OneToOne(mappedBy: 'customer')]
+    private GH11386EntityCart|null $cart = null;
+
+    public function getId(): int|null
+    {
+        return $this->id;
+    }
+
+    public function getName(): string|null
+    {
+        return $this->name;
+    }
+
+    public function setName(string $name): static
+    {
+        $this->name = $name;
+
+        return $this;
+    }
+
+    public function getType(): GH11386EnumType|null
+    {
+        return $this->type;
+    }
+
+    public function setType(GH11386EnumType $type): static
+    {
+        $this->type = $type;
+
+        return $this;
+    }
+
+    public function getCart(): GH11386EntityCart|null
+    {
+        return $this->cart;
+    }
+
+    public function setCart(GH11386EntityCart|null $cart): self
+    {
+        // unset the owning side of the relation if necessary
+        if ($cart === null && $this->cart !== null) {
+            $this->cart->setCustomer(null);
+        }
+
+        // set the owning side of the relation if necessary
+        if ($cart !== null && $cart->getCustomer() !== $this) {
+            $cart->setCustomer($this);
+        }
+
+        $this->cart = $cart;
+
+        return $this;
+    }
+}
diff --git a/tests/Tests/ORM/Functional/Ticket/GH11386/GH11386EnumType.php b/tests/Tests/ORM/Functional/Ticket/GH11386/GH11386EnumType.php
new file mode 100644
index 000000000..c07da865b
--- /dev/null
+++ b/tests/Tests/ORM/Functional/Ticket/GH11386/GH11386EnumType.php
@@ -0,0 +1,11 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Doctrine\Tests\ORM\Functional\Ticket\GH11386;
+
+enum GH11386EnumType: int
+{
+    case MALE   = 1;
+    case FEMALE = 2;
+}
diff --git a/tests/Tests/ORM/Functional/Ticket/GH11386/GH11386Test.php b/tests/Tests/ORM/Functional/Ticket/GH11386/GH11386Test.php
new file mode 100644
index 000000000..b1ceef16c
--- /dev/null
+++ b/tests/Tests/ORM/Functional/Ticket/GH11386/GH11386Test.php
@@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Doctrine\Tests\ORM\Functional\Ticket\GH11386;
+
+use Doctrine\Tests\OrmFunctionalTestCase;
+
+final class GH11386Test extends OrmFunctionalTestCase
+{
+    protected function setUp(): void
+    {
+        parent::setUp();
+
+        $this->createSchemaForModels(
+            GH11386EntityCart::class,
+            GH11386EntityCustomer::class,
+        );
+    }
+
+    public function testInitializeClonedProxy(): void
+    {
+        $cart = new GH11386EntityCart();
+        $cart->setAmount(1000);
+
+        $customer = new GH11386EntityCustomer();
+        $customer->setName('John Doe')
+            ->setType(GH11386EnumType::MALE)
+            ->setCart($cart);
+
+        $this->_em->persist($cart);
+        $this->_em->flush();
+        $this->_em->clear();
+
+        $cart     = $this->_em->find(GH11386EntityCart::class, 1);
+        $customer = clone $cart->getCustomer();
+        self::assertEquals('John Doe', $customer->getName());
+    }
+}