Skip to content

Commit c4607ec

Browse files
[Config] fix path exclusion during glob discovery
1 parent 799ad2e commit c4607ec

File tree

3 files changed

+45
-25
lines changed

3 files changed

+45
-25
lines changed

src/Symfony/Component/Config/Resource/GlobResource.php

+22-3
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface,
3939
*/
4040
public function __construct(?string $prefix, string $pattern, bool $recursive, bool $forExclusion = false, array $excludedPrefixes = array())
4141
{
42-
$this->prefix = realpath($prefix) ?: (file_exists($prefix) ? $prefix : false);
42+
$this->prefix = str_replace('\\', '/', realpath($prefix) ?: (file_exists($prefix) ? $prefix : false));
4343
$this->pattern = $pattern;
4444
$this->recursive = $recursive;
4545
$this->forExclusion = $forExclusion;
@@ -99,6 +99,15 @@ public function getIterator()
9999

100100
if (0 !== strpos($this->prefix, 'phar://') && false === strpos($this->pattern, '/**/') && (\defined('GLOB_BRACE') || false === strpos($this->pattern, '{'))) {
101101
foreach (glob($this->prefix.$this->pattern, \defined('GLOB_BRACE') ? GLOB_BRACE : 0) as $path) {
102+
if ($this->excludedPrefixes) {
103+
$normalizedPath = str_replace('\\', '/', $path);
104+
do {
105+
if (isset($this->excludedPrefixes[$dirPath = $normalizedPath])) {
106+
continue 2;
107+
}
108+
} while ($this->prefix !== $dirPath && $dirPath !== $normalizedPath = \dirname($dirPath));
109+
}
110+
102111
if (is_file($path)) {
103112
yield $path => new \SplFileInfo($path);
104113
}
@@ -145,9 +154,19 @@ function (\SplFileInfo $file, $path) {
145154

146155
$prefixLen = \strlen($this->prefix);
147156
foreach ($finder->followLinks()->sortByName()->in($this->prefix) as $path => $info) {
148-
if (preg_match($regex, substr(str_replace('\\', '/', $path), $prefixLen)) && $info->isFile()) {
149-
yield $path => $info;
157+
$normalizedPath = str_replace('\\', '/', $path);
158+
if (!preg_match($regex, substr($normalizedPath, $prefixLen)) || !$info->isFile()) {
159+
continue;
150160
}
161+
if ($this->excludedPrefixes) {
162+
do {
163+
if (isset($this->excludedPrefixes[$dirPath = $normalizedPath])) {
164+
continue 2;
165+
}
166+
} while ($this->prefix !== $dirPath && $dirPath !== $normalizedPath = \dirname($dirPath));
167+
}
168+
169+
yield $path => $info;
151170
}
152171
}
153172

src/Symfony/Component/Config/Tests/Resource/GlobResourceTest.php

+14
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,20 @@ public function testIteratorSkipsFoldersForGivenExcludedPrefixes()
7373
$this->assertArrayNotHasKey($file, $paths);
7474
}
7575

76+
public function testIteratorSkipsSubfoldersForGivenExcludedPrefixes()
77+
{
78+
$dir = \dirname(__DIR__).\DIRECTORY_SEPARATOR.'Fixtures';
79+
$resource = new GlobResource($dir, '/*Exclude/*', true, false, array($dir.\DIRECTORY_SEPARATOR.'Exclude' => true));
80+
81+
$paths = iterator_to_array($resource);
82+
83+
$file = $dir.\DIRECTORY_SEPARATOR.'Exclude'.\DIRECTORY_SEPARATOR.'AnExcludedFile.txt';
84+
$this->assertArrayNotHasKey($file, $paths);
85+
86+
$file = $dir.\DIRECTORY_SEPARATOR.'Exclude'.\DIRECTORY_SEPARATOR.'ExcludeToo'.\DIRECTORY_SEPARATOR.'AnotheExcludedFile.txt';
87+
$this->assertArrayNotHasKey($file, $paths);
88+
}
89+
7690
public function testIteratorSkipsFoldersWithForwardSlashForGivenExcludedPrefixes()
7791
{
7892
$dir = \dirname(__DIR__).\DIRECTORY_SEPARATOR.'Fixtures';

src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php

+9-22
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
use Symfony\Component\DependencyInjection\ContainerBuilder;
1919
use Symfony\Component\DependencyInjection\ContainerInterface;
2020
use Symfony\Component\DependencyInjection\Definition;
21-
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
2221
use Symfony\Component\DependencyInjection\Loader\FileLoader;
2322
use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
2423
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
@@ -217,32 +216,20 @@ public function testRegisterClassesWithBadPrefix()
217216
}
218217

219218
/**
220-
* @dataProvider getIncompatibleExcludeTests
219+
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
220+
* @expectedExceptionMessage Invalid "exclude" pattern when importing classes for "Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\": make sure your "exclude" pattern (yaml/*) is a subset of the "resource" pattern (Prototype/*)
221221
*/
222-
public function testRegisterClassesWithIncompatibleExclude($resourcePattern, $excludePattern)
222+
public function testRegisterClassesWithIncompatibleExclude()
223223
{
224224
$container = new ContainerBuilder();
225225
$loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures'));
226226

227-
try {
228-
$loader->registerClasses(
229-
new Definition(),
230-
'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\',
231-
$resourcePattern,
232-
$excludePattern
233-
);
234-
} catch (InvalidArgumentException $e) {
235-
$this->assertEquals(
236-
sprintf('Invalid "exclude" pattern when importing classes for "Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\": make sure your "exclude" pattern (%s) is a subset of the "resource" pattern (%s)', $excludePattern, $resourcePattern),
237-
$e->getMessage()
238-
);
239-
}
240-
}
241-
242-
public function getIncompatibleExcludeTests()
243-
{
244-
yield array('Prototype/*', 'yaml/*', false);
245-
yield array('Prototype/OtherDir/*', 'Prototype/*', false);
227+
$loader->registerClasses(
228+
new Definition(),
229+
'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\',
230+
'Prototype/*',
231+
'yaml/*'
232+
);
246233
}
247234
}
248235

0 commit comments

Comments
 (0)