summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorIgnace Nyamagana Butera <nyamsprod@gmail.com>2014-05-09 13:58:41 +0200
committerIgnace Nyamagana Butera <nyamsprod@gmail.com>2014-05-09 13:58:41 +0200
commit4208a8c5b9f6c03a263eb1df1953220fc9a3f5c4 (patch)
tree2fbba382212b784d2ddd046aa21dfe218455b588 /src
parent3983ee8aebff00dcc53b68c5c4713c327d083091 (diff)
parent2d797799b7cfc7928ef1b8cc4a010312ad0d0c46 (diff)
downloadcsv-4208a8c5b9f6c03a263eb1df1953220fc9a3f5c4.zip
csv-4208a8c5b9f6c03a263eb1df1953220fc9a3f5c4.tar.gz
csv-4208a8c5b9f6c03a263eb1df1953220fc9a3f5c4.tar.bz2
Adding Stream Filtering capabilities #32
Diffstat (limited to 'src')
-rw-r--r--src/AbstractCsv.php225
-rw-r--r--src/Iterator/IteratorFilter.php48
-rw-r--r--src/Iterator/IteratorInterval.php49
-rw-r--r--src/Iterator/IteratorQuery.php80
-rw-r--r--src/Iterator/IteratorSortBy.php60
-rw-r--r--src/Iterator/MapIterator.php30
-rw-r--r--src/Reader.php91
-rw-r--r--src/Stream/StreamFilter.php259
-rw-r--r--src/Writer.php93
9 files changed, 535 insertions, 400 deletions
diff --git a/src/AbstractCsv.php b/src/AbstractCsv.php
index d4e0160..746f334 100644
--- a/src/AbstractCsv.php
+++ b/src/AbstractCsv.php
@@ -1,51 +1,30 @@
<?php
/**
-* League.csv - A CSV data manipulation library
+* This file is part of the League.csv library
*
-* @author Ignace Nyamagana Butera <nyamsprod@gmail.com>
-* @copyright 2014 Ignace Nyamagana Butera
-* @link https://github.com/thephpleague/csv/
* @license http://opensource.org/licenses/MIT
-* @version 5.4.0
+* @link https://github.com/thephpleague/csv/
+* @version 5.5.0
* @package League.csv
*
-* MIT LICENSE
-*
-* Permission is hereby granted, free of charge, to any person obtaining
-* a copy of this software and associated documentation files (the
-* "Software"), to deal in the Software without restriction, including
-* without limitation the rights to use, copy, modify, merge, publish,
-* distribute, sublicense, and/or sell copies of the Software, and to
-* permit persons to whom the Software is furnished to do so, subject to
-* the following conditions:
-*
-* The above copyright notice and this permission notice shall be
-* included in all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+* For the full copyright and license information, please view the LICENSE
+* file that was distributed with this source code.
*/
namespace League\Csv;
use DomDocument;
use JsonSerializable;
-
+use Traversable;
use SplFileInfo;
use SplFileObject;
use SplTempFileObject;
-
use RuntimeException;
use InvalidArgumentException;
-
use IteratorAggregate;
use LimitIterator;
use CallbackFilterIterator;
use League\Csv\Iterator\MapIterator;
+use League\Csv\Stream\StreamFilter;
/**
* An abstract class to enable basic CSV manipulation
@@ -56,13 +35,10 @@ use League\Csv\Iterator\MapIterator;
*/
abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
{
-
/**
- * The CSV object holder
- *
- * @var \SplFileObject
+ * Stream Filter Trait
*/
- protected $csv;
+ use StreamFilter;
/**
* the field delimiter (one character only)
@@ -97,7 +73,21 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
*
* @var string
*/
- protected $encoding = 'UTF-8';
+ protected $encodingFrom = 'UTF-8';
+
+ /**
+ * The constructor path
+ *
+ * @var mixed can be a SplFileInfo object or the path to a file
+ */
+ protected $path;
+
+ /**
+ * The file open mode flag
+ *
+ * @var string
+ */
+ protected $open_mode;
/**
* The constructor
@@ -107,18 +97,25 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
*/
public function __construct($path, $open_mode = 'r+')
{
- ini_set("auto_detect_line_endings", true);
- $this->setIterator($path, $open_mode);
+ if (! is_string($path) && ! $path instanceof SplFileInfo) {
+ throw new InvalidArgumentException(
+ 'path must be a valid string or a `SplFileInfo` object'
+ );
+ }
+ ini_set("auto_detect_line_endings", '1');
+ //lazy loading
+ $this->path = $path;
+ $this->open_mode = strtolower($open_mode);
+ $this->initStreamFilter($path);
}
/**
* The destructor
- *
- * Make sure the class reference is destroy when the class is no longer used
*/
public function __destruct()
{
- $this->csv = null;
+ //in case path is a SplFileObject we need to remove its reference
+ $this->path = null;
}
/**
@@ -146,6 +143,50 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
}
/**
+ * Instantiate a AbstractCsv extended class
+ *
+ * @param string $class_name the Class to load {@link Writer} or {@link Reader}
+ * @param string $open_mode the file open mode flag
+ *
+ * @return \League\Csv\AbstractCSv
+ */
+ protected function createFromCurrentInstance($class_name, $open_mode)
+ {
+ $obj = new $class_name($this->path, $open_mode);
+ $obj->delimiter = $this->delimiter;
+ $obj->enclosure = $this->enclosure;
+ $obj->escape = $this->escape;
+ $obj->flags = $this->flags;
+ $obj->encoding = $this->encodingFrom;
+
+ return $obj;
+ }
+
+ /**
+ * Instantiate a {@link Writer} class from the current object
+ *
+ * @param string $open_mode the file open mode flag
+ *
+ * @return \League\Csv\Writer
+ */
+ public function createWriter($open_mode = 'r+')
+ {
+ return $this->createFromCurrentInstance('\League\Csv\Writer', $open_mode);
+ }
+
+ /**
+ * Instantiate a {@link Reader} class from the current object
+ *
+ * @param string $open_mode the file open mode flag
+ *
+ * @return \League\Csv\Reader
+ */
+ public function createReader($open_mode = 'r+')
+ {
+ return $this->createFromCurrentInstance('\League\Csv\Reader', $open_mode);
+ }
+
+ /**
* Validate a variable to be stringable
*
* @param mixed $str
@@ -320,48 +361,40 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
}
/**
- * set the csv container as a SplFileObject instance
- *
- * @param mixed $path A SplFileInfo object or the path to a file
- *
- * @return self
+ * Return the CSV Iterator
*
- * @throws \InvalidArgumentException If the $file is not set
- * @throws \RuntimeException If the $file could not be created and/or opened
+ * @return \SplFileObject
*/
- protected function setIterator($path, $open_mode)
+ public function getIterator()
{
- if ($path instanceof SplFileObject) {
- $this->csv = $path;
-
- return $this;
+ $obj = $this->path;
+ if (! $obj instanceof SplFileObject) {
+ $obj = new SplFileObject($this->getStreamFilterPath(), $this->open_mode);
}
- $open_mode = strtolower($open_mode);
- if ($path instanceof SplFileInfo) {
- $this->csv = $path->openFile($open_mode);
-
- return $this;
- } elseif (is_string($path)) {
- $this->csv = new SplFileObject($path, $open_mode);
+ $obj->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
+ $obj->setFlags($this->flags);
- return $this;
- }
- throw new InvalidArgumentException(
- '$path must be a `SplFileInfo` object or a valid file path.'
- );
+ return $obj;
}
/**
- * Return the CSV Iterator
+ * DEPRECATION WARNING! This method will be removed in the next major point release
*
- * @return \SplFileObject
+ * @deprecated deprecated since version 5.5
*/
- public function getIterator()
+ public function setEncoding($str)
{
- $this->csv->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
- $this->csv->setFlags($this->flags);
+ return $this->setEncodingFrom($str);
+ }
- return $this->csv;
+ /**
+ * DEPRECATION WARNING! This method will be removed in the next major point release
+ *
+ * @deprecated deprecated since version 5.5
+ */
+ public function getEncoding()
+ {
+ return $this->getEncodingFrom();
}
/**
@@ -371,66 +404,42 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
*
* @return self
*/
- public function setEncoding($str)
+ public function setEncodingFrom($str)
{
$str = str_replace('_', '-', $str);
$str = filter_var($str, FILTER_SANITIZE_STRING, ['flags' => FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH]);
if (empty($str)) {
throw new InvalidArgumentException('you should use a valid charset');
}
- $this->encoding = strtoupper($str);
+ $this->encodingFrom = strtoupper($str);
return $this;
}
/**
- * Get the CSV encoding charset
+ * Get the source CSV encoding charset
*
* @return string
*/
- public function getEncoding()
- {
- return $this->encoding;
- }
-
- /**
- * Instantiate a AbstractCsv extended class
- *
- * @param string $class_name the Class to load {@link Writer} or {@link Reader}
- * @param string $open_mode the file open mode flag
- *
- * @return \League\Csv\AbstractCSv
- */
- protected function getInstance($class_name, $open_mode = 'r+')
+ public function getEncodingFrom()
{
- $obj = $this->csv;
- if (! $obj instanceof SplTempFileObject && ($path = $obj->getRealPath()) !== false) {
- $obj = new SplFileObject($path, $open_mode);
- }
- $csv = new $class_name($obj);
- $csv->setDelimiter($this->delimiter);
- $csv->setEnclosure($this->enclosure);
- $csv->setEscape($this->escape);
- $csv->setFlags($this->flags);
- $csv->setEncoding($this->encoding);
-
- return $csv;
+ return $this->encodingFrom;
}
/**
* Convert Csv file into UTF-8
*
- * @return \Iterator
+ * @return \Traversable
*/
- protected function convert2Utf8()
+ protected function convert2Utf8(Traversable $iterator)
{
- if ('UTF-8' == $this->encoding) {
- return $this->getIterator();
+ if ('UTF-8' == $this->encodingFrom) {
+ return $iterator;
}
- return new MapIterator($this->getIterator(), function ($row) {
+ return new MapIterator($iterator, function ($row) {
foreach ($row as &$value) {
- $value = mb_convert_encoding($value, 'UTF-8', $this->encoding);
+ $value = mb_convert_encoding($value, 'UTF-8', $this->encodingFrom);
}
unset($value);
@@ -445,7 +454,7 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
*/
public function jsonSerialize()
{
- return iterator_to_array($this->convert2Utf8(), false);
+ return iterator_to_array($this->convert2Utf8($this->getIterator()), false);
}
/**
@@ -458,8 +467,9 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
$iterator = $this->getIterator();
//@codeCoverageIgnoreStart
if (! is_null($filename) && AbstractCsv::isValidString($filename)) {
- header('Content-Type: text/csv; charset="'.$this->encoding.'"');
+ header('Content-Type: text/csv; charset="'.$this->encodingFrom.'"');
header('Content-Disposition: attachment; filename="'.$filename.'"');
+ header('Content-Transfer-Encoding: binary');
if (! $iterator instanceof SplTempFileObject) {
header('Content-Length: '.$iterator->getSize());
}
@@ -495,7 +505,8 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
{
$doc = new DomDocument('1.0', 'UTF-8');
$root = $doc->createElement($root_name);
- foreach ($this->convert2Utf8() as $row) {
+ $csv = $this->convert2Utf8($this->getIterator());
+ foreach ($csv as $row) {
$item = $doc->createElement($row_name);
foreach ($row as $value) {
$content = $doc->createTextNode($value);
diff --git a/src/Iterator/IteratorFilter.php b/src/Iterator/IteratorFilter.php
index bd44d10..888c97c 100644
--- a/src/Iterator/IteratorFilter.php
+++ b/src/Iterator/IteratorFilter.php
@@ -1,34 +1,14 @@
<?php
/**
-* League.csv - A CSV data manipulation library
+* This file is part of the League.csv library
*
-* @author Ignace Nyamagana Butera <nyamsprod@gmail.com>
-* @copyright 2014 Ignace Nyamagana Butera
-* @link https://github.com/thephpleague/csv/
* @license http://opensource.org/licenses/MIT
-* @version 5.4.0
+* @link https://github.com/thephpleague/csv/
+* @version 5.5.0
* @package League.csv
*
-* MIT LICENSE
-*
-* Permission is hereby granted, free of charge, to any person obtaining
-* a copy of this software and associated documentation files (the
-* "Software"), to deal in the Software without restriction, including
-* without limitation the rights to use, copy, modify, merge, publish,
-* distribute, sublicense, and/or sell copies of the Software, and to
-* permit persons to whom the Software is furnished to do so, subject to
-* the following conditions:
-*
-* The above copyright notice and this permission notice shall be
-* included in all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+* For the full copyright and license information, please view the LICENSE
+* file that was distributed with this source code.
*/
namespace League\Csv\Iterator;
@@ -49,7 +29,7 @@ trait IteratorFilter
*
* @var array
*/
- private $filter = [];
+ protected $iterator_filters = [];
/**
* Set the Iterator filter method
@@ -70,13 +50,13 @@ trait IteratorFilter
/**
* Set the Iterator filter method
*
- * @param callable $filter
+ * @param callable $callable
*
* @return self
*/
public function addFilter(callable $callable)
{
- $this->filter[] = $callable;
+ $this->iterator_filters[] = $callable;
return $this;
}
@@ -90,9 +70,9 @@ trait IteratorFilter
*/
public function removeFilter(callable $callable)
{
- $res = array_search($callable, $this->filter, true);
+ $res = array_search($callable, $this->iterator_filters, true);
if (false !== $res) {
- unset($this->filter[$res]);
+ unset($this->iterator_filters[$res]);
}
return $this;
@@ -107,7 +87,7 @@ trait IteratorFilter
*/
public function hasFilter(callable $callable)
{
- return false !== array_search($callable, $this->filter, true);
+ return false !== array_search($callable, $this->iterator_filters, true);
}
/**
@@ -117,7 +97,7 @@ trait IteratorFilter
*/
public function clearFilter()
{
- $this->filter = [];
+ $this->iterator_filters = [];
return $this;
}
@@ -129,9 +109,9 @@ trait IteratorFilter
*
* @return \Iterator
*/
- protected function applyFilter(Iterator $iterator)
+ protected function applyIteratorFilter(Iterator $iterator)
{
- foreach ($this->filter as $callable) {
+ foreach ($this->iterator_filters as $callable) {
$iterator = new CallbackFilterIterator($iterator, $callable);
}
$this->clearFilter();
diff --git a/src/Iterator/IteratorInterval.php b/src/Iterator/IteratorInterval.php
index a77b90c..fe3cbb4 100644
--- a/src/Iterator/IteratorInterval.php
+++ b/src/Iterator/IteratorInterval.php
@@ -1,34 +1,13 @@
<?php
/**
-* League.csv - A CSV data manipulation library
+* This file is part of the League.csv library
*
-* @author Ignace Nyamagana Butera <nyamsprod@gmail.com>
-* @copyright 2014 Ignace Nyamagana Butera
-* @link https://github.com/thephpleague/csv/
* @license http://opensource.org/licenses/MIT
-* @version 5.4.0
+* @version 5.5.0
* @package League.csv
*
-* MIT LICENSE
-*
-* Permission is hereby granted, free of charge, to any person obtaining
-* a copy of this software and associated documentation files (the
-* "Software"), to deal in the Software without restriction, including
-* without limitation the rights to use, copy, modify, merge, publish,
-* distribute, sublicense, and/or sell copies of the Software, and to
-* permit persons to whom the Software is furnished to do so, subject to
-* the following conditions:
-*
-* The above copyright notice and this permission notice shall be
-* included in all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+* For the full copyright and license information, please view the LICENSE
+* file that was distributed with this source code.
*/
namespace League\Csv\Iterator;
@@ -50,14 +29,14 @@ trait IteratorInterval
*
* @var integer
*/
- private $offset = 0;
+ protected $iterator_offset = 0;
/**
* iterator maximum length
*
* @var integer
*/
- private $limit = -1;
+ protected $iterator_limit = -1;
/**
* Set LimitIterator Offset
@@ -71,7 +50,7 @@ trait IteratorInterval
if (false === filter_var($offset, FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]])) {
throw new InvalidArgumentException('the offset must be a positive integer or 0');
}
- $this->offset = $offset;
+ $this->iterator_offset = $offset;
return $this;
}
@@ -88,7 +67,7 @@ trait IteratorInterval
if (false === filter_var($limit, FILTER_VALIDATE_INT, ['options' => ['min_range' => -1]])) {
throw new InvalidArgumentException('the limit must an integer greater or equals to -1');
}
- $this->limit = $limit;
+ $this->iterator_limit = $limit;
return $this;
}
@@ -100,16 +79,16 @@ trait IteratorInterval
*
* @return \LimitIterator
*/
- protected function applyInterval(Iterator $iterator)
+ protected function applyIteratorInterval(Iterator $iterator)
{
- if (0 == $this->offset && -1 == $this->limit) {
+ if (0 == $this->iterator_offset && -1 == $this->iterator_limit) {
return $iterator;
}
- $offset = $this->offset;
- $limit = $this->limit;
+ $offset = $this->iterator_offset;
+ $limit = $this->iterator_limit;
- $this->limit = -1;
- $this->offset = 0;
+ $this->iterator_limit = -1;
+ $this->iterator_offset = 0;
return new LimitIterator($iterator, $offset, $limit);
}
diff --git a/src/Iterator/IteratorQuery.php b/src/Iterator/IteratorQuery.php
deleted file mode 100644
index 5ec12e2..0000000
--- a/src/Iterator/IteratorQuery.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-/**
-* League.csv - A CSV data manipulation library
-*
-* @author Ignace Nyamagana Butera <nyamsprod@gmail.com>
-* @copyright 2014 Ignace Nyamagana Butera
-* @link https://github.com/thephpleague/csv/
-* @license http://opensource.org/licenses/MIT
-* @version 5.4.0
-* @package League.csv
-*
-* MIT LICENSE
-*
-* Permission is hereby granted, free of charge, to any person obtaining
-* a copy of this software and associated documentation files (the
-* "Software"), to deal in the Software without restriction, including
-* without limitation the rights to use, copy, modify, merge, publish,
-* distribute, sublicense, and/or sell copies of the Software, and to
-* permit persons to whom the Software is furnished to do so, subject to
-* the following conditions:
-*
-* The above copyright notice and this permission notice shall be
-* included in all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-namespace League\Csv\Iterator;
-
-use Iterator;
-
-/**
- * A Trait to Query in a SQL-like manner Iterators
- *
- * @package League.csv
- * @since 4.0.0
- *
- */
-trait IteratorQuery
-{
- /**
- * Iterator Filtering Trait
- */
- use IteratorFilter;
-
- /**
- * Iterator Sorting Trait
- */
- use IteratorSortBy;
-
- /**
- * Iterator Set Interval Trait
- */
- use IteratorInterval;
-
- /**
- * Return a filtered Iterator based on the filtering settings
- *
- * @param Iterator $iterator The iterator to be filtered
- * @param callable $callable a callable function to be applied to each Iterator item
- *
- * @return Iterator
- */
- protected function execute(Iterator $iterator, callable $callable = null)
- {
- $iterator = $this->applyFilter($iterator);
- $iterator = $this->applySortBy($iterator);
- $iterator = $this->applyInterval($iterator);
- if (! is_null($callable)) {
- $iterator = new MapIterator($iterator, $callable);
- }
-
- return $iterator;
- }
-}
diff --git a/src/Iterator/IteratorSortBy.php b/src/Iterator/IteratorSortBy.php
index 9a64d92..9324364 100644
--- a/src/Iterator/IteratorSortBy.php
+++ b/src/Iterator/IteratorSortBy.php
@@ -1,34 +1,14 @@
<?php
/**
-* League.csv - A CSV data manipulation library
+* This file is part of the League.csv library
*
-* @author Ignace Nyamagana Butera <nyamsprod@gmail.com>
-* @copyright 2014 Ignace Nyamagana Butera
-* @link https://github.com/thephpleague/csv/
* @license http://opensource.org/licenses/MIT
-* @version 5.4.0
+* @link https://github.com/thephpleague/csv/
+* @version 5.5.0
* @package League.csv
*
-* MIT LICENSE
-*
-* Permission is hereby granted, free of charge, to any person obtaining
-* a copy of this software and associated documentation files (the
-* "Software"), to deal in the Software without restriction, including
-* without limitation the rights to use, copy, modify, merge, publish,
-* distribute, sublicense, and/or sell copies of the Software, and to
-* permit persons to whom the Software is furnished to do so, subject to
-* the following conditions:
-*
-* The above copyright notice and this permission notice shall be
-* included in all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+* For the full copyright and license information, please view the LICENSE
+* file that was distributed with this source code.
*/
namespace League\Csv\Iterator;
@@ -49,7 +29,7 @@ trait IteratorSortBy
*
* @var callable
*/
- private $sortBy = [];
+ protected $iterator_sort_by = [];
/**
* Set the Iterator SortBy method
@@ -68,15 +48,15 @@ trait IteratorSortBy
}
/**
- * Set an Iterator sortBy method
+ * Set an Iterator sorting callable function
*
- * @param callable $filter
+ * @param callable $callable
*
* @return self
*/
public function addSortBy(callable $callable)
{
- $this->sortBy[] = $callable;
+ $this->iterator_sort_by[] = $callable;
return $this;
}
@@ -84,15 +64,15 @@ trait IteratorSortBy
/**
* Remove a callable from the collection
*
- * @param callable $filter
+ * @param callable $callable
*
* @return self
*/
public function removeSortBy(callable $callable)
{
- $res = array_search($callable, $this->sortBy, true);
+ $res = array_search($callable, $this->iterator_sort_by, true);
if (false !== $res) {
- unset($this->sortBy[$res]);
+ unset($this->iterator_sort_by[$res]);
}
return $this;
@@ -101,13 +81,13 @@ trait IteratorSortBy
/**
* Detect if the callable is already registered
*
- * @param callable $filter
+ * @param callable $callable
*
* @return boolean
*/
public function hasSortBy(callable $callable)
{
- return false !== array_search($callable, $this->sortBy, true);
+ return false !== array_search($callable, $this->iterator_sort_by, true);
}
/**
@@ -117,7 +97,7 @@ trait IteratorSortBy
*/
public function clearSortBy()
{
- $this->sortBy = [];
+ $this->iterator_sort_by = [];
return $this;
}
@@ -129,22 +109,22 @@ trait IteratorSortBy
*
* @return \ArrayIterator
*/
- protected function applySortBy(Iterator $iterator)
+ protected function applyIteratorSortBy(Iterator $iterator)
{
- if (! $this->sortBy) {
+ if (! $this->iterator_sort_by) {
return $iterator;
}
$res = iterator_to_array($iterator, false);
uasort($res, function ($rowA, $rowB) {
- foreach ($this->sortBy as $callable) {
+ foreach ($this->iterator_sort_by as $callable) {
$res = $callable($rowA, $rowB);
if (0 !== $res) {
- break;
+ return $res;
}
}
- return $res;
+ return 0;
});
$this->clearSortBy();
diff --git a/src/Iterator/MapIterator.php b/src/Iterator/MapIterator.php
index 6e3cc8c..3239902 100644
--- a/src/Iterator/MapIterator.php
+++ b/src/Iterator/MapIterator.php
@@ -1,34 +1,14 @@
<?php
/**
-* League.csv - A CSV data manipulation library
+* This file is part of the League.csv library
*
-* @author Ignace Nyamagana Butera <nyamsprod@gmail.com>
-* @copyright 2014 Ignace Nyamagana Butera
-* @link https://github.com/thephpleague/csv/
* @license http://opensource.org/licenses/MIT
-* @version 5.4.0
+* @link https://github.com/thephpleague/csv/
+* @version 5.5.0
* @package League.csv
*
-* MIT LICENSE
-*
-* Permission is hereby granted, free of charge, to any person obtaining
-* a copy of this software and associated documentation files (the
-* "Software"), to deal in the Software without restriction, including
-* without limitation the rights to use, copy, modify, merge, publish,
-* distribute, sublicense, and/or sell copies of the Software, and to
-* permit persons to whom the Software is furnished to do so, subject to
-* the following conditions:
-*
-* The above copyright notice and this permission notice shall be
-* included in all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+* For the full copyright and license information, please view the LICENSE
+* file that was distributed with this source code.
*/
namespace League\Csv\Iterator;
diff --git a/src/Reader.php b/src/Reader.php
index 15056ac..f8c733b 100644
--- a/src/Reader.php
+++ b/src/Reader.php
@@ -1,42 +1,24 @@
<?php
/**
-* League.csv - A CSV data manipulation library
+* This file is part of the League.csv library
*
-* @author Ignace Nyamagana Butera <nyamsprod@gmail.com>
-* @copyright 2014 Ignace Nyamagana Butera
-* @link https://github.com/thephpleague/csv/
* @license http://opensource.org/licenses/MIT
-* @version 5.4.0
+* @link https://github.com/thephpleague/csv/
+* @version 5.5.0
* @package League.csv
*
-* MIT LICENSE
-*
-* Permission is hereby granted, free of charge, to any person obtaining
-* a copy of this software and associated documentation files (the
-* "Software"), to deal in the Software without restriction, including
-* without limitation the rights to use, copy, modify, merge, publish,
-* distribute, sublicense, and/or sell copies of the Software, and to
-* permit persons to whom the Software is furnished to do so, subject to
-* the following conditions:
-*
-* The above copyright notice and this permission notice shall be
-* included in all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+* For the full copyright and license information, please view the LICENSE
+* file that was distributed with this source code.
*/
namespace League\Csv;
use InvalidArgumentException;
-
+use Iterator;
use CallbackFilterIterator;
use League\Csv\Iterator\MapIterator;
-use League\Csv\Iterator\IteratorQuery;
+use League\Csv\Iterator\IteratorFilter;
+use League\Csv\Iterator\IteratorSortBy;
+use League\Csv\Iterator\IteratorInterval;
/**
* A class to manage extracting and filtering a CSV
@@ -48,13 +30,31 @@ use League\Csv\Iterator\IteratorQuery;
class Reader extends AbstractCsv
{
/**
- * Iterator Query Trait
+ * Iterator Filtering Trait
*/
- use IteratorQuery;
+ use IteratorFilter;
+
+ /**
+ * Iterator Sorting Trait
+ */
+ use IteratorSortBy;
+
+ /**
+ * Iterator Set Interval Trait
+ */
+ use IteratorInterval;
+
+ /**
+ * {@ihneritdoc}
+ */
+ protected $stream_filter_mode = STREAM_FILTER_READ;
/**
* Intelligent Array Combine
*
+ * add or remove values from the $value array to
+ * match array $keys length before using PHP array_combine function
+ *
* @param array $keys
* @param array $value
*
@@ -78,7 +78,7 @@ class Reader extends AbstractCsv
*
* @param callable $callable a callable function to be applied to each Iterator item
*
- * @return \Iterator
+ * @return \Traversable
*/
public function query(callable $callable = null)
{
@@ -86,7 +86,14 @@ class Reader extends AbstractCsv
return is_array($row);
});
- return $this->execute($iterator, $callable);
+ $iterator = $this->applyIteratorFilter($iterator);
+ $iterator = $this->applyIteratorSortBy($iterator);
+ $iterator = $this->applyIteratorInterval($iterator);
+ if (! is_null($callable)) {
+ $iterator = new MapIterator($iterator, $callable);
+ }
+
+ return $iterator;
}
/**
@@ -100,11 +107,7 @@ class Reader extends AbstractCsv
*/
public function each(callable $callable)
{
- $iterator = new CallbackFilterIterator($this->getIterator(), function ($row) {
- return is_array($row);
- });
-
- $iterator = $this->execute($iterator);
+ $iterator = $this->query();
$index = 0;
foreach ($iterator as $rowIndex => $row) {
if (true !== $callable($row, $rowIndex, $iterator)) {
@@ -190,8 +193,8 @@ class Reader extends AbstractCsv
*
* @deprecated deprecated since version 5.4
*
- * @param integer $fieldIndex field Index
- * @param callable $callable a callable function to be applied to each value to be return
+ * @param integer $column_index field Index
+ * @param callable $callable a callable function to be applied to each value to be return
*
* @return array
*
@@ -205,8 +208,8 @@ class Reader extends AbstractCsv
/**
* Return a single column from the CSV data
*
- * @param integer $fieldIndex field Index
- * @param callable $callable a callable function to be applied to each value to be return
+ * @param integer $column_index field Index
+ * @param callable $callable a callable function to be applied to each value to be return
*
* @return array
*
@@ -233,14 +236,12 @@ class Reader extends AbstractCsv
}
/**
- * Instantiate a {@link Writer} class from the current {@link Reader}
- *
- * @param string $open_mode the file open mode flag
+ * DEPRECATION WARNING! This method will be removed in the next major point release
*
- * @return \League\Csv\Writer
+ * @deprecated deprecated since version 5.5
*/
public function getWriter($open_mode = 'r+')
{
- return $this->getInstance('\League\Csv\Writer', $open_mode);
+ return $this->createWriter($open_mode);
}
}
diff --git a/src/Stream/StreamFilter.php b/src/Stream/StreamFilter.php
new file mode 100644
index 0000000..1f2ac6e
--- /dev/null
+++ b/src/Stream/StreamFilter.php
@@ -0,0 +1,259 @@
+<?php
+/**
+* This file is part of the League.csv library
+*
+* @license http://opensource.org/licenses/MIT
+* @link https://github.com/thephpleague/csv/
+* @version 5.5.0
+* @package League.csv
+*
+* For the full copyright and license information, please view the LICENSE
+* file that was distributed with this source code.
+*/
+namespace League\Csv\Stream;
+
+use SplFileInfo;
+use SplTempFileObject;
+use InvalidArgumentException;
+use RuntimeException;
+use OutOfBoundsException;
+
+/**
+ * A Trait to add ease manipulation Stream Filters
+ *
+ * @package League.csv
+ * @since 5.5.0
+ *
+ */
+trait StreamFilter
+{
+ /**
+ * 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;
+
+ /**
+ *the real path
+ *
+ * @var string the real path to the file
+ *
+ */
+ protected $stream_real_path;
+
+ /**
+ * Internal path setter
+ *
+ * @param mixed $path can be a SplFileInfo object or the path to a file
+ *
+ * @return self
+ *
+ * @throws InvalidArgumentException If $path is invalid
+ */
+ protected function initStreamFilter($path)
+ {
+ if ($path instanceof SplTempFileObject) {
+ $this->stream_real_path = null;
+
+ return $this;
+
+ } elseif ($path instanceof SplFileInfo) {
+ //$path->getRealPath() returns false for php stream wrapper
+ $path = $path->getPath().'/'.$path->getBasename();
+ }
+
+ $path = trim($path);
+ //if we are submitting a filter meta wrapper
+ //we extract and inject the mode, the filter and the path
+ if (preg_match(
+ ',^php://filter/(?P<mode>:?read=|write=)?(?P<filters>.*?)/resource=(?P<resource>.*)$,i',
+ $path,
+ $matches
+ )) {
+ $matches['mode'] = strtolower($matches['mode']);
+ $mode = STREAM_FILTER_ALL;
+ if ('write=' == $matches['mode']) {
+ $mode = STREAM_FILTER_WRITE;
+ } elseif ('read=' == $matches['mode']) {
+ $mode = STREAM_FILTER_READ;
+ }
+ $this->stream_filter_mode = $mode;
+ $this->stream_real_path = $matches['resource'];
+ $this->stream_filters = explode('|', $matches['filters']);
+
+ return $this;
+ }
+
+ $this->stream_real_path = $path;
+ $this->stream_filters = [];
+
+ return $this;
+ }
+
+ /**
+ * stream filter mode Setter
+ *
+ * Set the new Stream Filter mode and remove all
+ * previously attached stream filters
+ *
+ * @param integer $mode
+ *
+ * @return self
+ */
+ public function setStreamFilterMode($mode)
+ {
+ if (! in_array($mode, [STREAM_FILTER_ALL, STREAM_FILTER_READ, STREAM_FILTER_WRITE])) {
+ throw new OutOfBoundsException('the $mode should be a valid `STREAM_FILTER_*` constant');
+ }
+
+ $this->stream_filter_mode = $mode;
+ $this->stream_filters = [];
+
+ return $this;
+ }
+
+ /**
+ * stream filter mode getter
+ *
+ * @return integer
+ */
+ public function getStreamFilterMode()
+ {
+ return $this->stream_filter_mode;
+ }
+
+ /**
+ * Sanitize the stream filter name
+ *
+ * @param string $filter_name the stream filter name
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If $filter_name is not a string
+ */
+ protected function sanitizeStreamFilter($filter_name)
+ {
+ if (! is_string($filter_name)) {
+ throw new InvalidArgumentException(
+ 'the filtername variable must be a string'
+ );
+ }
+
+ return trim($filter_name);
+ }
+
+ /**
+ * append a stream filter
+ *
+ * @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)
+ {
+ if (is_null($this->stream_real_path)) {
+ throw new RuntimeException(
+ 'no stream path found, you can not append a stream filter'
+ );
+ }
+ $this->stream_filters[] = $this->sanitizeStreamFilter($filter_name);
+
+ return $this;
+ }
+
+ /**
+ * prepend a stream filter
+ *
+ * @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 prependStreamFilter($filter_name)
+ {
+ if (is_null($this->stream_real_path)) {
+ throw new RuntimeException(
+ 'no stream path found, you can not prepend a stream filter'
+ );
+ }
+
+ array_unshift($this->stream_filters, $this->sanitizeStreamFilter($filter_name));
+
+ return $this;
+ }
+
+ /**
+ * Detect if the stream filter is already present
+ *
+ * @param string $filter_name
+ *
+ * @return boolean
+ */
+ public function hasStreamFilter($filter_name)
+ {
+ return false !== array_search($filter_name, $this->stream_filters, true);
+ }
+
+ /**
+ * Remove a filter from the collection
+ *
+ * @param string $filter_name
+ *
+ * @return self
+ */
+ public function removeStreamFilter($filter_name)
+ {
+ $res = array_search($filter_name, $this->stream_filters, true);
+ if (false !== $res) {
+ unset($this->stream_filters[$res]);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Remove all registered stream filter
+ *
+ * @return self
+ */
+ public function clearStreamFilter()
+ {
+ $this->stream_filters = [];
+
+ return $this;
+ }
+
+ /**
+ * Return the filter path
+ *
+ * @return string
+ */
+ protected function getStreamFilterPath()
+ {
+ if (! $this->stream_filters) {
+ return $this->stream_real_path;
+ }
+
+ $prefix = '';
+ if (STREAM_FILTER_READ == $this->stream_filter_mode) {
+ $prefix = 'read=';
+ } elseif (STREAM_FILTER_WRITE == $this->stream_filter_mode) {
+ $prefix = 'write=';
+ }
+
+ return 'php://filter/'.$prefix.implode('|', $this->stream_filters).'/resource='.$this->stream_real_path;
+ }
+}
diff --git a/src/Writer.php b/src/Writer.php
index d379d7d..02a2da1 100644
--- a/src/Writer.php
+++ b/src/Writer.php
@@ -1,39 +1,19 @@
<?php
/**
-* League.csv - A CSV data manipulation library
+* This file is part of the League.csv library
*
-* @author Ignace Nyamagana Butera <nyamsprod@gmail.com>
-* @copyright 2014 Ignace Nyamagana Butera
-* @link https://github.com/thephpleague/csv/
* @license http://opensource.org/licenses/MIT
-* @version 5.4.0
+* @link https://github.com/thephpleague/csv/
+* @version 5.5.0
* @package League.csv
*
-* MIT LICENSE
-*
-* Permission is hereby granted, free of charge, to any person obtaining
-* a copy of this software and associated documentation files (the
-* "Software"), to deal in the Software without restriction, including
-* without limitation the rights to use, copy, modify, merge, publish,
-* distribute, sublicense, and/or sell copies of the Software, and to
-* permit persons to whom the Software is furnished to do so, subject to
-* the following conditions:
-*
-* The above copyright notice and this permission notice shall be
-* included in all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+* For the full copyright and license information, please view the LICENSE
+* file that was distributed with this source code.
*/
namespace League\Csv;
use Traversable;
-
+use SplFileObject;
use InvalidArgumentException;
use OutOfBoundsException;
@@ -83,6 +63,27 @@ class Writer extends AbstractCsv
protected $detect_columns_count = false;
/**
+ * {@ihneritdoc}
+ */
+ protected $stream_filter_mode = STREAM_FILTER_WRITE;
+
+ /**
+ * The CSV object holder
+ *
+ * @var \SplFileObject
+ */
+ protected $csv;
+
+ /**
+ * The destructor
+ */
+ public function __destruct()
+ {
+ $this->csv = null;
+ parent::__destruct();
+ }
+
+ /**
* Tell the class how to handle null value
*
* @param integer $value a Writer null behavior constant
@@ -213,7 +214,7 @@ class Writer extends AbstractCsv
*/
private function validateRow($row)
{
- //convert input row into a proper array
+ //convert input string row into a proper array
if (self::isValidString($row)) {
$row = str_getcsv((string) $row, $this->delimiter, $this->enclosure, $this->escape);
}
@@ -224,6 +225,7 @@ class Writer extends AbstractCsv
);
}
+ //validate row according to null handling mode
$check = array_filter($row, function ($value) {
return (is_null($value) && self::NULL_AS_EXCEPTION != $this->null_handling_mode)
|| self::isValidString($value);
@@ -239,6 +241,30 @@ class Writer extends AbstractCsv
}
/**
+ * set the csv container as a SplFileObject instance
+ * insure we use the same object for insertion to
+ * avoid loosing the cursor position
+ *
+ * @return SplFileObject
+ *
+ * @throws \RuntimeException If the file could not be created and/or opened
+ */
+ protected function getCsv()
+ {
+ if (! is_null($this->csv)) {
+ return $this->csv;
+ } elseif ($this->path instanceof SplFileObject) {
+ $this->csv = $this->path;
+
+ return $this->csv;
+ }
+
+ $this->csv = new SplFileObject($this->getStreamFilterPath(), $this->open_mode);
+
+ return $this->csv;
+ }
+
+ /**
* Add a new CSV row to the generated CSV
*
* @param mixed $data a string, an array or an object implementing to '__toString' method
@@ -257,8 +283,7 @@ class Writer extends AbstractCsv
that requires '.$this->columns_count.' columns per row.'
);
}
-
- $this->csv->fputcsv($data, $this->delimiter, $this->enclosure);
+ $this->getCsv()->fputcsv($data, $this->delimiter, $this->enclosure);
return $this;
}
@@ -266,6 +291,8 @@ class Writer extends AbstractCsv
/**
* Add multiple lines to the CSV your are generating
*
+ * a simple helper/Wrapper method around insertOne
+ *
* @param mixed $rows a multidimentional array or a Traversable object
*
* @return self
@@ -288,14 +315,12 @@ class Writer extends AbstractCsv
}
/**
- * Instantiate a {@link Reader} class from the current {@link Writer}
- *
- * @param string $open_mode the file open mode flag
+ * DEPRECATION WARNING! This method will be removed in the next major point release
*
- * @return \League\Csv\Reader
+ * @deprecated deprecated since version 5.5
*/
public function getReader($open_mode = 'r+')
{
- return $this->getInstance('\League\Csv\Reader', $open_mode);
+ return $this->createReader($open_mode);
}
}