merged branch everzet/config-additions-from-rw (PR #4619)

Commits
-------

241aa92 [Config] added existence check to some resource methods
56b60c8 [Config] use is_file in FileResource::exists()
ff9c132 [Config] added type prefixes to resource ids
ece489f [Config] skip dots in getFilteredChilds() (fixes test suite on Linux)
c9eaa72 [Config] made ResourceInterface extends Serializable
d7c24eb [Config] added new methods and their tests to File and Directory resources
9fe0d00 [Config] update FileResourceTest
45a45ba [Config] updated DirectoryResource tests
1f9ba38 [Config] getFilteredChildResources() method added to DirectoryResource
6b39688 [Config] moved DirectoryResource childs retrieving to the special getFilteredChilds method
45df2e6 [Config] updated resources API to be more explicit

Discussion
----------

[Config] additions from ResourceWatcher

Extracted `Config` component changes from `ResourceWatcher` component.

---------------------------------------------------------------------------

by travisbot at 2012-06-20T08:27:30Z

This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1662786) (merged 241aa92c into 092b5dde).
This commit is contained in:
Fabien Potencier 2012-06-20 21:17:10 +02:00
commit 041286e601
5 changed files with 359 additions and 23 deletions

View File

@ -16,7 +16,7 @@ namespace Symfony\Component\Config\Resource;
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DirectoryResource implements ResourceInterface, \Serializable
class DirectoryResource implements ResourceInterface
{
private $resource;
private $pattern;
@ -33,6 +33,82 @@ class DirectoryResource implements ResourceInterface, \Serializable
$this->pattern = $pattern;
}
/**
* Returns the list of filtered file and directory childs of directory resource.
*
* @return array An array of files
*/
public function getFilteredChilds()
{
if (!$this->exists()) {
return array();
}
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($this->resource, \FilesystemIterator::SKIP_DOTS),
\RecursiveIteratorIterator::SELF_FIRST
);
$childs = array();
foreach ($iterator as $file) {
// if regex filtering is enabled only return matching files
if ($file->isFile() && !$this->hasFile($file)) {
continue;
}
// always monitor directories for changes, except the .. entries
// (otherwise deleted files wouldn't get detected)
if ($file->isDir() && '/..' === substr($file, -3)) {
continue;
}
$childs[] = $file;
}
return $childs;
}
/**
* Returns child resources that matches directory filters.
*
* @return array
*/
public function getFilteredResources()
{
if (!$this->exists()) {
return array();
}
$iterator = new \DirectoryIterator($this->resource);
$resources = array();
foreach ($iterator as $file) {
// if regex filtering is enabled only return matching files
if ($file->isFile() && !$this->hasFile($file)) {
continue;
}
// always monitor directories for changes, except the .. entries
// (otherwise deleted files wouldn't get detected)
if ($file->isDir() && '/..' === substr($file, -3)) {
continue;
}
// if file is dot - continue
if ($file->isDot()) {
continue;
}
if ($file->isFile()) {
$resources[] = new FileResource($file->getRealPath());
} elseif ($file->isDir()) {
$resources[] = new DirectoryResource($file->getRealPath());
}
}
return $resources;
}
/**
* Returns a string representation of the Resource.
*
@ -53,11 +129,62 @@ class DirectoryResource implements ResourceInterface, \Serializable
return $this->resource;
}
/**
* Returns check pattern.
*
* @return mixed
*/
public function getPattern()
{
return $this->pattern;
}
/**
* Checks that passed file exists in resource and matches resource filters.
*
* @param SplFileInfo|string $file
*
* @return Boolean
*/
public function hasFile($file)
{
if (!$file instanceof \SplFileInfo) {
$file = new \SplFileInfo($file);
}
if (0 !== strpos($file->getRealPath(), realpath($this->resource))) {
return false;
}
if ($this->pattern) {
return (bool) preg_match($this->pattern, $file->getBasename());
}
return true;
}
/**
* Returns resource mtime.
*
* @return integer
*/
public function getModificationTime()
{
if (!$this->exists()) {
return -1;
}
clearstatcache(true, $this->resource);
$newestMTime = filemtime($this->resource);
foreach ($this->getFilteredChilds() as $file) {
clearstatcache(true, (string) $file);
$newestMTime = max($file->getMTime(), $newestMTime);
}
return $newestMTime;
}
/**
* Returns true if the resource has not been updated since the given timestamp.
*
@ -67,27 +194,31 @@ class DirectoryResource implements ResourceInterface, \Serializable
*/
public function isFresh($timestamp)
{
if (!is_dir($this->resource)) {
if (!$this->exists()) {
return false;
}
$newestMTime = filemtime($this->resource);
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->resource), \RecursiveIteratorIterator::SELF_FIRST) as $file) {
// if regex filtering is enabled only check matching files
if ($this->pattern && $file->isFile() && !preg_match($this->pattern, $file->getBasename())) {
continue;
}
return $this->getModificationTime() < $timestamp;
}
// always monitor directories for changes, except the .. entries
// (otherwise deleted files wouldn't get detected)
if ($file->isDir() && '/..' === substr($file, -3)) {
continue;
}
/**
* Returns true if the resource exists in the filesystem.
*
* @return Boolean
*/
public function exists()
{
return is_dir($this->resource);
}
$newestMTime = max($file->getMTime(), $newestMTime);
}
return $newestMTime < $timestamp;
/**
* Returns unique resource ID.
*
* @return string
*/
public function getId()
{
return md5('d'.$this->resource.$this->pattern);
}
public function serialize()

