Skip to content

Commit

Permalink
stream filtering enhanced
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Apr 24, 2014
1 parent 351ca37 commit 74f7471
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 94 deletions.
25 changes: 14 additions & 11 deletions examples/stream.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

stream_filter_register(FilterTranscode::FILTER_NAME."*", "\lib\FilterTranscode");
$reader = new Reader('data/prenoms.csv');
$reader->appendStreamFilter(FilterTranscode::FILTER_NAME."iso-8859-1:utf-8");
$reader->appendStreamFilter('string.toupper');
$reader->prependStreamFilter('string.rot13');
$reader->addStreamFilter(FilterTranscode::FILTER_NAME."iso-8859-1:utf-8");
$reader->addStreamFilter('string.toupper');
$reader->addStreamFilter('string.rot13');
$reader->setDelimiter(';');
$reader->setOffset(6);
$reader->setLimit(3);
Expand All @@ -41,22 +41,25 @@
*/
var_dump($res);

//BETWEEN insert* call you CAN NOT update/remove/add stream filter you MUST call a new Writer instance
// This is a side effect because we don't want to mess with the file cursor position during all your
// insertion
// because of the limited support for stream filters with the SplFileObject

// BETWEEN insert* call you CAN NOT UPDATE stream filters
// You must instantiate a new Class for each changes
touch('/tmp/test.csv');
$writer = new Writer(new SplFileInfo('/tmp/test.csv'), 'w');
$writer->appendStreamFilter('string.toupper');
$writer->addStreamFilter('string.toupper');
$writer->insertOne('je,suis,toto,le,héros');
$writer->appendStreamFilter('string.rot13');
$writer->addStreamFilter('string.rot13');
$writer->insertOne('je,suis,toto,le,héros');
/*
the data is :
- uppercased only
*/
$writer = new Writer(new SplFileInfo('/tmp/test.csv'), 'a+');
$writer->appendStreamFilter('string.toupper');
$writer->appendStreamFilter('string.rot13');
$writer = new Writer('/tmp/test.csv', 'a+');
$writer->addStreamFilter('string.toupper');
$writer->addStreamFilter(FilterTranscode::FILTER_NAME."iso-8859-1:utf-8");
$writer->addStreamFilter('string.rot13');
$writer->removeStreamFilter(FilterTranscode::FILTER_NAME."iso-8859-1:utf-8");
$writer->insertOne('je,suis,toto,le,héros');
/*
the data is :
Expand Down
29 changes: 5 additions & 24 deletions src/AbstractCsv.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
public function __construct($path, $open_mode = 'r+')
{
ini_set("auto_detect_line_endings", true);
$this->path = $path;
$this->open_mode = strtolower($open_mode);
$this->setPath($path);
}

/**
Expand Down Expand Up @@ -342,8 +342,8 @@ public function getFlags()
*
* @return self
*
* @throws \InvalidArgumentException If the $file is not set
* @throws \RuntimeException If the $file could not be created and/or opened
* @throws \InvalidArgumentException If the path is not valid
* @throws \RuntimeException If the file could not be created and/or opened
*/
protected function setIterator()
{
Expand All @@ -353,28 +353,9 @@ protected function setIterator()
return $this;
}

if ($this->path instanceof SplFileInfo) {
$path = $this->getStreamFilterPath($this->path);
if (! isset($path)) {
$this->csv = $this->path->openFile($this->open_mode);
$this->csv = new SplFileObject($this->getStreamFilterPath(), $this->open_mode);

return $this;
}
$this->csv = new SplFileObject($path, $this->open_mode);

return $this;
}

if (is_string($this->path)) {

$this->csv = new SplFileObject($this->getStreamFilterPath($this->path), $this->open_mode);

return $this;
}

throw new InvalidArgumentException(
'$path must be a `SplFileInfo` object or a valid file path.'
);
return $this;
}

/**
Expand Down
102 changes: 61 additions & 41 deletions src/Stream/StreamFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@
*/
namespace League\Csv\Stream;

use InvalidArgumentException;
use SplFileInfo;
use League\Csv\AbstractCsv;
use SplTempFileObject;

use InvalidArgumentException;
use RuntimeException;

