Skip to content

Commit

Permalink
compilation options (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
smpl authored Aug 7, 2023
2 parents 6d26634 + ec159b0 commit 1ec15be
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 52 deletions.
13 changes: 10 additions & 3 deletions src/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,25 @@ public function __construct(array $params, array $alias, array $definitions, str

/**
* @param array<string> $containers
* @param bool $definition_overridable
* @param bool $alias_overridable
* @param bool $reflection_enabled
* @return string|false
*/
public function __invoke(array $containers): string|false
{
public function __invoke(
array $containers,
bool $definition_overridable,
bool $alias_overridable,
bool $reflection_enabled
): string|false {
$this->reflection = new Reflection();
$namespace = $this->getNamespace();
$class = $this->getClass();
$alias = $this->alias;
$definitions = $this->definitions;
$containers = $this->generateContainers($containers);
ob_start();
include __DIR__ . '/../template/container.compiler';
include __DIR__ . '/../template/container.compiler.php';
return ob_get_clean();
}

Expand Down
18 changes: 15 additions & 3 deletions src/ContainerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,23 @@ public function fqcn(string $fqcn): self

/**
* @param array<string> $containers
* @param bool $definition_overridable
* @param bool $alias_overridable
* @param bool $reflection_enabled
* @return string|false
*/
public function compile(array $containers): string|false
{
public function compile(
array $containers,
bool $definition_overridable = true,
bool $alias_overridable = true,
bool $reflection_enabled = false
): string|false {
$compiler = new Compiler($this->params, $this->alias, $this->definitions, $this->fqcn);
return $compiler($containers);
return $compiler(
$containers,
$definition_overridable,
$alias_overridable,
$reflection_enabled,
);
}
}
45 changes: 0 additions & 45 deletions template/container.compiler

This file was deleted.

84 changes: 84 additions & 0 deletions template/container.compiler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?= '<?php' . PHP_EOL; ?><?php
/**
* @var string $class
* @var bool $reflection_enabled
* @var bool $alias_overridable
* @var bool $definition_overridable
* @var array $alias
* @var array $alias
* @var array $containers
*/
?>

declare(strict_types=1);

<?php if (!empty($namespace)) { ?>namespace <?= $namespace ?>; <?php } ?>

class <?= $class ?> implements \Psr\Container\ContainerInterface
{
private array $params;
private array $alias;
<?php if ($definition_overridable) { ?>
private array $definitions;
<?php } ?>
private array $containers;
<?php if ($reflection_enabled) { ?>
private \Cekta\DI\Strategy\Autowiring $autowiring;
<?php } ?>

public function __construct(array $params, array $alias, array $definitions)
{
$this->params = $params;
<?php if ($alias_overridable) { ?>
$this->alias = $alias;
<?php } ?>
<?php if ($definition_overridable) { ?>
$this->definitions = $definitions;
<?php } ?>
<?php if ($reflection_enabled) { ?>
$this->autowiring = new \Cekta\DI\Strategy\Autowiring(new \Cekta\DI\Reflection(), $this, $this->alias);
<?php } ?>
$this->containers = <?= var_export(array_unique(array_merge(array_keys($containers), array_keys($alias)))) ?>;
}

public function get($name)
{
if (!array_key_exists($name, $this->params)) {
$this->params[$name] = match($name) {
<?php if ($definition_overridable) { ?>
array_key_exists($name, $this->definitions) ? $name: false => $this->definitions[$name]($this),
<?php } ?>
<?php if ($alias_overridable) { ?>
array_key_exists($name, $this->alias) ? $name: false => $this->get($this->alias[$name]),
<?php } ?>
<?php foreach ($containers as $key => $value) { ?>
<?= var_export($key, true) ?> => <?= $value ?>,
<?php } ?>
<?php foreach ($alias as $key => $value) { ?>
<?= var_export($key, true) ?> => $this->get('<?= $value ?>'),
<?php } ?>
<?php if ($reflection_enabled) { ?>
$this->autowiring->has($name) === true ? $name: false => $this->autowiring->get($name),
<?php } ?>
default => throw new \Cekta\DI\Exception\NotFound($name),
};
}
return $this->params[$name];
}

public function has($name)
{
return array_key_exists($name, $this->params)
<?php if ($alias_overridable) { ?>
|| array_key_exists($name, $this->alias)
<?php } ?>
<?php if ($definition_overridable) { ?>
|| array_key_exists($name, $this->definitions)
<?php } ?>
|| in_array($name, $this->containers)
<?php if ($reflection_enabled) { ?>
|| $this->autowiring->has($name)
<?php } ?>
;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use PHPUnit\Framework\TestCase;
use UnexpectedValueException;

class ContainerCompilationTest extends TestCase
class CompilerTest extends TestCase
{
public function testFail(): void
{
Expand Down
102 changes: 102 additions & 0 deletions tests/ContainerCompiledTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@

namespace Cekta\DI\Test;

use Cekta\DI\ContainerBuilder;
use Cekta\DI\Exception\NotFound;
use Cekta\DI\Test\Fixture\Builder;
use Cekta\DI\Test\Fixture\ExampleWithoutConstructor;
use Cekta\DI\Test\Fixture\I;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use stdClass;

class ContainerCompiledTest extends ContainerTest
{
Expand All @@ -28,4 +35,99 @@ public static function tearDownAfterClass(): void
unlink(__DIR__ . '/ExampleCompiled.php');
}
}

/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function testOverwriteBuildAlias(): void
{
$builder = new ContainerBuilder();
$builder->fqcn(Builder::$FQCN)
->alias([I::class => 'username'])
->params(['username' => 'root']);
$container = $builder->build();
$this->assertSame('root', $container->get(I::class));
}

/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function testReflectionEnabled(): void
{
/** @psalm-var class-string<object> $fqcn */
$fqcn = 'Cekta\\DI\\Test\\TestReflectionEnabled';
$filename = __DIR__ . '/TestReflectionEnabled.php';
$builder = new ContainerBuilder();
file_put_contents(
$filename,
$builder->fqcn($fqcn)
->compile([], reflection_enabled: true)
);
$container = $builder->build();
unlink($filename);
$this->assertInstanceOf($fqcn, $container);
$this->assertInstanceOf(ExampleWithoutConstructor::class, $container->get(ExampleWithoutConstructor::class));
}

/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function testReflectionDisabledByDefault(): void
{
$this->expectException(NotFound::class);
$this->container->get(stdClass::class);
}

/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function testAliasOverridableFalse(): void
{
/** @psalm-var class-string<object> $fqcn */
$fqcn = 'Cekta\\DI\\Test\\TestAliasOverridableFalse';
$filename = __DIR__ . '/TestAliasOverridableFalse.php';
$builder = new ContainerBuilder();
file_put_contents(
$filename,
$builder->fqcn($fqcn)
->alias(['test' => 'value1'])
->params(['value1' => 'value1'])
->compile([], alias_overridable: false)
);
$builder->alias(['test' => 'value2']);
$container = $builder->build();
unlink($filename);
$this->assertInstanceOf($fqcn, $container);
$this->assertSame('value1', $container->get('test'));
}

/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function testDefinitionOverridableFalse(): void
{
/** @psalm-var class-string<object> $fqcn */
$fqcn = 'Cekta\\DI\\Test\\TestDefinitionOverridableFalse';
$filename = __DIR__ . '/TestDefinitionOverridableFalse.php';
$builder = new ContainerBuilder();
file_put_contents(
$filename,
$builder->fqcn($fqcn)
->alias(['test' => 'value1'])
->params(['value1' => 'value1'])
->compile([], definition_overridable: false)
);
$builder->definitions(['test' => function () {
return 'value2';
}]);
$container = $builder->build();
unlink($filename);
$this->assertInstanceOf($fqcn, $container);
$this->assertSame('value1', $container->get('test'));
}
}
9 changes: 9 additions & 0 deletions tests/ContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ protected function setUp(): void
}
}

/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function testNull(): void
{
$this->assertNull($this->container->get('null'));
}

/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
Expand Down
1 change: 1 addition & 0 deletions tests/Fixture/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public function __construct()
A::class . '|int' => 54321,
'...variadic_params' => [123, 456],
'...variadic_strings' => ['hello', 'world'],
'null' => null,
];
self::$PARAMS[sprintf('(%s&%s)|int', A::class, B::class)] = 12345;
self::$PARAMS[sprintf('...(%s&%s)|int', A::class, B::class)] = [456, 321];
Expand Down

0 comments on commit 1ec15be

Please sign in to comment.