diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 18e64be813bc..c118ed3d2aa2 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -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 ----- diff --git a/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php index c09ed5d2bdba..68cf818c5bb4 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php @@ -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; @@ -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. * @@ -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]))), '\\'); @@ -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) { @@ -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); } } @@ -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; } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php new file mode 100644 index 000000000000..956bfd7e4f26 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php @@ -0,0 +1,88 @@ + + * + * 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; + } +}