Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[Component][Finder] ->path(), ->notPath() methods (with basic tests)

  • Loading branch information...
commit 7ff1cb63374fb2699f96dafa3d5a85841cdbce56 1 parent 6436f61
@gajdaw gajdaw authored
View
23 Adapter/AbstractAdapter.php
@@ -31,6 +31,8 @@
protected $dates = array();
protected $filters = array();
protected $sort = false;
+ protected $paths = array();
+ protected $notPaths = array();
/**
* {@inheritdoc}
@@ -171,4 +173,25 @@ public function setSort($sort)
return $this;
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPath(array $paths)
+ {
+ $this->paths = $paths;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setNotPath(array $notPaths)
+ {
+ $this->notPaths = $notPaths;
+
+ return $this;
+ }
+
}
View
4 Adapter/PhpAdapter.php
@@ -73,6 +73,10 @@ public function searchInDirectory($dir)
$iterator = $iteratorAggregate->getIterator();
}
+ if ($this->paths || $this->notPaths) {
+ $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
+ }
+
return $iterator;
}
View
52 Finder.php
@@ -52,6 +52,8 @@ class Finder implements \IteratorAggregate, \Countable
private $contains = array();
private $notContains = array();
private $adapters = array();
+ private $paths = array();
+ private $notPaths = array();
private static $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');
@@ -284,6 +286,52 @@ public function notContains($pattern)
}
/**
+ * Adds rules that filenames must match.
+ *
+ * You can use patterns (delimited with / sign) or simple strings.
+ *
+ * $finder->path('some/special/dir')
+ * $finder->path('/some\/special\/dir/') // same as above
+ *
+ * Use only / as dirname separator.
+ *
+ * @param string $pattern A pattern (a regexp or a string)
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see Symfony\Component\Finder\Iterator\FilenameFilterIterator
+ */
+ public function path($pattern)
+ {
+ $this->paths[] = $pattern;
+
+ return $this;
+ }
+
+ /**
+ * Adds rules that filenames must not match.
+ *
+ * You can use patterns (delimited with / sign) or simple strings.
+ *
+ * $finder->notPath('some/special/dir')
+ * $finder->notPath('/some\/special\/dir/') // same as above
+ *
+ * Use only / as dirname separator.
+ *
+ * @param string $pattern A pattern (a regexp or a string)
+ *
+ * @return Finder The current Finder instance
+ *
+ * @see Symfony\Component\Finder\Iterator\FilenameFilterIterator
+ */
+ public function notPath($pattern)
+ {
+ $this->notPaths[] = $pattern;
+
+ return $this;
+ }
+
+ /**
* Adds tests for file sizes.
*
* $finder->size('> 10K');
@@ -682,6 +730,8 @@ private function buildAdapter(AdapterInterface $adapter)
->setSizes($this->sizes)
->setDates($this->dates)
->setFilters($this->filters)
- ->setSort($this->sort);
+ ->setSort($this->sort)
+ ->setPath($this->paths)
+ ->setNotPath($this->notPaths);
}
}
View
75 Iterator/PathFilterIterator.php
@@ -0,0 +1,75 @@
+<?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\Finder\Iterator;
+
+/**
+ * PathFilterIterator filters files by path patterns (e.g. some/special/dir).
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
+ */
+class PathFilterIterator extends MultiplePcreFilterIterator
+{
+
+ /**
+ * Filters the iterator values.
+ *
+ * @return Boolean true if the value should be kept, false otherwise
+ */
+ public function accept()
+ {
+ $filename = $this->current()->getRelativePathname();
+
+ if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
+ $filename = strtr($filename, '\\', '/');
+ }
+
+ // should at least not match one rule to exclude
+ foreach ($this->noMatchRegexps as $regex) {
+ if (preg_match($regex, $filename)) {
+ return false;
+ }
+ }
+
+ // should at least match one rule
+ $match = true;
+ if ($this->matchRegexps) {
+ $match = false;
+ foreach ($this->matchRegexps as $regex) {
+ if (preg_match($regex, $filename)) {
+ return true;
+ }
+ }
+ }
+
+ return $match;
+ }
+
+ /**
+ * Converts strings to regexp.
+ *
+ * PCRE patterns are left unchanged.
+ *
+ * Default conversion:
+ * 'lorem/ipsum/dolor' ==> 'lorem\/ipsum\/dolor/'
+ *
+ * Use only / as directory separator (on Windows also).
+ *
+ * @param string $str Pattern: regexp or dirname.
+ *
+ * @return string regexp corresponding to a given string or regexp
+ */
+ protected function toRegex($str)
+ {
+ return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
+ }
+}
View
61 Tests/FinderTest.php
@@ -646,4 +646,65 @@ private function buildTestData(array $tests)
return $data;
}
+
+ /**
+ * @dataProvider getTestPathData
+ */
+ public function testPath($matchPatterns, $noMatchPatterns, $expected)
+ {
+ $finder = new Finder();
+ $finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures')
+ ->path($matchPatterns)
+ ->notPath($noMatchPatterns);
+
+ $this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
+ }
+
+ public function getTestPathData()
+ {
+ return array(
+ array('', '', array()),
+
+ array('/^A\/B\/C/', '/C$/',
+ array('A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat')
+ ),
+
+ array('/^A\/B/', 'foobar',
+ array(
+ 'A'.DIRECTORY_SEPARATOR.'B',
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
+ )
+ ),
+
+ array('A/B/C', 'foobar',
+ array(
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat.copy',
+ )
+ ),
+
+ array('A/B', 'foobar',
+ array(
+ //dirs
+ 'A'.DIRECTORY_SEPARATOR.'B',
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B',
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C',
+
+ //files
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat',
+ 'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat',
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'ab.dat.copy',
+ 'copy'.DIRECTORY_SEPARATOR.'A'.DIRECTORY_SEPARATOR.'B'.DIRECTORY_SEPARATOR.'C'.DIRECTORY_SEPARATOR.'abc.dat.copy',
+ )
+ ),
+
+
+ );
+ }
+
}
View
0  Tests/Fixtures/A/B/C/abc.dat
No changes.
View
0  Tests/Fixtures/A/B/ab.dat
No changes.
View
0  Tests/Fixtures/A/a.dat
No changes.
View
0  Tests/Fixtures/copy/A/B/C/abc.dat.copy
No changes.
View
0  Tests/Fixtures/copy/A/B/ab.dat.copy
No changes.
View
0  Tests/Fixtures/copy/A/a.dat.copy
No changes.
View
106 Tests/Iterator/FilecontentFilterIteratorTest.php
@@ -12,6 +12,8 @@
namespace Symfony\Component\Finder\Tests\Iterator;
use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
+use Symfony\Component\Finder\Tests\Iterator\MockSplFileInfo;
+use Symfony\Component\Finder\Tests\Iterator\MockFileListIterator;
class FilecontentFilterIteratorTest extends IteratorTestCase
{
@@ -85,107 +87,3 @@ public function getTestFilterData()
);
}
}
-
-class MockSplFileInfo extends \SplFileInfo
-{
- const TYPE_DIRECTORY = 1;
- const TYPE_FILE = 2;
- const TYPE_UNKNOWN = 3;
-
- private $contents = null;
- private $mode = null;
- private $type = null;
-
- public function __construct($param)
- {
- if (is_string($param)) {
- parent::__construct($param);
- } elseif (is_array($param)) {
-
- $defaults = array(
- 'name' => 'file.txt',
- 'contents' => null,
- 'mode' => null,
- 'type' => null
- );
- $defaults = array_merge($defaults, $param);
- parent::__construct($defaults['name']);
- $this->setContents($defaults['contents']);
- $this->setMode($defaults['mode']);
- $this->setType($defaults['type']);
- } else {
- throw new \RuntimeException(sprintf('Incorrect parameter "%s"', $param));
- }
- }
-
- public function isFile()
- {
- if ($this->type === null) {
- return preg_match('/file/', $this->getFilename());
- };
-
- return self::TYPE_FILE === $this->type;
- }
-
- public function isDir()
- {
- if ($this->type === null) {
- return preg_match('/directory/', $this->getFilename());
- }
-
- return self::TYPE_DIRECTORY === $this->type;
- }
-
- public function isReadable()
- {
- if ($this->mode === null) {
- return preg_match('/r\+/', $this->getFilename());
- }
-
- return preg_match('/r\+/', $this->mode);
- }
-
- public function getContents()
- {
- return $this->contents;
- }
-
- public function setContents($contents)
- {
- $this->contents = $contents;
- }
-
- public function setMode($mode)
- {
- $this->mode = $mode;
- }
-
- public function setType($type)
- {
- if (is_string($type)) {
- switch ($type) {
- case 'directory':
- case 'd':
- $this->type = self::TYPE_DIRECTORY;
- break;
- case 'file':
- case 'f':
- $this->type = self::TYPE_FILE;
- break;
- default:
- $this->type = self::TYPE_UNKNOWN;
- }
- } else {
- $this->type = $type;
- }
- }
-}
-
-class MockFileListIterator extends \ArrayIterator
-{
- public function __construct(array $filesArray = array())
- {
- $files = array_map(function($file){ return new MockSplFileInfo($file); }, $filesArray);
- parent::__construct($files);
- }
-}
View
21 Tests/Iterator/MockFileListIterator.php
@@ -0,0 +1,21 @@
+<?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\Finder\Tests\Iterator;
+
+class MockFileListIterator extends \ArrayIterator
+{
+ public function __construct(array $filesArray = array())
+ {
+ $files = array_map(function($file){ return new MockSplFileInfo($file); }, $filesArray);
+ parent::__construct($files);
+ }
+}
View
136 Tests/Iterator/MockSplFileInfo.php
@@ -0,0 +1,136 @@
+<?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\Finder\Tests\Iterator;
+
+class MockSplFileInfo extends \SplFileInfo
+{
+ const TYPE_DIRECTORY = 1;
+ const TYPE_FILE = 2;
+ const TYPE_UNKNOWN = 3;
+
+ private $contents = null;
+ private $mode = null;
+ private $type = null;
+ private $relativePath = null;
+ private $relativePathname = null;
+
+ public function __construct($param)
+ {
+ if (is_string($param)) {
+ parent::__construct($param);
+ } elseif (is_array($param)) {
+
+ $defaults = array(
+ 'name' => 'file.txt',
+ 'contents' => null,
+ 'mode' => null,
+ 'type' => null,
+ 'relativePath' => null,
+ 'relativePathname' => null,
+ );
+ $defaults = array_merge($defaults, $param);
+ parent::__construct($defaults['name']);
+ $this->setContents($defaults['contents']);
+ $this->setMode($defaults['mode']);
+ $this->setType($defaults['type']);
+ $this->setRelativePath($defaults['relativePath']);
+ $this->setRelativePathname($defaults['relativePathname']);
+ } else {
+ throw new \RuntimeException(sprintf('Incorrect parameter "%s"', $param));
+ }
+ }
+
+ public function isFile()
+ {
+ if ($this->type === null) {
+ return preg_match('/file/', $this->getFilename());
+ };
+
+ return self::TYPE_FILE === $this->type;
+ }
+
+ public function isDir()
+ {
+ if ($this->type === null) {
+ return preg_match('/directory/', $this->getFilename());
+ }
+
+ return self::TYPE_DIRECTORY === $this->type;
+ }
+
+ public function isReadable()
+ {
+ if ($this->mode === null) {
+ return preg_match('/r\+/', $this->getFilename());
+ }
+
+ return preg_match('/r\+/', $this->mode);
+ }
+
+ public function getContents()
+ {
+ return $this->contents;
+ }
+
+ public function setContents($contents)
+ {
+ $this->contents = $contents;
+ }
+
+ public function setMode($mode)
+ {
+ $this->mode = $mode;
+ }
+
+ public function setType($type)
+ {
+ if (is_string($type)) {
+ switch ($type) {
+ case 'directory':
+ $this->type = self::TYPE_DIRECTORY;
+ case 'd':
+ $this->type = self::TYPE_DIRECTORY;
+ break;
+ case 'file':
+ $this->type = self::TYPE_FILE;
+ case 'f':
+ $this->type = self::TYPE_FILE;
+ break;
+ default:
+ $this->type = self::TYPE_UNKNOWN;
+ }
+ } else {
+ $this->type = $type;
+ }
+ }
+
+ public function setRelativePath($relativePath)
+ {
+ $this->relativePath = $relativePath;
+ }
+
+ public function setRelativePathname($relativePathname)
+ {
+ $this->relativePathname = $relativePathname;
+ }
+
+ public function getRelativePath()
+ {
+ return $this->relativePath;
+ }
+
+ public function getRelativePathname()
+ {
+ return $this->relativePathname;
+ }
+
+}
View
86 Tests/Iterator/PathFilterIteratorTest.php
@@ -0,0 +1,86 @@
+<?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\Finder\Tests\Iterator;
+
+use Symfony\Component\Finder\Iterator\PathFilterIterator;
+
+class PathFilterIteratorTest extends IteratorTestCase
+{
+
+ /**
+ * @dataProvider getTestFilterData
+ */
+ public function testFilter(\Iterator $inner, array $matchPatterns, array $noMatchPatterns, array $resultArray)
+ {
+ $iterator = new PathFilterIterator($inner, $matchPatterns, $noMatchPatterns);
+ $this->assertIterator($resultArray, $iterator);
+ }
+
+ public function getTestFilterData()
+ {
+ $inner = new MockFileListIterator();
+
+ //PATH: A/B/C/abc.dat
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'abc.dat',
+ 'relativePathname' => 'A' . DIRECTORY_SEPARATOR . 'B' . DIRECTORY_SEPARATOR . 'C' . DIRECTORY_SEPARATOR . 'abc.dat',
+ ));
+
+ //PATH: A/B/ab.dat
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'ab.dat',
+ 'relativePathname' => 'A' . DIRECTORY_SEPARATOR . 'B' . DIRECTORY_SEPARATOR . 'ab.dat',
+ ));
+
+ //PATH: A/a.dat
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'a.dat',
+ 'relativePathname' => 'A' . DIRECTORY_SEPARATOR . 'a.dat',
+ ));
+
+ //PATH: copy/A/B/C/abc.dat.copy
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'abc.dat.copy',
+ 'relativePathname' => 'copy' . DIRECTORY_SEPARATOR . 'A' . DIRECTORY_SEPARATOR . 'B' . DIRECTORY_SEPARATOR . 'C' . DIRECTORY_SEPARATOR . 'abc.dat',
+ ));
+
+ //PATH: copy/A/B/ab.dat.copy
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'ab.dat.copy',
+ 'relativePathname' => 'copy' . DIRECTORY_SEPARATOR . 'A' . DIRECTORY_SEPARATOR . 'B' . DIRECTORY_SEPARATOR . 'ab.dat',
+ ));
+
+ //PATH: copy/A/a.dat.copy
+ $inner[] = new MockSplFileInfo(array(
+ 'name' => 'a.dat.copy',
+ 'relativePathname' => 'copy' . DIRECTORY_SEPARATOR . 'A' . DIRECTORY_SEPARATOR . 'a.dat',
+ ));
+
+ return array(
+ array($inner, array('/^A/'), array(), array('abc.dat', 'ab.dat', 'a.dat')),
+ array($inner, array('/^A\/B/'), array(), array('abc.dat', 'ab.dat')),
+ array($inner, array('/^A\/B\/C/'), array(), array('abc.dat')),
+ array($inner, array('/A\/B\/C/'), array(), array('abc.dat', 'abc.dat.copy')),
+
+ array($inner, array('A'), array(), array('abc.dat', 'ab.dat', 'a.dat', 'abc.dat.copy', 'ab.dat.copy', 'a.dat.copy')),
+ array($inner, array('A/B'), array(), array('abc.dat', 'ab.dat', 'abc.dat.copy', 'ab.dat.copy')),
+ array($inner, array('A/B/C'), array(), array('abc.dat', 'abc.dat.copy')),
+
+ array($inner, array('copy/A'), array(), array('abc.dat.copy', 'ab.dat.copy', 'a.dat.copy')),
+ array($inner, array('copy/A/B'), array(), array('abc.dat.copy', 'ab.dat.copy')),
+ array($inner, array('copy/A/B/C'), array(), array('abc.dat.copy')),
+
+ );
+ }
+
+}
+
Please sign in to comment.
Something went wrong with that request. Please try again.