Skip to content

Commit 3f5484f

Browse files
committed
ContainerBuilder::resolveEntityClass() checking whether factory is callable counts with interfaces and traits [Closes #32]
1 parent 9ad7c71 commit 3f5484f

File tree

3 files changed

+70
-5
lines changed

3 files changed

+70
-5
lines changed

src/DI/ContainerBuilder.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -376,15 +376,20 @@ private function resolveEntityClass($entity, $recursive = array())
376376

377377
try {
378378
$reflection = Nette\Utils\Callback::toReflection($entity);
379+
$refClass = $reflection instanceof \ReflectionMethod ? $reflection->getDeclaringClass() : NULL;
379380
} catch (\ReflectionException $e) {
380381
}
381-
if (isset($e) || !is_callable($entity)) {
382+
383+
if (isset($e) || ($refClass && (!$reflection->isPublic()
384+
|| (PHP_VERSION_ID >= 50400 && $refClass->isTrait() && !$reflection->isStatic())
385+
))) {
382386
$name = array_slice(array_keys($recursive), -1);
383387
throw new ServiceCreationException(sprintf("Factory '%s' used in service '%s' is not callable.", Nette\Utils\Callback::toString($entity), $name[0]));
384388
}
389+
385390
$class = preg_replace('#[|\s].*#', '', $reflection->getAnnotation('return'));
386-
if ($class && $reflection instanceof \ReflectionMethod) {
387-
$class = Reflection\AnnotationsParser::expandClassName($class, $reflection->getDeclaringClass());
391+
if ($class && $refClass) {
392+
$class = Reflection\AnnotationsParser::expandClassName($class, $refClass);
388393
}
389394
return $class;
390395

tests/DI/ContainerBuilder.byClass.phpt

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ use Nette\DI,
1111
require __DIR__ . '/../bootstrap.php';
1212

1313

14-
class Factory
14+
interface IFactory
15+
{
16+
static function create();
17+
}
18+
19+
class Factory implements IFactory
1520
{
1621
public static $methods;
1722

18-
static function create($arg)
23+
static function create()
1924
{
2025
self::$methods[] = array(__FUNCTION__, func_get_args());
2126
return new stdClass;
@@ -37,6 +42,22 @@ class AnnotatedFactory
3742
}
3843

3944

45+
class UninstantiableFactory
46+
{
47+
public static function getInstance()
48+
{
49+
return new self;
50+
}
51+
52+
private function __construct()
53+
{}
54+
55+
/** @return stdClass */
56+
function create()
57+
{}
58+
}
59+
60+
4061
$builder = new DI\ContainerBuilder;
4162
$builder->addDefinition('factory')
4263
->setClass('Factory');
@@ -59,6 +80,19 @@ $builder->addDefinition('four')
5980
->setAutowired(FALSE)
6081
->setFactory('@\AnnotatedFactory::create');
6182

83+
$builder->addDefinition('five')
84+
->setAutowired(FALSE)
85+
->setFactory('@\IFactory::create');
86+
87+
$builder->addDefinition('uninstantiableFactory')
88+
->setClass('UninstantiableFactory')
89+
->setFactory('UninstantiableFactory::getInstance');
90+
91+
$builder->addDefinition('six')
92+
->setAutowired(FALSE)
93+
->setFactory('@\UninstantiableFactory::create');
94+
95+
6296

6397
$container = createContainer($builder);
6498

@@ -85,3 +119,5 @@ Assert::type( 'stdClass', $container->getService('four') );
85119
Assert::same(array(
86120
array('create', array()),
87121
), $annotatedFactory->methods);
122+
123+
Assert::type( 'stdClass', $container->getService('five') );
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/**
4+
* Test: Nette\DI\ContainerBuilder and generated factories errors.
5+
* @phpversion 5.4
6+
*/
7+
8+
use Nette\DI,
9+
Tester\Assert;
10+
11+
12+
require __DIR__ . '/../bootstrap.php';
13+
14+
15+
trait Bad1
16+
{
17+
function method() {}
18+
}
19+
20+
Assert::exception(function() {
21+
$builder = new DI\ContainerBuilder;
22+
$builder->addDefinition('one')->setFactory('Bad1::method');
23+
$builder->generateClasses();
24+
}, 'Nette\InvalidStateException', "Factory 'Bad1::method' used in service 'one' is not callable.");

0 commit comments

Comments
 (0)