Skip to content
This repository has been archived by the owner on Jan 1, 2018. It is now read-only.

Commit

Permalink
Add GroupedNeonAdapter
Browse files Browse the repository at this point in the history
  • Loading branch information
mrtnzlml committed Feb 1, 2017
1 parent fe7b6ff commit de0d7be
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 1 deletion.
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,36 @@ services:
```

Remember that this is possible only if you are using custom config added by `provideConfig` method. It will not work in configs added in bootstrap file (via `Nette\DI\Compiler::addConfig`). This is because only under extension it's possible to get key from the right extension section (`ext2.ext_key2` in this case).

### Experimental features
These features are not enabled by default now (but may be enabled by default in the future). To enable experimental features now you have to register this extension differently:

```php
$configurator->defaultExtensions['extensions'] = [\Adeira\ConfigurableExtensionsExtension::class, [TRUE]]; // Become superhero!
```

At this moment there is so called `GroupedNeonAdapter`. It allows you to write service definitions in NEON with grouped syntax. Before:

```php
graphql:
types:
- Adeira\Connector\Devices\Infrastructure\Delivery\API\GraphQL\Type\WeatherStationRecordType
- Adeira\Connector\Devices\Infrastructure\Delivery\API\GraphQL\Type\WeatherStationsConnectionType
- Adeira\Connector\Devices\Infrastructure\Delivery\API\GraphQL\Type\WeatherStationsEdgeType
- Adeira\Connector\Devices\Infrastructure\Delivery\API\GraphQL\Type\WeatherStationType
```

After:

```php
graphql:
types:
- Adeira\Connector\Devices\Infrastructure\Delivery\API\GraphQL\Type\( # namespace must end with backslash
WeatherStationRecordType
WeatherStationsConnectionType
WeatherStationsEdgeType
WeatherStationType
)
```

This feature is optional and works only in NEON files provided via `provideConfig` method. All classes must be registered anonymously. If it's not possible just don't use this feature.
18 changes: 18 additions & 0 deletions src/ConfigurableExtensionsExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@
class ConfigurableExtensionsExtension extends \Nette\DI\Extensions\ExtensionsExtension
{

private $experimental;

public function __construct($experimental = FALSE)
{
$this->experimental = $experimental;
}

public function loadFromFile($file)
{
$loader = new \Nette\DI\Config\Loader;
if ($this->experimental === TRUE) {
$loader->addAdapter('neon', GroupedNeonAdapter::class);
}
$res = $loader->load($file);
$this->compiler->addDependencies($loader->getDependencies());
return $res;
}

public function loadConfiguration()
{
$ceeConfig = $this->getConfig(); // configuration of this extension (list of extensions)
Expand Down
42 changes: 42 additions & 0 deletions src/GroupedNeonAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Adeira;

final class GroupedNeonAdapter extends \Nette\DI\Config\Adapters\NeonAdapter
{

public function process(array $arr)
{
foreach ($arr as &$configKeys) {
if (is_array($configKeys)) {
foreach ($configKeys as $originalKey => $entity) {
if ($entity instanceof \Nette\Neon\Entity) {
if (\Nette\Utils\Strings::endsWith($entity->value, '\\')) {
if (!$this->isEntityRegisteredAsAnonymous($originalKey)) {
throw new \Nette\Neon\Exception("Service with grouped classes must be anonymous. You have to remove key '$originalKey' to use this feature.");
}

unset($configKeys[$originalKey]);

foreach ($entity->attributes as $attributeKey => $attribute) {
if (!$this->isEntityRegisteredAsAnonymous($attributeKey)) {
throw new \Nette\Neon\Exception("Grouped classes in service definition must be anonymous. Please remove key '$attributeKey'.");
}

$configKeys[] = $entity->value . $attribute; //add grouped services
}
}
}
}
}
}
unset($configKeys); //unreference
return parent::process($arr);
}

private function isEntityRegisteredAsAnonymous($entityKey)
{
return (string)(int)$entityKey === (string)$entityKey; //anonymous
}

}
2 changes: 1 addition & 1 deletion tests/src/CompilerExtension.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class CompilerExtension extends \Tester\TestCase

$configurator = new Nette\Configurator;
$configurator->defaultExtensions = [
'extensions' => \Adeira\ConfigurableExtensionsExtension::class,
'extensions' => [\Adeira\ConfigurableExtensionsExtension::class, [TRUE]],
'application' => [Nette\Bridges\ApplicationDI\ApplicationExtension::class, ['%debugMode%', ['%appDir%'], '%tempDir%/cache']],
'http' => [Nette\Bridges\HttpDI\HttpExtension::class, ['%consoleMode%']],
'latte' => [Nette\Bridges\ApplicationDI\LatteExtension::class, ['%tempDir%/cache/latte', '%debugMode%']],
Expand Down
84 changes: 84 additions & 0 deletions tests/src/GroupedNeonAdapterTest.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

namespace Adeira\Tests;

use Adeira\GroupedNeonAdapter;
use Tester\Assert;
use Tester\FileMock;

require dirname(__DIR__) . '/bootstrap.php';

/**
* @testCase
*/
class GroupedNeonAdapterTest extends \Tester\TestCase
{

public function testThatProcessExpandsEntities()
{
$loader = new \Nette\DI\Config\Loader;
$loader->addAdapter($extension = 'neon', GroupedNeonAdapter::class);
$configuration = <<<NEON
section:
- Namespace\ClassA
B: Namespace\ClassB
- Namespace\(Class_1)
- Namespace\ClassC
- Namespace\(
Class_2
Class_3
Class_4
)
NEON;
Assert::same([
'section' => [
0 => 'Namespace\\ClassA',
'B' => 'Namespace\\ClassB',
2 => 'Namespace\\ClassC', // it doesn't cleanup indices but who cares
4 => 'Namespace\\Class_1',
5 => 'Namespace\\Class_2',
6 => 'Namespace\\Class_3',
7 => 'Namespace\\Class_4',
],
], $loader->load(FileMock::create($configuration, $extension)));
}

public function testThatClassMustBeAnonymous()
{
$loader = new \Nette\DI\Config\Loader;
$loader->addAdapter($extension = 'neon', GroupedNeonAdapter::class);
$configuration = <<<NEON
section:
A: Namespace\ClassA
B: Namespace\(
Class_2
Class_3
Class_4
)
NEON;
Assert::exception(function () use ($loader, $configuration, $extension) {
$loader->load(FileMock::create($configuration, $extension));
}, \Nette\Neon\Exception::class, 'Service with grouped classes must be anonymous. You have to remove key \'B\' to use this feature.');
}

public function testThatExpandedClassMustBeAnonymous()
{
$loader = new \Nette\DI\Config\Loader;
$loader->addAdapter($extension = 'neon', GroupedNeonAdapter::class);
$configuration = <<<NEON
section:
A: Namespace\ClassA
- Namespace\(
Class_2,
c3: Class_3,
Class_4,
)
NEON;
Assert::exception(function () use ($loader, $configuration, $extension) {
$loader->load(FileMock::create($configuration, $extension));
}, \Nette\Neon\Exception::class, 'Grouped classes in service definition must be anonymous. Please remove key \'c3\'.');
}

}

(new GroupedNeonAdapterTest)->run();

0 comments on commit de0d7be

Please sign in to comment.