View File

@ -18,7 +18,7 @@ namespace Symfony\Component\Config\Resource;
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FileResource implements ResourceInterface, \Serializable
class FileResource implements ResourceInterface
{
private $resource;
@ -29,7 +29,7 @@ class FileResource implements ResourceInterface, \Serializable
*/
public function __construct($resource)
{
$this->resource = realpath($resource);
$this->resource = file_exists($resource) ? realpath($resource) : $resource;
}
/**
@ -52,6 +52,22 @@ class FileResource implements ResourceInterface, \Serializable
return $this->resource;
}
/**
* Returns resource mtime.
*
* @return integer
*/
public function getModificationTime()
{
if (!$this->exists()) {
return -1;
}
clearstatcache(true, $this->resource);
return filemtime($this->resource);
}
/**
* Returns true if the resource has not been updated since the given timestamp.
*
@ -61,11 +77,31 @@ class FileResource implements ResourceInterface, \Serializable
*/
public function isFresh($timestamp)
{
if (!file_exists($this->resource)) {
if (!$this->exists()) {
return false;
}
return filemtime($this->resource) < $timestamp;
return $this->getModificationTime() <= $timestamp;
}
/**
* Returns true if the resource exists in the filesystem.
*
* @return Boolean
*/
public function exists()
{
return is_file($this->resource);
}
/**
* Returns unique resource ID.
*
* @return string
*/
public function getId()
{
return md5('f'.$this->resource);
}
public function serialize()

View File

@ -16,7 +16,7 @@ namespace Symfony\Component\Config\Resource;
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ResourceInterface
interface ResourceInterface extends \Serializable
{
/**
* Returns a string representation of the Resource.
@ -34,10 +34,31 @@ interface ResourceInterface
*/
function isFresh($timestamp);
/**
* Returns resource mtime.
*
* @return integer
*/
function getModificationTime();
/**
* Returns true if the resource exists in the filesystem.
*
* @return Boolean
*/
function exists();
/**
* Returns the resource tied to this Resource.
*
* @return mixed The resource
*/
function getResource();
/**
* Returns unique resource ID.
*
* @return string
*/
function getId();
}

View File

@ -50,6 +50,20 @@ class DirectoryResourceTest extends \PHPUnit_Framework_TestCase
rmdir($directory);
}
/**
* @covers Symfony\Component\Config\Resource\DirectoryResource::getId
*/
public function testGetId()
{
$resource1 = new DirectoryResource($this->directory);
$resource2 = new DirectoryResource($this->directory);
$resource3 = new DirectoryResource($this->directory, '/\.(foo|xml)$/');
$this->assertNotNull($resource1->getId());
$this->assertEquals($resource1->getId(), $resource2->getId());
$this->assertNotEquals($resource1->getId(), $resource3->getId());
}
/**
* @covers Symfony\Component\Config\Resource\DirectoryResource::getResource
*/
@ -168,4 +182,102 @@ class DirectoryResourceTest extends \PHPUnit_Framework_TestCase
touch($this->directory.'/new.xml', time() + 20);
$this->assertFalse($resource->isFresh(time() + 10), '->isFresh() returns false if an new file matching the filter regex is created ');
}
/**
* @covers Symfony\Component\Config\Resource\DirectoryResource::hasFile
*/
public function testHasFile()
{
$resource = new DirectoryResource($this->directory, '/\.foo$/');
touch($this->directory.'/new.foo', time() + 20);
$this->assertFalse($resource->hasFile($this->directory.'/tmp.xml'));
$this->assertTrue($resource->hasFile($this->directory.'/new.foo'));
}
/**
* @covers Symfony\Component\Config\Resource\DirectoryResource::getFilteredChilds
*/
public function testGetFilteredChilds()
{
$resource = new DirectoryResource($this->directory, '/\.(foo|xml)$/');
touch($file1 = $this->directory.'/new.xml', time() + 20);
touch($file2 = $this->directory.'/old.foo', time() + 20);
touch($this->directory.'/old', time() + 20);
mkdir($dir = $this->directory.'/sub');
touch($file3 = $this->directory.'/sub/file.foo', time() + 20);
$childs = $resource->getFilteredChilds();
$this->assertSame(5, count($childs));
$childs = array_map(function($item) {
return (string) $item;
}, $childs);
$this->assertContains($file1, $childs);
$this->assertContains($file2, $childs);
$this->assertContains($dir, $childs);
$this->assertContains($this->directory.'/tmp.xml', $childs);
$this->assertContains($file3, $childs);
}
/**
* @covers Symfony\Component\Config\Resource\DirectoryResource::getFilteredResources
*/
public function testGetFilteredResources()
{
$resource = new DirectoryResource($this->directory, '/\.(foo|xml)$/');
touch($file1 = $this->directory.'/new.xml', time() + 20);
touch($file2 = $this->directory.'/old.foo', time() + 20);
touch($this->directory.'/old', time() + 20);
mkdir($dir = $this->directory.'/sub');
touch($file3 = $this->directory.'/sub/file.foo', time() + 20);
$resources = $resource->getFilteredResources();
$this->assertSame(4, count($resources));
$childs = array_map(function($item) {
return realpath($item->getResource());
}, $resources);
$this->assertContains(realpath($file1), $childs);
$this->assertContains(realpath($file2), $childs);
$this->assertContains(realpath($dir), $childs);
$this->assertContains(realpath($this->directory.'/tmp.xml'), $childs);
}
/**
* @covers Symfony\Component\Config\Resource\DirectoryResource::exists
*/
public function testDirectoryExists()
{
$resource = new DirectoryResource($this->directory);
$this->assertTrue($resource->exists(), '->exists() returns true if directory exists ');
unlink($this->directory.'/tmp.xml');
rmdir($this->directory);
$this->assertFalse($resource->exists(), '->exists() returns false if directory does not exists');
}
/**
* @covers Symfony\Component\Config\Resource\DirectoryResource::getModificationTime
*/
public function testGetModificationTime()
{
$resource = new DirectoryResource($this->directory, '/\.(foo|xml)$/');
touch($this->directory.'/new.xml', $time = time() + 20);
$this->assertSame($time, $resource->getModificationTime(), '->getModificationTime() returns time of the last modificated resource');
touch($this->directory.'/some', time() + 60);
$this->assertSame($time, $resource->getModificationTime(), '->getModificationTime() returns time of last modificated resource, that only matches pattern');
touch($this->directory, $time2 = time() + 90);
$this->assertSame($time2, $resource->getModificationTime(), '->getModificationTime() returns modification time of the directory itself');
}
}

