Skip to content

Commit

Permalink
Merge pull request #3 from Jibbarth/feature/check-config-before-write
Browse files Browse the repository at this point in the history
Feature/check config before write
  • Loading branch information
Jibbarth authored Oct 28, 2018
2 parents f3a73e8 + 1924fd3 commit b2440b9
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 78 deletions.
73 changes: 12 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ References this [documentation example](http://symfony.com/doc/current/bundles/c

The mechanism behind is to retrieve all available configuration for a bundle, display it in a form, and dump the submitted data in a new _config file_ that will override the default configuration.


## Installation

### Step 1: Download the Bundle
Expand All @@ -18,36 +17,6 @@ Open a command console, enter your project directory and execute:
$ composer require barth/simple-config-bundle
```

> :warning: This is not already available as I didn't yet submit this package to [Packagist](https://packagist.org)
> Stay tuned for update by giving a :star: ?
Or open your `composer.json`, and add following content :

```js
{
// ...
"repositories": [
{
"type": "vcs",
"url": "[email protected]:Jibbarth/SimpleConfigBundle",
"vendor-alias": "barth"
}
],
"require": {
//...
"barth/simple-config-bundle": "dev-master"
}
//...
}
```

Open a command console, enter your project directory and execute the
following command to download the latest stable version of this bundle:

```console
$ composer update
```

This command requires you to have Composer installed globally, as explained
in the [installation chapter](https://getcomposer.org/doc/00-intro.md)
of the Composer documentation.
Expand All @@ -67,32 +36,7 @@ return [
];
```

### Step 3: Active the override for configuration

In your `src/Kernel.php`, alter the `configureContainer` function :

```php
protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
{
$container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php'));
// Feel free to remove the "container.autowiring.strict_mode" parameter
// if you are using symfony/dependency-injection 4.0+ as it's the default behavior
$container->setParameter('container.autowiring.strict_mode', true);
$container->setParameter('container.dumper.inline_class_loader', true);
$confDir = $this->getProjectDir().'/config';

$loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{packages}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob');

// ADD THIS LINE
$loader->load($confDir.'/{packages}/override/**/*'.self::CONFIG_EXTS, 'glob');

$loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob');
$loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob');
}
```

### Step 4: Import routes
### Step 3: Import routes

In your `config/routes.yaml`, add the following route definition :

Expand Down Expand Up @@ -132,10 +76,16 @@ When installation is completed, you have two new routes :
* http://yourdomain.org/admin/config That exposes all available configuration routes
* http://yourdomain.org/admin/config/{package} That display your form configuration

## Customize
## Customization and Integration

### Custom Backend

By default, pages don't look very pretty. To integrate it in your template, don't hesitate to override the `base.html.twig` template by creating a new one in `templates/bundles/BarthSimpleConfigBundle/` and make it extend your base template.

### Third-party bundles

SimpleConfigBundle can easily be integrated in [EasyAdminBundle](https://github.com/EasyCorp/EasyAdminBundle).
Just require it.

## Contribute

Expand All @@ -145,10 +95,11 @@ If you find any typo/misconfiguration/... please send me a PR or open an issue.

Also, while creating your PR, please write a description which gives the context and/or explains why you are creating it.


## TODOs

- [ ] Make installation as simple as a `composer require barth/simple-config-bundle`, so submit it to packagist
- [ ] Process configuration when form is submitted to validate it immediatly.
- [x] Make installation as simple as a `composer require barth/simple-config-bundle`, so submit it to packagist
- [x] Process configuration when form is submitted to validate it immediatly.
- [ ] Write Tests Suite
- [ ] Add translations
- [x] Integration with [EasyAdminBundle](https://github.com/EasyCorp/EasyAdminBundle)
- [ ] Integration with [Sonata](https://sonata-project.org/)
29 changes: 20 additions & 9 deletions src/Controller/DefaultController.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,25 +74,36 @@ public function editAction(
FormConfigService $formConfigService
): Response {
$extension = $this->extensionLocatorService->retrieveByPackageName($package);
$config = $this->extensionConfigurationService->getConfiguration($extension);
$config = $this->extensionConfigurationService->getCurrentConfiguration($extension);

$form = $formConfigService->getFormForConfig($config);
$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
$nameConverter = new SnakeCaseToCamelCaseNameConverter();
$data = $this->cleanData($form->getData());
// TODO validate configuration
try {
$data = $this->configService->parseConfig($data);
$data = $this->extensionConfigurationService->validateConfiguration($extension, [$extension->getAlias() => $data]);
$this->configService->saveNewConfig($package, $data);
if ($this->configService->isOverrideConfigForPackageExist($package)) {
$nameConverter = new SnakeCaseToCamelCaseNameConverter();
$this->get('session')->getFlashBag()->add(
'success',
'Successfully registered config for ' . $nameConverter->handle($package)
);
}

$this->configService->saveNewConfig($package, $data);
if ($this->configService->isOverrideConfigForPackageExist($package)) {
$nameConverter = new SnakeCaseToCamelCaseNameConverter();
return $this->redirect($this->generateUrl('barth_simpleconfig_index'));
} catch (\Throwable $throwable) {
$this->get('session')->getFlashBag()->add(
'success',
'Successfully registered config for ' . $nameConverter->handle($package)
'error',
sprintf('Error for %s : %s',
$nameConverter->handle($package),
$throwable->getMessage()
)
);
}

return $this->redirect($this->generateUrl('barth_simpleconfig_index'));
}

$nameConverter = new SnakeCaseToCamelCaseNameConverter();
Expand Down
18 changes: 15 additions & 3 deletions src/Service/ConfigService.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,30 @@ public function saveNewConfig(string $package, array $config): void
{
$fs = new Filesystem();
$packageOverrideFile = $this->getOverridePackagePath() . \DIRECTORY_SEPARATOR . $package . '.yaml';
$config = $this->parseConfig($config);

$fs->dumpFile($packageOverrideFile, Yaml::dump([$package => $config], 4));
}

public function parseConfig(array $config): array
{
foreach ($config as $key => $value) {
if (\strpos('-', $key)) {
if (\strpos($key, '_dot_')) {
unset($config[$key]);
$key = \str_replace('.', '-', $key);
$key = \str_replace('_dot_', '.', $key);
$config[$key] = $value;
}
if (\strpos($key, '_backslash_')) {
unset($config[$key]);
$key = \str_replace('_backslash_', '\\', $key);
$config[$key] = $value;
}
if (\strpos($key, ':')) {
$this->unflattenArray($config, $key, $value);
unset($config[$key]);
}
}
$fs->dumpFile($packageOverrideFile, Yaml::dump([$package => $config], 4));
return $config;
}

public function isOverrideConfigForPackageExist(string $package): bool
Expand Down
48 changes: 44 additions & 4 deletions src/Service/ExtensionConfigurationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Barth\SimpleConfigBundle\Service;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
Expand All @@ -26,23 +27,40 @@ public function __construct(
$this->kernel = $kernel;
}

public function getConfiguration(ExtensionInterface $extension): array
/**
* @throws \Exception
*/
public function validateConfiguration(ExtensionInterface $extension, array $configs): array
{
$configs[$extension->getAlias()] = $this->cleanConfig($configs[$extension->getAlias()], $this->getCurrentConfiguration($extension));
$processor = new Processor();
$container = $this->getContainerBuilder();
$container->resolveEnvPlaceholders(
$container->getParameterBag()->resolveValue(
$processor->processConfiguration($this->getExtensionConfiguration($extension), $configs)
)
);


return $configs[$extension->getAlias()];
}

public function getCurrentConfiguration(ExtensionInterface $extension): array
{
$config = [];

try {
$container = $this->getContainerBuilder();
$configs = $container->getExtensionConfig($extension->getAlias());

$configuration = $extension->getConfiguration($configs, $container);
$configs = $container->resolveEnvPlaceholders(
$container->getParameterBag()->resolveValue($configs)
);
$processor = new Processor();

$processor = new Processor();
$config = $container->resolveEnvPlaceholders(
$container->getParameterBag()->resolveValue(
$processor->processConfiguration($configuration, $configs)
$processor->processConfiguration($this->getExtensionConfiguration($extension), $configs)
)
);
} catch (\Throwable $throwable) {
Expand All @@ -62,6 +80,14 @@ public function getTreeBuilderForExtension(ExtensionInterface $extension): TreeB
return $configuration->getConfigTreeBuilder();
}

protected function getExtensionConfiguration(ExtensionInterface $extension): ConfigurationInterface
{
$container = $this->getContainerBuilder();
$configs = $container->getExtensionConfig($extension->getAlias());

return $extension->getConfiguration($configs, $container);
}

protected function getContainerBuilder(): ContainerBuilder
{
if (null === $this->containerBuilder) {
Expand All @@ -78,4 +104,18 @@ protected function getContainerBuilder(): ContainerBuilder

return $this->containerBuilder;
}

/**
* Remove key that is equals to current configuration
*/
protected function cleanConfig(array $configs, array $currentConfig): array
{
foreach ($configs as $key => $config) {
if (isset($currentConfig[$key]) && $currentConfig[$key] === $config ) {
unset($configs[$key]);
}
}

return $configs;
}
}
3 changes: 2 additions & 1 deletion src/Service/FormConfigService.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ protected function addToForm(FormBuilderInterface $formBuilder, string $key, $fi
if ('' !== $parentKey) {
$key = $parentKey . ':' . $key;
}
$key = \str_replace('.', '-', $key);
$key = \str_replace('.', '_dot_', $key);
$key = \str_replace('\\', '_backslash_', $key);
$formBuilder->add($key, $type, $params);
}

Expand Down

0 comments on commit b2440b9

Please sign in to comment.