[Config][DI] Add ComposerResource to track runtime + vendors
This commit is contained in:
parent
a46e691ae1
commit
a960c761d1
@ -16,7 +16,6 @@ use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
/**
|
||||
* This abstract classes groups common code that Doctrine Object Manager extensions (ORM, MongoDB, CouchDB) need.
|
||||
@ -268,30 +267,28 @@ abstract class AbstractDoctrineExtension extends Extension
|
||||
*/
|
||||
protected function detectMetadataDriver($dir, ContainerBuilder $container)
|
||||
{
|
||||
// add the closest existing directory as a resource
|
||||
$configPath = $this->getMappingResourceConfigDirectory();
|
||||
$resource = $dir.'/'.$configPath;
|
||||
while (!is_dir($resource)) {
|
||||
$resource = dirname($resource);
|
||||
}
|
||||
|
||||
$container->addResource(new FileResource($resource));
|
||||
|
||||
$extension = $this->getMappingResourceExtension();
|
||||
if (($files = glob($dir.'/'.$configPath.'/*.'.$extension.'.xml')) && count($files)) {
|
||||
return 'xml';
|
||||
} elseif (($files = glob($dir.'/'.$configPath.'/*.'.$extension.'.yml')) && count($files)) {
|
||||
return 'yml';
|
||||
} elseif (($files = glob($dir.'/'.$configPath.'/*.'.$extension.'.php')) && count($files)) {
|
||||
return 'php';
|
||||
}
|
||||
|
||||
// add the directory itself as a resource
|
||||
$container->addResource(new FileResource($dir));
|
||||
if (glob($dir.'/'.$configPath.'/*.'.$extension.'.xml')) {
|
||||
$driver = 'xml';
|
||||
} elseif (glob($dir.'/'.$configPath.'/*.'.$extension.'.yml')) {
|
||||
$driver = 'yml';
|
||||
} elseif (glob($dir.'/'.$configPath.'/*.'.$extension.'.php')) {
|
||||
$driver = 'php';
|
||||
} else {
|
||||
// add the closest existing directory as a resource
|
||||
$resource = $dir.'/'.$configPath;
|
||||
while (!is_dir($resource)) {
|
||||
$resource = dirname($resource);
|
||||
}
|
||||
$container->fileExists($resource, false);
|
||||
|
||||
if (is_dir($dir.'/'.$this->getMappingObjectDefaultName())) {
|
||||
return 'annotation';
|
||||
return $container->fileExists($dir.'/'.$this->getMappingObjectDefaultName(), false) ? 'annotation' : null;
|
||||
}
|
||||
$container->fileExists($dir.'/'.$configPath, false);
|
||||
|
||||
return $driver;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,7 +23,6 @@ use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
@ -994,8 +993,7 @@ class FrameworkExtension extends Extension
|
||||
{
|
||||
if (interface_exists('Symfony\Component\Form\FormInterface')) {
|
||||
$reflClass = new \ReflectionClass('Symfony\Component\Form\FormInterface');
|
||||
$files['xml'][] = $file = dirname($reflClass->getFileName()).'/Resources/config/validation.xml';
|
||||
$container->addResource(new FileResource($file));
|
||||
$files['xml'][] = dirname($reflClass->getFileName()).'/Resources/config/validation.xml';
|
||||
}
|
||||
|
||||
foreach ($container->getParameter('kernel.bundles_metadata') as $bundle) {
|
||||
|
94
src/Symfony/Component/Config/Resource/ComposerResource.php
Normal file
94
src/Symfony/Component/Config/Resource/ComposerResource.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* ComposerResource tracks the PHP version and Composer dependencies.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ComposerResource implements SelfCheckingResourceInterface, \Serializable
|
||||
{
|
||||
private $versions;
|
||||
private $vendors;
|
||||
|
||||
private static $runtimeVersion;
|
||||
private static $runtimeVendors;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
self::refresh();
|
||||
$this->versions = self::$runtimeVersion;
|
||||
$this->vendors = self::$runtimeVendors;
|
||||
}
|
||||
|
||||
public function getVendors()
|
||||
{
|
||||
return array_keys($this->vendors);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return __CLASS__;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
self::refresh();
|
||||
|
||||
if (self::$runtimeVersion !== $this->versions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return self::$runtimeVendors === $this->vendors;
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
{
|
||||
return serialize(array($this->versions, $this->vendors));
|
||||
}
|
||||
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
list($this->versions, $this->vendors) = unserialize($serialized);
|
||||
}
|
||||
|
||||
private static function refresh()
|
||||
{
|
||||
if (null !== self::$runtimeVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$runtimeVersion = array();
|
||||
self::$runtimeVendors = array();
|
||||
|
||||
foreach (get_loaded_extensions() as $ext) {
|
||||
self::$runtimeVersion[$ext] = phpversion($ext);
|
||||
}
|
||||
|
||||
foreach (get_declared_classes() as $class) {
|
||||
if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) {
|
||||
$r = new \ReflectionClass($class);
|
||||
$v = dirname(dirname($r->getFileName()));
|
||||
if (file_exists($v.'/composer/installed.json')) {
|
||||
self::$runtimeVendors[$v] = @filemtime($v.'/composer/installed.json');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -19,12 +19,14 @@ class ReflectionClassResource implements SelfCheckingResourceInterface, \Seriali
|
||||
private $files = array();
|
||||
private $className;
|
||||
private $classReflector;
|
||||
private $excludedVendors = array();
|
||||
private $hash;
|
||||
|
||||
public function __construct(\ReflectionClass $classReflector)
|
||||
public function __construct(\ReflectionClass $classReflector, $excludedVendors = array())
|
||||
{
|
||||
$this->className = $classReflector->name;
|
||||
$this->classReflector = $classReflector;
|
||||
$this->excludedVendors = $excludedVendors;
|
||||
}
|
||||
|
||||
public function isFresh($timestamp)
|
||||
@ -75,7 +77,15 @@ class ReflectionClassResource implements SelfCheckingResourceInterface, \Seriali
|
||||
do {
|
||||
$file = $class->getFileName();
|
||||
if (false !== $file && file_exists($file)) {
|
||||
$this->files[$file] = null;
|
||||
foreach ($this->excludedVendors as $vendor) {
|
||||
if (0 === strpos($file, $vendor) && false !== strpbrk(substr($file, strlen($vendor), 1), '/'.DIRECTORY_SEPARATOR)) {
|
||||
$file = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($file) {
|
||||
$this->files[$file] = null;
|
||||
}
|
||||
}
|
||||
foreach ($class->getTraits() as $v) {
|
||||
$this->loadFiles($v);
|
||||
|
@ -0,0 +1,46 @@
|
||||
<?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 Composer\Autoload\ClassLoader;
|
||||
use Symfony\Component\Config\Resource\ComposerResource;
|
||||
|
||||
class ComposerResourceTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testGetVendor()
|
||||
{
|
||||
$res = new ComposerResource();
|
||||
|
||||
$r = new \ReflectionClass(ClassLoader::class);
|
||||
$found = false;
|
||||
|
||||
foreach ($res->getVendors() as $vendor) {
|
||||
if ($vendor && 0 === strpos($r->getFileName(), $vendor)) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertTrue($found);
|
||||
}
|
||||
|
||||
public function testSerializeUnserialize()
|
||||
{
|
||||
$res = new ComposerResource();
|
||||
$ser = unserialize(serialize($res));
|
||||
|
||||
$this->assertTrue($res->isFresh(0));
|
||||
$this->assertTrue($ser->isFresh(0));
|
||||
|
||||
$this->assertEquals($res, $ser);
|
||||
}
|
||||
}
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
@ -67,7 +66,7 @@ class FactoryReturnTypePass implements CompilerPassInterface
|
||||
try {
|
||||
$m = new \ReflectionFunction($factory);
|
||||
if (false !== $m->getFileName() && file_exists($m->getFileName())) {
|
||||
$container->addResource(new FileResource($m->getFileName()));
|
||||
$container->fileExists($m->getFileName());
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
return;
|
||||
|
@ -26,6 +26,7 @@ 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\ComposerResource;
|
||||
use Symfony\Component\Config\Resource\DirectoryResource;
|
||||
use Symfony\Component\Config\Resource\FileExistenceResource;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
@ -108,6 +109,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
*/
|
||||
private $envCounters = array();
|
||||
|
||||
/**
|
||||
* @var string[] the list of vendor directories
|
||||
*/
|
||||
private $vendors;
|
||||
|
||||
/**
|
||||
* Sets the track resources flag.
|
||||
*
|
||||
@ -269,13 +275,13 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
}
|
||||
$file = $interface->getFileName();
|
||||
if (false !== $file && file_exists($file)) {
|
||||
$this->addResource(new FileResource($file));
|
||||
$this->fileExists($file);
|
||||
}
|
||||
}
|
||||
do {
|
||||
$file = $class->getFileName();
|
||||
if (false !== $file && file_exists($file)) {
|
||||
$this->addResource(new FileResource($file));
|
||||
$this->fileExists($file);
|
||||
}
|
||||
foreach ($class->getTraitNames() as $name) {
|
||||
$this->addObjectResource($name);
|
||||
@ -337,7 +343,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
if (!$classReflector) {
|
||||
$this->addResource($resource ?: new ClassExistenceResource($class, ClassExistenceResource::EXISTS_KO));
|
||||
} elseif (!$classReflector->isInternal()) {
|
||||
$this->addResource(new ReflectionClassResource($classReflector));
|
||||
$path = $classReflector->getFileName();
|
||||
|
||||
if (!$this->inVendors($path)) {
|
||||
$this->addResource(new ReflectionClassResource($classReflector, $this->vendors));
|
||||
}
|
||||
}
|
||||
$this->classReflectors[$class] = $classReflector;
|
||||
}
|
||||
@ -360,7 +370,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
{
|
||||
$exists = file_exists($path);
|
||||
|
||||
if (!$this->trackResources) {
|
||||
if (!$this->trackResources || $this->inVendors($path)) {
|
||||
return $exists;
|
||||
}
|
||||
|
||||
@ -370,12 +380,10 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
return $exists;
|
||||
}
|
||||
|
||||
if ($trackContents) {
|
||||
if (is_file($path)) {
|
||||
$this->addResource(new FileResource($path));
|
||||
} else {
|
||||
$this->addResource(new DirectoryResource($path, is_string($trackContents) ? $trackContents : null));
|
||||
}
|
||||
if ($trackContents && is_dir($path)) {
|
||||
$this->addResource(new DirectoryResource($path, is_string($trackContents) ? $trackContents : null));
|
||||
} elseif ($trackContents || is_dir($path)) {
|
||||
$this->addResource(new FileResource($path));
|
||||
}
|
||||
|
||||
return $exists;
|
||||
@ -1488,4 +1496,22 @@ EOF;
|
||||
|
||||
return $this->expressionLanguage;
|
||||
}
|
||||
|
||||
private function inVendors($path)
|
||||
{
|
||||
if (null === $this->vendors) {
|
||||
$resource = new ComposerResource();
|
||||
$this->vendors = $resource->getVendors();
|
||||
$this->addResource($resource);
|
||||
}
|
||||
$path = realpath($path) ?: $path;
|
||||
|
||||
foreach ($this->vendors as $vendor) {
|
||||
if (0 === strpos($path, $vendor) && false !== strpbrk(substr($path, strlen($vendor), 1), '/'.DIRECTORY_SEPARATOR)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ class DirectoryLoader extends FileLoader
|
||||
{
|
||||
$file = rtrim($file, '/');
|
||||
$path = $this->locator->locate($file);
|
||||
$this->container->addResource(new DirectoryResource($path));
|
||||
$this->container->fileExists($path, false);
|
||||
|
||||
foreach (scandir($path) as $dir) {
|
||||
if ('.' !== $dir[0]) {
|
||||
|
@ -29,7 +29,7 @@ class IniFileLoader extends FileLoader
|
||||
{
|
||||
$path = $this->locator->locate($resource);
|
||||
|
||||
$this->container->addResource(new FileResource($path));
|
||||
$this->container->fileExists($path);
|
||||
|
||||
// first pass to catch parsing errors
|
||||
$result = parse_ini_file($path, true);
|
||||
|
@ -34,7 +34,7 @@ class PhpFileLoader extends FileLoader
|
||||
|
||||
$path = $this->locator->locate($resource);
|
||||
$this->setCurrentDir(dirname($path));
|
||||
$this->container->addResource(new FileResource($path));
|
||||
$this->container->fileExists($path);
|
||||
|
||||
include $path;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ class XmlFileLoader extends FileLoader
|
||||
|
||||
$xml = $this->parseFileToDOM($path);
|
||||
|
||||
$this->container->addResource(new FileResource($path));
|
||||
$this->container->fileExists($path);
|
||||
|
||||
// anonymous services
|
||||
$this->processAnonymousServices($xml, $path);
|
||||
|
@ -72,7 +72,7 @@ class YamlFileLoader extends FileLoader
|
||||
|
||||
$content = $this->loadFile($path);
|
||||
|
||||
$this->container->addResource(new FileResource($path));
|
||||
$this->container->fileExists($path);
|
||||
|
||||
// empty file
|
||||
if (null === $content) {
|
||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\DependencyInjection\Tests;
|
||||
require_once __DIR__.'/Fixtures/includes/classes.php';
|
||||
require_once __DIR__.'/Fixtures/includes/ProjectExtension.php';
|
||||
|
||||
use Symfony\Component\Config\Resource\ComposerResource;
|
||||
use Symfony\Component\Config\Resource\ResourceInterface;
|
||||
use Symfony\Component\Config\Resource\DirectoryResource;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
@ -614,7 +615,7 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$resources = $container->getResources();
|
||||
|
||||
$this->assertCount(1, $resources, '1 resource was registered');
|
||||
$this->assertCount(2, $resources, '2 resources were registered');
|
||||
|
||||
/* @var $resource \Symfony\Component\Config\Resource\FileResource */
|
||||
$resource = end($resources);
|
||||
@ -640,7 +641,7 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$resources = $container->getResources();
|
||||
|
||||
$this->assertCount(1, $resources, '1 resource was registered');
|
||||
$this->assertCount(2, $resources, '2 resources were registered');
|
||||
|
||||
/* @var $resource \Symfony\Component\Config\Resource\FileResource */
|
||||
$resource = end($resources);
|
||||
@ -669,9 +670,9 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$resources = $container->getResources();
|
||||
|
||||
$this->assertCount(2, $resources, '2 resources were registered');
|
||||
$this->assertCount(3, $resources, '3 resources were registered');
|
||||
|
||||
$this->assertSame('reflection.BarClass', (string) $resources[0]);
|
||||
$this->assertSame('reflection.BarClass', (string) $resources[1]);
|
||||
$this->assertSame('BarMissingClass', (string) end($resources));
|
||||
}
|
||||
|
||||
@ -715,6 +716,7 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
public function testFileExists()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$A = new ComposerResource();
|
||||
$a = new FileResource(__DIR__.'/Fixtures/xml/services1.xml');
|
||||
$b = new FileResource(__DIR__.'/Fixtures/xml/services2.xml');
|
||||
$c = new DirectoryResource($dir = dirname($b));
|
||||
@ -728,7 +730,7 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertEquals(array($a, $b, $c), $resources, '->getResources() returns an array of resources read for the current configuration');
|
||||
$this->assertEquals(array($A, $a, $b, $c), $resources, '->getResources() returns an array of resources read for the current configuration');
|
||||
}
|
||||
|
||||
public function testExtension()
|
||||
|
Reference in New Issue
Block a user