[Finder] content(), notContent() methods
This commit is contained in:
parent
0cd63852aa
commit
082d86e3a0
@ -44,6 +44,8 @@ class Finder implements \IteratorAggregate
|
||||
private $dirs = array();
|
||||
private $dates = array();
|
||||
private $iterators = array();
|
||||
private $contents = array();
|
||||
private $notContents = array();
|
||||
|
||||
static private $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');
|
||||
|
||||
@ -188,6 +190,53 @@ class Finder implements \IteratorAggregate
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds tests that file contents must match.
|
||||
*
|
||||
* Strings or PCRE patterns can be used:
|
||||
*
|
||||
* $finder->content('Lorem ipsum')
|
||||
* $finder->content('/Lorem ipsum/i')
|
||||
*
|
||||
* @param string $pattern A pattern (string or regexp)
|
||||
*
|
||||
* @return Finder The current Finder instance
|
||||
*
|
||||
* @see Symfony\Component\Finder\Iterator\FilecontentFilterIterator
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function content($pattern)
|
||||
{
|
||||
$this->contents[] = $pattern;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds tests that file contents must not match.
|
||||
*
|
||||
* Strings or PCRE patterns can be used:
|
||||
*
|
||||
* $finder->notContent('Lorem ipsum')
|
||||
* $finder->notContent('/Lorem ipsum/i')
|
||||
|
||||
*
|
||||
* @param string $pattern A pattern (string or regexp)
|
||||
*
|
||||
* @return Finder The current Finder instance
|
||||
*
|
||||
* @see Symfony\Component\Finder\Iterator\FilecontentFilterIterator
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function notContent($pattern)
|
||||
{
|
||||
$this->notContents[] = $pattern;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds tests for file sizes.
|
||||
*
|
||||
@ -551,6 +600,10 @@ class Finder implements \IteratorAggregate
|
||||
$iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
|
||||
}
|
||||
|
||||
if ($this->contents || $this->notContents) {
|
||||
$iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contents, $this->notContents);
|
||||
}
|
||||
|
||||
if ($this->sizes) {
|
||||
$iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
|
||||
}
|
||||
|
@ -0,0 +1,83 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* FilecontentFilterIterator filters files by their contents using patterns (regexps or strings).
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
|
||||
*/
|
||||
class FilecontentFilterIterator extends MultiplePcreFilterIterator
|
||||
{
|
||||
|
||||
/**
|
||||
* Filters the iterator values.
|
||||
*
|
||||
* @return Boolean true if the value should be kept, false otherwise
|
||||
*/
|
||||
public function accept()
|
||||
{
|
||||
// should at least match one rule
|
||||
if ($this->matchRegexps) {
|
||||
$match = false;
|
||||
foreach ($this->matchRegexps as $regex) {
|
||||
$content = file_get_contents($this->getRealpath());
|
||||
if (false === $content) {
|
||||
throw new \RuntimeException(sprintf('Error reading file "%s".', $this->getRealpath()));
|
||||
}
|
||||
if (preg_match($regex, $content)) {
|
||||
$match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$match = true;
|
||||
}
|
||||
|
||||
// should at least not match one rule to exclude
|
||||
if ($this->noMatchRegexps) {
|
||||
$exclude = false;
|
||||
foreach ($this->noMatchRegexps as $regex) {
|
||||
$content = file_get_contents($this->getRealpath());
|
||||
if (false === $content) {
|
||||
throw new \RuntimeException(sprintf('Error reading file "%s".', $this->getRealpath()));
|
||||
}
|
||||
if (preg_match($regex, $content)) {
|
||||
$exclude = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$exclude = false;
|
||||
}
|
||||
|
||||
return $match && !$exclude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string to regexp if necessary.
|
||||
*
|
||||
* @param string $str Pattern: string or regexp
|
||||
*
|
||||
* @return string regexp corresponding to a given string or regexp
|
||||
*/
|
||||
protected function toRegex($str)
|
||||
{
|
||||
if (preg_match('/^([^a-zA-Z0-9\\\\]).+?\\1[ims]?$/', $str)) {
|
||||
return $str;
|
||||
}
|
||||
|
||||
return sprintf('/%s/', preg_quote($str, '/'));
|
||||
}
|
||||
|
||||
}
|
@ -18,32 +18,8 @@ use Symfony\Component\Finder\Glob;
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class FilenameFilterIterator extends \FilterIterator
|
||||
class FilenameFilterIterator extends MultiplePcreFilterIterator
|
||||
{
|
||||
private $matchRegexps;
|
||||
private $noMatchRegexps;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Iterator $iterator The Iterator to filter
|
||||
* @param array $matchPatterns An array of patterns that need to match
|
||||
* @param array $noMatchPatterns An array of patterns that need to not match
|
||||
*/
|
||||
public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
|
||||
{
|
||||
$this->matchRegexps = array();
|
||||
foreach ($matchPatterns as $pattern) {
|
||||
$this->matchRegexps[] = $this->toRegex($pattern);
|
||||
}
|
||||
|
||||
$this->noMatchRegexps = array();
|
||||
foreach ($noMatchPatterns as $pattern) {
|
||||
$this->noMatchRegexps[] = $this->toRegex($pattern);
|
||||
}
|
||||
|
||||
parent::__construct($iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the iterator values.
|
||||
@ -81,7 +57,17 @@ class FilenameFilterIterator extends \FilterIterator
|
||||
return $match && !$exclude;
|
||||
}
|
||||
|
||||
private function toRegex($str)
|
||||
/**
|
||||
* Converts glob to regexp.
|
||||
*
|
||||
* PCRE patterns are left unchanged.
|
||||
* Glob strings are transformed with Glob::toRegex().
|
||||
*
|
||||
* @param string $str Pattern: glob or regexp
|
||||
*
|
||||
* @return string regexp corresponding to a given glob or regexp
|
||||
*/
|
||||
protected function toRegex($str)
|
||||
{
|
||||
if (preg_match('/^([^a-zA-Z0-9\\\\]).+?\\1[ims]?$/', $str)) {
|
||||
return $str;
|
||||
|
@ -0,0 +1,57 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\Finder\Glob;
|
||||
|
||||
/**
|
||||
* MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings).
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class MultiplePcreFilterIterator extends \FilterIterator
|
||||
{
|
||||
protected $matchRegexps;
|
||||
protected $noMatchRegexps;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Iterator $iterator The Iterator to filter
|
||||
* @param array $matchPatterns An array of patterns that need to match
|
||||
* @param array $noMatchPatterns An array of patterns that need to not match
|
||||
*/
|
||||
public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
|
||||
{
|
||||
$this->matchRegexps = array();
|
||||
foreach ($matchPatterns as $pattern) {
|
||||
$this->matchRegexps[] = $this->toRegex($pattern);
|
||||
}
|
||||
|
||||
$this->noMatchRegexps = array();
|
||||
foreach ($noMatchPatterns as $pattern) {
|
||||
$this->noMatchRegexps[] = $this->toRegex($pattern);
|
||||
}
|
||||
|
||||
parent::__construct($iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string into regexp.
|
||||
*
|
||||
* @param string $str Pattern
|
||||
*
|
||||
* @return string regexp corresponding to a given string
|
||||
*/
|
||||
abstract protected function toRegex($str);
|
||||
|
||||
}
|
@ -330,4 +330,46 @@ class FinderTest extends Iterator\RealIteratorTestCase
|
||||
|
||||
return $f;
|
||||
}
|
||||
|
||||
protected function toAbsoluteFixtures($files)
|
||||
{
|
||||
$f = array();
|
||||
foreach ($files as $file) {
|
||||
$f[] = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$file;
|
||||
}
|
||||
|
||||
return $f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getContentTestData
|
||||
*/
|
||||
public function testContent($matchPatterns, $noMatchPatterns, $expected)
|
||||
{
|
||||
$finder = new Finder();
|
||||
$finder->in(__DIR__.DIRECTORY_SEPARATOR.'Fixtures')
|
||||
->name('*.txt')->sortByName()
|
||||
->content($matchPatterns)
|
||||
->notContent($noMatchPatterns);
|
||||
|
||||
$this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
|
||||
}
|
||||
|
||||
public function getContentTestData()
|
||||
{
|
||||
return array(
|
||||
array('', '', array()),
|
||||
array('foo', 'bar', array()),
|
||||
array('', 'foobar', array('dolor.txt', 'ipsum.txt', 'lorem.txt')),
|
||||
array('lorem ipsum dolor sit amet', 'foobar', array('lorem.txt')),
|
||||
array('sit', 'bar', array('dolor.txt', 'ipsum.txt', 'lorem.txt')),
|
||||
array('dolor sit amet', '@^L@m', array('dolor.txt', 'ipsum.txt')),
|
||||
array('/^lorem ipsum dolor sit amet$/m', 'foobar', array('lorem.txt')),
|
||||
array('lorem', 'foobar', array('lorem.txt')),
|
||||
|
||||
array('', 'lorem', array('dolor.txt', 'ipsum.txt')),
|
||||
array('ipsum dolor sit amet', '/^IPSUM/m', array('lorem.txt')),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
2
src/Symfony/Component/Finder/Tests/Fixtures/dolor.txt
Normal file
2
src/Symfony/Component/Finder/Tests/Fixtures/dolor.txt
Normal file
@ -0,0 +1,2 @@
|
||||
dolor sit amet
|
||||
DOLOR SIT AMET
|
2
src/Symfony/Component/Finder/Tests/Fixtures/ipsum.txt
Normal file
2
src/Symfony/Component/Finder/Tests/Fixtures/ipsum.txt
Normal file
@ -0,0 +1,2 @@
|
||||
ipsum dolor sit amet
|
||||
IPSUM DOLOR SIT AMET
|
2
src/Symfony/Component/Finder/Tests/Fixtures/lorem.txt
Normal file
2
src/Symfony/Component/Finder/Tests/Fixtures/lorem.txt
Normal file
@ -0,0 +1,2 @@
|
||||
lorem ipsum dolor sit amet
|
||||
LOREM IPSUM DOLOR SIT AMET
|
@ -0,0 +1,41 @@
|
||||
<?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\FilecontentFilterIterator;
|
||||
|
||||
class FilecontentFilterIteratorTest extends IteratorTestCase
|
||||
{
|
||||
|
||||
public function testAccept()
|
||||
{
|
||||
$inner = new ContentInnerNameIterator(array('test.txt'));
|
||||
|
||||
$iterator = new FilecontentFilterIterator($inner, array(), array());
|
||||
|
||||
$this->assertIterator(array('test.txt'), $iterator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ContentInnerNameIterator extends \ArrayIterator
|
||||
{
|
||||
public function current()
|
||||
{
|
||||
return new \SplFileInfo(parent::current());
|
||||
}
|
||||
|
||||
public function getFilename()
|
||||
{
|
||||
return parent::current();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user