From a38986131d64dc4efd4cd23a2b8717aa34946414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Niedzielski?= Date: Wed, 9 Sep 2026 16:05:02 +0200 Subject: [PATCH 1/3] Built IbexaKernelTestTrait schema from SchemaBuilderEvent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit loadSchema() pushed raw schema.yaml files listed by getSchemaFiles() through LegacySchemaImporter, which never dispatches SchemaBuilderEvent. That left two different schema-building paths in the test stack once ibexa/test-core#43 moved DatabaseSchemaHook onto the event, and it is the only reason a package still has to keep a getSchemaFiles() override alive. It now builds through SchemaBuilderInterface and applies the result with doctrine-schema's new SchemaApplier, keeping the drop-then-create ordering LegacySchemaImporter had, since loadSchema() runs per test case. IbexaTestKernel gains DoctrineSchemaBundle and IbexaRepositoryInstallerBundle, without which the event is not reachable — core's own kernel does not extend ibexa/test-core's, so it does not inherit them. getSchemaFiles() is deprecated on both IbexaTestKernelInterface and the trait. LegacySchemaImporter stays: SetupFactory\Legacy and Persistence\Legacy\TestCase still use it. --- phpstan-baseline.neon | 6 ------ src/contracts/Test/IbexaKernelTestTrait.php | 20 ++++++++++++++----- src/contracts/Test/IbexaTestKernel.php | 4 ++++ .../Test/IbexaTestKernelInterface.php | 6 ++++++ 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 9b8ac82db4..6fbeac101b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -8910,12 +8910,6 @@ parameters: count: 1 path: src/contracts/Test/IbexaKernelTestCase.php - - - message: '#^Cannot call method importSchema\(\) on object\|null\.$#' - identifier: method.nonObject - count: 1 - path: src/contracts/Test/IbexaKernelTestCase.php - - message: '#^Method Ibexa\\Contracts\\Core\\Test\\Persistence\\Fixture\:\:load\(\) return type has no value type specified in iterable type array\.$#' identifier: missingType.iterableValue diff --git a/src/contracts/Test/IbexaKernelTestTrait.php b/src/contracts/Test/IbexaKernelTestTrait.php index c40329634d..4c8a04a55d 100644 --- a/src/contracts/Test/IbexaKernelTestTrait.php +++ b/src/contracts/Test/IbexaKernelTestTrait.php @@ -23,8 +23,9 @@ use Ibexa\Contracts\Core\Repository\URLAliasService; use Ibexa\Contracts\Core\Repository\UserService; use Ibexa\Contracts\Core\Test\Persistence\Fixture\FixtureImporter; +use Ibexa\Contracts\DoctrineSchema\Builder\SchemaBuilderInterface; use Ibexa\Core\Repository\Values\User\UserReference; -use Ibexa\Tests\Core\Repository\LegacySchemaImporter; +use Ibexa\DoctrineSchema\Builder\SchemaApplier; use RuntimeException; /** @@ -34,14 +35,23 @@ trait IbexaKernelTestTrait { final protected static function loadSchema(): void { - $schemaImporter = self::getContainer()->get(LegacySchemaImporter::class); - foreach (static::getSchemaFiles() as $schemaFile) { - $schemaImporter->importSchema($schemaFile); - } + $schemaBuilder = self::getContainer()->get(SchemaBuilderInterface::class); + assert($schemaBuilder instanceof SchemaBuilderInterface); + $schema = $schemaBuilder->buildSchema(); + + // Constructed rather than fetched: SchemaApplier is a stateless helper, and its service is + // private and unreferenced in a plain test kernel, so the compiler removes it. + // drop first: this runs per test case, so the tables are normally already present + (new SchemaApplier(self::getDoctrineConnection()))->applySchema($schema, true); } /** * @return iterable + * + * @deprecated since Ibexa 4.6.x, no longer used. {@see loadSchema()} now builds the schema from + * {@see \Ibexa\Contracts\DoctrineSchema\Event\SchemaBuilderEvent} instead of reading + * raw schema files, so a bundle contributes its tables through its own + * BuildSchemaSubscriber and nothing needs to list files. Will be removed in 6.0. */ protected static function getSchemaFiles(): iterable { diff --git a/src/contracts/Test/IbexaTestKernel.php b/src/contracts/Test/IbexaTestKernel.php index 5c89768f84..b02b40f594 100644 --- a/src/contracts/Test/IbexaTestKernel.php +++ b/src/contracts/Test/IbexaTestKernel.php @@ -12,7 +12,9 @@ use Doctrine\DBAL\Connection; use FOS\JsRoutingBundle\FOSJsRoutingBundle; use Ibexa\Bundle\Core\IbexaCoreBundle; +use Ibexa\Bundle\DoctrineSchema\DoctrineSchemaBundle; use Ibexa\Bundle\LegacySearchEngine\IbexaLegacySearchEngineBundle; +use Ibexa\Bundle\RepositoryInstaller\IbexaRepositoryInstallerBundle; use Ibexa\Contracts\Core\Persistence\Handler; use Ibexa\Contracts\Core\Persistence\TransactionHandler; use Ibexa\Contracts\Core\Repository; @@ -139,6 +141,8 @@ public function registerBundles(): iterable { yield new SecurityBundle(); yield new IbexaCoreBundle(); + yield new DoctrineSchemaBundle(); + yield new IbexaRepositoryInstallerBundle(); yield new IbexaLegacySearchEngineBundle(); yield new JMSTranslationBundle(); yield new FOSJsRoutingBundle(); diff --git a/src/contracts/Test/IbexaTestKernelInterface.php b/src/contracts/Test/IbexaTestKernelInterface.php index 55f6e42186..460f27fa4d 100644 --- a/src/contracts/Test/IbexaTestKernelInterface.php +++ b/src/contracts/Test/IbexaTestKernelInterface.php @@ -21,6 +21,12 @@ public static function getAliasServiceId(string $id): string; /** * @return iterable + * + * @deprecated since Ibexa 4.6.x. Test schema is built from + * {@see \Ibexa\Contracts\DoctrineSchema\Event\SchemaBuilderEvent} — the same path + * `ibexa:install` uses — so a kernel no longer declares which schema files to load; + * whichever bundles it registers is what the schema contains. Implementations may + * return an empty iterable. Will be removed in 6.0. */ public function getSchemaFiles(): iterable; From 9b74c40d493cfb1574eb23a99bfb0b88f997939a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Niedzielski?= Date: Wed, 9 Sep 2026 16:05:03 +0200 Subject: [PATCH 2/3] TEMPORARY: Added dependencies.json to test against ibexa/doctrine-schema#49 Points CI at the branch that adds SchemaApplier, so this PR's tests can run before that PR merges. Must be removed before merging. --- dependencies.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 dependencies.json diff --git a/dependencies.json b/dependencies.json new file mode 100644 index 0000000000..838a86c0ec --- /dev/null +++ b/dependencies.json @@ -0,0 +1,11 @@ +{ + "recipesEndpoint": "", + "packages": [ + { + "requirement": "dev-feature/schema-applier-4.6 as 4.6.x-dev", + "repositoryUrl": "https://github.com/ibexa/doctrine-schema.git", + "package": "ibexa/doctrine-schema", + "shouldBeAddedAsVCS": false + } + ] +} From d330f9ab652a5a52db6e7fd6bb439ef8d6eecba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Niedzielski?= Date: Wed, 9 Sep 2026 16:26:18 +0200 Subject: [PATCH 3/3] Dropped the now-inherited bundle registration from RepositoryInstaller TestKernel It registered DoctrineSchemaBundle and IbexaRepositoryInstallerBundle itself and extends IbexaTestKernel, which now yields both, so booting it threw "Trying to register two bundles with the same name". Its registerBundles() override did nothing else, so it goes entirely. --- tests/integration/RepositoryInstaller/TestKernel.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/integration/RepositoryInstaller/TestKernel.php b/tests/integration/RepositoryInstaller/TestKernel.php index 6cee2d1315..b70e79cf72 100644 --- a/tests/integration/RepositoryInstaller/TestKernel.php +++ b/tests/integration/RepositoryInstaller/TestKernel.php @@ -8,21 +8,11 @@ namespace Ibexa\Tests\Integration\RepositoryInstaller; -use Ibexa\Bundle\DoctrineSchema\DoctrineSchemaBundle; -use Ibexa\Bundle\RepositoryInstaller\IbexaRepositoryInstallerBundle; use Ibexa\Bundle\RepositoryInstaller\Installer\CoreInstaller; use Ibexa\Contracts\Core\Test\IbexaTestKernel; final class TestKernel extends IbexaTestKernel { - public function registerBundles(): iterable - { - yield from parent::registerBundles(); - - yield new DoctrineSchemaBundle(); - yield new IbexaRepositoryInstallerBundle(); - } - protected static function getExposedServicesByClass(): iterable { yield from parent::getExposedServicesByClass();