8000 [DI][Config] Add ContainerBuilder::getClassExists() for checking and … · symfony/symfony@2839a7e · GitHub
[go: up one dir, main page]

Skip to content

Commit 2839a7e

Browse files
[DI][Config] Add ContainerBuilder::getClassExists() for checking and tracking class, interface or trait existence
1 parent b1098d9 commit 2839a7e

File tree

12 files changed

+82
-26
lines changed

12 files changed

+82
-26
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
use Symfony\Component\Finder\Finder;
2929
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
3030
use Symfony\Component\Config\FileLocator;
31-
use Symfony\Component\Config\Resource\ClassExistenceResource;
3231
use Symfony\Component\PropertyAccess\PropertyAccessor;
3332
use Symfony\Component\Serializer\Encoder\YamlEncoder;
3433
use Symfony\Component\Serializer\Encoder\CsvEncoder;
@@ -85,8 +84,7 @@ public function load(array $configs, ContainerBuilder $container)
8584

8685
$loader->load('fragment_renderer.xml');
8786

88-
$container->addResource(new ClassExistenceResource(Application::class));
89-
if (class_exists(Application::class)) {
87+
if ($container->classExists(Application::class)) {
9088
$loader->load('console.xml');
9189
}
9290

@@ -525,7 +523,7 @@ private function registerDebugConfiguration(array $config, ContainerBuilder $con
525523
$definition->replaceArgument(4, $debug);
526524
$definition->replaceArgument(6, $debug);
527525 B422

528-
if ($debug && class_exists(DebugProcessor::class)) {
526+
if ($debug && $container->classExists(DebugProcessor::class)) {
529527
$definition = new Definition(DebugProcessor::class);
530528
$definition->setPublic(false);
531529
$container->setDefinition('debug.log_processor', $definition);
@@ -1252,7 +1250,7 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
12521250
$container->getDefinition('serializer.mapping.class_metadata_factory')->replaceArgument(
12531251
1, new Reference($config['cache'])
12541252
);
1255-
} elseif (!$container->getParameter('kernel.debug') && class_exists(CacheClassMetadataFactory::class)) {
1253+
} elseif (!$container->getParameter('kernel.debug') && $container->classExists(CacheClassMetadataFactory::class)) {
12561254
$cacheMetadataFactory = new Definition(
12571255
CacheClassMetadataFactory::class,
12581256
array(

src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExceptionListenerPass.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
namespace Symfony\Bundle\TwigBundle\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\Debug\Exception\FlattenException;
1415
use Symfony\Component\DependencyInjection\ContainerBuilder;
1516
use Symfony\Component\DependencyInjection< F438 /span>\Compiler\CompilerPassInterface;
17+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
1618

1719
/**
1820
* Registers the Twig exception listener if Twig is registered as a templating engine.
@@ -28,7 +30,7 @@ public function process(ContainerBuilder $container)
2830
}
2931

3032
// register the exception controller only if Twig is enabled and required dependencies do exist
31-
if (!class_exists('Symfony\Component\Debug\Exception\FlattenException') || !interface_exists('Symfony\Component\EventDispatcher\EventSubscriberInterface')) {
33+
if (!$container->classExists(FlattenException::class) || !$container->classExists(EventSubscriberInterface::class)) {
3234
$container->removeDefinition('twig.exception_listener');
3335
} elseif ($container->hasParameter('templating.engines')) {
3436
$engines = $container->getParameter('templating.engines');

src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111

1212
namespace Symfony\Bundle\TwigBundle\DependencyInjection\Compiler;
1313

14-
use Symfony\Component\Config\Resource\ClassExistenceResource;
14+
use Symfony\Component\Asset\Packages;
1515
use Symfony\Component\DependencyInjection\Alias;
1616
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
1717
use Symfony\Component\DependencyInjection\ContainerBuilder;
1818
use Symfony\Component\DependencyInjection\Reference;
1919
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
20+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
2021
use Symfony\Component\Stopwatch\Stopwatch;
22+
use Symfony\Component\Translation\TranslatorInterface;
2123
use Symfony\Component\Yaml\Parser as YamlParser;
2224

2325
/**
@@ -27,22 +29,23 @@ class ExtensionPass implements CompilerPassInterface
2729
{
2830
public function process(ContainerBuilder $container)
2931
{
30-
if (!class_exists('Symfony\Component\Asset\Packages')) {
32+
if (!$container->classExists(Packages::class)) {
3133
$container->removeDefinition('twig.extension.assets');
3234
}
3335

34-
if (!class_exists('Symfony\Component\ExpressionLanguage\Expression')) {
36+
if (!$container->classExists(ExpressionLanguage::class)) {
3537
$container->removeDefinition('twig.extension.expression');
3638
}
3739

38-
if (!interface_exists('Symfony\Component\Routing\Generator\UrlGeneratorInterface')) {
40+
if (!$container->classExists(UrlGeneratorInterface::class)) {
3941
$container->removeDefinition('twig.extension.routing');
4042
}
41-
if (!interface_exists('Symfony\Component\Translation\TranslatorInterface')) {
43+
44+
if (!$container->classExists(TranslatorInterface::class)) {
4245
$container->removeDefinition('twig.extension.trans');
4346
}
4447

45-
if (!class_exists('Symfony\Component\Yaml\Yaml')) {
48+
if (!$container->classExists(YamlParser::class)) {
4649
$container->removeDefinition('twig.extension.yaml');
4750
}
4851

@@ -101,18 +104,15 @@ public function process(ContainerBuilder $container)
101104
$container->getDefinition('twig.extension.assets')->addTag('twig.extension');
102105
}
103106

104-
$container->addResource(new ClassExistenceResource(YamlParser::class));
105-
if (class_exists(YamlParser::class)) {
107+
if ($container->hasDefinition('twig.extension.yaml')) {
106108
$container->getDefinition('twig.extension.yaml')->addTag('twig.extension');
107109
}
108110

109-
$container->addResource(new ClassExistenceResource(Stopwatch::class));
110-
if (class_exists(Stopwatch::class)) {
111+
if ($container->classExists(Stopwatch::class)) {
111112
$container->getDefinition('twig.extension.debug.stopwatch')->addTag('twig.extension');
112113
}
113114

114-
$container->addResource(new ClassExistenceResource(ExpressionLanguage::class));
115-
if (class_exists(ExpressionLanguage::class)) {
115+
if ($container->hasDefinition('twig.extension.expression')) {
116116
$container->getDefinition('twig.extension.expression')->addTag('twig.extension');
117117
}
118118
}

src/Symfony/Bundle/TwigBundle/composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
],
1818
"require": {
1919
"php": ">=5.5.9",
20-
"symfony/config": "~3.2",
20+
"symfony/config": "~3.3",
2121
"symfony/twig-bridge": "^3.2.1",
2222
"symfony/http-foundation": "~2.8|~3.0",
2323
"symfony/http-kernel": "~2.8.16|~3.1.9|^3.2.2",
@@ -26,7 +26,7 @@
2626
"require-dev": {
2727
"symfony/asset": "~2.8|~3.0",
2828
"symfony/stopwatch": "~2.8|~3.0",
29-
"symfony/dependency-injection": "~2.8|~3.0",
29+
"symfony/dependency-injection": "~3.3",
3030
"symfony/expression-language": "~2.8|~3.0",
3131
"symfony/finder": "~2.8|~3.0",
3232
"symfony/form": "~2.8|~3.0",

src/Symfony/Component/Config/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
3.3.0
5+
-----
6+
7+
* made `ClassExistenceResource` to work with interfaces and traits
8+
49
3.0.0
510
-----
611

src/Symfony/Component/Config/Resource/ClassExistenceResource.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
3030
public function __construct($resource)
3131
{
3232
$this->resource = $resource;
33-
$this->exists = class_exists($resource);
33+
$this->exists = class_exists($resource) || interface_exists($resource, false) || trait_exists($resource, false);
3434
}
3535

3636
/**
@@ -54,7 +54,7 @@ public function getResource()
5454
*/
5555
public function isFresh($timestamp)
5656
{
57-
return class_exists($this->resource) === $this->exists;
57+
return (class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false)) === $this->exists;
5858
}
5959

6060
/**

src/Symfony/Component/Config/Resource/FileExistenceResource.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ class FileExistenceResource implements SelfCheckingResourceInterface, \Serializa
3333
public function __construct($resource)
3434
{
3535
$this->resource = (string) $resource;
36-
$this->exists = file_exists($resource);
3736
}
3837

3938
/**
@@ -57,6 +56,10 @@ public function getResource()
5756
*/
5857
public function isFresh($timestamp)
5958
{
59+
if (null === $this->exists) {
60+
$this->exists = file_exists($this->resource);
61+
}
62+
6063
return file_exists($this->resource) === $this->exists;
6164
}
6265

@@ -65,6 +68,10 @@ public function isFresh($timestamp)
6568
*/
6669
public function serialize()
6770
{
71+
if (null === $this->exists) {
72+
$this->exists = file_exists($this->resource);
73+
}
74+
6875
return serialize(array($this->resource, $this->exists));
6976
}
7077

src/Symfony/Component/Config/Tests/Resource/ClassExistenceResourceTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public function testIsFreshWhenClassDoesNotExist()
3636
eval(<<<EOF
3737
namespace Symfony\Component\Config\Tests\Fixtures;
3838
39-
class BarClass
39+
interface BarClass
4040
{
4141
}
4242
EOF
@@ -50,5 +50,6 @@ public function testIsFreshWhenClassExists()
5050
$res = new ClassExistenceResource('Symfony\Component\Config\Tests\Resource\ClassExistenceResourceTest');
5151

5252
$this->assertTrue($res->isFresh(time()));
53+
$this->assertTrue(class_exists('Symfony\Component\Config\Tests\Resource\ClassExistenceResourceTest', false));
5354
}
5455
}

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
3.3.0
55
-----
66

7+
* added `ContainerBuilder::classExists()` for checking and tracking class, interface or trait existence
78
* added support for omitting the factory class name in a service definition if the definition class is set
89
* deprecated case insensitivity of service identifiers
910
* added "iterator" argument type for lazy iteration over a set of values and services

src/Symfony/Component/DependencyInjection/Compiler/FactoryReturnTypePass.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\Config\Resource\FileResource;
1415
use Symfony\Component\DependencyInjection\ContainerBuilder;
1516
use Symfony\Component\DependencyInjection\Definition;
1617
use Symfony\Component\DependencyInjection\Reference;
@@ -65,6 +66,9 @@ private function updateDefinition(ContainerBuilder $container, $id, Definition $
6566
if (is_string($factory)) {
6667
try {
6768
$m = new \ReflectionFunction($factory);
69+
if (false !== $m->getFileName() && file_exists($m->getFileName())) {
70+
$container->addResource(new FileResource($m->getFileName()));
71+
}
6872
} catch (\ReflectionException $e) {
6973
return;
7074
}

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
2626
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
2727
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
28+
use Symfony\Component\Config\Resource\FileExistenceResource;
2829
use Symfony\Component\Config\Resource\FileResource;
2930
use Symfony\Component\Config\Resource\ResourceInterface;
3031
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
@@ -103,6 +104,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
103104
*/
104105
private $envCounters = array();
105106

107+
/**
108+
* @var \ReflectionClass[]
109+
*/
110+
private $classReflectors = array();
111+
106112
/**
107113
* Sets the track resources flag.
108114
*
@@ -278,6 +284,37 @@ public function addClassResource(\ReflectionClass $class)
278284
return $this;
279285
}
280286

287+
/**
288+
* Checks whether the requested class, interface or trait exists and registers the result for resource tracking.
289+
*
290+
* @param string $class
291+
*
292+
* @return bool
293+
*
294+
* @final
295+
*/
296+
public function classExists($class)
297+
{
298+
if (isset($this->classReflectors[$class])) {
299+
return (bool) $this->classReflectors[$class];
300+
}
301+
$exists = class_exists($class) || interface_exists($class, false) || trait_exists($class, false);
302+
303+
if ($this->trackResources) {
304+
if (!$exists) {
305+
$this->addResource(new ClassExistenceResource($class));
306+
$this->classReflectors[$class] = false;
307+
} else {
308+
$class = $this->classReflectors[$class] = new \ReflectionClass($class);
309+
if (!$class->isInternal() && false !== ($file = $class->getFileName()) && file_exists($file)) {
310+
$this->addResource(new FileExistenceResource($file));
311+
}
312+
}
313+
}
314+
315+
return $exists;
316+
}
317+
281318
/**
282319
* Loads the configuration for an extension.
283320
*
@@ -983,7 +1020,7 @@ public function resolveServices($value)
9831020
if ('service_container' === $id = (string) $reference) {
9841021
$class = parent::class;
9851022
} elseif (!$this->hasDefinition($id) && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
986-
return null;
1023+
return;
9871024
} else {
9881025
$class = $parameterBag->resolveValue($this->findDefinition($id)->getClass());
9891026
}

src/Symfony/Component/DependencyInjection/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
},
2121
"require-dev": {
2222
"symfony/yaml": "~3.2",
23-
"symfony/config": "~2.8|~3.0",
23+
"symfony/config": "~3.3",
2424
"symfony/expression-language": "~2.8|~3.0"
2525
},
2626
"suggest": {
@@ -30,6 +30,7 @@
3030
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them"
3131
},
3232
"conflict": {
33+
"symfony/config": "<3.3",
3334
"symfony/yaml": "<3.2"
3435
},
3536
"autoload": {

0 commit comments

Comments
 (0)
0