Skip to content

Commit

Permalink
Drivers can be configured
Browse files Browse the repository at this point in the history
  • Loading branch information
Prometee committed Jul 7, 2023
1 parent 0d40366 commit 8c2a866
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 34 deletions.
2 changes: 2 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,11 @@
<referencedMethod name="Symfony\Component\Config\Definition\Builder\NodeDefinition::arrayNode" />
<referencedMethod name="Symfony\Component\Config\Definition\Builder\NodeDefinition::scalarNode" />
<referencedMethod name="Symfony\Component\Config\Definition\Builder\NodeDefinition::variableNode" />
<referencedMethod name="Symfony\Component\Config\Definition\Builder\NodeDefinition::prototype" />
<referencedMethod name="Symfony\Component\Config\Definition\Builder\NodeParentInterface::end" />
<referencedMethod name="Symfony\Component\Config\Definition\Builder\VariableNodeDefinition::scalarNode" />
<referencedMethod name="Symfony\Component\Config\Definition\Builder\VariableNodeDefinition::variableNode" />
<referencedMethod name="Symfony\Component\Config\Definition\Builder\VariableNodeDefinition::prototype" />
</errorLevel>
</PossiblyUndefinedMethod>

Expand Down
77 changes: 75 additions & 2 deletions src/Bundle/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@
namespace Sylius\Bundle\ResourceBundle\DependencyInjection;

use Sylius\Bundle\ResourceBundle\Controller\ResourceController;
use Sylius\Bundle\ResourceBundle\DependencyInjection\Driver\Doctrine\DoctrineODMDriver;
use Sylius\Bundle\ResourceBundle\DependencyInjection\Driver\Doctrine\DoctrineORMDriver;
use Sylius\Bundle\ResourceBundle\DependencyInjection\Driver\Doctrine\DoctrinePHPCRDriver;
use Sylius\Bundle\ResourceBundle\DependencyInjection\Driver\DriverInterface;
use Sylius\Bundle\ResourceBundle\Form\Type\DefaultResourceType;
use Sylius\Bundle\ResourceBundle\SyliusResourceBundle;
use Sylius\Component\Resource\Factory\Factory;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;

