diff --git a/src/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php b/src/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php index d9ad2b1054..1e3117fd51 100644 --- a/src/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php +++ b/src/Symfony/Component/Finder/Adapter/AbstractFindAdapter.php @@ -154,6 +154,11 @@ abstract class AbstractFindAdapter extends AbstractAdapter foreach ($names as $i => $name) { $expr = Expression::create($name); + // Find does not support expandable globs ("*.{a,b}" syntax). + if ($expr->isGlob() && $expr->getGlob()->isExpandable()) { + $expr = Expression::create($expr->getGlob()->toRegex(false)); + } + // Fixes 'not search' and 'full path matching' regex problems. // - Jokers '.' are replaced by [^/]. // - We add '[^/]*' before and after regex (if no ^|$ flags are present). @@ -197,6 +202,11 @@ abstract class AbstractFindAdapter extends AbstractAdapter foreach ($paths as $i => $path) { $expr = Expression::create($path); + // Find does not support expandable globs ("*.{a,b}" syntax). + if ($expr->isGlob() && $expr->getGlob()->isExpandable()) { + $expr = Expression::create($expr->getGlob()->toRegex(false)); + } + // Fixes 'not search' regex problems. if ($expr->isRegex()) { $regex = $expr->getRegex(); diff --git a/src/Symfony/Component/Finder/Expression/Expression.php b/src/Symfony/Component/Finder/Expression/Expression.php index 9c87ddf3da..ceedbc18a9 100644 --- a/src/Symfony/Component/Finder/Expression/Expression.php +++ b/src/Symfony/Component/Finder/Expression/Expression.php @@ -122,6 +122,20 @@ class Expression implements ValueInterface return self::TYPE_GLOB === $this->value->getType(); } + /** + * @throws \LogicException + * + * @return Glob + */ + public function getGlob() + { + if (self::TYPE_GLOB !== $this->value->getType()) { + throw new \LogicException('Regex cant be transformed to glob.'); + } + + return $this->value; + } + /** * @return Regex */ diff --git a/src/Symfony/Component/Finder/Expression/Glob.php b/src/Symfony/Component/Finder/Expression/Glob.php index f6af7d0129..3023ceea69 100644 --- a/src/Symfony/Component/Finder/Expression/Glob.php +++ b/src/Symfony/Component/Finder/Expression/Glob.php @@ -81,6 +81,17 @@ class Glob implements ValueInterface return $this; } + /** + * Tests if glob is expandable ("*.{a,b}" syntax). + * + * @return bool + */ + public function isExpandable() + { + return false !== strpos($this->pattern, '{') + && false !== strpos($this->pattern, '}'); + } + /** * @param bool $strictLeadingDot * @param bool $strictWildcardSlash diff --git a/src/Symfony/Component/Finder/Tests/FinderTest.php b/src/Symfony/Component/Finder/Tests/FinderTest.php index c919264f2e..854fe4ee3c 100644 --- a/src/Symfony/Component/Finder/Tests/FinderTest.php +++ b/src/Symfony/Component/Finder/Tests/FinderTest.php @@ -106,6 +106,10 @@ class FinderTest extends Iterator\RealIteratorTestCase $finder = $this->buildFinder($adapter); $finder->name('~\\.php$~i'); $this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator()); + + $finder = $this->buildFinder($adapter); + $finder->name('test.p{hp,y}'); + $this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator()); } /** @@ -128,6 +132,12 @@ class FinderTest extends Iterator\RealIteratorTestCase $finder->notName('*.php'); $finder->notName('*.py'); $this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator()); + + $finder = $this->buildFinder($adapter); + $finder->name('test.ph*'); + $finder->name('test.py'); + $finder->notName('*.p{hp,y}'); + $this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator()); } /**