diff --git a/src/DI/ContainerBuilder.php b/src/DI/ContainerBuilder.php index ad6a8e643..fb8a655ed 100644 --- a/src/DI/ContainerBuilder.php +++ b/src/DI/ContainerBuilder.php @@ -376,15 +376,20 @@ private function resolveEntityClass($entity, $recursive = array()) try { $reflection = Nette\Utils\Callback::toReflection($entity); + $refClass = $reflection instanceof \ReflectionMethod ? $reflection->getDeclaringClass() : NULL; } catch (\ReflectionException $e) { } - if (isset($e) || !is_callable($entity)) { + + if (isset($e) || ($refClass && (!$reflection->isPublic() + || (PHP_VERSION_ID >= 50400 && $refClass->isTrait() && !$reflection->isStatic()) + ))) { $name = array_slice(array_keys($recursive), -1); throw new ServiceCreationException(sprintf("Factory '%s' used in service '%s' is not callable.", Nette\Utils\Callback::toString($entity), $name[0])); } + $class = preg_replace('#[|\s].*#', '', $reflection->getAnnotation('return')); - if ($class && $reflection instanceof \ReflectionMethod) { - $class = Reflection\AnnotationsParser::expandClassName($class, $reflection->getDeclaringClass()); + if ($class && $refClass) { + $class = Reflection\AnnotationsParser::expandClassName($class, $refClass); } return $class; diff --git a/tests/DI/ContainerBuilder.byClass.phpt b/tests/DI/ContainerBuilder.byClass.phpt index 2706a2564..e636c836a 100644 --- a/tests/DI/ContainerBuilder.byClass.phpt +++ b/tests/DI/ContainerBuilder.byClass.phpt @@ -11,11 +11,16 @@ use Nette\DI, require __DIR__ . '/../bootstrap.php'; -class Factory +interface IFactory +{ + static function create(); +} + +class Factory implements IFactory { public static $methods; - static function create($arg) + static function create() { self::$methods[] = array(__FUNCTION__, func_get_args()); return new stdClass; @@ -37,6 +42,22 @@ class AnnotatedFactory } +class UninstantiableFactory +{ + public static function getInstance() + { + return new self; + } + + private function __construct() + {} + + /** @return stdClass */ + function create() + {} +} + + $builder = new DI\ContainerBuilder; $builder->addDefinition('factory') ->setClass('Factory'); @@ -59,6 +80,19 @@ $builder->addDefinition('four') ->setAutowired(FALSE) ->setFactory('@\AnnotatedFactory::create'); +$builder->addDefinition('five') + ->setAutowired(FALSE) + ->setFactory('@\IFactory::create'); + +$builder->addDefinition('uninstantiableFactory') + ->setClass('UninstantiableFactory') + ->setFactory('UninstantiableFactory::getInstance'); + +$builder->addDefinition('six') + ->setAutowired(FALSE) + ->setFactory('@\UninstantiableFactory::create'); + + $container = createContainer($builder); @@ -85,3 +119,5 @@ Assert::type( 'stdClass', $container->getService('four') ); Assert::same(array( array('create', array()), ), $annotatedFactory->methods); + +Assert::type( 'stdClass', $container->getService('five') ); diff --git a/tests/DI/ContainerBuilder.factory.error2.phpt b/tests/DI/ContainerBuilder.factory.error2.phpt new file mode 100644 index 000000000..9b42dccfa --- /dev/null +++ b/tests/DI/ContainerBuilder.factory.error2.phpt @@ -0,0 +1,24 @@ +addDefinition('one')->setFactory('Bad1::method'); + $builder->generateClasses(); +}, 'Nette\InvalidStateException', "Factory 'Bad1::method' used in service 'one' is not callable.");