Skip to content

Commit

Permalink
Merge ef582b1 into 5e8b809
Browse files Browse the repository at this point in the history
  • Loading branch information
holtkamp committed Sep 22, 2018
2 parents 5e8b809 + ef582b1 commit 3563ac7
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 4 deletions.
26 changes: 22 additions & 4 deletions src/Compiler/Compiler.php
Expand Up @@ -141,15 +141,33 @@ public function compile(
return $fileName;
}

/**
* Use a hash to ensure that the used method names in the CompiledContainer are both unique and idempotent.
*/
private function getHashedValue(string $prefix, string $value): string
{
return $prefix . md5($value);
}

/**
* @throws DependencyException
* @throws InvalidDefinition
* @return string The method name
*/
private function compileDefinition(string $entryName, Definition $definition) : string
{
// Generate a unique method name
$methodName = str_replace('.', '', uniqid('get', true));
$methodName = $this->getHashedValue('get', $entryName);

//In case an Entry is already added, the used method should be equal
if(isset($this->entryToMethodMapping[$entryName]) && $this->entryToMethodMapping[$entryName] !== $methodName){
throw new InvalidDefinition(sprintf(
'Entry "%s" cannot be compiled. An Entry with the same name already exists pointing to method %s(), while this one points to method %s().',
$entryName,
$this->entryToMethodMapping[$entryName],
$methodName
));
}

$this->entryToMethodMapping[$entryName] = $methodName;

switch (true) {
Expand Down Expand Up @@ -260,8 +278,8 @@ public function compileValue($value) : string
}

if ($value instanceof Definition) {
// Give it an arbitrary unique name
$subEntryName = uniqid('SubEntry');
$subEntryName = $this->getHashedValue('SubEntry', $value->getName() . $value);

// Compile the sub-definition in another method
$methodName = $this->compileDefinition($subEntryName, $value);
// The value is now a method call to that method (which returns the value)
Expand Down
74 changes: 74 additions & 0 deletions tests/IntegrationTest/CompiledContainerTest.php
Expand Up @@ -56,6 +56,54 @@ public function the_container_is_compiled_once_and_never_recompiled_after()
self::assertEquals('bar', $container->get('foo'));
}

/** @test */
public function the_compiled_container_is_idempotent()
{
$compiledContainerClass1 = self::generateCompiledClassName();
$compiledContainerClass2 = self::generateCompiledClassName();

$definitions = [
'foo' => 'barFromFoo',
'fooReference' => \DI\get('foo'),
'factory' => function () {
return 'barFromFactory';
},
'factoryReference' => \DI\get('factory'),
'array' => [
1,
2,
3,
'fooBar',
],
'arrayValue' => \DI\value('array'),
CompiledContainerTest\AllKindsOfInjections::class => create()
->constructor(create('stdClass'))
->property('property', autowire(CompiledContainerTest\Autowireable::class))
->method('method', \DI\factory(
function () {
return new \stdClass;
}
)
),
CompiledContainerTest\Autowireable::class => \DI\autowire(),
];

// Create a compiled container in a specific file
$builder1 = new ContainerBuilder;
$builder1->addDefinitions($definitions);
$builder1->enableCompilation(self::COMPILATION_DIR, $compiledContainerClass1);
$builder1->build();

// Create a second compiled container with the same configuration but in a different file
$builder2 = new ContainerBuilder;
$builder2->addDefinitions($definitions);
$builder2->enableCompilation(self::COMPILATION_DIR, $compiledContainerClass2);
$builder2->build();

// The method mapping of the resulting CompiledContainers should be equal
self::assertEquals($compiledContainerClass1::METHOD_MAPPING, $compiledContainerClass2::METHOD_MAPPING);
}

/**
* @test
* @expectedException \DI\Definition\Exception\InvalidDefinition
Expand Down Expand Up @@ -253,3 +301,29 @@ public function __construct(AbstractClass $param)
abstract class AbstractClass
{
}

class AllKindsOfInjections
{
public $property;
public $constructorParameter;
public $methodParameter;
public function __construct($constructorParameter)
{
$this->constructorParameter = $constructorParameter;
}
public function method($methodParameter)
{
$this->methodParameter = $methodParameter;
}
}
class Autowireable
{
private $dependency;
public function __construct(AutowireableDependency $dependency)
{
$this->dependency = $dependency;
}
}
class AutowireableDependency
{
}

0 comments on commit 3563ac7

Please sign in to comment.