Skip to content

Commit

Permalink
[DependencyInjection] New Dependency Injection component
Browse files Browse the repository at this point in the history
  • Loading branch information
mpoiriert committed Jun 28, 2024
1 parent e533813 commit 4faa2e0
Show file tree
Hide file tree
Showing 52 changed files with 383 additions and 108 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/after_splitting_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
- console
- core
- cron-job
- dependency-injection
- doctrine-extra
- entity-migrator
- fixer
Expand All @@ -39,6 +40,7 @@ jobs:
- validator
- workflow


name: After Split Testing of ${{ matrix.package_name }}

steps:
Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
"draw/contracts": "self.version",
"draw/core": "self.version",
"draw/cron-job": "self.version",
"draw/dependency-injection": "self.version",
"draw/doctrine-extra": "self.version",
"draw/entity-migrator": "self.version",
"draw/fixer": "self.version",
Expand Down Expand Up @@ -180,6 +181,7 @@
"Draw\\Component\\Console\\": "packages/console/",
"Draw\\Component\\Core\\": "packages/core/",
"Draw\\Component\\CronJob\\": "packages/cron-job/",
"Draw\\Component\\DependencyInjection\\": "packages/dependency-injection/",
"Draw\\Component\\EntityMigrator\\": "packages/entity-migrator/",
"Draw\\Component\\Log\\": "packages/log/",
"Draw\\Component\\Mailer\\": "packages/mailer/",
Expand Down Expand Up @@ -294,4 +296,4 @@
"vendor/bin/phpstan analyse --generate-baseline"
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace Draw\Component\DependencyInjection\Integration;

use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;

