Skip to content

Commit

Permalink
feature #21270 [DependencyInjection] Use glob pattern to load config …
Browse files Browse the repository at this point in the history
…files (pierredup)

This PR was merged into the 3.3-dev branch.

Discussion
----------

[DependencyInjection] Use glob pattern to load config files

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #21173
| License       | MIT
| Doc PR        | -

This relates to #21173, but I'm not sure if it completely fixes the issue.

This allows to use a glob pattern to load config files, which makes the following possible:

```
# config.yml
imports:
    - { resource: "*.yml" }
    - { resource: "folder/*.yml" }
    - { resource: "/etc/myapp/*.{yml,xml}" }
```

It can also be used in a container extension, if a bundle uses a lot of configs:

```
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('*.yml');
$loader->load('routing/*');
```

Commits
-------

519180e Use glob pattern to load config file
  • Loading branch information
fabpot committed Feb 14, 2017
2 parents 1079668 + 519180e commit 00d20ea
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/Symfony/Component/DependencyInjection/CHANGELOG.md
Expand Up @@ -23,6 +23,7 @@ CHANGELOG
* using the `PhpDumper` with an uncompiled `ContainerBuilder` is deprecated and
will not be supported anymore in 4.0
* deprecated the `DefinitionDecorator` class in favor of `ChildDefinition`
* allow config files to be loaded using a glob pattern

3.2.0
-----
Expand Down
32 changes: 28 additions & 4 deletions src/Symfony/Component/DependencyInjection/Loader/FileLoader.php
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Component\DependencyInjection\Loader;

use Symfony\Component\Config\Exception\FileLocatorFileNotFoundException;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -40,6 +41,22 @@ public function __construct(ContainerBuilder $container, FileLocatorInterface $l
parent::__construct($locator);
}

/**
* {@inheritdoc}
*/
public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null)
{
try {
foreach ($this->glob($resource, false) as $path => $info) {
parent::import($path, $type, $ignoreErrors, $sourceResource);
}
} catch (FileLocatorFileNotFoundException $e) {
if (!$ignoreErrors) {
throw $e;
}
}
}

/**
* Registers a set of classes as services using PSR-4 for discovery.
*
Expand Down Expand Up @@ -73,7 +90,7 @@ private function findClasses($namespace, $resource)
$extRegexp = defined('HHVM_VERSION') ? '/\\.(?:php|hh)$/' : '/\\.php$/';

foreach ($this->glob($resource, true, $prefixLen) as $path => $info) {
if (!preg_match($extRegexp, $path, $m) || !$info->isFile() || !$info->isReadable()) {
if (!preg_match($extRegexp, $path, $m) || !$info->isReadable()) {
continue;
}
$class = $namespace.ltrim(str_replace('/', '\\', substr($path, $prefixLen, -strlen($m[0]))), '\\');
Expand All @@ -95,6 +112,11 @@ private function findClasses($namespace, $resource)
private function glob($resource, $recursive, &$prefixLen = null)
{
if (strlen($resource) === $i = strcspn($resource, '*?{[')) {
if (!$recursive) {
yield $resource => new \SplFileInfo($resource);

return;
}
$resourcePrefix = $resource;
$resource = '';
} elseif (0 === $i) {
Expand All @@ -117,9 +139,11 @@ private function glob($resource, $recursive, &$prefixLen = null)
if ($recursive && is_dir($path)) {
$flags = \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS;
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, $flags)) as $path => $info) {
yield $path => $info;
if ($info->isFile()) {
yield $path => $info;
}
}
} else {
} elseif (is_file($path)) {
yield $path => new \SplFileInfo($path);
}
}
Expand All @@ -138,7 +162,7 @@ private function glob($resource, $recursive, &$prefixLen = null)
}

foreach ($finder->followLinks()->in($resourcePrefix) as $path => $info) {
if (preg_match($regex, substr($path, $prefixLen))) {
if (preg_match($regex, substr($path, $prefixLen)) && $info->isFile()) {
yield $path => $info;
}
}
Expand Down
@@ -0,0 +1,88 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\DependencyInjection\Tests\Loader;

use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Loader\LoaderResolver;
use Symfony\Component\DependencyInjection\ContainerBuilder;
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;

class FileLoaderTest extends \PHPUnit_Framework_TestCase
{
protected static $fixturesPath;

public static function setUpBeforeClass()
{
self::$fixturesPath = realpath(__DIR__.'/../');
}

public function testImportWithGlobPattern()
{
$container = new ContainerBuilder();
$loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath));

$resolver = new LoaderResolver(array(
new IniFileLoader($container, new FileLocator(self::$fixturesPath.'/ini')),
new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')),
new PhpFileLoader($container, new FileLocator(self::$fixturesPath.'/php')),
new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')),
));

$loader->setResolver($resolver);
$loader->import('{F}ixtures/{xml,yaml}/services2.{yml,xml}');

$actual = $container->getParameterBag()->all();
$expected = array(
'a string',
'foo' => 'bar',
'values' => array(
0,
'integer' => 4,
100 => null,
'true',
true,
false,
'on',
'off',
'float' => 1.3,
1000.3,
'a string',
array('foo', 'bar'),
),
'mixedcase' => array('MixedCaseKey' => 'value'),
'constant' => PHP_EOL,
'bar' => '%foo%',
'escape' => '@escapeme',
'foo_bar' => new Reference('foo_bar'),
);

$this->assertEquals(array_keys($expected), array_keys($actual), '->load() imports and merges imported files');
}
}

class TestFileLoader extends FileLoader
{
public function load($resource, $type = null)
{
return $resource;
}

public function supports($resource, $type = null)
{
return false;
}
}

0 comments on commit 00d20ea

Please sign in to comment.