Add stream_metadata to stream wrapper

This adds support for functions like `touch`.
This commit is contained in:
adlawson 2014-09-06 17:33:18 +01:00
parent 6e2e685f6f
commit 90c02999bd
6 changed files with 149 additions and 4 deletions

View File

@ -33,8 +33,8 @@ class Directory implements NodeContainerInterface
$this->mode = self::TYPE_BLOCK & self::TYPE_DIR;
$this->dateAccessed = new DateTime();
$this->dateCreated = new DateTime();
$this->dateModified = new DateTime();
$this->dateCreated = $this->dateAccessed;
$this->dateModified = $this->dateAccessed;
foreach ($nodes as $name => $node) {
$this->add($name, $node);
@ -108,6 +108,14 @@ class Directory implements NodeContainerInterface
return $this->dateAccessed;
}
/**
* @param DateTime $dateTime
*/
public function setDateAccessed(DateTime $dateTime)
{
$this->dateAccessed = $dateTime;
}
/**
* {@inheritdoc}
*/
@ -124,6 +132,14 @@ class Directory implements NodeContainerInterface
return $this->dateModified;
}
/**
* @param DateTime $dateTime
*/
public function setDateModified(DateTime $dateTime)
{
$this->dateModified = $dateTime;
}
/**
* {@inheritdoc}
*/

View File

@ -28,8 +28,8 @@ class File implements FileInterface
$this->mode = self::TYPE_BLOCK & self::TYPE_FILE;
$this->dateAccessed = new DateTime();
$this->dateCreated = new DateTime();
$this->dateModified = new DateTime();
$this->dateCreated = clone $this->dateAccessed;
$this->dateModified = clone $this->dateAccessed;
}
/**
@ -56,6 +56,14 @@ class File implements FileInterface
return $this->dateAccessed;
}
/**
* @param DateTime $dateTime
*/
public function setDateAccessed(DateTime $dateTime)
{
$this->dateAccessed = $dateTime;
}
/**
* {@inheritdoc}
*/
@ -72,6 +80,14 @@ class File implements FileInterface
return $this->dateModified;
}
/**
* @param DateTime $dateTime
*/
public function setDateModified(DateTime $dateTime)
{
$this->dateModified = $dateTime;
}
/**
* {@inheritdoc}
*/

View File

@ -18,6 +18,11 @@ interface NodeInterface extends StatInterface
*/
public function getDateAccessed();
/**
* @param DateTime $dateTime
*/
public function setDateAccessed(DateTime $dateTime);
/**
* @return DateTime
*/
@ -28,6 +33,11 @@ interface NodeInterface extends StatInterface
*/
public function getDateModified();
/**
* @param DateTime $dateTime
*/
public function setDateModified(DateTime $dateTime);
/**
* @return integer
*/

View File

@ -9,6 +9,7 @@
*/
namespace Vfs\Stream;
use DateTime;
use Vfs\Exception\UnopenedHandleException;
use Vfs\Node\FileInterface;
use Vfs\Node\NodeContainerInterface;
@ -89,6 +90,28 @@ class FileHandle extends AbstractHandle
return substr($this->node->getContent(), $offset);
}
/**
* @param DateTime $mtime
* @param DateTime $atime
* @return NodeInterface
*/
public function touch(DateTime $mtime = null, DateTime $atime = null)
{
$node = $this->findOrBuildNode();
if (!$node) {
throw new UnopenedHandleException($this, $this->url);
}
$mtime = $mtime ?: new DateTime();
$atime = $atime ?: clone $mtime;
$node->setDateAccessed($atime);
$node->setDateModified($mtime);
return $node;
}
/**
* @param string $content
* @return boolean

View File

@ -9,6 +9,7 @@
*/
namespace Vfs\Stream;
use DateTime;
use Vfs\Node\LinkInterface;
use Vfs\FileSystemRegistry;
@ -132,6 +133,28 @@ class StreamWrapper
return true; // Non-buffered writing
}
/**
* @param string $url
* @param integer $option
* @param mixed $args
* @return boolean
*/
public function stream_metadata($url, $option, $args)
{
if (STREAM_META_TOUCH === $option) {
$this->handle = $this->buildFileHandle($url, HandleInterface::MODE_WRITE_NEW);
$mtime = isset($args[0]) ? new DateTime(sprintf('@%s', $args[0])) : null;
$atime = isset($args[1]) ? new DateTime(sprintf('@%s', $args[1])) : $mtime;
$this->handle->touch($mtime, $atime);
return true;
}
return false;
}
/**
* @param string $url
* @param string $mode

View File

@ -44,6 +44,15 @@ class FileHandleTest extends UnitTestCase
];
}
public function dataTouch()
{
return [
['a'], ['ab'], ['a+'], ['at'],
['w'], ['wb'], ['w+'], ['wt'],
['c'], ['cb'], ['c+'], ['ct']
];
}
public function testInterface()
{
$handle = new FileHandle($this->fs, '');
@ -261,4 +270,52 @@ class FileHandleTest extends UnitTestCase
$handle->write('');
}
/**
* @dataProvider dataTouch
*/
public function testTouch($mode)
{
$handle = new FileHandle($this->fs, 'foo://bar', $mode);
$atime = Mockery::mock('DateTime');
$mtime = Mockery::mock('DateTime');
$file = Mockery::mock('Vfs\Node\FileInterface');
$file->shouldReceive('setDateAccessed')->once()->with($atime);
$file->shouldReceive('setDateModified')->once()->with($mtime);
$factory = Mockery::mock('Vfs\Node\Factory\NodeFactoryInterface');
$factory->shouldReceive('buildFile')->once()->withNoArgs()->andReturn($file);
$root = Mockery::mock('Vfs\Node\NodeContainerInterface');
$root->shouldReceive('set')->once()->with('bar', $file);
$this->fs->shouldReceive('get')->once()->with('/')->andReturn($root);
$this->fs->shouldReceive('get')->once()->with('/bar');
$this->fs->shouldReceive('getNodeFactory')->once()->withNoArgs()->andReturn($factory);
$node = $handle->touch($mtime, $atime);
$this->assertSame($file, $node);
}
/**
* @dataProvider dataTouch
*/
public function testTouchExistingFile($mode)
{
$handle = new FileHandle($this->fs, 'foo://bar', $mode);
$atime = Mockery::mock('DateTime');
$mtime = Mockery::mock('DateTime');
$file = Mockery::mock('Vfs\Node\FileInterface');
$file->shouldReceive('setDateAccessed')->once()->with($atime);
$file->shouldReceive('setDateModified')->once()->with($mtime);
$this->fs->shouldReceive('get')->once()->with('/bar')->andReturn($file);
$node = $handle->touch($mtime, $atime);
$this->assertSame($file, $node);
}
}