View File

@ -27,7 +27,21 @@ class FileResourceTest extends \PHPUnit_Framework_TestCase
protected function tearDown()
{
unlink($this->file);
if ($this->file) {
unlink($this->file);
}
}
/**
* @covers Symfony\Component\Config\Resource\DirectoryResource::getId
*/
public function testGetId()
{
$resource1 = new FileResource($this->file);
$resource2 = new FileResource($this->file);
$this->assertNotNull($resource1->getId());
$this->assertEquals($resource1->getId(), $resource2->getId());
}
/**
@ -49,4 +63,26 @@ class FileResourceTest extends \PHPUnit_Framework_TestCase
$resource = new FileResource('/____foo/foobar'.rand(1, 999999));
$this->assertFalse($resource->isFresh(time()), '->isFresh() returns false if the resource does not exist');
}
/**
* @covers Symfony\Component\Config\Resource\FileResource::getModificationTime
*/
public function testGetModificationTime()
{
touch($this->file, $time = time() + 100);
$this->assertSame($time, $this->resource->getModificationTime());
}
/**
* @covers Symfony\Component\Config\Resource\FileResource::exists
*/
public function testExists()
{
$this->assertTrue($this->resource->exists(), '->exists() returns true if the resource exists');
unlink($this->file);
$this->file = null;
$this->assertFalse($this->resource->exists(), '->exists() returns false if the resource does not exists');
}
}