8000 added support for glob loaders in Config · symfony/symfony@025585d · GitHub
[go: up one dir, main page]

Skip to content

Commit 025585d

Browse files
committed
added support for glob loaders in Config
1 parent 8c6ad5b commit 025585d

File tree

6 files changed

+162
-94
lines changed

6 files changed

+162
-94
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@
3636
<argument type="service" id="file_locator" />
3737
</service>
3838

39+
<service id="routing.loader.glob" class="Symfony\Component\Config\Loader\GlobFileLoader" public="false">
40+
<tag name="routing.loader" />
41+
<argument type="service" id="file_locator" />
42+
</service>
43+
3944
<service id="routing.loader.directory" class="Symfony\Component\Routing\Loader\DirectoryLoader" public="false">
4045
<tag name="routing.loader" />
4146
<argument type="service" id="file_locator" />

src/Symfony/Component/Config/Loader/FileLoader.php

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
use Symfony\Component\Config\FileLocatorInterface;
1515
use Symfony\Component\Config\Exception\FileLoaderLoadException;
1616
use Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException;
17+
use Symfony\Component\Config\Exception\FileLocatorFileNotFoundException;
18+
use Symfony\Component\Finder\Finder;
19+
use Symfony\Component\Finder\Glob;
1720

1821
/**
1922
* FileLoader is the abstract class used by all built-in loaders that are file based.
@@ -32,7 +35,7 @@ abstract class FileLoader extends Loader
3235
*/
3336
protected $locator;
3437

35-
protected $currentDir;
38+
A93C private $currentDir;
3639

