Skip to content

Add more classExists() checks #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
use Symfony\Component\Finder\Finder;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Resource\ClassExistenceResource;
use Symfony\Component\PropertyAccess\PropertyAccessor;
use Symfony\Component\Serializer\Encoder\YamlEncoder;
use Symfony\Component\Serializer\Encoder\CsvEncoder;
Expand Down Expand Up @@ -85,8 +84,7 @@ public function load(array $configs, ContainerBuilder $container)

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

$container->addResource(new ClassExistenceResource(Application::class));
if (class_exists(Application::class)) {
if ($container->classExists(Application::class)) {
$loader->load('console.xml');
}

Expand Down Expand Up @@ -525,7 +523,7 @@ private function registerDebugConfiguration(array $config, ContainerBuilder $con
$definition->replaceArgument(4, $debug);
$definition->replaceArgument(6, $debug);

if ($debug && class_exists(DebugProcessor::class)) {
if ($debug && $container->classExists(DebugProcessor::class)) {
$definition = new Definition(DebugProcessor::class);
$definition->setPublic(false);
$container->setDefinition('debug.log_processor', $definition);
Expand Down Expand Up @@ -860,17 +858,17 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder

// Discover translation directories
$dirs = array();
if (class_exists('Symfony\Component\Validator\Validation')) {
if ($container->classExists('Symfony\Component\Validator\Validation')) {
$r = new \ReflectionClass('Symfony\Component\Validator\Validation');

$dirs[] = dirname($r->getFileName()).'/Resources/translations';
}
if (class_exists('Symfony\Component\Form\Form')) {
if ($container->classExists('Symfony\Component\Form\Form')) {
$r = new \ReflectionClass('Symfony\Component\Form\Form');

$dirs[] = dirname($r->getFileName()).'/Resources/translations';
}
if (class_exists('Symfony\Component\Security\Core\Exception\AuthenticationException')) {
if ($container->classExists('Symfony\Component\Security\Core\Exception\AuthenticationException')) {
$r = new \ReflectionClass('Symfony\Component\Security\Core\Exception\AuthenticationException');

$dirs[] = dirname(dirname($r->getFileName())).'/Resources/translations';
Expand Down Expand Up @@ -1150,34 +1148,34 @@ private function registerSecurityCsrfConfiguration(array $config, ContainerBuild
*/
private function registerSerializerConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
if (class_exists('Symfony\Component\Serializer\Normalizer\DataUriNormalizer')) {
if ($container->classExists('Symfony\Component\Serializer\Normalizer\DataUriNormalizer')) {
// Run after serializer.normalizer.object
$definition = $container->register('serializer.normalizer.data_uri', DataUriNormalizer::class);
$definition->setPublic(false);
$definition->addTag('serializer.normalizer', array('priority' => -920));
}

if (class_exists('Symfony\Component\Serializer\Normalizer\DateTimeNormalizer')) {
if ($container->classExists('Symfony\Component\Serializer\Normalizer\DateTimeNormalizer')) {
// Run before serializer.normalizer.object
$definition = $container->register('serializer.normalizer.datetime', DateTimeNormalizer::class);
$definition->setPublic(false);
$definition->addTag('serializer.normalizer', array('priority' => -910));
}

if (class_exists('Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer')) {
if ($container->classExists('Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer')) {
// Run before serializer.normalizer.object
$definition = $container->register('serializer.normalizer.json_serializable', JsonSerializableNormalizer::class);
$definition->setPublic(false);
$definition->addTag('serializer.normalizer', array('priority' => -900));
}

if (class_exists(YamlEncoder::class) && defined('Symfony\Component\Yaml\Yaml::DUMP_OBJECT')) {
if ($container->classExists(YamlEncoder::class) && defined('Symfony\Component\Yaml\Yaml::DUMP_OBJECT')) {
$definition = $container->register('serializer.encoder.yaml', YamlEncoder::class);
$definition->setPublic(false);
$definition->addTag('serializer.encoder');
}

if (class_exists(CsvEncoder::class)) {
if ($container->classExists(CsvEncoder::class)) {
$definition = $container->register('serializer.encoder.csv', CsvEncoder::class);
$definition->setPublic(false);
$definition->addTag('serializer.encoder');
Expand Down Expand Up @@ -1252,7 +1250,7 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
$container->getDefinition('serializer.mapping.class_metadata_factory')->replaceArgument(
1, new Reference($config['cache'])
);
} elseif (!$container->getParameter('kernel.debug') && class_exists(CacheClassMetadataFactory::class)) {
} elseif (!$container->getParameter('kernel.debug') && $container->classExists(CacheClassMetadataFactory::class)) {
$cacheMetadataFactory = new Definition(
CacheClassMetadataFactory::class,
array(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@

namespace Symfony\Bundle\TwigBundle\DependencyInjection\Compiler;

use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

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

// register the exception controller only if Twig is enabled and required dependencies do exist
if (!class_exists('Symfony\Component\Debug\Exception\FlattenException') || !interface_exists('Symfony\Component\EventDispatcher\EventSubscriberInterface')) {
if (!$container->classExists(FlattenException::class) || !$container->classExists(EventSubscriberInterface::class)) {
$container->removeDefinition('twig.exception_listener');
} elseif ($container->hasParameter('templating.engines')) {
$engines = $container->getParameter('templating.engines');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@

namespace Symfony\Bundle\TwigBundle\DependencyInjection\Compiler;

use Symfony\Component\Config\Resource\ClassExistenceResource;
use Symfony\Component\Asset\Packages;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Yaml\Parser as YamlParser;

/**
Expand All @@ -27,22 +29,23 @@ class ExtensionPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!class_exists('Symfony\Component\Asset\Packages')) {
if (!$container->classExists(Packages::class)) {
$container->removeDefinition('twig.extension.assets');
}

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

if (!interface_exists('Symfony\Component\Routing\Generator\UrlGeneratorInterface')) {
if (!$container->classExists(UrlGeneratorInterface::class)) {
$container->removeDefinition('twig.extension.routing');
}
if (!interface_exists('Symfony\Component\Translation\TranslatorInterface')) {

if (!$container->classExists(TranslatorInterface::class)) {
$container->removeDefinition('twig.extension.trans');
}

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

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

$container->addResource(new ClassExistenceResource(YamlParser::class));
if (class_exists(YamlParser::class)) {
if ($container->hasDefinition('twig.extension.yaml')) {
$container->getDefinition('twig.extension.yaml')->addTag('twig.extension');
}

$container->addResource(new ClassExistenceResource(Stopwatch::class));
if (class_exists(Stopwatch::class)) {
if ($container->classExists(Stopwatch::class)) {
$container->getDefinition('twig.extension.debug.stopwatch')->addTag('twig.extension');
}

$container->addResource(new ClassExistenceResource(ExpressionLanguage::class));
if (class_exists(ExpressionLanguage::class)) {
if ($container->hasDefinition('twig.extension.expression')) {
$container->getDefinition('twig.extension.expression')->addTag('twig.extension');
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Bundle/TwigBundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
],
"require": {
"php": ">=5.5.9",
"symfony/config": "~3.2",
"symfony/config": "~3.3",
"symfony/twig-bridge": "^3.2.1",
"symfony/http-foundation": "~2.8|~3.0",
"symfony/http-kernel": "~2.8.16|~3.1.9|^3.2.2",
Expand All @@ -26,7 +26,7 @@
"require-dev": {
"symfony/asset": "~2.8|~3.0",
"symfony/stopwatch": "~2.8|~3.0",
"symfony/dependency-injection": "~2.8|~3.0",
"symfony/dependency-injection": "~3.3",
"symfony/expression-language": "~2.8|~3.0",
"symfony/finder": "~2.8|~3.0",
"symfony/form": "~2.8|~3.0",
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Config/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

3.3.0
-----

* made `ClassExistenceResource` to work with interfaces and traits

3.0.0
-----

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
public function __construct($resource)
{
$this->resource = $resource;
$this->exists = class_exists($resource);
$this->exists = class_exists($resource) || interface_exists($resource, false) || trait_exists($resource, false);
}

/**
Expand All @@ -54,7 +54,7 @@ public function getResource()
*/
public function isFresh($timestamp)
{
return class_exists($this->resource) === $this->exists;
return (class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false)) === $this->exists;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ class FileExistenceResource implements SelfCheckingResourceInterface, \Serializa
public function __construct($resource)
{
$this->resource = (string) $resource;
$this->exists = file_exists($resource);
}

/**
Expand All @@ -57,6 +56,10 @@ public function getResource()
*/
public function isFresh($timestamp)
{
if (null === $this->exists) {
$this->exists = file_exists($this->resource);
}

return file_exists($this->resource) === $this->exists;
}

Expand All @@ -65,6 +68,10 @@ public function isFresh($timestamp)
*/
public function serialize()
{
if (null === $this->exists) {
$this->exists = file_exists($this->resource);
}

return serialize(array($this->resource, $this->exists));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function testIsFreshWhenClassDoesNotExist()
eval(<<<EOF
namespace Symfony\Component\Config\Tests\Fixtures;

class BarClass
interface BarClass
{
}
EOF
Expand All @@ -50,5 +50,6 @@ public function testIsFreshWhenClassExists()
$res = new ClassExistenceResource('Symfony\Component\Config\Tests\Resource\ClassExistenceResourceTest');

$this->assertTrue($res->isFresh(time()));
$this->assertTrue(class_exists('Symfony\Component\Config\Tests\Resource\ClassExistenceResourceTest', false));
}
}
1 change: 1 addition & 0 deletions src/Symfony/Component/DependencyInjection/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ CHANGELOG
3.3.0
-----

* added `ContainerBuilder::classExists()` for checking and tracking class, interface or trait existence
* added support for omitting the factory class name in a service definition if the definition class is set
* deprecated case insensitivity of service identifiers
* added "iterator" argument type for lazy iteration over a set of values and services
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

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;
Expand Down Expand Up @@ -65,6 +66,9 @@ private function updateDefinition(ContainerBuilder $container, $id, Definition $
if (is_string($factory)) {
try {
$m = new \ReflectionFunction($factory);
if (false !== $m->getFileName() && file_exists($m->getFileName())) {
$container->addResource(new FileResource($m->getFileName()));
}
} catch (\ReflectionException $e) {
return;
}
Expand Down
40 changes: 39 additions & 1 deletion src/Symfony/Component/DependencyInjection/ContainerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
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\FileExistenceResource;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Config\Resource\ResourceInterface;
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
Expand Down Expand Up @@ -103,6 +105,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
*/
private $envCounters = array();

/**
* @var \ReflectionClass[]
*/
private $classReflectors = array();

/**
* Sets the track resources flag.
*
Expand Down Expand Up @@ -278,6 +285,37 @@ public function addClassResource(\ReflectionClass $class)
return $this;
}

/**
* Checks whether the requested class, interface or trait exists and registers the result for resource tracking.
*
* @param string $class
*
* @return bool
*
* @final
*/
public function classExists($class)
{
if (isset($this->classReflectors[$class])) {
return (bool) $this->classReflectors[$class];
}
$exists = class_exists($class) || interface_exists($class, false) || trait_exists($class, false);

if ($this->trackResources) {
if (!$exists) {
$this->addResource(new ClassExistenceResource($class));
$this->classReflectors[$class] = false;
} else {
$class = $this->classReflectors[$class] = new \ReflectionClass($class);
if (!$class->isInternal() && false !== ($file = $class->getFileName()) && file_exists($file)) {
$this->addResource(new FileExistenceResource($file));
}
}
}

return $exists;
}

/**
* Loads the configuration for an extension.
*
Expand Down Expand Up @@ -983,7 +1021,7 @@ public function resolveServices($value)
if ('service_container' === $id = (string) $reference) {
$class = parent::class;
} elseif (!$this->hasDefinition($id) && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
return null;
return;
} else {
$class = $parameterBag->resolveValue($this->findDefinition($id)->getClass());
}
Expand Down
3 changes: 2 additions & 1 deletion src/Symfony/Component/DependencyInjection/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand All @@ -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": {
Expand Down