/**
* A Trait to add ease manipulation Stream Filters
Expand All @@ -45,62 +47,88 @@
*/
trait StreamFilter
{
/**
* collection of stream filters
*
* @var array
*/
protected $stream_filters = [];

/**
* Stream filtering mode to apply on all filters
*the real path
*
* @var string the real path to the file
*
* @var integer
*/
protected $stream_filter_mode = STREAM_FILTER_ALL;
protected $real_path;

/**
* prepend a stream filter
* Internal path setter
*
* @param mixed $filter_name a string or an object that implements the '__toString' method
* @param mixed $path can be a SplFileInfo object or the path to a file
*
* @return self
*
* @throws \InvalidArgumentException If what you try to add is invalid
* @throws InvalidArgumentException If $path is invalid
*/
public function prependStreamFilter($filter_name)
protected function setPath($path)
{
if (AbstractCsv::isValidString($filter_name)) {
array_unshift($this->stream_filters, (string) $filter_name);
if ($path instanceof SplTempFileObject) {
$this->real_path = null;
$this->path = $path;

return $this;
} elseif ($path instanceof SplFileInfo) {
$this->path = $path;
$this->real_path = $path->getPath().'/'.$path->getBasename();

return $this;
}
if (! is_string($path)) {
throw new InvalidArgumentException(
'path must be a valid string or a `SplFileInfo` object'
);
}
$this->real_path = trim($path);
$this->path = $path;

throw new InvalidArgumentException(
'you must submit a string, or a method that implements the `__toString method`'
);
return $this;
}

/**
* collection of stream filters
*
* @var array
*/
protected $stream_filters = [];

/**
* Stream filtering mode to apply on all filters
*
* @var integer
*/
protected $stream_filter_mode = STREAM_FILTER_ALL;

/**
* append a stream filter
*
* @param mixed $filter_name a string or an object that implements the '__toString' method
* @param string $filter_name a string or an object that implements the '__toString' method
*
* @return self
*
* @throws \InvalidArgumentException If what you try to add is invalid
* @throws \RuntimeException If adding Stream Filter is not possible
*/
public function appendStreamFilter($filter_name)
public function addStreamFilter($filter_name)
{
if (AbstractCsv::isValidString($filter_name)) {
$this->stream_filters[] = (string) $filter_name;

return $this;
if (is_null($this->real_path) || stripos($this->real_path, 'php://filter/') === 0) {
throw new RuntimeException(
'you can not add a stream filter to '.get_class($this).' instance'
);
} elseif (! is_string($filter_name)) {
throw new InvalidArgumentException(
'you must submit a valid the filtername'
);
}

throw new InvalidArgumentException(
'you must submit a string, or a method that implements the `__toString method`'
);
$filter_name = trim($filter_name);
$this->stream_filters[] = $filter_name;

return $this;
}

/**
Expand Down Expand Up @@ -147,20 +175,12 @@ public function clearStreamFilter()
/**
* Return the filter path
*
* @param mixed $path a SplFileInfo object or a string
*
* @return string
*/
protected function getStreamFilterPath($path)
protected function getStreamFilterPath()
{
if ($path instanceof SplFileInfo) {
$path = $path->getRealPath();
}
$path = trim($path);
if (! is_string($path) || empty($path)) {
return null;
} elseif (! $this->stream_filters) {
return $path;
if (! $this->stream_filters) {
return $this->real_path;
}

$prefix = '';
Expand All @@ -170,6 +190,6 @@ protected function getStreamFilterPath($path)
$prefix = 'write=';
}

return 'php://filter/'.$prefix.implode('|', $this->stream_filters).'/resource='.$path;
return 'php://filter/'.$prefix.implode('|', $this->stream_filters).'/resource='.$this->real_path;
}
}
32 changes: 14 additions & 18 deletions test/CsvTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -265,46 +265,42 @@ public function testaddStreamFilter()
{
$path = __DIR__.'/foo.csv';
$csv = new Reader(new SplFileInfo($path));
$csv->appendStreamFilter('string.toupper');
$csv->addStreamFilter('string.toupper');
foreach ($csv->getIterator() as $row) {
$this->assertSame($row, ['JOHN', 'DOE', 'JOHN.DOE@EXAMPLE.COM']);
}
$csv->appendStreamFilter(new DateTime);
$csv->addStreamFilter(new DateTime);
}

public function testaddMultipleStreamFilter()
{
$path = __DIR__.'/foo.csv';
$csv = new Reader(new SplFileInfo($path));
$csv->appendStreamFilter('string.rot13');
$csv->appendStreamFilter('string.toupper');
$this->assertTrue($csv->hasStreamFilter('string.rot13'));
$csv->removeStreamFilter('string.rot13');
$this->assertFalse($csv->hasStreamFilter('string.rot13'));
$csv->prependStreamFilter('string.rot13');
$csv->addStreamFilter('string.tolower');
$csv->addStreamFilter('string.rot13');
$csv->addStreamFilter('string.toupper');
$this->assertTrue($csv->hasStreamFilter('string.tolower'));
$csv->removeStreamFilter('string.tolower');
$this->assertFalse($csv->hasStreamFilter('string.tolower'));

foreach ($csv->getIterator() as $row) {
$this->assertSame($row, ['WBUA', 'QBR', 'WBUA.QBR@RKNZCYR.PBZ']);
}
$csv->clearStreamFilter();
$this->assertFalse($csv->hasStreamFilter('string.tolower'));
$this->assertFalse($csv->hasStreamFilter('string.rot13'));
}

/**
* @expectedException InvalidArgumentException
* @expectedException RuntimeException
*/
public function testGetFilterPath()
{
$csv = new Reader(new SplTempFileObject);
$csv->prependStreamFilter('string.rot13');
$csv->appendStreamFilter('string.toupper');
$this->assertFalse($csv->getIterator()->getRealPath());

$path = __DIR__.'/foo.csv';
$csv = new Writer(new SplFileInfo($path));
$csv->prependStreamFilter('string.rot13');
$csv->appendStreamFilter('string.toupper');
$csv->addStreamFilter('string.rot13');
$csv->addStreamFilter('string.toupper');
$this->assertFalse($csv->getIterator()->getRealPath());

$csv->prependStreamFilter(['string.rot13']);
(new Reader(new SplTempFileObject))->addStreamFilter('string.rot13');
}
}

0 comments on commit 74f7471

Please sign in to comment.