3740
/**
3841
* Constructor.
@@ -78,6 +81,87 @@ public function getLocator()
7881
* @throws FileLoaderImportCircularReferenceException
7982
*/
8083
public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null)
84+
{
85+
$ret = array();
86+
$ct = 0;
87+
foreach ($this->glob($resource, false, $_, $ignoreErrors) as $resource => $info) {
88+
++$ct;
89+
$ret[] = $this->doImport($resource, $type, $ignoreErrors, $sourceResource);
90+
}
91+
92+
return $ct > 1 ? $ret : isset($ret[0]) ? $ret[0] : null;
93+
}
94+
95+
/**
96+
* @internal
97+
*/
98+
protected function glob($resource, $recursive, &$prefix = null, $ignoreErrors = false)
99+
{
100+
if (strlen($resource) === $i = strcspn($resource, '*?{[')) {
101+
if (!$recursive) {
102+
$prefix = null;
103+
104+
yield $resource => new \SplFileInfo($resource);
105+
106+
return;
107+
}
108+
$prefix = $resource;
109+
$resource = '';
110+
} elseif (0 === $i) {
111+
$prefix = '.';
112+
$resource = '/'.$resource;
113+
} else {
114+
$prefix = dirname(substr($resource, 0, 1 + $i));
115+
$resource = substr($resource, strlen($prefix));
116+
}
117+
118+
try {
119+
$prefix = $this->locator->locate($prefix, $this->currentDir, true);
120+
} catch (FileLocatorFileNotFoundException $e) {
121+
if (!$ignoreErrors) {
122+
throw $e;
123+
}
124+
125+
return;
126+
}
127+
$prefix = realpath($prefix) ?: $prefix;
128+
129+
if (false === strpos($resource, '/**/') && (defined('GLOB_BRACE') || false === strpos($resource, '{'))) {
130+
foreach (glob($prefix.$resource, defined('GLOB_BRACE') ? GLOB_BRACE : 0) as $path) {
131+
if ($recursive && is_dir($path)) {
132+
$flags = \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS;
133+
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, $flags)) as $path => $info) {
134+
if ($info->isFile()) {
135+
yield $path => $info;
136+
}
137+
}
138+
} elseif (is_file($path)) {
139+
yield $path => new \SplFileInfo($path);
140+
}
141+
}
142+
143+
return;
144+
}
145+
146+
if (!class_exists(Finder::class)) {
147+
throw new LogicException(sprintf('Extended glob pattern "%s" cannot be used as the Finder component is not installed.', $resource));
148+
}
149+
150+
$finder = new Finder();
151+
$regex = Glob::toRegex($resource);
152+
if ($recursive) {
153+
$regex = substr_replace($regex, '(/|$)', -2, 1);
154+
}
155+
156+
$prefixLen = strlen($prefix);
157+
foreach ($finder->followLinks()->in($prefix) as $path => $info) {
158+
if (preg_match($regex, substr($path, $prefixLen)) && $info->isFile()) {
159+
yield $path => $info;
160+
}
161+
}
162+
}
163+
164+
private function doImport($resource, $type = null, $ignoreErrors = false, $sourceResource = null)
81165
{
82166
try {
83167
$loader = $this->resolve($resource, $type);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Config\Loader;
13+
14+
/**
15+
* GlobFileLoader loads files from a glob pattern.
16+
*
17+
* @author Fabien Potencier <fabien@symfony.com>
18+
*/
19+
class GlobFileLoader extends FileLoader
20+
{
21+
/**
22+
* {@inheritdoc}
23+
*/
24+
public function load($resource, $type = null)
25+
{
26+
return $this->import($resource, null, true);
27+
}
28+
29+
/**
30+
* {@inheritdoc}
31+
*/
32+
public function supports($resource, $type = null)
33+
{
34+
return 'glob' === $type;
35+
}
36+
}

src/Symfony/Component/DependencyInjection/Loader/FileLoader.php

Lines changed: 9 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,12 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Loader;
1313

14-
use Symfony\Component\Config\Exception\FileLocatorFileNotFoundException;
1514
use Symfony\Component\DependencyInjection\ChildDefinition;
1615
use Symfony\Component\DependencyInjection\ContainerBuilder;
1716
use Symfony\Component\DependencyInjection\Definition;
1817
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
19-
use Symfony\Component\DependencyInjection\Exception\LogicException;
2018
use Symfony\Component\Config\Loader\FileLoader as BaseFileLoader;
2119
use Symfony\Component\Config\FileLocatorInterface;
22-
use Symfony\Component\Finder\Finder;
23-
use Symfony\Component\Finder\Glob;
2420

2521
/**
2622
* FileLoader is the abstract class used by all built-in loaders that are file based.
@@ -44,22 +40,6 @@ public function __construct(ContainerBuilder $container, FileLocatorInterface $l
4440
parent::__construct($locator);
4541
}
4642

47-
/**
48-
* {@inheritdoc}
49-
*/
50-
public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null)
51-
{
52-
try {
53-
foreach ($this->glob($resource, false) as $path => $info) {
54-
parent::import($path, $type, $ignoreErrors, $sourceResource);
55-
}
56-
} catch (FileLocatorFileNotFoundException $e) {
57-
if (!$ignoreErrors) {
58-
throw $e;
59-
}
60-
}
61-
}
62-
6343
/**
6444
* Registers a set of classes as services using PSR-4 for discovery.
6545
*
@@ -106,8 +86,12 @@ private function findClasses($namespace, $resource)
10686
{
10787
$classes = array();
10888
$extRegexp = defined('HHVM_VERSION') ? '/\\.(?:php|hh)$/' : '/\\.php$/';
89+
$prefixLen = null;
90+
foreach ($this->glob($resource, true, $prefix) as $path => $info) {
91+
if (null === $prefixLen) {
92+
$prefixLen = strlen($prefix);
93+
}
10994

110-
foreach ($this->glob($resource, true, $prefixLen) as $path => $info) {
11195
if (!preg_match($extRegexp, $path, $m) || !$info->isReadable()) {
11296
continue;
11397
}
@@ -124,65 +108,11 @@ private function findClasses($namespace, $resource)
124108
}
125109
}
126110

127-
return $classes;
128-
}
129-
130-
private function glob($resource, $recursive, &$prefixLen = null)
131-
{
132-
if (strlen($resource) === $i = strcspn($resource, '*?{[')) {
133-
if (!$recursive) {
134-
yield $resource => new \SplFileInfo($resource);
135-
136-
return;
137-
}
138-
$resourcePrefix = $resource;
139-
$resource = '';
140-
} elseif (0 === $i) {
141-
$resourcePrefix = '.';
142-
$resource = '/'.$resource;
143-
} else {
144-
$resourcePrefix = dirname(substr($resource, 0, 1 + $i));
145-
$resource = substr($resource, strlen($resourcePrefix));
146-
}
147-
148-
$resourcePrefix = $this->locator->locate($resourcePrefix, $this->currentDir, true);
149-
$resourcePrefix = realpath($resourcePrefix) ?: $resourcePrefix;
150-
$prefixLen = strlen($resourcePrefix);
151-
152-
// track directories only for new & removed files
153-
$this->container->fileExists($resourcePrefix, '/^$/');
154-
155-
if (false === strpos($resource, '/**/') && (defined('GLOB_BRACE') || false === strpos($resource, '{'))) {
156-
foreach (glob($resourcePrefix.$resource, defined('GLOB_BRACE') ? GLOB_BRACE : 0) as $path) {
157-
if ($recursive && is_dir($path)) {
158-
$flags = \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS;
159-
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, $flags)) as $path => $info) {
160-
if ($info->isFile()) {
161-
yield $path => $info;
162-
}
163-
}
164-
} elseif (is_file($path)) {
165-
yield $path => new \SplFileInfo($path);
166-
}
167-
}
168-
169-
return;
111+
if (null !== $prefix) {
112+
// track directories only for new & removed files
113+
$this->container->fileExists($prefix, '/^$/');
170114
}
171115