final class Configuration implements ConfigurationInterface
{
Expand Down Expand Up @@ -146,8 +151,76 @@ private function addDriversSection(ArrayNodeDefinition $node): void
$node
->children()
->arrayNode('drivers')
->defaultValue([SyliusResourceBundle::DRIVER_DOCTRINE_ORM])
->enumPrototype()->values(SyliusResourceBundle::getAvailableDrivers())->end()
->info('The list of enabled drivers with there related class.')
->normalizeKeys(false) // do not replace dashes with underscores
->useAttributeAsKey('type')
->defaultValue([
SyliusResourceBundle::DRIVER_DOCTRINE_ORM => ['class' => DoctrineORMDriver::class],
])
->beforeNormalization()
->ifArray()
->then(static function (array $v) {
foreach ($v as $driver => $value) {
if (isset($value['class'])) {
continue;
}
// retro-compatibility
if (in_array($value, SyliusResourceBundle::getAvailableDrivers(), true)) {
$v[$value] = ['class' => match ($value) {
SyliusResourceBundle::DRIVER_DOCTRINE_ORM => DoctrineORMDriver::class,
SyliusResourceBundle::DRIVER_DOCTRINE_MONGODB_ODM => DoctrineODMDriver::class,
SyliusResourceBundle::DRIVER_DOCTRINE_PHPCR_ODM => DoctrinePHPCRDriver::class,
}];

unset($v[$driver]);

continue;
}

$v[$driver] = ['class' => $value];
}

return $v;
})
->end()
->validate()
->ifArray()
->then(static function (array $v) {
foreach ($v as $driver => $value) {
/** @var string|null $class */
$class = $value['class'] ?? null;
if (null === $class) {
throw new InvalidConfigurationException(sprintf(
'The Sylius Resource driver "%s" must have a class!',
$driver,
));
}

if (false === class_exists($class)) {
throw new InvalidConfigurationException(sprintf(
'The Sylius Resource driver "%s" class must be an existing class, "%s" given.',
$driver,
$class,
));
}

if (false === is_a($class, DriverInterface::class, true)) {
throw new InvalidConfigurationException(sprintf(
'The Sylius Resource driver "%s" class must be an instance of "%s".',
$driver,
DriverInterface::class,
));
}
}

return $v;
})
->end()
->prototype('array')
->children()
->scalarNode('class')->cannotBeEmpty()->end()
->end()
->end()
->end()
->end()
;
Expand Down
28 changes: 12 additions & 16 deletions src/Bundle/DependencyInjection/Driver/DriverProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,37 @@

namespace Sylius\Bundle\ResourceBundle\DependencyInjection\Driver;

use Sylius\Bundle\ResourceBundle\DependencyInjection\Driver\Doctrine\DoctrineODMDriver;
use Sylius\Bundle\ResourceBundle\DependencyInjection\Driver\Doctrine\DoctrineORMDriver;
use Sylius\Bundle\ResourceBundle\DependencyInjection\Driver\Doctrine\DoctrinePHPCRDriver;
use Sylius\Bundle\ResourceBundle\DependencyInjection\Driver\Exception\UnknownDriverException;
use Sylius\Bundle\ResourceBundle\SyliusResourceBundle;
use Sylius\Component\Resource\Metadata\MetadataInterface;
use Webmozart\Assert\Assert;

final class DriverProvider
{
/** @var DriverInterface[] */
/** @var array<string, array<string, string>> */
private static array $drivers = [];

public static function build(array $drivers): void
{
self::$drivers = $drivers;
}

/**
* @throws UnknownDriverException
*/
public static function get(MetadataInterface $metadata): DriverInterface
{
$type = $metadata->getDriver();

if (isset(self::$drivers[$type])) {
return self::$drivers[$type];
/** @var class-string|null $class */
$class = self::$drivers[$type]['class'] ?? null;
if (null !== $class) {
$driver = new $class();
Assert::isInstanceOf($driver, DriverInterface::class);
return $driver;
}

Assert::notFalse($type, sprintf('No driver was configured on the resource "%s".', $metadata->getAlias()));

switch ($type) {
case SyliusResourceBundle::DRIVER_DOCTRINE_ORM:
return self::$drivers[$type] = new DoctrineORMDriver();
case SyliusResourceBundle::DRIVER_DOCTRINE_MONGODB_ODM:
return self::$drivers[$type] = new DoctrineODMDriver();
case SyliusResourceBundle::DRIVER_DOCTRINE_PHPCR_ODM:
return self::$drivers[$type] = new DoctrinePHPCRDriver();
}

throw new UnknownDriverException($type);
}
}
41 changes: 25 additions & 16 deletions src/Bundle/DependencyInjection/SyliusResourceExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,42 +169,51 @@ private function getResourceAlias(Resource $resource, string $className): string
return 'app.' . u($shortName)->snake()->toString();
}

/**
* @param array<string, array<string, string>> $drivers
*/
private function loadPersistence(array $drivers, array $resources, LoaderInterface $loader): void
{
$integrateDoctrine = array_reduce($drivers, function (bool $result, string $driver): bool {
return $result || in_array($driver, [SyliusResourceBundle::DRIVER_DOCTRINE_ORM, SyliusResourceBundle::DRIVER_DOCTRINE_PHPCR_ODM, SyliusResourceBundle::DRIVER_DOCTRINE_MONGODB_ODM], true);
DriverProvider::build($drivers);

$integrateDoctrine = array_reduce(array_keys($drivers), static function (bool $result, string $type): bool {
return $result || in_array($type, [SyliusResourceBundle::DRIVER_DOCTRINE_ORM, SyliusResourceBundle::DRIVER_DOCTRINE_PHPCR_ODM, SyliusResourceBundle::DRIVER_DOCTRINE_MONGODB_ODM], true);
}, false);

if ($integrateDoctrine) {
$loader->load('services/integrations/doctrine.xml');
}

foreach ($drivers as $type => $driver) {
if (in_array($type, [SyliusResourceBundle::DRIVER_DOCTRINE_PHPCR_ODM, SyliusResourceBundle::DRIVER_DOCTRINE_MONGODB_ODM], true)) {
trigger_deprecation(
'sylius/resource-bundle',
'1.3',
'The "%s" driver is deprecated. Doctrine MongoDB and PHPCR will no longer be supported in 2.0.',
$type,
);
}

if (false === in_array($type, SyliusResourceBundle::getAvailableDrivers(), true)) {
continue;
}

$loader->load(sprintf('services/integrations/%s.xml', $type));
}

foreach ($resources as $alias => $resource) {
if (false === $resource['driver']) {
break;
}

if (!in_array($resource['driver'], $drivers, true)) {
if (!array_key_exists($resource['driver'], $drivers)) {
throw new InvalidArgumentException(sprintf(
'Resource "%s" uses driver "%s", but this driver has not been enabled.',
$alias,
$resource['driver'],
));
}
}

foreach ($drivers as $driver) {
if (in_array($driver, [SyliusResourceBundle::DRIVER_DOCTRINE_PHPCR_ODM, SyliusResourceBundle::DRIVER_DOCTRINE_MONGODB_ODM], true)) {
trigger_deprecation(
'sylius/resource-bundle',
'1.3',
'The "%s" driver is deprecated. Doctrine MongoDB and PHPCR will no longer be supported in 2.0.',
$driver,
);
}

$loader->load(sprintf('services/integrations/%s.xml', $driver));
}
}

private function loadResources(array $loadedResources, ContainerBuilder $container): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use App\Factory\BookFactory;
use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionTestCase;
use Sylius\Bundle\ResourceBundle\Controller\ResourceController;
use Sylius\Bundle\ResourceBundle\DependencyInjection\Driver\Doctrine\DoctrineORMDriver;
use Sylius\Bundle\ResourceBundle\DependencyInjection\SyliusResourceExtension;
use Sylius\Bundle\ResourceBundle\Form\Type\DefaultResourceType;
use Sylius\Bundle\ResourceBundle\Tests\DependencyInjection\Dummy\BookWithAliasResource;
Expand Down Expand Up @@ -179,6 +180,76 @@ public function it_auto_registers_resources(): void
]);
}

/**
* @test
*/
public function it_allows_registering_custom_driver(): void
{
$this->setParameter('kernel.bundles', []);
$this->load([
'drivers' => [
'custom' => [
'class' => DoctrineORMDriver::class,
],
],
]);

// services/integrations/doctrine.xml not loaded
$this->assertContainerBuilderNotHasService('sylius_resource.doctrine.mapping_driver_chain');
// services/integrations/doctrine/orm.xml not loaded
$this->assertContainerBuilderNotHasService('sylius.event_subscriber.orm_mapped_super_class');
}

/**
* @test
*/
public function it_allows_registering_custom_driver_with_simple_array_values(): void
{
$this->setParameter('kernel.bundles', []);
$this->load([
'drivers' => [
'custom' => DoctrineORMDriver::class,
],
]);

// services/integrations/doctrine.xml not loaded
$this->assertContainerBuilderNotHasService('sylius_resource.doctrine.mapping_driver_chain');
// services/integrations/doctrine/orm.xml not loaded
$this->assertContainerBuilderNotHasService('sylius.event_subscriber.orm_mapped_super_class');
}

/**
* @test
*/
public function it_allows_registering_drivers_with_the_legacy_string_array(): void
{
$this->setParameter('kernel.bundles', []);
$this->load([
'drivers' => [
'doctrine/orm',
],
]);

// services/integrations/doctrine.xml is loaded
$this->assertContainerBuilderHasService('sylius_resource.doctrine.mapping_driver_chain');
// services/integrations/doctrine/orm.xml is loaded
$this->assertContainerBuilderHasService('sylius.event_subscriber.orm_mapped_super_class');
}

/**
* @test
*/
public function it_allows_registering_drivers_with_defaults_values(): void
{
$this->setParameter('kernel.bundles', []);
$this->load();

// services/integrations/doctrine.xml is loaded
$this->assertContainerBuilderHasService('sylius_resource.doctrine.mapping_driver_chain');
// services/integrations/doctrine/orm.xml is loaded
$this->assertContainerBuilderHasService('sylius.event_subscriber.orm_mapped_super_class');
}

protected function getContainerExtensions(): array
{
return [
Expand Down

0 comments on commit 8c2a866

Please sign in to comment.