Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/DI/ContainerBuilder.php
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
services:

circle:
implement: ICircleFactory

triangle:
implement: ITriangleFactory

ellipse:
implement: IEllipseFactory