Skip to content

Commit

Permalink
ContainerBuilder:resolveImplement supports polymorphism (#175)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartkCz authored and dg committed Sep 16, 2018
1 parent ed14761 commit 15e6676
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/DI/ContainerBuilder.php
Expand Up @@ -417,7 +417,12 @@ private function resolveImplement(ServiceDefinition $def, $name): void
$hint = Reflection::getParameterType($param);
if (isset($ctorParams[$param->getName()])) {
$arg = $ctorParams[$param->getName()];
if ($hint !== Reflection::getParameterType($arg)) {
if ($hint && class_exists($hint)) {
$hints = [$hint => $hint] + class_parents($hint) + class_implements($hint);
if (!isset($hints[Reflection::getParameterType($arg)])) {
throw new ServiceCreationException("Type hint for \${$param->getName()} in $methodName doesn't match type hint in $class constructor.");
}
} elseif ($hint !== Reflection::getParameterType($arg)) {
throw new ServiceCreationException("Type hint for \${$param->getName()} in $methodName doesn't match type hint in $class constructor.");
}
$def->getFactory()->arguments[$arg->getPosition()] = self::literal('$' . $arg->getName());
Expand Down
101 changes: 101 additions & 0 deletions tests/DI/Compiler.generatedFactory.polymorphism.phpt
@@ -0,0 +1,101 @@
<?php

/**
* Test: Nette\DI\Compiler: generated services factories from interfaces with class type hints in parameters.
*/

declare(strict_types=1);

use Nette\DI;
use Tester\Assert;


require __DIR__ . '/../bootstrap.php';

interface IShape
{
public function getName(): string;
}

class Circle implements IShape
{
public function getName(): string
{
return 'circle';
}
}

class Triangle implements IShape
{
public function getName(): string
{
return 'triangle';
}
}

class Ellipse extends Circle
{
public function getName(): string
{
return 'ellipse';
}
}

interface ICircleFactory
{
public function create(Circle $shape): Picture;
}

interface ITriangleFactory
{
public function create(Triangle $shape): Picture;
}

interface IEllipseFactory
{
public function create(Ellipse $shape): Picture;
}

class Picture
{
public $shape;


public function __construct(IShape $shape)
{
$this->shape = $shape;
}


public function getName(): string
{
return $this->shape->getName();
}
}

$compiler = new DI\Compiler;
$container = createContainer($compiler, 'files/compiler.generatedFactory.polymorphism.neon');

Assert::type(ICircleFactory::class, $container->getService('circle'));
$picture = $container->getService('circle')->create(new Circle());
Assert::type(Picture::class, $picture);
Assert::same('circle', $picture->getName());

Assert::type(ITriangleFactory::class, $container->getService('triangle'));
$picture = $container->getService('triangle')->create(new Triangle());
Assert::type(Picture::class, $picture);
Assert::same('triangle', $picture->getName());

Assert::type(IEllipseFactory::class, $container->getService('ellipse'));
$picture = $container->getService('ellipse')->create(new Ellipse());
Assert::type(Picture::class, $picture);
Assert::same('ellipse', $picture->getName());

Assert::type(ICircleFactory::class, $container->getService('circle'));
$picture = $container->getService('circle')->create(new Ellipse());
Assert::type(Picture::class, $picture);
Assert::same('ellipse', $picture->getName());

Assert::throws(function () use ($container) {
$container->getService('ellipse')->create(new Circle());
}, TypeError::class);
10 changes: 10 additions & 0 deletions tests/DI/files/compiler.generatedFactory.polymorphism.neon
@@ -0,0 +1,10 @@
services:

circle:
implement: ICircleFactory

triangle:
implement: ITriangleFactory

ellipse:
implement: IEllipseFactory

0 comments on commit 15e6676

Please sign in to comment.