From 332ff8811c3cd053abf3a96d86f265ba950d1062 Mon Sep 17 00:00:00 2001 From: Tristan Bessoussa Date: Wed, 22 May 2019 12:29:55 +0200 Subject: [PATCH] =?UTF-8?q?[Routing][Config]=C2=A0Allow=20patterns=20of=20?= =?UTF-8?q?resources=20to=20be=20excluded=20from=20config=20loading?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UPGRADE-4.4.md | 5 ++++ UPGRADE-5.0.md | 2 ++ src/Symfony/Component/Config/CHANGELOG.md | 5 ++++ .../Component/Config/Loader/FileLoader.php | 26 ++++++++++++++----- .../Tests/Fixtures/Include/ExcludeFile.txt | 0 .../Fixtures/Include/IncludeAnotherFile.txt | 0 .../Tests/Fixtures/Include/IncludeFile.txt | 0 .../Config/Tests/Loader/FileLoaderTest.php | 8 ++++++ .../Tests/Loader/GlobFileLoaderTest.php | 2 +- src/Symfony/Component/Routing/CHANGELOG.md | 1 + .../Configurator/RoutingConfigurator.php | 7 +++-- .../Routing/Loader/XmlFileLoader.php | 16 +++++++++++- .../Routing/Loader/YamlFileLoader.php | 5 ++-- .../Loader/schema/routing/routing-1.0.xsd | 2 ++ .../Tests/Loader/GlobFileLoaderTest.php | 2 +- 15 files changed, 68 insertions(+), 13 deletions(-) create mode 100644 src/Symfony/Component/Config/Tests/Fixtures/Include/ExcludeFile.txt create mode 100644 src/Symfony/Component/Config/Tests/Fixtures/Include/IncludeAnotherFile.txt create mode 100644 src/Symfony/Component/Config/Tests/Fixtures/Include/IncludeFile.txt diff --git a/UPGRADE-4.4.md b/UPGRADE-4.4.md index d6f6cbe529..1b9f3dd08d 100644 --- a/UPGRADE-4.4.md +++ b/UPGRADE-4.4.md @@ -19,6 +19,11 @@ Debug * Deprecated the `FlattenException` class, use the one from the `ErrorRenderer` component instead * Deprecated the component in favor of the `ErrorHandler` component +Config +------ + + * Deprecated overriding the `FilerLoader::import()` method without declaring the optional `$exclude` argument + DependencyInjection ------------------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 44557336d7..c24187e444 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -27,6 +27,7 @@ Config * Removed `FileLoaderLoadException`, use `LoaderLoadException` instead. * Using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` will throw an exception. * Removed the `root()` method in `TreeBuilder`, pass the root node information to the constructor instead + * The `FilerLoader::import()` method has a new `$exclude` argument. Console ------- @@ -411,6 +412,7 @@ Routing with the new serialization methods in PHP 7.4. * Removed `ServiceRouterLoader` and `ObjectRouteLoader`. * Service route loaders must be tagged with `routing.route_loader`. + * The `RoutingConfigurator::import()` method has a new optional `$exclude` argument. Security -------- diff --git a/src/Symfony/Component/Config/CHANGELOG.md b/src/Symfony/Component/Config/CHANGELOG.md index 4d15e9aeda..a650e10ab8 100644 --- a/src/Symfony/Component/Config/CHANGELOG.md +++ b/src/Symfony/Component/Config/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.4.0 +----- + + * added a way to exclude patterns of resources from being imported by the `import()` method + 4.3.0 ----- diff --git a/src/Symfony/Component/Config/Loader/FileLoader.php b/src/Symfony/Component/Config/Loader/FileLoader.php index 49e1b0fd89..0ab6b648ab 100644 --- a/src/Symfony/Component/Config/Loader/FileLoader.php +++ b/src/Symfony/Component/Config/Loader/FileLoader.php @@ -59,10 +59,11 @@ abstract class FileLoader extends Loader /** * Imports a resource. * - * @param mixed $resource A Resource - * @param string|null $type The resource type or null if unknown - * @param bool $ignoreErrors Whether to ignore import errors or not - * @param string|null $sourceResource The original resource importing the new resource + * @param mixed $resource A Resource + * @param string|null $type The resource type or null if unknown + * @param bool $ignoreErrors Whether to ignore import errors or not + * @param string|null $sourceResource The original resource importing the new resource + * @param string|string[]|null $exclude Glob patterns to exclude from the import * * @return mixed * @@ -70,12 +71,25 @@ abstract class FileLoader extends Loader * @throws FileLoaderImportCircularReferenceException * @throws FileLocatorFileNotFoundException */ - public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null) + public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null/*, $exclude = null*/) { + if (\func_num_args() < 5 && __CLASS__ !== \get_class($this) && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface) { + @trigger_error(sprintf('The "%s()" method will have a new "$exclude = null" argument in version 5.0, not defining it is deprecated since Symfony 4.4.', __METHOD__), E_USER_DEPRECATED); + } + $exclude = \func_num_args() >= 5 ? func_get_arg(4) : null; + if (\is_string($resource) && \strlen($resource) !== $i = strcspn($resource, '*?{[')) { + $excluded = []; + foreach ((array) $exclude as $pattern) { + foreach ($this->glob($pattern, true, $_, false, true) as $path => $info) { + // normalize Windows slashes + $excluded[str_replace('\\', '/', $path)] = true; + } + } + $ret = []; $isSubpath = 0 !== $i && false !== strpos(substr($resource, 0, $i), '/'); - foreach ($this->glob($resource, false, $_, $ignoreErrors || !$isSubpath) as $path => $info) { + foreach ($this->glob($resource, false, $_, $ignoreErrors || !$isSubpath, false, $excluded) as $path => $info) { if (null !== $res = $this->doImport($path, $type, $ignoreErrors, $sourceResource)) { $ret[] = $res; } diff --git a/src/Symfony/Component/Config/Tests/Fixtures/Include/ExcludeFile.txt b/src/Symfony/Component/Config/Tests/Fixtures/Include/ExcludeFile.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Symfony/Component/Config/Tests/Fixtures/Include/IncludeAnotherFile.txt b/src/Symfony/Component/Config/Tests/Fixtures/Include/IncludeAnotherFile.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Symfony/Component/Config/Tests/Fixtures/Include/IncludeFile.txt b/src/Symfony/Component/Config/Tests/Fixtures/Include/IncludeFile.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Symfony/Component/Config/Tests/Loader/FileLoaderTest.php b/src/Symfony/Component/Config/Tests/Loader/FileLoaderTest.php index f2f8818420..6cf625e6c7 100644 --- a/src/Symfony/Component/Config/Tests/Loader/FileLoaderTest.php +++ b/src/Symfony/Component/Config/Tests/Loader/FileLoaderTest.php @@ -92,6 +92,14 @@ class FileLoaderTest extends TestCase $this->assertSame(__FILE__, strtr($loader->import('FileLoaderTest.*'), '/', \DIRECTORY_SEPARATOR)); } + + public function testImportWithExclude() + { + $loader = new TestFileLoader(new FileLocator(__DIR__.'/../Fixtures')); + $loadedFiles = $loader->import('Include/*', null, false, null, __DIR__.'/../Fixtures/Include/{ExcludeFile.txt}'); + $this->assertCount(2, $loadedFiles); + $this->assertNotContains('ExcludeFile.txt', $loadedFiles); + } } class TestFileLoader extends FileLoader diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/GlobFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/GlobFileLoaderTest.php index 74822f5518..493e935611 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/GlobFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/GlobFileLoaderTest.php @@ -38,7 +38,7 @@ class GlobFileLoaderTest extends TestCase class GlobFileLoaderWithoutImport extends GlobFileLoader { - public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null) + public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null, $exclude = null) { } } diff --git a/src/Symfony/Component/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index 554997099d..4eebca6206 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Deprecated `ServiceRouterLoader` in favor of `ContainerLoader`. * Deprecated `ObjectRouteLoader` in favor of `ObjectLoader`. + * Added a way to exclude patterns of resources from being imported by the `import()` method 4.3.0 ----- diff --git a/src/Symfony/Component/Routing/Loader/Configurator/RoutingConfigurator.php b/src/Symfony/Component/Routing/Loader/Configurator/RoutingConfigurator.php index 33b6060abf..8ed06f307c 100644 --- a/src/Symfony/Component/Routing/Loader/Configurator/RoutingConfigurator.php +++ b/src/Symfony/Component/Routing/Loader/Configurator/RoutingConfigurator.php @@ -33,11 +33,14 @@ class RoutingConfigurator $this->file = $file; } - final public function import($resource, string $type = null, bool $ignoreErrors = false): ImportConfigurator + /** + * @param string|string[]|null $exclude Glob patterns to exclude from the import + */ + final public function import($resource, string $type = null, bool $ignoreErrors = false, $exclude = null): ImportConfigurator { $this->loader->setCurrentDir(\dirname($this->path)); - $imported = $this->loader->import($resource, $type, $ignoreErrors, $this->file) ?: []; + $imported = $this->loader->import($resource, $type, $ignoreErrors, $this->file, $exclude) ?: []; if (!\is_array($imported)) { return new ImportConfigurator($this->collection, $imported); } diff --git a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php index b7e7aeb410..dc208f28e1 100644 --- a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php @@ -163,10 +163,24 @@ class XmlFileLoader extends FileLoader throw new \InvalidArgumentException(sprintf('The element in file "%s" must not have both a "prefix" attribute and child nodes.', $path)); } + $exclude = []; + foreach ($node->childNodes as $child) { + if ($child instanceof \DOMElement && $child->localName === $exclude && self::NAMESPACE_URI === $child->namespaceURI) { + $exclude[] = $child->nodeValue; + } + } + + if ($node->hasAttribute('exclude')) { + if ($exclude) { + throw new \InvalidArgumentException('You cannot use both the attribute "exclude" and tags at the same time.'); + } + $exclude = [$node->getAttribute('exclude')]; + } + $this->setCurrentDir(\dirname($path)); /** @var RouteCollection[] $imported */ - $imported = $this->import($resource, ('' !== $type ? $type : null), false, $file) ?: []; + $imported = $this->import($resource, ('' !== $type ? $type : null), false, $file, $exclude) ?: []; if (!\is_array($imported)) { $imported = [$imported]; diff --git a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php index d9593fb3fd..0de36c93b2 100644 --- a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php @@ -28,7 +28,7 @@ use Symfony\Component\Yaml\Yaml; class YamlFileLoader extends FileLoader { private static $availableKeys = [ - 'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix', 'trailing_slash_on_root', 'locale', 'format', 'utf8', + 'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix', 'trailing_slash_on_root', 'locale', 'format', 'utf8', 'exclude', ]; private $yamlParser; @@ -169,6 +169,7 @@ class YamlFileLoader extends FileLoader $schemes = isset($config['schemes']) ? $config['schemes'] : null; $methods = isset($config['methods']) ? $config['methods'] : null; $trailingSlashOnRoot = $config['trailing_slash_on_root'] ?? true; + $exclude = $config['exclude'] ?? null; if (isset($config['controller'])) { $defaults['_controller'] = $config['controller']; @@ -185,7 +186,7 @@ class YamlFileLoader extends FileLoader $this->setCurrentDir(\dirname($path)); - $imported = $this->import($config['resource'], $type, false, $file) ?: []; + $imported = $this->import($config['resource'], $type, false, $file, $exclude) ?: []; if (!\is_array($imported)) { $imported = [$imported]; diff --git a/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd b/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd index ebf6632a57..8e61d03e9a 100644 --- a/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd +++ b/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd @@ -61,9 +61,11 @@ + + diff --git a/src/Symfony/Component/Routing/Tests/Loader/GlobFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/GlobFileLoaderTest.php index e4e12b8815..fd933e6c16 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/GlobFileLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/GlobFileLoaderTest.php @@ -38,7 +38,7 @@ class GlobFileLoaderTest extends TestCase class GlobFileLoaderWithoutImport extends GlobFileLoader { - public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null) + public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null, $exclude = null) { return new RouteCollection(); }