From 7d07f19459898096d8c148bfe1697fbd0da29745 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 9 May 2017 10:16:01 -0400 Subject: [PATCH] Allowing prototype/PSR4 service loading ability to exclude, because glob doesn't support this --- .../DependencyInjection/Loader/FileLoader.php | 30 +++++++++-- .../Loader/XmlFileLoader.php | 2 +- .../Loader/YamlFileLoader.php | 4 +- .../schema/dic/services/services-1.0.xsd | 1 + .../OtherDir/AnotherSub/DeeperBaz.php | 7 +++ .../Tests/Fixtures/Prototype/OtherDir/Baz.php | 7 +++ .../Tests/Fixtures/xml/services_prototype.xml | 2 +- .../Fixtures/yaml/services_prototype.yml | 1 + .../Tests/Loader/FileLoaderTest.php | 52 +++++++++++++++++++ 9 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/OtherDir/AnotherSub/DeeperBaz.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/OtherDir/Baz.php diff --git a/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php index 1910ec66a25c6..40cf8f9ee4cae 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php @@ -47,8 +47,9 @@ public function __construct(ContainerBuilder $container, FileLocatorInterface $l * @param Definition $prototype A definition to use as template * @param string $namespace The namespace prefix of classes in the scanned directory * @param string $resource The directory to look for classes, glob-patterns allowed + * @param string $exclude A globed path of files to exclude */ - public function registerClasses(Definition $prototype, $namespace, $resource) + public function registerClasses(Definition $prototype, $namespace, $resource, $exclude = null) { if ('\\' !== substr($namespace, -1)) { throw new InvalidArgumentException(sprintf('Namespace prefix must end with a "\\": %s.', $namespace)); @@ -57,7 +58,7 @@ public function registerClasses(Definition $prototype, $namespace, $resource) throw new InvalidArgumentException(sprintf('Namespace is not a valid PSR-4 prefix: %s.', $namespace)); } - $classes = $this->findClasses($namespace, $resource); + $classes = $this->findClasses($namespace, $resource, $exclude); // prepare for deep cloning $prototype = serialize($prototype); @@ -84,9 +85,24 @@ protected function setDefinition($id, Definition $definition) } } - private function findClasses($namespace, $pattern) + private function findClasses($namespace, $pattern, $excludePattern) { $parameterBag = $this->container->getParameterBag(); + + $excludePaths = array(); + $excludePrefix = null; + if ($excludePattern) { + $excludePattern = $parameterBag->unescapeValue($parameterBag->resolveValue($excludePattern)); + foreach ($this->glob($excludePattern, true, $resource) as $path => $info) { + if (null === $excludePrefix) { + $excludePrefix = $resource->getPrefix(); + } + + // normalize Windows slashes + $excludePaths[str_replace('\\', '/', $path)] = true; + } + } + $pattern = $parameterBag->unescapeValue($parameterBag->resolveValue($pattern)); $classes = array(); $extRegexp = defined('HHVM_VERSION') ? '/\\.(?:php|hh)$/' : '/\\.php$/'; @@ -94,6 +110,14 @@ private function findClasses($namespace, $pattern) foreach ($this->glob($pattern, true, $resource) as $path => $info) { if (null === $prefixLen) { $prefixLen = strlen($resource->getPrefix()); + + if ($excludePrefix && strpos($excludePrefix, $resource->getPrefix()) !== 0) { + throw new InvalidArgumentException(sprintf('Invalid "exclude" pattern when importing classes for "%s": make sure your "exclude" pattern (%s) is a subset of the "resource" pattern (%s)', $namespace, $excludePattern, $pattern)); + } + } + + if (isset($excludePaths[str_replace('\\', '/', $path)])) { + continue; } if (!preg_match($extRegexp, $path, $m) || !$info->isReadable()) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 3ccbdbc79155e..79c8fbf9677ab 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -143,7 +143,7 @@ private function parseDefinitions(\DOMDocument $xml, $file, $defaults) foreach ($services as $service) { if (null !== $definition = $this->parseDefinition($service, $file, $defaults)) { if ('prototype' === $service->tagName) { - $this->registerClasses($definition, (string) $service->getAttribute('namespace'), (string) $service->getAttribute('resource')); + $this->registerClasses($definition, (string) $service->getAttribute('namespace'), (string) $service->getAttribute('resource'), (string) $service->getAttribute('exclude')); } else { $this->setDefinition((string) $service->getAttribute('id'), $definition); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 3214f4e023cb6..c3e697c1b5207 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -61,6 +61,7 @@ class YamlFileLoader extends FileLoader private static $prototypeKeywords = array( 'resource' => 'resource', + 'exclude' => 'exclude', 'parent' => 'parent', 'shared' => 'shared', 'lazy' => 'lazy', @@ -528,7 +529,8 @@ private function parseDefinition($id, $service, $file, array $defaults) if (!is_string($service['resource'])) { throw new InvalidArgumentException(sprintf('A "resource" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file)); } - $this->registerClasses($definition, $id, $service['resource']); + $exclude = isset($service['exclude']) ? $service['exclude'] : null; + $this->registerClasses($definition, $id, $service['resource'], $exclude); } else { $this->setDefinition($id, $definition); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd index 43ea65a2d8577..2de786bdb7cba 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd +++ b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd @@ -161,6 +161,7 @@ + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/OtherDir/AnotherSub/DeeperBaz.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/OtherDir/AnotherSub/DeeperBaz.php new file mode 100644 index 0000000000000..37f0e7ac45399 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/OtherDir/AnotherSub/DeeperBaz.php @@ -0,0 +1,7 @@ + - + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_prototype.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_prototype.yml index 7113c9d957505..fb47bcb7e7a52 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_prototype.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_prototype.yml @@ -1,3 +1,4 @@ services: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\: resource: ../Prototype + exclude: '../Prototype/{OtherDir}' diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php index b0245c3556388..6544145c4e0e0 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php @@ -16,12 +16,15 @@ use Symfony\Component\Config\Loader\LoaderResolver; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Loader\FileLoader; use Symfony\Component\DependencyInjection\Loader\IniFileLoader; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\AnotherSub\DeeperBaz; +use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\Baz; use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar; class FileLoaderTest extends TestCase @@ -90,6 +93,26 @@ public function testRegisterClasses() ); } + public function testRegisterClassesWithExclude() + { + $container = new ContainerBuilder(); + $container->setParameter('other_dir', 'OtherDir'); + $loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures')); + + $loader->registerClasses( + new Definition(), + 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\', + 'Prototype/*', + // load everything, except OtherDir/AnotherSub & Foo.php + 'Prototype/{%other_dir%/AnotherSub,Foo.php}' + ); + + $this->assertTrue($container->has(Bar::class)); + $this->assertTrue($container->has(Baz::class)); + $this->assertFalse($container->has(Foo::class)); + $this->assertFalse($container->has(DeeperBaz::class)); + } + /** * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException * @expectedExceptionMessageRegExp /Expected to find class "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\Prototype\\Bar" in file ".+" while importing services from resource "Prototype\/Sub\/\*", but it was not found\! Check the namespace prefix used with the resource/ @@ -102,6 +125,35 @@ public function testRegisterClassesWithBadPrefix() // the Sub is missing from namespace prefix $loader->registerClasses(new Definition(), 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\', 'Prototype/Sub/*'); } + + /** + * @dataProvider getIncompatibleExcludeTests + */ + public function testRegisterClassesWithIncompatibleExclude($resourcePattern, $excludePattern) + { + $container = new ContainerBuilder(); + $loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures')); + + try { + $loader->registerClasses( + new Definition(), + 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\', + $resourcePattern, + $excludePattern + ); + } catch (InvalidArgumentException $e) { + $this->assertEquals( + sprintf('Invalid "exclude" pattern when importing classes for "Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\": make sure your "exclude" pattern (%s) is a subset of the "resource" pattern (%s)', $excludePattern, $resourcePattern), + $e->getMessage() + ); + } + } + + public function getIncompatibleExcludeTests() + { + yield array('Prototype/*', 'yaml/*', false); + yield array('Prototype/OtherDir/*', 'Prototype/*', false); + } } class TestFileLoader extends FileLoader pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy