Repository: symfony/ux
Pull request #1929 (2024-06-20 06:13:09)

[Turbo] Fix Doctrine Proxy are not Broadcasted
| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| Issues        | Fix #... 
| License       | MIT

* Resolve old Doctrine proxy class
* Make the CI green again? 


Update: this fix the bug you can experience on this page: https://ux.symfony.com/turbo 

<img width="1056" alt="Capture d’écran 2024-06-20 à 17 01 25" src="https://github.com/symfony/ux/assets/1359581/b96c996f-ed4b-47a7-8273-eed3c58a0d98">


smnandre: Yep, i'll fix it on a distinct PR (i really try to not change website and packages in the same PR)

Patch:
diff --git a/src/Turbo/CHANGELOG.md b/src/Turbo/CHANGELOG.md
index 4ece2756..b5ad566c 100644
--- a/src/Turbo/CHANGELOG.md
+++ b/src/Turbo/CHANGELOG.md
@@ -1,5 +1,9 @@
 # CHANGELOG
 
+## 2.19.0
+
+-   Fix Doctrine proxies are not Broadcasted #3139
+
 ## 2.15.0
 
 -   Add Turbo 8 support #1476
diff --git a/src/Turbo/src/Doctrine/ClassUtil.php b/src/Turbo/src/Doctrine/ClassUtil.php
index 49e7e7a5..c8f37ed7 100644
--- a/src/Turbo/src/Doctrine/ClassUtil.php
+++ b/src/Turbo/src/Doctrine/ClassUtil.php
@@ -11,7 +11,6 @@
 
 namespace Symfony\UX\Turbo\Doctrine;
 
-use Doctrine\Common\Util\ClassUtils as LegacyClassUtils;
 use Symfony\Component\VarExporter\LazyObjectInterface;
 
 /**
@@ -24,13 +23,13 @@ final class ClassUtil
      */
     public static function getEntityClass(object $entity): string
     {
-        if ($entity instanceof LazyObjectInterface) {
+        // Doctrine proxies (old versions)
+        if (str_contains($entity::class, 'Proxies\\__CG__')) {
             return get_parent_class($entity) ?: $entity::class;
         }
 
-        // @legacy for old versions of Doctrine
-        if (class_exists(LegacyClassUtils::class)) {
-            return LegacyClassUtils::getClass($entity);
+        if ($entity instanceof LazyObjectInterface) {
+            return get_parent_class($entity) ?: $entity::class;
         }
 
         return $entity::class;


Test patch:
diff --git a/src/Turbo/tests/BroadcastTest.php b/src/Turbo/tests/BroadcastTest.php
index 87c06d9f..3fee2ec3 100644
--- a/src/Turbo/tests/BroadcastTest.php
+++ b/src/Turbo/tests/BroadcastTest.php
@@ -27,7 +27,7 @@ class BroadcastTest extends PantherTestCase
     protected function setUp(): void
     {
         if (!file_exists(__DIR__.'/app/public/build')) {
-            throw new \Exception(\sprintf('Move into %s and execute Encore before running this test.', realpath(__DIR__.'/app')));
+            throw new \Exception(\sprintf('Move into "%s" and execute Encore before running this test.', realpath(__DIR__.'/app')));
         }
 
         parent::setUp();
@@ -38,7 +38,7 @@ class BroadcastTest extends PantherTestCase
         ($client = self::createPantherClient())->request('GET', '/books');
 
         $crawler = $client->submitForm('Submit', ['title' => self::BOOK_TITLE]);
-        $client->waitForElementToContain('#books div', self::BOOK_TITLE);
+        // $client->waitForElementToContain('#books div', self::BOOK_TITLE);
 
         $this->assertSelectorWillContain('#books', self::BOOK_TITLE);
         if (!preg_match('/\(#(\d+)\)/', $crawler->filter('#books div')->text(), $matches)) {
@@ -57,9 +57,10 @@ class BroadcastTest extends PantherTestCase
         ($client = self::createPantherClient())->request('GET', '/artists');
 
         $client->submitForm('Submit', ['name' => self::ARTIST_NAME_1]);
-        $client->waitForElementToContain('#artists div:nth-child(1)', self::ARTIST_NAME_1);
+        $client->waitForElementToContain('#artists div:nth-child(1)', self::ARTIST_NAME_1, 5);
+
         $client->submitForm('Submit', ['name' => self::ARTIST_NAME_2]);
-        $client->waitForElementToContain('#artists div:nth-child(2)', self::ARTIST_NAME_2);
+        $client->waitForElementToContain('#artists div:nth-child(2)', self::ARTIST_NAME_2, 5);
 
         $crawlerArtist = $client->getCrawler();
 
@@ -78,7 +79,7 @@ class BroadcastTest extends PantherTestCase
 
         $client->submitForm('Submit', ['title' => self::SONG_TITLE, 'artistId' => $artist1Id]);
 
-        $clientArtist1->waitForElementToContain('#songs div', self::SONG_TITLE);
+        $clientArtist1->waitForElementToContain('#songs div', self::SONG_TITLE, 5);
 
         $songsElement = $clientArtist2->findElement(WebDriverBy::cssSelector('#songs'));