trait ExtendableExtensionTrait
{
/**
* @var array<IntegrationInterface>
*/
private array $integrations = [];

abstract private function provideExtensionClasses(): array;

private function registerDefaultIntegrations(): void
{
foreach ($this->provideExtensionClasses() as $extensionClass) {
if (class_exists($extensionClass)) {
$integration = new $extensionClass();

if (!$integration instanceof IntegrationInterface) {
throw new \RuntimeException(sprintf('The class "%s" must implement "%s".', $extensionClass, IntegrationInterface::class));
}

$this->integrations[] = $integration;
}
}
}

/**
* @return array Parsed configuration
*/
private function loadIntegrations(array $configs, ContainerBuilder $container): array
{
$config = $this->processConfiguration($this->getConfiguration($configs, $container), $configs);

foreach ($this->integrations as $integration) {
$container->addObjectResource($integration);
}

$loader = new PhpFileLoader($container, new FileLocator([]));

foreach ($this->integrations as $integration) {
if ($this->isConfigEnabled($container, $config[$integration->getConfigSectionName()])) {
$integration->load($config[$integration->getConfigSectionName()], $loader, $container);
}
}

return $config;
}

private function prependIntegrations(ContainerBuilder $container, string $mainExtension): void
{
$configs = $container->getExtensionConfig($mainExtension);

$config = $this->processConfiguration(
$this->getConfiguration($configs, $container),
$container->getParameterBag()->resolveValue($configs)
);

foreach ($this->integrations as $integration) {
if (!$integration instanceof PrependIntegrationInterface) {
continue;
}

$integrationConfiguration = $config[$integration->getConfigSectionName()];

if ($this->isConfigEnabled($container, $integrationConfiguration)) {
$integration->prepend($container, $integrationConfiguration);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Draw\Bundle\FrameworkExtraBundle\DependencyInjection\Integration;
namespace Draw\Component\DependencyInjection\Integration;

use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<?php

namespace Draw\Bundle\FrameworkExtraBundle\DependencyInjection\Integration;
namespace Draw\Component\DependencyInjection\Integration;

use Draw\Component\Core\Reflection\ReflectionAccessor;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
Expand All @@ -12,6 +11,21 @@ trait IntegrationTrait
{
abstract public function getConfigSectionName(): string;

private static function getDefaultExcludedDirectories(): array
{
return [
'Attribute/',
'Email/',
'Entity/',
'Event/',
'Exception/',
'Message/',
'Resources/',
'Stamp/',
'Tests/',
];
}

protected function registerClasses(
PhpFileLoader $loader,
string $namespace,
Expand All @@ -23,30 +37,19 @@ protected function registerClasses(
->setAutowired(true)
->setAutoconfigured(true);

foreach ($this->getDefaultExcludedDirectories() as $defaultExcludedDirectory) {
$exclude[] = $directory.'/'.$defaultExcludedDirectory;
}

$loader->registerClasses(
$prototype,
$namespace,
$directory,
array_merge(
$exclude,
[
$directory.'/Attribute/',
$directory.'/Email/',
$directory.'/Entity/',
$directory.'/Event/',
$directory.'/Exception/',
$directory.'/Message/',
$directory.'/Resources/',
$directory.'/Stamp/',
$directory.'/Tests/',
]
)
$exclude
);

$container = ReflectionAccessor::getPropertyValue(
$loader,
'container',
);
$container = (new \ReflectionProperty($loader, 'container'))
->getValue($loader);

\assert($container instanceof ContainerBuilder);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Draw\Bundle\FrameworkExtraBundle\DependencyInjection\Integration;
namespace Draw\Component\DependencyInjection\Integration;

use Symfony\Component\DependencyInjection\ContainerBuilder;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
<?php

namespace Draw\Bundle\FrameworkExtraBundle\Tests\DependencyInjection\Integration;
namespace Draw\Component\DependencyInjection\Integration\Test;

use Draw\Bundle\FrameworkExtraBundle\DependencyInjection\DrawFrameworkExtraExtension;
use Draw\Bundle\FrameworkExtraBundle\DependencyInjection\Integration\IntegrationInterface;
use Draw\Bundle\FrameworkExtraBundle\DependencyInjection\Integration\PrependIntegrationInterface;
use Draw\Component\DependencyInjection\Integration\IntegrationInterface;
use Draw\Component\DependencyInjection\Integration\PrependIntegrationInterface;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
Expand Down Expand Up @@ -57,9 +56,8 @@ public function testLoad(
array $extraAliases = [],
array $expectedParameters = []
): void {
$dirname = \dirname((new \ReflectionClass(DrawFrameworkExtraExtension::class))->getFileName(), 2);
$container = new ContainerBuilder();
$loader = new PhpFileLoader($container, new FileLocator($dirname.'/Resources/config'));
$loader = new PhpFileLoader($container, new FileLocator([]));

$configuration = $this->processConfiguration($configuration);

Expand Down
98 changes: 98 additions & 0 deletions packages/dependency-injection/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Dependency Injection

This package provides addons to the Symfony Dependency Injection component.

## Installation

```
composer require draw/dependency-injection
```

## Integration

The `Draw\Component\DependencyInjection\Integration` namespace contains classes that can be used to easily integrate
subcomponents into a main bundle.

An example of this is all the draw components that are integrated into the `DrawFrameworkExtraBundle`.

When creating the main bundle extension you can use the `IntegrationTrait` to easily integrate all the subcomponents.

```php

namespace Example\Bundle\MyBundle\DependencyInjection;

use Draw\Component\DependencyInjection\IntegrationTrait;
use Example\Component\MyComponent\DependencyInjection\MyCompnentIntegration;
use Example\Component\MyOtherComponent\DependencyInjection\MyOtherComponentIntegration;

class ExampleMyBundle extends Bundle
{
use ExtendableExtensionTrait;

public function __construct()
{
$this->registerDefaultIntegrations();
}

private function provideExtensionClasses(): array
{
return [
MyCompnentIntegration::class,
];
}

public function getConfiguration(array $config, ContainerBuilder $container): ConfigurationInterface
{
return new Configuration($this->integrations);
}

public function load(array $configs, ContainerBuilder $container): void
{
$config = $this->loadIntegrations($configs, $container);

// Do your bundle specific configuration here
}

public function prepend(ContainerBuilder $container): void
{
$this->prependIntegrations($container, 'example_my_bundle');
}
}
```

**registerDefaultIntegrations**

The `registerDefaultIntegrations` method will automatically register all the integrations that are in the `provideExtensionClasses` method.

It will check if the class exists and if it does it will create a new instance of it and add it to the `integrations` property.

That way you can define the integration classes in the specific component, and it will automatically be integrated into the main bundle
if your component is installed.

**loadIntegrations**

The `loadIntegrations` method will call the `load` method on all the integrations that are registered.

It will automatically pass the configuration to the existing configuration only if they are `enabled`.

**prependIntegrations**

The `prependIntegrations` method will call the `prepend` method on all the integrations that are registered.

It will check if the configuration is `enabled` and if it is it will call the `prepend` method.

### Configuration

Here is an example of configuration base on the example above.

```yaml
example_my_bundle:
my_component:
enabled: true
my_component_configuration: true
my_other_component:
enabled: false
```
This example will enable the `MyComponentIntegration` and disable the `MyOtherComponentIntegration`.

32 changes: 32 additions & 0 deletions packages/dependency-injection/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "draw/dependency-injection",
"description": "Dependency injection addons to Symfony",
"license": "MIT",
"type": "library",
"keywords": ["draw", "component", "symfony"],
"authors": [
{
"name": "Martin Poirier Theoret",
"email": "[email protected]"
}
],
"require": {
"php": ">=8.1",
"symfony/config": "^6.4.0"
},
"require-dev": {
"phpunit/phpunit": "^10.0"
},
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
"psr-4": {
"Draw\\Component\\DependencyInjection\\": ""
}
},
"extra": {
"branch-alias": {
"dev-master": "0.11-dev"
}
}
}
9 changes: 9 additions & 0 deletions packages/dependency-injection/phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd">
<testsuites>
<testsuite name="Main">
<directory>./Tests</directory>
</testsuite>
</testsuites>
</phpunit>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Draw\Bundle\FrameworkExtraBundle\DependencyInjection;

use Draw\Bundle\FrameworkExtraBundle\DependencyInjection\Integration\IntegrationInterface;
use Draw\Component\DependencyInjection\Integration\IntegrationInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
Expand Down
Loading

0 comments on commit 4faa2e0

Please sign in to comment.