[Routing][Config] Allow patterns of resources to be excluded from config loading
This commit is contained in:
parent
791810a4e1
commit
332ff8811c
|
@ -19,6 +19,11 @@ Debug
|
||||||
* Deprecated the `FlattenException` class, use the one from the `ErrorRenderer` component instead
|
* Deprecated the `FlattenException` class, use the one from the `ErrorRenderer` component instead
|
||||||
* Deprecated the component in favor of the `ErrorHandler` component
|
* Deprecated the component in favor of the `ErrorHandler` component
|
||||||
|
|
||||||
|
Config
|
||||||
|
------
|
||||||
|
|
||||||
|
* Deprecated overriding the `FilerLoader::import()` method without declaring the optional `$exclude` argument
|
||||||
|
|
||||||
DependencyInjection
|
DependencyInjection
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ Config
|
||||||
* Removed `FileLoaderLoadException`, use `LoaderLoadException` instead.
|
* Removed `FileLoaderLoadException`, use `LoaderLoadException` instead.
|
||||||
* Using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` will throw an exception.
|
* 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
|
* 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
|
Console
|
||||||
-------
|
-------
|
||||||
|
@ -411,6 +412,7 @@ Routing
|
||||||
with the new serialization methods in PHP 7.4.
|
with the new serialization methods in PHP 7.4.
|
||||||
* Removed `ServiceRouterLoader` and `ObjectRouteLoader`.
|
* Removed `ServiceRouterLoader` and `ObjectRouteLoader`.
|
||||||
* Service route loaders must be tagged with `routing.route_loader`.
|
* Service route loaders must be tagged with `routing.route_loader`.
|
||||||
|
* The `RoutingConfigurator::import()` method has a new optional `$exclude` argument.
|
||||||
|
|
||||||
Security
|
Security
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
4.4.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* added a way to exclude patterns of resources from being imported by the `import()` method
|
||||||
|
|
||||||
4.3.0
|
4.3.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
|
@ -59,10 +59,11 @@ abstract class FileLoader extends Loader
|
||||||
/**
|
/**
|
||||||
* Imports a resource.
|
* Imports a resource.
|
||||||
*
|
*
|
||||||
* @param mixed $resource A Resource
|
* @param mixed $resource A Resource
|
||||||
* @param string|null $type The resource type or null if unknown
|
* @param string|null $type The resource type or null if unknown
|
||||||
* @param bool $ignoreErrors Whether to ignore import errors or not
|
* @param bool $ignoreErrors Whether to ignore import errors or not
|
||||||
* @param string|null $sourceResource The original resource importing the new resource
|
* @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
|
* @return mixed
|
||||||
*
|
*
|
||||||
|
@ -70,12 +71,25 @@ abstract class FileLoader extends Loader
|
||||||
* @throws FileLoaderImportCircularReferenceException
|
* @throws FileLoaderImportCircularReferenceException
|
||||||
* @throws FileLocatorFileNotFoundException
|
* @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, '*?{[')) {
|
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 = [];
|
$ret = [];
|
||||||
$isSubpath = 0 !== $i && false !== strpos(substr($resource, 0, $i), '/');
|
$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)) {
|
if (null !== $res = $this->doImport($path, $type, $ignoreErrors, $sourceResource)) {
|
||||||
$ret[] = $res;
|
$ret[] = $res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,14 @@ class FileLoaderTest extends TestCase
|
||||||
|
|
||||||
$this->assertSame(__FILE__, strtr($loader->import('FileLoaderTest.*'), '/', \DIRECTORY_SEPARATOR));
|
$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
|
class TestFileLoader extends FileLoader
|
||||||
|
|
|
@ -38,7 +38,7 @@ class GlobFileLoaderTest extends TestCase
|
||||||
|
|
||||||
class GlobFileLoaderWithoutImport extends GlobFileLoader
|
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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ CHANGELOG
|
||||||
|
|
||||||
* Deprecated `ServiceRouterLoader` in favor of `ContainerLoader`.
|
* Deprecated `ServiceRouterLoader` in favor of `ContainerLoader`.
|
||||||
* Deprecated `ObjectRouteLoader` in favor of `ObjectLoader`.
|
* Deprecated `ObjectRouteLoader` in favor of `ObjectLoader`.
|
||||||
|
* Added a way to exclude patterns of resources from being imported by the `import()` method
|
||||||
|
|
||||||
4.3.0
|
4.3.0
|
||||||
-----
|
-----
|
||||||
|
|
|
@ -33,11 +33,14 @@ class RoutingConfigurator
|
||||||
$this->file = $file;
|
$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));
|
$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)) {
|
if (!\is_array($imported)) {
|
||||||
return new ImportConfigurator($this->collection, $imported);
|
return new ImportConfigurator($this->collection, $imported);
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,10 +163,24 @@ class XmlFileLoader extends FileLoader
|
||||||
throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must not have both a "prefix" attribute and <prefix> child nodes.', $path));
|
throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must not have both a "prefix" attribute and <prefix> 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 <exclude> tags at the same time.');
|
||||||
|
}
|
||||||
|
$exclude = [$node->getAttribute('exclude')];
|
||||||
|
}
|
||||||
|
|
||||||
$this->setCurrentDir(\dirname($path));
|
$this->setCurrentDir(\dirname($path));
|
||||||
|
|
||||||
/** @var RouteCollection[] $imported */
|
/** @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)) {
|
if (!\is_array($imported)) {
|
||||||
$imported = [$imported];
|
$imported = [$imported];
|
||||||
|
|
|
@ -28,7 +28,7 @@ use Symfony\Component\Yaml\Yaml;
|
||||||
class YamlFileLoader extends FileLoader
|
class YamlFileLoader extends FileLoader
|
||||||
{
|
{
|
||||||
private static $availableKeys = [
|
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;
|
private $yamlParser;
|
||||||
|
|
||||||
|
@ -169,6 +169,7 @@ class YamlFileLoader extends FileLoader
|
||||||
$schemes = isset($config['schemes']) ? $config['schemes'] : null;
|
$schemes = isset($config['schemes']) ? $config['schemes'] : null;
|
||||||
$methods = isset($config['methods']) ? $config['methods'] : null;
|
$methods = isset($config['methods']) ? $config['methods'] : null;
|
||||||
$trailingSlashOnRoot = $config['trailing_slash_on_root'] ?? true;
|
$trailingSlashOnRoot = $config['trailing_slash_on_root'] ?? true;
|
||||||
|
$exclude = $config['exclude'] ?? null;
|
||||||
|
|
||||||
if (isset($config['controller'])) {
|
if (isset($config['controller'])) {
|
||||||
$defaults['_controller'] = $config['controller'];
|
$defaults['_controller'] = $config['controller'];
|
||||||
|
@ -185,7 +186,7 @@ class YamlFileLoader extends FileLoader
|
||||||
|
|
||||||
$this->setCurrentDir(\dirname($path));
|
$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)) {
|
if (!\is_array($imported)) {
|
||||||
$imported = [$imported];
|
$imported = [$imported];
|
||||||
|
|
|
@ -61,9 +61,11 @@
|
||||||
<xsd:sequence maxOccurs="unbounded" minOccurs="0">
|
<xsd:sequence maxOccurs="unbounded" minOccurs="0">
|
||||||
<xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
|
<xsd:group ref="configs" minOccurs="0" maxOccurs="unbounded" />
|
||||||
<xsd:element name="prefix" type="localized-path" minOccurs="0" maxOccurs="unbounded" />
|
<xsd:element name="prefix" type="localized-path" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
<xsd:element name="exclude" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
|
||||||
</xsd:sequence>
|
</xsd:sequence>
|
||||||
<xsd:attribute name="resource" type="xsd:string" use="required" />
|
<xsd:attribute name="resource" type="xsd:string" use="required" />
|
||||||
<xsd:attribute name="type" type="xsd:string" />
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="exclude" type="xsd:string" />
|
||||||
<xsd:attribute name="prefix" type="xsd:string" />
|
<xsd:attribute name="prefix" type="xsd:string" />
|
||||||
<xsd:attribute name="name-prefix" type="xsd:string" />
|
<xsd:attribute name="name-prefix" type="xsd:string" />
|
||||||
<xsd:attribute name="host" type="xsd:string" />
|
<xsd:attribute name="host" type="xsd:string" />
|
||||||
|
|
|
@ -38,7 +38,7 @@ class GlobFileLoaderTest extends TestCase
|
||||||
|
|
||||||
class GlobFileLoaderWithoutImport extends GlobFileLoader
|
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();
|
return new RouteCollection();
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue