diff --git a/src/Symfony/Component/Config/Resource/DirectoryResource.php b/src/Symfony/Component/Config/Resource/DirectoryResource.php index 5ccd204ef9334..9f5c98310a2b7 100644 --- a/src/Symfony/Component/Config/Resource/DirectoryResource.php +++ b/src/Symfony/Component/Config/Resource/DirectoryResource.php @@ -16,7 +16,7 @@ * * @author Fabien Potencier */ -class DirectoryResource implements ResourceInterface, \Serializable +class DirectoryResource implements ResourceInterface { private $resource; private $pattern; @@ -33,6 +33,82 @@ public function __construct($resource, $pattern = null) $this->pattern = $pattern; } + /** + * Returns the list of filtered file and directory children of directory resource. + * + * @return array An array of files + */ + public function getFilteredChildren() + { + if (!$this->exists()) { + return array(); + } + + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($this->resource, \FilesystemIterator::SKIP_DOTS), + \RecursiveIteratorIterator::SELF_FIRST + ); + + $children = 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; + } + + $children[] = $file; + } + + return $children; + } + + /** + * 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 @@ public function getResource() 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->getFilteredChildren() 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 @@ public function getPattern() */ 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; - } - - // always monitor directories for changes, except the .. entries - // (otherwise deleted files wouldn't get detected) - if ($file->isDir() && '/..' === substr($file, -3)) { - continue; - } + return $this->getModificationTime() < $timestamp; + } - $newestMTime = max($file->getMTime(), $newestMTime); - } + /** + * Returns true if the resource exists in the filesystem. + * + * @return Boolean + */ + public function exists() + { + return is_dir($this->resource); + } - return $newestMTime < $timestamp; + /** + * Returns unique resource ID. + * + * @return string + */ + public function getId() + { + return md5('d'.$this->resource.$this->pattern); } public function serialize() diff --git a/src/Symfony/Component/Config/Resource/FileResource.php b/src/Symfony/Component/Config/Resource/FileResource.php index 619f84bcef2ec..259db3c75de89 100644 --- a/src/Symfony/Component/Config/Resource/FileResource.php +++ b/src/Symfony/Component/Config/Resource/FileResource.php @@ -18,7 +18,7 @@ * * @author Fabien Potencier */ -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 @@ public function getResource() 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 @@ public function getResource() */ 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() diff --git a/src/Symfony/Component/Config/Resource/ResourceInterface.php b/src/Symfony/Component/Config/Resource/ResourceInterface.php index d624a573b0067..f4030ed2e7408 100644 --- a/src/Symfony/Component/Config/Resource/ResourceInterface.php +++ b/src/Symfony/Component/Config/Resource/ResourceInterface.php @@ -16,7 +16,7 @@ * * @author Fabien Potencier */ -interface ResourceInterface +interface ResourceInterface extends \Serializable { /** * Returns a string representation of the Resource. @@ -34,10 +34,31 @@ public function __toString(); */ public function isFresh($timestamp); + /** + * Returns resource mtime. + * + * @return integer + */ + public function getModificationTime(); + + /** + * Returns true if the resource exists in the filesystem. + * + * @return Boolean + */ + public function exists(); + /** * Returns the resource tied to this Resource. * * @return mixed The resource */ public function getResource(); + + /** + * Returns unique resource ID. + * + * @return string + */ + public function getId(); } diff --git a/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php index 4bd56b7ca2343..bd3b6cf86831d 100644 --- a/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php +++ b/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php @@ -38,18 +38,32 @@ protected function removeDirectory($directory) { $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($directory), \RecursiveIteratorIterator::CHILD_FIRST); foreach ($iterator as $path) { - if (preg_match('#[/\\\\]\.\.?$#', $path->__toString())) { + if (preg_match('#[/\\\\]\.\.?$#', (string) $path)) { continue; } if ($path->isDir()) { - rmdir($path->__toString()); + rmdir((string) $path); } else { - unlink($path->__toString()); + unlink((string) $path); } } 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 @@ public function testFilterRegexListMatch() 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::getFilteredChildren + */ + public function testGetFilteredChildren() + { + $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); + + $children = $resource->getFilteredChildren(); + $this->assertCount(5, $children); + + $children = array_map(function($item) { + return $item->getRealPath(); + }, $children); + + $this->assertContains(realpath($file1), $children); + $this->assertContains(realpath($file2), $children); + $this->assertContains(realpath($dir), $children); + $this->assertContains(realpath($this->directory.'/tmp.xml'), $children); + $this->assertContains(realpath($file3), $children); + } + + /** + * @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->assertCount(4, $resources); + + $children = array_map(function($item) { + return realpath($item->getResource()); + }, $resources); + + $this->assertContains(realpath($file1), $children); + $this->assertContains(realpath($file2), $children); + $this->assertContains(realpath($dir), $children); + $this->assertContains(realpath($this->directory.'/tmp.xml'), $children); + } + + /** + * @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'); + } } diff --git a/src/Symfony/Component/Config/Tests/Resource/FileResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/FileResourceTest.php index 83c403bbe7c42..5413c7ed70ad4 100644 --- a/src/Symfony/Component/Config/Tests/Resource/FileResourceTest.php +++ b/src/Symfony/Component/Config/Tests/Resource/FileResourceTest.php @@ -27,7 +27,21 @@ protected function setUp() 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 @@ public function testIsFresh() $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'); + } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy