Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Bundle\Test\Core\DependencyInjection\CompilerPass;

use Ibexa\Bundle\RepositoryInstaller\Event\Subscriber\BuildSchemaSubscriber;
use Ibexa\Contracts\Core\Test\Persistence\Fixture\FixtureImporter;
use Ibexa\Contracts\DoctrineSchema\Builder\SchemaBuilderInterface;
use Ibexa\Contracts\Test\Core\Bootstrapper\DatabaseSchemaHook;
use Ibexa\Contracts\Test\Core\Bootstrapper\FixtureHook;
use Ibexa\Contracts\Test\Core\Bootstrapper\PurgeIndexAfterFixturesHook;
use Ibexa\Contracts\Test\Core\Bootstrapper\PurgeSearchIndexHook;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
* Drops built-in hooks whose collaborators the consuming kernel doesn't provide, so registering
* this bundle never costs a kernel more than the hooks it can actually satisfy.
*/
final class RemoveUnsatisfiableHooksPass implements CompilerPassInterface
{
/**
* @var array<class-string, list<string>> hook service id => service ids it cannot work without
*/
private const HOOK_REQUIREMENTS = [
DatabaseSchemaHook::class => [
SchemaBuilderInterface::class,
// core's own schema contribution; without it the event yields every other package's
// tables but none of core's
BuildSchemaSubscriber::class,
],
FixtureHook::class => [FixtureImporter::class],
PurgeSearchIndexHook::class => ['ibexa.spi.search'],
PurgeIndexAfterFixturesHook::class => ['ibexa.spi.search'],
];

public function process(ContainerBuilder $container): void
{
foreach (self::HOOK_REQUIREMENTS as $hookId => $requiredServiceIds) {
if (!$container->hasDefinition($hookId)) {
continue;
}

foreach ($requiredServiceIds as $serviceId) {
if (!$container->has($serviceId)) {
$container->removeDefinition($hookId);

break;
}
}
}
}
}
2 changes: 2 additions & 0 deletions src/bundle/IbexaTestCoreBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace Ibexa\Bundle\Test\Core;

use Ibexa\Bundle\Test\Core\DependencyInjection\CompilerPass\PersistenceCheckCompilerPass;
use Ibexa\Bundle\Test\Core\DependencyInjection\CompilerPass\RemoveUnsatisfiableHooksPass;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
Expand All @@ -18,5 +19,6 @@ final class IbexaTestCoreBundle extends Bundle
public function build(ContainerBuilder $container): void
{
$container->addCompilerPass(new PersistenceCheckCompilerPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new RemoveUnsatisfiableHooksPass());
}
}
19 changes: 1 addition & 18 deletions src/bundle/Resources/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,16 @@
use Ibexa\Contracts\Test\Core\Bootstrapper\HooksExecutorInterface;
use Ibexa\Contracts\Test\Core\Bootstrapper\PurgeIndexAfterFixturesHook;
use Ibexa\Contracts\Test\Core\Bootstrapper\PurgeSearchIndexHook;
use Ibexa\Contracts\Test\Core\Bootstrapper\SchemaFilesProviderInterface;
use Ibexa\Test\Core\Bootstrapper\FixtureKernelMethodProvider;
use Ibexa\Test\Core\Bootstrapper\FixtureParameterProvider;
use Ibexa\Test\Core\Bootstrapper\FixtureProviderChain;
use Ibexa\Test\Core\Bootstrapper\HooksExecutor;
use Ibexa\Test\Core\Bootstrapper\SchemaFilesKernelMethodProvider;
use Ibexa\Test\Core\Bootstrapper\SchemaFilesParameterProvider;
use Ibexa\Test\Core\Bootstrapper\SchemaFilesProviderChain;

return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->parameters()
// null (not []): an unset/unconfigured parameter must be distinguishable from a consumer
// deliberately configuring an empty list, since only the latter should stop the fallback
// chain in *ProviderChain — see SchemaFilesProviderInterface's docblock.
->set('ibexa.test.schema_files', null)
// chain in FixtureProviderChain — see FixtureProviderInterface's docblock.
->set('ibexa.test.fixture_files', null);

$services = $containerConfigurator->services();
Expand All @@ -56,17 +51,6 @@

$services->set(DefaultFixtureProvider::class);

$services->set(SchemaFilesKernelMethodProvider::class)
->arg('$kernel', service('kernel'))
->tag(SchemaFilesProviderInterface::TAG, ['priority' => 0]);

$services->set(SchemaFilesParameterProvider::class)
->arg('$schemaFiles', '%ibexa.test.schema_files%')
->tag(SchemaFilesProviderInterface::TAG, ['priority' => 100]);

