Skip to content

[2.1] Resource watcher component #391

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
55cc03b
[ResourceWatcher] resource change event created
everzet Mar 25, 2011
9eec6a1
[ResourceWatcher] resource event listener interface described
everzet Mar 25, 2011
2435265
[ResourceWatcher] created basic resource event listener object
everzet Mar 25, 2011
27afac8
[ResourceWatcher] resource state checker interface described
everzet Mar 25, 2011
d1249df
[ResourceWatcher] created recursive iterator resource state checker
everzet Mar 25, 2011
c8bfa18
[ResourceWatcher] resources tracker interface described
everzet Mar 25, 2011
73b3ea0
[ResourceWatcher] recursive iterator resources tracker created
everzet Mar 25, 2011
150bc5a
[ResourceWatcher] resource watcher object created
everzet Mar 25, 2011
f78ff91
[ResourceWatcher] inotify tracker added
everzet Mar 25, 2011
fe664a6
[ResourceWatcher] use best tracker by default
everzet Mar 25, 2011
d40d2e0
[ResourceWatcher] renamed Event::handes to Event::supports to be cons…
everzet Mar 25, 2011
d661a16
[ResourceWatcher] fixed non-empty directory events
everzet Aug 20, 2011
dcb58fa
[Config] updated resources API to be more explicit
everzet Nov 19, 2011
d9b88bd
[Config] moved DirectoryResource childs retrieving to the special get…
everzet Nov 19, 2011
62a116d
[ResourceWatcher] cleaned code little bit
everzet Nov 19, 2011
a714bed
[ResourceWatcher] refactored recursive state checkers into 2 separate…
everzet Nov 19, 2011
7a5587d
[Config] getFilteredChildResources() method added to DirectoryResource
everzet Nov 19, 2011
c6d85a6
[ResourceWatcher] refactored recursive iterator tracker to support ne…
everzet Nov 19, 2011
7429646
[Config] updated DirectoryResource tests
everzet Nov 25, 2011
ebd6fd8
[Config] update FileResourceTest
everzet Nov 25, 2011
0ab201d
[ResourceWatcher] removed InotifyTracker as i have no ability to test…
everzet Nov 25, 2011
816373d
[Config] added new methods and their tests to File and Directory reso…
everzet Nov 29, 2011
bc8e437
[ResourceWatcher] updated ResourceWatcher and TrackerInterface
everzet Nov 29, 2011
40e7f4e
[ResourceWatcher] added time information to events
everzet Nov 29, 2011
6752b30
[ResourceWatcher] updated FileStateChecker to match FileResource API
everzet Nov 29, 2011
e73385b
[ResourceWatcher] refactored DirectoryStateChecker
everzet Nov 29, 2011
554a48d
[ResourceWatcher] refactored RecursiveIteratorTracker
everzet Nov 29, 2011
cd9a2a7
[ResourceWatcher] updated StateCheckerInterface
everzet Nov 29, 2011
51172e2
[ResourceWatcher] return of the InotifyTracker
everzet Nov 29, 2011
f0f9fd9
[ResourceWatcher] removed unneeded code
fabpot Dec 5, 2011
cb8a3d1
[ResourceWatcher] added an exception when inotify is not available
fabpot Dec 5, 2011
879ddff
[Config] made ResourceInterface extends Serializable
fabpot Dec 5, 2011
a62c413
[ResourceWatcher] removed dead code
fabpot Dec 5, 2011
fbb5849
[ResourceWatcher] added the possibility to watch files that do not ex…
fabpot Dec 5, 2011
51b8613
[ResourceWatcher] added exception classes for the component
fabpot Dec 29, 2011
11611e9
-
fabpot Dec 29, 2011
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 139 additions & 17 deletions src/Symfony/Component/Config/Resource/DirectoryResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DirectoryResource implements ResourceInterface, \Serializable
class DirectoryResource implements ResourceInterface
{
private $resource;
private $pattern;
Expand All @@ -33,6 +33,73 @@ public function __construct($resource, $pattern = null)
$this->pattern = $pattern;
}

/**
* Returns the list of filtered file and directory childs of directory resource.
*
* @return array An array of files
*/
public function getFilteredChilds()
{
$childs = array();
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->resource), \RecursiveIteratorIterator::SELF_FIRST) 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.
*
Expand All @@ -53,11 +120,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->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.
*
Expand All @@ -67,27 +185,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($this->resource.$this->pattern);
}

public function serialize()
Expand Down
44 changes: 40 additions & 4 deletions src/Symfony/Component/Config/Resource/FileResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FileResource implements ResourceInterface, \Serializable
class FileResource implements ResourceInterface
{
private $resource;

Expand All @@ -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;
}

/**
Expand All @@ -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.
*
Expand All @@ -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 file_exists($this->resource);
}

/**
* Returns unique resource ID.
*
* @return string
*/
public function getId()
{
return md5($this->resource);
}

public function serialize()
Expand Down
23 changes: 22 additions & 1 deletion src/Symfony/Component/Config/Resource/ResourceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ResourceInterface
interface ResourceInterface extends \Serializable
{
/**
* Returns a string representation of the Resource.
Expand All @@ -34,10 +34,31 @@ function __toString();
*/
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();
}
87 changes: 87 additions & 0 deletions src/Symfony/Component/ResourceWatcher/Event/Event.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?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\ResourceWatcher\Event;

use Symfony\Component\Config\Resource\ResourceInterface;

/**
* Resource change event.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
class Event
{
const CREATED = 1;
const MODIFIED = 2;
const DELETED = 4;
const ALL = 7;

private $trackingId;
private $resource;
private $type;
private $time;

/**
* Initializes resource event.
*
* @param mixed $trackingId id of resource inside tracker
* @param ResourceInterface $resource resource instance
* @param integer $type event type bit
*/
public function __construct($trackingId, ResourceInterface $resource, $type)
{
$this->trackingId = $trackingId;
$this->resource = $resource;
$this->type = $type;
$this->time = time();
}

/**
* Returns id of resource inside tracker.
*
* @return integer
*/
public function getTrackingId()
{
return $this->trackingId;
}

/**
* Returns changed resource.
*
* @return ResourceInterface
*/
public function getResource()
{
return $this->resource;
}

/**
* Returns event type.
*
* @return integer
*/
public function getType()
{
return $this->type;
}

/**
* Returns time on which event occured.
*
* @return integer
*/
public function getTime()
{
return $this->time;
}
}
Loading