172-
if (!class_exists(Finder::class)) {
173-
throw new LogicException(sprintf('Extended glob pattern "%s" cannot be used as the Finder component is not installed.', $resource));
174-
}
175-
176-
$finder = new Finder();
177-
$regex = Glob::toRegex($resource);
178-
if ($recursive) {
179-
$regex = substr_replace($regex, '(/|$)', -2, 1);
180-
}
181-
182-
foreach ($finder->followLinks()->in($resourcePrefix) as $path => $info) {
183-
if (preg_match($regex, substr($path, $prefixLen)) && $info->isFile()) {
184-
yield $path => $info;
185-
}
186-
}
116+
return $classes;
187117
}
188118
}

src/Symfony/Component/HttpKernel/Kernel.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
use Symfony\Component\HttpKernel\Config\FileLocator;
3030
use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass;
3131
use Symfony\Component\HttpKernel\DependencyInjection\AddClassesToCachePass;
32+
use Symfony\Component\Config\Loader\GlobFileLoader;
3233
use Symfony\Component\Config\Loader\LoaderResolver;
3334
use Symfony\Component\Config\Loader\DelegatingLoader;
3435
use Symfony\Component\Config\ConfigCache;
@@ -686,6 +687,7 @@ protected function getContainerLoader(ContainerInterface $container)
686687
new YamlFileLoader($container, $locator),
687688
new IniFileLoader($container, $locator),
688689
new PhpFileLoader($container, $locator),
690+
new GlobFileLoader($locator),
689691
new DirectoryLoader($container, $locator),
690692
new ClosureLoader($container),
691693
));

src/Symfony/Component/Routing/RouteCollectionBuilder.php

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,21 +61,28 @@ public function __construct(LoaderInterface $loader = null)
6161
*/
6262
public function import($resource, $prefix = '/', $type = null)
6363
{
64-
/** @var RouteCollection $collection */
65-
$collection = $this->load($resource, $type);
64+
/** @var RouteCollection[] $collection */
65+
$collections = $this->load($resource, $type);
6666

6767
// create a builder from the RouteCollection
6868
$builder = $this->createBuilder();
69-
foreach ($collection->all() as $name => $route) {
70-
$builder->addRoute($route, $name);
71-
}
7269

73-
foreach ($collection->getResources() as $resource) {
74-
$builder->addResource($resource);
75-
}
70+
foreach ($collections as $collection) {
71+
if (null === $collection) {
72+
continue;
73+
}
7674

77-
// mount into this builder
78-
$this->mount($prefix, $builder);
75+
foreach ($collection->all() as $name => $route) {
76+
$builder->addRoute($route, $name);
77+
}
78+
79+
foreach ($collection->getResources() as $resource) {
80+
$builder->addResource($resource);
81+
}
82+
83+
// mount into this builder
84+
$this->mount($prefix, $builder);
85+
}
7986

8087
return $builder;
8188
}
@@ -201,7 +208,7 @@ public function setRequirement($key, $regex)
201208
}
202209

203210
/**
204-
* Sets an opiton that will be added to all embedded routes (unless that
211+
* Sets an option that will be added to all embedded routes (unless that
205212
* option is already set).
206213
*
207214
* @param string $key
@@ -345,7 +352,7 @@ private function generateRouteName(Route $route)
345352
* @param mixed $resource A resource
346353
* @param string|null $type The resource type or null if unknown
347354
*
348-
* @return RouteCollection
355+
* @return RouteCollection[]
349356
*
350357
* @throws FileLoaderLoadException If no loader is found
351358
*/
@@ -356,7 +363,9 @@ private function load($resource, $type = null)
356363
}
357364

358365
if ($this->loader->supports($resource, $type)) {
359-
return $this->loader->load($resource, $type);
366+
$collections = $this->loader->load($resource, $type);
367+
368+
return is_array($collections) ? $collections : array($collections);
360369
}
361370

362371
if (null === $resolver = $this->loader->getResolver()) {
@@ -367,6 +376,8 @@ private function load($resource, $type = null)
367376
throw new FileLoaderLoadException($resource);
368377
}
369378

370-
return $loader->load($resource, $type);
379+
$collections = $loader->load($resource, $type);
380+
381+
return is_array($collections) ? $collections : array($collections);
371382
}
372383
}

0 commit comments

Comments
 (0)
0