$services->set(SchemaFilesProviderChain::class)
->arg('$providers', tagged_iterator(SchemaFilesProviderInterface::TAG));

$services->set(FixtureKernelMethodProvider::class)
->arg('$kernel', service('kernel'))
->tag(FixtureProviderInterface::TAG, ['priority' => 0]);
Expand All @@ -79,7 +63,6 @@
->arg('$providers', tagged_iterator(FixtureProviderInterface::TAG));

$services->set(DatabaseSchemaHook::class)
->arg('$provider', service(SchemaFilesProviderChain::class))
->tag(HookInterface::TAG, ['priority' => DatabaseSchemaHook::PRIORITY]);

$services->set(FixtureHook::class)
Expand Down
4 changes: 2 additions & 2 deletions src/contracts/Bootstrapper/Bootstrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@

namespace Ibexa\Contracts\Test\Core\Bootstrapper;

use Ibexa\Contracts\Test\Core\IbexaTestKernel;
use LogicException;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;

Expand Down Expand Up @@ -74,7 +74,7 @@ public function __construct(
public function bootstrap(
?string $kernelClass = null,
array $options = []
): IbexaTestKernel {
): KernelInterface {
$kernel = $this->kernelProvider->getKernel($kernelClass);

$testContainer = self::getService($kernel->getContainer(), 'test.service_container', ContainerInterface::class);
Expand Down
4 changes: 2 additions & 2 deletions src/contracts/Bootstrapper/DatabasePreparer.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

namespace Ibexa\Contracts\Test\Core\Bootstrapper;

use Ibexa\Contracts\Test\Core\IbexaTestKernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\HttpKernel\KernelInterface;

/**
* @internal
Expand All @@ -24,7 +24,7 @@ public function __construct()
}

public function prepareDatabase(
IbexaTestKernel $kernel,
KernelInterface $kernel,
bool $runSchemaUpdate
): void {
$application = new Application($kernel);
Expand Down
4 changes: 2 additions & 2 deletions src/contracts/Bootstrapper/DatabasePreparerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Ibexa\Contracts\Test\Core\Bootstrapper;

use Ibexa\Contracts\Test\Core\IbexaTestKernel;
use Symfony\Component\HttpKernel\KernelInterface;

/**
* @experimental
Expand All @@ -23,7 +23,7 @@ interface DatabasePreparerInterface
* @throws \Exception command failures propagate as-is
*/
public function prepareDatabase(
IbexaTestKernel $kernel,
KernelInterface $kernel,
bool $runSchemaUpdate
): void;
}
32 changes: 20 additions & 12 deletions src/contracts/Bootstrapper/DatabaseSchemaHook.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@

namespace Ibexa\Contracts\Test\Core\Bootstrapper;

use Ibexa\Tests\Core\Repository\LegacySchemaImporter;
use Doctrine\DBAL\Connection;
use Ibexa\Bundle\Test\Core\DependencyInjection\CompilerPass\RemoveUnsatisfiableHooksPass;
use Ibexa\Contracts\DoctrineSchema\Builder\SchemaBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
* Imports the legacy raw-SQL schema files exposed by {@see SchemaFilesProviderInterface}.
* Installs the database schema built by {@see SchemaBuilderInterface::buildSchema()}, i.e. from
* every registered bundle's own SchemaBuilderEvent subscriber. Requires `DoctrineSchemaBundle` and
* `IbexaRepositoryInstallerBundle`; removed from the container when either is missing, by
* {@see RemoveUnsatisfiableHooksPass}.
*
* Enabled by default; pass `[self::OPTION_LOAD_SCHEMA => false]` as this hook's own options (keyed
* by its own service id in the bootstrap options array) to skip it.
* Enabled by default; pass `[self::OPTION_LOAD_SCHEMA => false]` as this hook's own options to
* skip it.
*/
final class DatabaseSchemaHook implements HookInterface
{
Expand All @@ -27,16 +32,16 @@ final class DatabaseSchemaHook implements HookInterface

public const OPTION_LOAD_SCHEMA = 'load_schema';

private SchemaFilesProviderInterface $provider;
private SchemaBuilderInterface $schemaBuilder;

private LegacySchemaImporter $schemaImporter;
private Connection $connection;

public function __construct(
SchemaFilesProviderInterface $provider,
LegacySchemaImporter $schemaImporter
SchemaBuilderInterface $schemaBuilder,
Connection $connection
) {
$this->provider = $provider;
$this->schemaImporter = $schemaImporter;
$this->schemaBuilder = $schemaBuilder;
$this->connection = $connection;
}

public function configureOptions(OptionsResolver $resolver): void
Expand All @@ -52,8 +57,11 @@ public function __invoke(array $options): void
return;
}

