[DI][Config] Add & use ReflectionClassResource
This commit is contained in:
parent
35a49fb577
commit
37e44939ef
@ -13,7 +13,10 @@ namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Symfony\Component\Translation\TranslatorBagInterface;
|
||||
|
||||
/**
|
||||
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
|
||||
@ -31,7 +34,10 @@ class LoggingTranslatorPass implements CompilerPassInterface
|
||||
$definition = $container->getDefinition((string) $translatorAlias);
|
||||
$class = $container->getParameterBag()->resolveValue($definition->getClass());
|
||||
|
||||
if (is_subclass_of($class, 'Symfony\Component\Translation\TranslatorInterface') && is_subclass_of($class, 'Symfony\Component\Translation\TranslatorBagInterface')) {
|
||||
if (!$r = $container->getReflectionClass($class)) {
|
||||
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $translatorAlias));
|
||||
}
|
||||
if ($r->isSubclassOf(TranslatorInterface::class) && $r->isSubclassOf(TranslatorBagInterface::class)) {
|
||||
$container->getDefinition('translator.logging')->setDecoratedService('translator');
|
||||
$container->getDefinition('translation.warmer')->replaceArgument(0, new Reference('translator.logging.inner'));
|
||||
}
|
||||
|
@ -54,6 +54,11 @@ class LoggingTranslatorPassTest extends \PHPUnit_Framework_TestCase
|
||||
->method('getParameterBag')
|
||||
->will($this->returnValue($parameterBag));
|
||||
|
||||
$container->expects($this->once())
|
||||
->method('getReflectionClass')
|
||||
->with('Symfony\Bundle\FrameworkBundle\Translation\Translator')
|
||||
->will($this->returnValue(new \ReflectionClass('Symfony\Bundle\FrameworkBundle\Translation\Translator')));
|
||||
|
||||
$pass = new LoggingTranslatorPass();
|
||||
$pass->process($container);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
"symfony/dependency-injection": "~3.3",
|
||||
"symfony/config": "~3.3",
|
||||
"symfony/event-dispatcher": "~3.3",
|
||||
"symfony/http-foundation": "~3.1",
|
||||
"symfony/http-foundation": "~3.3",
|
||||
"symfony/http-kernel": "~3.3",
|
||||
"symfony/polyfill-mbstring": "~1.0",
|
||||
"symfony/filesystem": "~2.8|~3.0",
|
||||
|
@ -1,6 +1,13 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
3.3.0
|
||||
-----
|
||||
|
||||
* added `ReflectionClassResource` class
|
||||
* added second `$exists` constructor argument to `ClassExistenceResource`
|
||||
* made `ClassExistenceResource` work with interfaces and traits
|
||||
|
||||
3.0.0
|
||||
-----
|
||||
|
||||
|
@ -21,16 +21,27 @@ namespace Symfony\Component\Config\Resource;
|
||||
*/
|
||||
class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializable
|
||||
{
|
||||
const EXISTS_OK = 1;
|
||||
const EXISTS_KO = 0;
|
||||
const EXISTS_KO_WITH_THROWING_AUTOLOADER = -1;
|
||||
|
||||
private $resource;
|
||||
private $exists;
|
||||
private $existsStatus;
|
||||
|
||||
private static $checkingLevel = 0;
|
||||
private static $throwingAutoloader;
|
||||
private static $existsCache = array();
|
||||
|
||||
/**
|
||||
* @param string $resource The fully-qualified class name
|
||||
* @param int|null $existsStatus One of the self::EXISTS_* const if the existency check has already been done
|
||||
*/
|
||||
public function __construct($resource)
|
||||
public function __construct($resource, $existsStatus = null)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
$this->exists = class_exists($resource);
|
||||
if (null !== $existsStatus) {
|
||||
$this->existsStatus = (int) $existsStatus;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,7 +65,35 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
||||
*/
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
return class_exists($this->resource) === $this->exists;
|
||||
if (null !== $exists = &self::$existsCache[$this->resource]) {
|
||||
$exists = $exists || class_exists($this->resource, false) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
|
||||
} elseif (self::EXISTS_KO_WITH_THROWING_AUTOLOADER === $this->existsStatus) {
|
||||
if (null === self::$throwingAutoloader) {
|
||||
$signalingException = new \ReflectionException();
|
||||
self::$throwingAutoloader = function () use ($signalingException) { throw $signalingException; };
|
||||
}
|
||||
if (!self::$checkingLevel++) {
|
||||
spl_autoload_register(self::$throwingAutoloader);
|
||||
}
|
||||
|
||||
try {
|
||||
$exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
|
||||
} catch (\ReflectionException $e) {
|
||||
$exists = false;
|
||||
} finally {
|
||||
if (!--self::$checkingLevel) {
|
||||
spl_autoload_unregister(self::$throwingAutoloader);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
|
||||
}
|
||||
|
||||
if (null === $this->existsStatus) {
|
||||
$this->existsStatus = $exists ? self::EXISTS_OK : self::EXISTS_KO;
|
||||
}
|
||||
|
||||
return self::EXISTS_OK === $this->existsStatus xor !$exists;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,7 +101,11 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
return serialize(array($this->resource, $this->exists));
|
||||
if (null === $this->existsStatus) {
|
||||
$this->isFresh(0);
|
||||
}
|
||||
|
||||
return serialize(array($this->resource, $this->existsStatus));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,6 +113,6 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
list($this->resource, $this->exists) = unserialize($serialized);
|
||||
list($this->resource, $this->existsStatus) = unserialize($serialized);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Config\Resource;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ReflectionClassResource implements SelfCheckingResourceInterface, \Serializable
|
||||
{
|
||||
private $files = array();
|
||||
private $className;
|
||||
private $classReflector;
|
||||
private $hash;
|
||||
|
||||
public function __construct(\ReflectionClass $classReflector)
|
||||
{
|
||||
$this->className = $classReflector->name;
|
||||
$this->classReflector = $classReflector;
|
||||
}
|
||||
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
if (null === $this->hash) {
|
||||
$this->hash = $this->computeHash();
|
||||
$this->loadFiles($this->classReflector);
|
||||
}
|
||||
|
||||
foreach ($this->files as $file => $v) {
|
||||
if (!file_exists($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (@filemtime($file) > $timestamp) {
|
||||
return $this->hash === $this->computeHash();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return 'reflection.'.$this->className;
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
{
|
||||
if (null === $this->hash) {
|
||||
$this->hash = $this->computeHash();
|
||||
$this->loadFiles($this->classReflector);
|
||||
}
|
||||
|
||||
return serialize(array($this->files, $this->className, $this->hash));
|
||||
}
|
||||
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
list($this->files, $this->className, $this->hash) = unserialize($serialized);
|
||||
}
|
||||
|
||||
private function loadFiles(\ReflectionClass $class)
|
||||
{
|
||||
foreach ($class->getInterfaces() as $v) {
|
||||
$this->loadFiles($v);
|
||||
}
|
||||
do {
|
||||
$file = $class->getFileName();
|
||||
if (false !== $file && file_exists($file)) {
|
||||
$this->files[$file] = null;
|
||||
}
|
||||
foreach ($class->getTraits() as $v) {
|
||||
$this->loadFiles($v);
|
||||
}
|
||||
} while ($class = $class->getParentClass());
|
||||
}
|
||||
|
||||
private function computeHash()
|
||||
{
|
||||
if (null === $this->classReflector) {
|
||||
try {
|
||||
$this->classReflector = new \ReflectionClass($this->className);
|
||||
} catch (\ReflectionException $e) {
|
||||
// the class does not exist anymore
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$hash = hash_init('md5');
|
||||
|
||||
foreach ($this->generateSignature($this->classReflector) as $info) {
|
||||
hash_update($hash, $info);
|
||||
}
|
||||
|
||||
return hash_final($hash);
|
||||
}
|
||||
|
||||
private function generateSignature(\ReflectionClass $class)
|
||||
{
|
||||
yield $class->getDocComment().$class->getModifiers();
|
||||
|
||||
if ($class->isTrait()) {
|
||||
yield print_r(class_uses($class->name), true);
|
||||
} else {
|
||||
yield print_r(class_parents($class->name), true);
|
||||
yield print_r(class_implements($class->name), true);
|
||||
yield print_r($class->getConstants(), true);
|
||||
}
|
||||
|
||||
if (!$class->isInterface()) {
|
||||
$defaults = $class->getDefaultProperties();
|
||||
|
||||
foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED) as $p) {
|
||||
yield $p->getDocComment().$p;
|
||||
yield print_r($defaults[$p->name], true);
|
||||
}
|
||||
}
|
||||
|
||||
if (defined('HHVM_VERSION')) {
|
||||
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) {
|
||||
// workaround HHVM bug with variadics, see https://github.com/facebook/hhvm/issues/5762
|
||||
yield preg_replace('/^ @@.*/m', '', new ReflectionMethodHhvmWrapper($m->class, $m->name));
|
||||
}
|
||||
} else {
|
||||
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) {
|
||||
yield preg_replace('/^ @@.*/m', '', $m);
|
||||
|
||||
$defaults = array();
|
||||
foreach ($m->getParameters() as $p) {
|
||||
$defaults[$p->name] = $p->isDefaultValueAvailable() ? $p->getDefaultValue() : null;
|
||||
}
|
||||
yield print_r($defaults, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class ReflectionMethodHhvmWrapper extends \ReflectionMethod
|
||||
{
|
||||
public function getParameters()
|
||||
{
|
||||
$params = array();
|
||||
|
||||
foreach (parent::getParameters() as $i => $p) {
|
||||
$params[] = new ReflectionParameterHhvmWrapper(array($this->class, $this->name), $i);
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class ReflectionParameterHhvmWrapper extends \ReflectionParameter
|
||||
{
|
||||
public function getDefaultValue()
|
||||
{
|
||||
return array($this->isVariadic(), $this->isDefaultValueAvailable() ? parent::getDefaultValue() : null);
|
||||
}
|
||||
}
|
@ -51,4 +51,24 @@ EOF
|
||||
|
||||
$this->assertTrue($res->isFresh(time()));
|
||||
}
|
||||
|
||||
public function testExistsKo()
|
||||
{
|
||||
spl_autoload_register($autoloader = function ($class) use (&$loadedClass) { $loadedClass = $class; });
|
||||
|
||||
try {
|
||||
$res = new ClassExistenceResource('MissingFooClass');
|
||||
$this->assertTrue($res->isFresh(0));
|
||||
|
||||
$this->assertSame('MissingFooClass', $loadedClass);
|
||||
|
||||
$loadedClass = 123;
|
||||
|
||||
$res = new ClassExistenceResource('MissingFooClass', ClassExistenceResource::EXISTS_KO);
|
||||
|
||||
$this->assertSame(123, $loadedClass);
|
||||
} finally {
|
||||
spl_autoload_unregister($autoloader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Config\Tests\Resource;
|
||||
|
||||
use Symfony\Component\Config\Resource\ReflectionClassResource;
|
||||
|
||||
class ReflectionClassResourceTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testToString()
|
||||
{
|
||||
$res = new ReflectionClassResource(new \ReflectionClass('ErrorException'));
|
||||
|
||||
$this->assertSame('reflection.ErrorException', (string) $res);
|
||||
}
|
||||
|
||||
public function testSerializeUnserialize()
|
||||
{
|
||||
$res = new ReflectionClassResource(new \ReflectionClass(DummyInterface::class));
|
||||
$ser = unserialize(serialize($res));
|
||||
|
||||
$this->assertTrue($res->isFresh(0));
|
||||
$this->assertTrue($ser->isFresh(0));
|
||||
|
||||
$this->assertSame((string) $res, (string) $ser);
|
||||
}
|
||||
|
||||
public function testIsFresh()
|
||||
{
|
||||
$res = new ReflectionClassResource(new \ReflectionClass(__CLASS__));
|
||||
$mtime = filemtime(__FILE__);
|
||||
|
||||
$this->assertTrue($res->isFresh($mtime), '->isFresh() returns true if the resource has not changed in same second');
|
||||
$this->assertTrue($res->isFresh($mtime + 10), '->isFresh() returns true if the resource has not changed');
|
||||
$this->assertTrue($res->isFresh($mtime - 86400), '->isFresh() returns true if the resource has not changed');
|
||||
}
|
||||
|
||||
public function testIsFreshForDeletedResources()
|
||||
{
|
||||
$now = time();
|
||||
$tmp = sys_get_temp_dir().'/tmp.php';
|
||||
file_put_contents($tmp, '<?php class ReflectionClassResourceTestClass {}');
|
||||
require $tmp;
|
||||
|
||||
$res = new ReflectionClassResource(new \ReflectionClass('ReflectionClassResourceTestClass'));
|
||||
$this->assertTrue($res->isFresh($now));
|
||||
|
||||
unlink($tmp);
|
||||
$this->assertFalse($res->isFresh($now), '->isFresh() returns false if the resource does not exist');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideHashedSignature
|
||||
*/
|
||||
public function testHashedSignature($changeExpected, $changedLine, $changedCode)
|
||||
{
|
||||
$code = <<<'EOPHP'
|
||||
/* 0*/
|
||||
/* 1*/ class %s extends ErrorException
|
||||
/* 2*/ {
|
||||
/* 3*/ const FOO = 123;
|
||||
/* 4*/
|
||||
/* 5*/ public $pub = array();
|
||||
/* 6*/
|
||||
/* 7*/ protected $prot;
|
||||
/* 8*/
|
||||
/* 9*/ private $priv;
|
||||
/*10*/
|
||||
/*11*/ public function pub($arg = null) {}
|
||||
/*12*/
|
||||
/*13*/ protected function prot($a = array()) {}
|
||||
/*14*/
|
||||
/*15*/ private function priv() {}
|
||||
/*16*/ }
|
||||
EOPHP;
|
||||
|
||||
static $expectedSignature, $generateSignature;
|
||||
|
||||
if (null === $expectedSignature) {
|
||||
eval(sprintf($code, $class = 'Foo'.str_replace('.', '_', uniqid('', true))));
|
||||
$r = new \ReflectionClass(ReflectionClassResource::class);
|
||||
$generateSignature = $r->getMethod('generateSignature')->getClosure($r->newInstanceWithoutConstructor());
|
||||
$expectedSignature = implode("\n", iterator_to_array($generateSignature(new \ReflectionClass($class))));
|
||||
}
|
||||
|
||||
$code = explode("\n", $code);
|
||||
$code[$changedLine] = $changedCode;
|
||||
eval(sprintf(implode("\n", $code), $class = 'Foo'.str_replace('.', '_', uniqid('', true))));
|
||||
$signature = implode("\n", iterator_to_array($generateSignature(new \ReflectionClass($class))));
|
||||
|
||||
if ($changeExpected) {
|
||||
$this->assertTrue($expectedSignature !== $signature);
|
||||
} else {
|
||||
$this->assertSame($expectedSignature, $signature);
|
||||
}
|
||||
}
|
||||
|
||||
public function provideHashedSignature()
|
||||
{
|
||||
yield array(0, 0, "// line change\n\n");
|
||||
yield array(1, 0, '/** class docblock */');
|
||||
yield array(1, 1, 'abstract class %s');
|
||||
yield array(1, 1, 'final class %s');
|
||||
yield array(1, 1, 'class %s extends Exception');
|
||||
yield array(1, 1, 'class %s implements '.DummyInterface::class);
|
||||
yield array(1, 3, 'const FOO = 456;');
|
||||
yield array(1, 3, 'const BAR = 123;');
|
||||
yield array(1, 4, '/** pub docblock */');
|
||||
yield array(1, 5, 'protected $pub = array();');
|
||||
yield array(1, 5, 'public $pub = array(123);');
|
||||
yield array(1, 6, '/** prot docblock */');
|
||||
yield array(1, 7, 'private $prot;');
|
||||
yield array(0, 8, '/** priv docblock */');
|
||||
yield array(0, 9, 'private $priv = 123;');
|
||||
yield array(1, 10, '/** pub docblock */');
|
||||
if (PHP_VERSION_ID >= 50600) {
|
||||
yield array(1, 11, 'public function pub(...$arg) {}');
|
||||
}
|
||||
if (PHP_VERSION_ID >= 70000) {
|
||||
yield array(1, 11, 'public function pub($arg = null): Foo {}');
|
||||
}
|
||||
yield array(0, 11, "public function pub(\$arg = null) {\nreturn 123;\n}");
|
||||
yield array(1, 12, '/** prot docblock */');
|
||||
yield array(1, 13, 'protected function prot($a = array(123)) {}');
|
||||
yield array(0, 14, '/** priv docblock */');
|
||||
yield array(0, 15, '');
|
||||
}
|
||||
}
|
||||
|
||||
interface DummyInterface
|
||||
{
|
||||
}
|
@ -11,8 +11,10 @@
|
||||
|
||||
namespace Symfony\Component\Console\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Registers console commands.
|
||||
@ -34,9 +36,14 @@ class AddConsoleCommandPass implements CompilerPassInterface
|
||||
}
|
||||
|
||||
$class = $container->getParameterBag()->resolveValue($definition->getClass());
|
||||
if (!is_subclass_of($class, 'Symfony\\Component\\Console\\Command\\Command')) {
|
||||
throw new \InvalidArgumentException(sprintf('The service "%s" tagged "console.command" must be a subclass of "Symfony\\Component\\Console\\Command\\Command".', $id));
|
||||
|
||||
if (!$r = $container->getReflectionClass($class)) {
|
||||
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
|
||||
}
|
||||
if (!$r->isSubclassOf(Command::class)) {
|
||||
throw new InvalidArgumentException(sprintf('The service "%s" tagged "console.command" must be a subclass of "%s".', $id, Command::class));
|
||||
}
|
||||
|
||||
$container->setAlias($serviceId = 'console.command.'.strtolower(str_replace('\\', '_', $class)), $id);
|
||||
$serviceIds[] = $definition->isPublic() ? $id : $serviceId;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
"require-dev": {
|
||||
"symfony/http-kernel": "~2.8|~3.0",
|
||||
"symfony/event-dispatcher": "~2.8|~3.0",
|
||||
"symfony/dependency-injection": "~2.8|~3.0",
|
||||
"symfony/dependency-injection": "~3.3",
|
||||
"symfony/filesystem": "~2.8|~3.0",
|
||||
"symfony/process": "~2.8|~3.0",
|
||||
"psr/log": "~1.0"
|
||||
@ -34,6 +34,9 @@
|
||||
"symfony/process": "",
|
||||
"psr/log": "For using the console logger"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/dependency-injection": "<3.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Symfony\\Component\\Console\\": "" },
|
||||
"exclude-from-classmap": [
|
||||
|
@ -4,6 +4,8 @@ CHANGELOG
|
||||
3.3.0
|
||||
-----
|
||||
|
||||
* added `ContainerBuilder::getReflectionClass()` for retrieving and tracking reflection class info
|
||||
* deprecated `ContainerBuilder::getClassResource()`, use `ContainerBuilder::getReflectionClass()` or `ContainerBuilder::addObjectResource()` instead
|
||||
* added `ContainerBuilder::fileExists()` for checking and tracking file or directory existence
|
||||
* deprecated autowiring-types, use aliases instead
|
||||
* [EXPERIMENTAL] added support for getter-injection
|
||||
|
@ -24,7 +24,6 @@ use Symfony\Component\DependencyInjection\Reference;
|
||||
*/
|
||||
class AutowirePass extends AbstractRecursivePass
|
||||
{
|
||||
private $reflectionClasses = array();
|
||||
private $definedTypes = array();
|
||||
private $types;
|
||||
private $ambiguousServiceTypes = array();
|
||||
@ -34,16 +33,10 @@ class AutowirePass extends AbstractRecursivePass
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$throwingAutoloader = function ($class) { throw new \ReflectionException(sprintf('Class %s does not exist', $class)); };
|
||||
spl_autoload_register($throwingAutoloader);
|
||||
|
||||
try {
|
||||
parent::process($container);
|
||||
} finally {
|
||||
spl_autoload_unregister($throwingAutoloader);
|
||||
|
||||
// Free memory and remove circular reference to container
|
||||
$this->reflectionClasses = array();
|
||||
$this->definedTypes = array();
|
||||
$this->types = null;
|
||||
$this->ambiguousServiceTypes = array();
|
||||
@ -56,9 +49,13 @@ class AutowirePass extends AbstractRecursivePass
|
||||
* @param \ReflectionClass $reflectionClass
|
||||
*
|
||||
* @return AutowireServiceResource
|
||||
*
|
||||
* @deprecated since version 3.3, to be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead.
|
||||
*/
|
||||
public static function createResourceForClass(\ReflectionClass $reflectionClass)
|
||||
{
|
||||
@trigger_error('The '.__METHOD__.'() method is deprecated since version 3.3 and will be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead.', E_USER_DEPRECATED);
|
||||
|
||||
$metadata = array();
|
||||
|
||||
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
|
||||
@ -79,14 +76,10 @@ class AutowirePass extends AbstractRecursivePass
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
if (!$reflectionClass = $this->getReflectionClass($isRoot ? $this->currentId : null, $value)) {
|
||||
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass())) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
if ($this->container->isTrackingResources()) {
|
||||
$this->container->addResource(static::createResourceForClass($reflectionClass));
|
||||
}
|
||||
|
||||
$autowiredMethods = $this->getMethodsToAutowire($reflectionClass, $autowiredMethods);
|
||||
$methodCalls = $value->getMethodCalls();
|
||||
|
||||
@ -257,20 +250,9 @@ class AutowirePass extends AbstractRecursivePass
|
||||
}
|
||||
|
||||
if (isset($this->types[$typeName])) {
|
||||
$arguments[$index] = new Reference($this->types[$typeName]);
|
||||
$value = new Reference($this->types[$typeName]);
|
||||
$didAutowire = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$typeHint = new \ReflectionClass($typeName);
|
||||
} catch (\ReflectionException $e) {
|
||||
// Typehint against a non-existing class
|
||||
$typeHint = false;
|
||||
}
|
||||
|
||||
if ($typeHint) {
|
||||
} elseif ($typeHint = $this->container->getReflectionClass($typeName, true)) {
|
||||
try {
|
||||
$value = $this->createAutowiredDefinition($typeHint);
|
||||
$didAutowire = true;
|
||||
@ -289,9 +271,11 @@ class AutowirePass extends AbstractRecursivePass
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Typehint against a non-existing class
|
||||
|
||||
if (!$parameter->isDefaultValueAvailable()) {
|
||||
if ($mustAutowire) {
|
||||
throw new RuntimeException(sprintf('Cannot autowire argument $%s of method %s::%s() for service "%s": %s.', $parameter->name, $reflectionMethod->class, $reflectionMethod->name, $this->currentId, $e->getMessage()), 0, $e);
|
||||
throw new RuntimeException(sprintf('Cannot autowire argument $%s of method %s::%s() for service "%s": Class %s does not exist.', $parameter->name, $reflectionMethod->class, $reflectionMethod->name, $this->currentId, $typeName));
|
||||
}
|
||||
|
||||
return array();
|
||||
@ -344,7 +328,7 @@ class AutowirePass extends AbstractRecursivePass
|
||||
$this->types[$type] = $id;
|
||||
}
|
||||
|
||||
if (!$reflectionClass = $this->getReflectionClass($id, $definition)) {
|
||||
if (!$reflectionClass = $this->container->getReflectionClass($definition->getClass(), true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -437,40 +421,6 @@ class AutowirePass extends AbstractRecursivePass
|
||||
return new Reference($argumentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the reflection class associated with the given service.
|
||||
*
|
||||
* @param string|null $id
|
||||
* @param Definition $definition
|
||||
*
|
||||
* @return \ReflectionClass|false
|
||||
*/
|
||||
private function getReflectionClass($id, Definition $definition)
|
||||
{
|
||||
if (null !== $id && isset($this->reflectionClasses[$id])) {
|
||||
return $this->reflectionClasses[$id];
|
||||
}
|
||||
|
||||
// Cannot use reflection if the class isn't set
|
||||
if (!$class = $definition->getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$class = $this->container->getParameterBag()->resolveValue($class);
|
||||
|
||||
try {
|
||||
$reflector = new \ReflectionClass($class);
|
||||
} catch (\ReflectionException $e) {
|
||||
$reflector = false;
|
||||
}
|
||||
|
||||
if (null !== $id) {
|
||||
$this->reflectionClasses[$id] = $reflector;
|
||||
}
|
||||
|
||||
return $reflector;
|
||||
}
|
||||
|
||||
private function addServiceToAmbiguousType($id, $type)
|
||||
{
|
||||
// keep an array of all services matching this type
|
||||
@ -482,6 +432,9 @@ class AutowirePass extends AbstractRecursivePass
|
||||
$this->ambiguousServiceTypes[$type][] = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since version 3.3, to be removed in 4.0.
|
||||
*/
|
||||
private static function getResourceMetadataForMethod(\ReflectionMethod $method)
|
||||
{
|
||||
$methodArgumentsMetadata = array();
|
||||
|
@ -82,8 +82,11 @@ class FactoryReturnTypePass implements CompilerPassInterface
|
||||
$class = $factory[0];
|
||||
}
|
||||
|
||||
if (!$m = $container->getReflectionClass($class)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
$m = new \ReflectionMethod($class, $factory[1]);
|
||||
$m = $m->getMethod($factory[1]);
|
||||
} catch (\ReflectionException $e) {
|
||||
return;
|
||||
}
|
||||
|
@ -11,9 +11,14 @@
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Config;
|
||||
|
||||
@trigger_error('The '.__NAMESPACE__.'\AutowireServiceResource class is deprecated since version 3.3 and will be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead.', E_USER_DEPRECATED);
|
||||
|
||||
use Symfony\Component\Config\Resource\SelfCheckingResourceInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
|
||||
|
||||
/**
|
||||
* @deprecated since version 3.3, to be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead.
|
||||
*/
|
||||
class AutowireServiceResource implements SelfCheckingResourceInterface, \Serializable
|
||||
{
|
||||
private $class;
|
||||
|
@ -25,9 +25,11 @@ use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceExce
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
|
||||
use Symfony\Component\Config\Resource\ClassExistenceResource;
|
||||
use Symfony\Component\Config\Resource\DirectoryResource;
|
||||
use Symfony\Component\Config\Resource\FileExistenceResource;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Config\Resource\ReflectionClassResource;
|
||||
use Symfony\Component\Config\Resource\ResourceInterface;
|
||||
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
|
||||
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
|
||||
@ -246,14 +248,39 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
/**
|
||||
* Adds the object class hierarchy as resources.
|
||||
*
|
||||
* @param object $object An object instance
|
||||
* @param object|string $object An object instance or class name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addObjectResource($object)
|
||||
{
|
||||
if ($this->trackResources) {
|
||||
$this->addClassResource(new \ReflectionClass($object));
|
||||
if (is_object($object)) {
|
||||
$object = get_class($object);
|
||||
}
|
||||
if (!isset($this->classReflectors[$object])) {
|
||||
$this->classReflectors[$object] = new \ReflectionClass($object);
|
||||
}
|
||||
$class = $this->classReflectors[$object];
|
||||
|
||||
foreach ($class->getInterfaceNames() as $name) {
|
||||
if (null === $interface = &$this->classReflectors[$name]) {
|
||||
$interface = new \ReflectionClass($name);
|
||||
}
|
||||
$file = $interface->getFileName();
|
||||
if (false !== $file && file_exists($file)) {
|
||||
$this->addResource(new FileResource($file));
|
||||
}
|
||||
}
|
||||
do {
|
||||
$file = $class->getFileName();
|
||||
if (false !== $file && file_exists($file)) {
|
||||
$this->addResource(new FileResource($file));
|
||||
}
|
||||
foreach ($class->getTraitNames() as $name) {
|
||||
$this->addObjectResource($name);
|
||||
}
|
||||
} while ($class = $class->getParentClass());
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -265,20 +292,93 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
* @param \ReflectionClass $class
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @deprecated since version 3.3, to be removed in 4.0. Use addObjectResource() or getReflectionClass() instead.
|
||||
*/
|
||||
public function addClassResource(\ReflectionClass $class)
|
||||
{
|
||||
@trigger_error('The '.__METHOD__.'() method is deprecated since version 3.3 and will be removed in 4.0. Use the addObjectResource() or the getReflectionClass() method instead.', E_USER_DEPRECATED);
|
||||
|
||||
return $this->addObjectResource($class->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the requested reflection class and registers it for resource tracking.
|
||||
*
|
||||
* @param string $class
|
||||
* @param bool $koWithThrowingAutoloader Whether autoload should be protected against bad parents or not
|
||||
*
|
||||
* @return \ReflectionClass|null
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function getReflectionClass($class, $koWithThrowingAutoloader = false)
|
||||
{
|
||||
if (!$class = $this->getParameterBag()->resolveValue($class)) {
|
||||
return;
|
||||
}
|
||||
$resource = null;
|
||||
|
||||
try {
|
||||
if (isset($this->classReflectors[$class])) {
|
||||
$classReflector = $this->classReflectors[$class];
|
||||
} elseif ($koWithThrowingAutoloader) {
|
||||
$resource = new ClassExistenceResource($class, ClassExistenceResource::EXISTS_KO_WITH_THROWING_AUTOLOADER);
|
||||
|
||||
$classReflector = $resource->isFresh(0) ? false : new \ReflectionClass($class);
|
||||
} else {
|
||||
$classReflector = new \ReflectionClass($class);
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
$classReflector = false;
|
||||
}
|
||||
|
||||
if ($this->trackResources) {
|
||||
if (!$classReflector) {
|
||||
$this->addResource($resource ?: new ClassExistenceResource($class, ClassExistenceResource::EXISTS_KO));
|
||||
} elseif (!$classReflector->isInternal()) {
|
||||
$this->addResource(new ReflectionClassResource($classReflector));
|
||||
}
|
||||
$this->classReflectors[$class] = $classReflector;
|
||||
}
|
||||
|
||||
return $classReflector ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the requested file or directory exists and registers the result for resource tracking.
|
||||
*
|
||||
* @param string $path The file or directory path for which to check the existence
|
||||
* @param bool|string $trackContents Whether to track contents of the given resource. If a string is passed,
|
||||
* it will be used as pattern for tracking contents of the requested directory
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function fileExists($path, $trackContents = true)
|
||||
{
|
||||
$exists = file_exists($path);
|
||||
|
||||
if (!$this->trackResources) {
|
||||
return $this;
|
||||
return $exists;
|
||||
}
|
||||
|
||||
do {
|
||||
if (is_file($class->getFileName())) {
|
||||
$this->addResource(new FileResource($class->getFileName()));
|
||||
}
|
||||
} while ($class = $class->getParentClass());
|
||||
if (!$exists) {
|
||||
$this->addResource(new FileExistenceResource($path));
|
||||
|
||||
return $this;
|
||||
return $exists;
|
||||
}
|
||||
|
||||
if ($trackContents) {
|
||||
if (is_file($path)) {
|
||||
$this->addResource(new FileResource($path));
|
||||
} else {
|
||||
$this->addResource(new DirectoryResource($path, is_string($trackContents) ? $trackContents : null));
|
||||
}
|
||||
}
|
||||
|
||||
return $exists;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -574,8 +674,8 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
if (!$definition->isPublic()) {
|
||||
$this->privates[$id] = true;
|
||||
}
|
||||
if ($this->trackResources && $definition->isLazy() && ($class = $definition->getClass()) && class_exists($class)) {
|
||||
$this->addClassResource(new \ReflectionClass($class));
|
||||
if ($this->trackResources && $definition->isLazy()) {
|
||||
$this->getReflectionClass($definition->getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1323,42 +1423,6 @@ EOF;
|
||||
return $services;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the requested file or directory exists and registers the result for resource tracking.
|
||||
*
|
||||
* @param string $path The file or directory path for which to check the existence
|
||||
* @param bool|string $trackContents Whether to track contents of the given resource. If a string is passed,
|
||||
* it will be used as pattern for tracking contents of the requested directory
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function fileExists($path, $trackContents = true)
|
||||
{
|
||||
$exists = file_exists($path);
|
||||
|
||||
if (!$this->trackResources) {
|
||||
return $exists;
|
||||
}
|
||||
|
||||
if (!$exists) {
|
||||
$this->addResource(new FileExistenceResource($path));
|
||||
|
||||
return $exists;
|
||||
}
|
||||
|
||||
if ($trackContents) {
|
||||
if (is_file($path)) {
|
||||
$this->addResource(new FileResource($path));
|
||||
} else {
|
||||
$this->addResource(new DirectoryResource($path, is_string($trackContents) ? $trackContents : null));
|
||||
}
|
||||
}
|
||||
|
||||
return $exists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the currently set proxy instantiator or instantiates one.
|
||||
*
|
||||
|
@ -64,7 +64,6 @@ class PhpDumper extends Dumper
|
||||
private $docStar;
|
||||
private $serviceIdToMethodNameMap;
|
||||
private $usedMethodNames;
|
||||
private $classResources = array();
|
||||
private $baseClass;
|
||||
private $getterProxies = array();
|
||||
private $useInstantiateProxy;
|
||||
@ -127,7 +126,6 @@ class PhpDumper extends Dumper
|
||||
$this->salt = substr(strtr(base64_encode(md5($options['namespace'].'\\'.$options['class'].'+'.$options['base_class'], true)), '+/', '__'), 0, -2);
|
||||
$this->getterProxies = array();
|
||||
$this->useInstantiateProxy = false;
|
||||
$this->classResources = array();
|
||||
$this->initializeMethodNamesMap($options['base_class']);
|
||||
$this->baseClass = $options['base_class'];
|
||||
|
||||
@ -177,16 +175,6 @@ class PhpDumper extends Dumper
|
||||
$this->targetDirRegex = null;
|
||||
$this->getterProxies = array();
|
||||
|
||||
foreach ($this->classResources as $r) {
|
||||
$this->container->addClassResource($r);
|
||||
}
|
||||
$this->classResources = array();
|
||||
|
||||
foreach ($this->classResources as $r) {
|
||||
$this->container->addClassResource($r);
|
||||
}
|
||||
$this->classResources = array();
|
||||
|
||||
$unusedEnvs = array();
|
||||
foreach ($this->container->getEnvCounters() as $env => $use) {
|
||||
if (!$use) {
|
||||
@ -508,10 +496,7 @@ class PhpDumper extends Dumper
|
||||
|
||||
private function addServiceOverriddenGetters($id, Definition $definition)
|
||||
{
|
||||
if (!isset($this->classResources[$class = $definition->getClass()])) {
|
||||
$this->classResources[$class] = new \ReflectionClass($class);
|
||||
}
|
||||
$class = $this->classResources[$class];
|
||||
$class = $this->container->getReflectionClass($definition->getClass());
|
||||
if ($class->isFinal()) {
|
||||
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": class "%s" cannot be marked as final.', $id, $class->name));
|
||||
}
|
||||
@ -864,7 +849,7 @@ EOF;
|
||||
$getterProxy = sprintf("%s implements \\%s\n{\n private \$container%s;\n private \$getters%3\$s;\n%s}\n", $class, GetterProxyInterface::class, $this->salt, $this->addServiceOverriddenGetters($id, $definition));
|
||||
$class = 'SymfonyProxy_'.md5($getterProxy);
|
||||
$this->getterProxies[$class] = $getterProxy;
|
||||
$constructor = $this->classResources[$definition->getClass()]->getConstructor();
|
||||
$constructor = $this->container->getReflectionClass($definition->getClass())->getConstructor();
|
||||
|
||||
if ($constructor && $constructor->isFinal()) {
|
||||
$this->useInstantiateProxy = true;
|
||||
@ -1607,10 +1592,7 @@ EOF;
|
||||
if (!method_exists($class, $method)) {
|
||||
throw new InvalidArgumentException(sprintf('Cannot create closure-proxy for service "%s": method "%s::%s" does not exist.', $reference, $class, $method));
|
||||
}
|
||||
if (!isset($this->classResources[$class])) {
|
||||
$this->classResources[$class] = new \ReflectionClass($class);
|
||||
}
|
||||
$r = $this->classResources[$class]->getMethod($method);
|
||||
$r = $this->container->getReflectionClass($class)->getMethod($method);
|
||||
if (!$r->isPublic()) {
|
||||
throw new InvalidArgumentException(sprintf('Cannot create closure-proxy for service "%s": method "%s::%s" must be public.', $reference, $class, $method));
|
||||
}
|
||||
@ -1731,12 +1713,10 @@ EOF;
|
||||
$this->serviceIdToMethodNameMap = array();
|
||||
$this->usedMethodNames = array();
|
||||
|
||||
try {
|
||||
$reflectionClass = new \ReflectionClass($class);
|
||||
if ($reflectionClass = $this->container->getReflectionClass($class)) {
|
||||
foreach ($reflectionClass->getMethods() as $method) {
|
||||
$this->usedMethodNames[strtolower($method->getName())] = true;
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@ namespace Symfony\Component\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Config\Definition\Processor;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
@ -78,17 +77,13 @@ abstract class Extension implements ExtensionInterface, ConfigurationExtensionIn
|
||||
*/
|
||||
public function getConfiguration(array $config, ContainerBuilder $container)
|
||||
{
|
||||
$reflected = new \ReflectionClass($this);
|
||||
$namespace = $reflected->getNamespaceName();
|
||||
$class = get_class($this);
|
||||
$class = substr_replace($class, '\Configuration', strrpos($class, '\\'));
|
||||
$class = $container->getReflectionClass($class);
|
||||
$constructor = $class ? $class->getConstructor() : null;
|
||||
|
||||
$class = $namespace.'\\Configuration';
|
||||
if (class_exists($class)) {
|
||||
$r = new \ReflectionClass($class);
|
||||
$container->addResource(new FileResource($r->getFileName()));
|
||||
|
||||
if (!method_exists($class, '__construct')) {
|
||||
return new $class();
|
||||
}
|
||||
if (!$constructor || !$constructor->getNumberOfRequiredParameters()) {
|
||||
return $class->newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -518,6 +518,7 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
/**
|
||||
* @dataProvider getCreateResourceTests
|
||||
* @group legacy
|
||||
*/
|
||||
public function testCreateResourceForClass($className, $isEqual)
|
||||
{
|
||||
|
@ -14,6 +14,9 @@ namespace Symfony\Component\DependencyInjection\Tests\Config;
|
||||
use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
|
||||
use Symfony\Component\DependencyInjection\Config\AutowireServiceResource;
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
class AutowireServiceResourceTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
|
@ -622,6 +622,9 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame(realpath(__DIR__.'/Fixtures/includes/classes.php'), realpath($resource->getResource()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testAddClassResource()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
@ -645,6 +648,32 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame(realpath(__DIR__.'/Fixtures/includes/classes.php'), realpath($resource->getResource()));
|
||||
}
|
||||
|
||||
public function testGetReflectionClass()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->setResourceTracking(false);
|
||||
$r1 = $container->getReflectionClass('BarClass');
|
||||
|
||||
$this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking');
|
||||
|
||||
$container->setResourceTracking(true);
|
||||
$r2 = $container->getReflectionClass('BarClass');
|
||||
$r3 = $container->getReflectionClass('BarClass');
|
||||
|
||||
$this->assertNull($container->getReflectionClass('BarMissingClass'));
|
||||
|
||||
$this->assertEquals($r1, $r2);
|
||||
$this->assertSame($r2, $r3);
|
||||
|
||||
$resources = $container->getResources();
|
||||
|
||||
$this->assertCount(2, $resources, '2 resources were registered');
|
||||
|
||||
$this->assertSame('reflection.BarClass', (string) $resources[0]);
|
||||
$this->assertSame('BarMissingClass', (string) end($resources));
|
||||
}
|
||||
|
||||
public function testCompilesClassDefinitionsOfLazyServices()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
@ -656,11 +685,10 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$container->compile();
|
||||
|
||||
$classesPath = realpath(__DIR__.'/Fixtures/includes/classes.php');
|
||||
$matchingResources = array_filter(
|
||||
$container->getResources(),
|
||||
function (ResourceInterface $resource) use ($classesPath) {
|
||||
return $resource instanceof FileResource && $classesPath === realpath($resource->getResource());
|
||||
function (ResourceInterface $resource) {
|
||||
return 'reflection.BarClass' === (string) $resource;
|
||||
}
|
||||
);
|
||||
|
||||
@ -899,16 +927,13 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$container->compile();
|
||||
|
||||
$class = new \BazClass();
|
||||
$reflectionClass = new \ReflectionClass($class);
|
||||
|
||||
$r = new \ReflectionProperty($container, 'resources');
|
||||
$r->setAccessible(true);
|
||||
$resources = $r->getValue($container);
|
||||
|
||||
$classInList = false;
|
||||
foreach ($resources as $resource) {
|
||||
if ($resource->getResource() === $reflectionClass->getFileName()) {
|
||||
if ('reflection.BazClass' === (string) $resource) {
|
||||
$classInList = true;
|
||||
break;
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
|
||||
$dump = $dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Overriden_Getters'));
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services29.php', $dump);
|
||||
$res = $container->getResources();
|
||||
$this->assertSame(realpath(self::$fixturesPath.'/containers/container29.php'), array_pop($res)->getResource());
|
||||
$this->assertSame('reflection.Symfony\Component\DependencyInjection\Tests\Fixtures\Container29\Foo', (string) array_pop($res));
|
||||
|
||||
eval('?>'.$dump);
|
||||
|
||||
@ -529,7 +529,7 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services31.php', $dumper->dump());
|
||||
$res = $container->getResources();
|
||||
$this->assertSame(realpath(self::$fixturesPath.'/containers/container31.php'), array_pop($res)->getResource());
|
||||
$this->assertSame('reflection.Symfony\Component\DependencyInjection\Tests\Fixtures\Container31\Foo', (string) array_pop($res));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -543,7 +543,7 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services32.php', $dumper->dump());
|
||||
$res = $container->getResources();
|
||||
$this->assertSame(realpath(self::$fixturesPath.'/containers/container32.php'), array_pop($res)->getResource());
|
||||
$this->assertSame('reflection.Symfony\Component\DependencyInjection\Tests\Fixtures\Container32\Foo', (string) array_pop($res));
|
||||
}
|
||||
|
||||
public function testNormalizedId()
|
||||
|
@ -20,7 +20,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/yaml": "~3.2",
|
||||
"symfony/config": "~2.8|~3.0",
|
||||
"symfony/config": "~3.3",
|
||||
"symfony/expression-language": "~2.8|~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
@ -30,6 +30,7 @@
|
||||
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/config": "<3.3",
|
||||
"symfony/yaml": "<3.2"
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -103,6 +103,7 @@ class RegisterListenersPass implements CompilerPassInterface
|
||||
|
||||
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface));
|
||||
}
|
||||
$container->addObjectResource($class);
|
||||
|
||||
$r = new \ReflectionClass($class);
|
||||
$extractingDispatcher->addSubscriber($r->newInstanceWithoutConstructor());
|
||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
|
||||
|
||||
/**
|
||||
* Adds services tagged kernel.fragment_renderer as HTTP content rendering strategies.
|
||||
@ -53,14 +54,12 @@ class FragmentRendererPass implements CompilerPassInterface
|
||||
}
|
||||
|
||||
$class = $container->getParameterBag()->resolveValue($def->getClass());
|
||||
$interface = 'Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface';
|
||||
|
||||
if (!is_subclass_of($class, $interface)) {
|
||||
if (!class_exists($class, false)) {
|
||||
if (!$r = $container->getReflectionClass($class)) {
|
||||
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface));
|
||||
if (!$r->isSubclassOf(FragmentRendererInterface::class)) {
|
||||
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, FragmentRendererInterface::class));
|
||||
}
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
|
@ -73,7 +73,7 @@ class FragmentRendererPassTest extends \PHPUnit_Framework_TestCase
|
||||
->will($this->returnValue(true))
|
||||
;
|
||||
|
||||
$builder = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')->setMethods(array('hasDefinition', 'findTaggedServiceIds', 'getDefinition'))->getMock();
|
||||
$builder = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')->setMethods(array('hasDefinition', 'findTaggedServiceIds', 'getDefinition', 'getReflectionClass'))->getMock();
|
||||
$builder->expects($this->any())
|
||||
->method('hasDefinition')
|
||||
->will($this->returnValue(true));
|
||||
@ -87,6 +87,11 @@ class FragmentRendererPassTest extends \PHPUnit_Framework_TestCase
|
||||
->method('getDefinition')
|
||||
->will($this->onConsecutiveCalls($renderer, $definition));
|
||||
|
||||
$builder->expects($this->atLeastOnce())
|
||||
->method('getReflectionClass')
|
||||
->with('Symfony\Component\HttpKernel\Tests\DependencyInjection\RendererService')
|
||||
->will($this->returnValue(new \ReflectionClass('Symfony\Component\HttpKernel\Tests\DependencyInjection\RendererService')));
|
||||
|
||||
$pass = new FragmentRendererPass();
|
||||
$pass->process($builder);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
"symfony/config": "~2.8|~3.0",
|
||||
"symfony/console": "~2.8|~3.0",
|
||||
"symfony/css-selector": "~2.8|~3.0",
|
||||
"symfony/dependency-injection": "~2.8|~3.0",
|
||||
"symfony/dependency-injection": "~3.3",
|
||||
"symfony/dom-crawler": "~2.8|~3.0",
|
||||
"symfony/expression-language": "~2.8|~3.0",
|
||||
"symfony/finder": "~2.8|~3.0",
|
||||
@ -41,7 +41,8 @@
|
||||
"psr/cache": "~1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/config": "<2.8"
|
||||
"symfony/config": "<2.8",
|
||||
"symfony/dependency-injection": "<3.3"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/browser-kit": "",
|
||||
|
Reference in New Issue
Block a user