foreach ($this->provider->getSchemaFiles() ?? [] as $file) {
$this->schemaImporter->importSchema($file);
$schema = $this->schemaBuilder->buildSchema();
$platform = $this->connection->getDatabasePlatform();

foreach ($schema->toSql($platform) as $sql) {
$this->connection->executeStatement($sql);
}
}
}
10 changes: 5 additions & 5 deletions src/contracts/Bootstrapper/KernelProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@

namespace Ibexa\Contracts\Test\Core\Bootstrapper;

use Ibexa\Contracts\Test\Core\IbexaTestKernel;
use LogicException;
use Symfony\Component\HttpKernel\KernelInterface;

/**
* @internal
*/
final class KernelProvider implements KernelProviderInterface
{
public function getKernel(?string $kernelClass): IbexaTestKernel
public function getKernel(?string $kernelClass): KernelInterface
{
$kernelClass ??= $_ENV['KERNEL_CLASS'] ?? $_SERVER['KERNEL_CLASS'] ?? null;
if ($kernelClass === null || !is_a($kernelClass, IbexaTestKernel::class, true)) {
if ($kernelClass === null || !is_a($kernelClass, KernelInterface::class, true)) {
throw new LogicException(sprintf(
'The kernel class "%s" must be a subclass of "%s". Ensure that the KERNEL_CLASS environment variable is set to a valid test kernel class.',
'The kernel class "%s" must implement "%s". Ensure that the KERNEL_CLASS environment variable is set to a valid test kernel class.',
$kernelClass ?? 'null',
IbexaTestKernel::class,
KernelInterface::class,
));
}

Expand Down
8 changes: 4 additions & 4 deletions src/contracts/Bootstrapper/KernelProviderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Ibexa\Contracts\Test\Core\Bootstrapper;

use Ibexa\Contracts\Test\Core\IbexaTestKernel;
use Symfony\Component\HttpKernel\KernelInterface;

/**
* @experimental
Expand All @@ -20,8 +20,8 @@
interface KernelProviderInterface
{
/**
* @throws \LogicException if $kernelClass (or its env/server fallback) isn't a valid
* IbexaTestKernel subclass
* @throws \LogicException if $kernelClass (or its env/server fallback) doesn't name a
* bootable {@see KernelInterface} implementation
*/
public function getKernel(?string $kernelClass): IbexaTestKernel;
public function getKernel(?string $kernelClass): KernelInterface;
}
29 changes: 0 additions & 29 deletions src/contracts/Bootstrapper/SchemaFilesProviderInterface.php

This file was deleted.

14 changes: 14 additions & 0 deletions src/contracts/IbexaTestKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
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\Bundle\Test\Core\IbexaTestCoreBundle;
use Ibexa\Contracts\Core\Persistence\TransactionHandler;
use Ibexa\Contracts\Core\Repository;
use Ibexa\Contracts\Core\Test\IbexaTestKernelInterface;
use Ibexa\Contracts\DoctrineSchema\Builder\SchemaBuilderInterface;
use Ibexa\Contracts\Test\Core\Bootstrapper\Bootstrapper;
use Ibexa\Contracts\Test\Core\Bootstrapper\DefaultFixtureProvider;
use Ibexa\Contracts\Test\Core\Bootstrapper\DefaultSchemaFilesProvider;
Expand Down Expand Up @@ -64,6 +67,15 @@
* {@see HooksExecutorInterface} and the built-in hooks it
* registers) must `yield new IbexaTestCoreBundle();` from its own registerBundles() override.
*
* It does register {@see DoctrineSchemaBundle} and
* {@see IbexaRepositoryInstallerBundle}, which together make
* SchemaBuilderEvent usable: the former provides
* {@see SchemaBuilderInterface}, the latter carries core's
* own BuildSchemaSubscriber (it lives there rather than in IbexaCoreBundle), without which the
* event yields every other package's tables but none of core's. They are a pair —
* IbexaRepositoryInstallerBundle::build() throws if DoctrineSchemaBundle is absent. A subclass must
* therefore NOT yield either of them again; Symfony rejects two bundles with the same name.
*
* ## Exposing your services
*
* To add services to the test Kernel and make them available in tests via IbexaKernelTestCase::getServiceByClassName(),
Expand Down Expand Up @@ -144,6 +156,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();
Expand Down
35 changes: 0 additions & 35 deletions src/lib/Bootstrapper/SchemaFilesKernelMethodProvider.php

This file was deleted.

Loading