summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorignace nyamagana butera <nyamsprod@gmail.com>2015-11-23 10:39:59 +0100
committerignace nyamagana butera <nyamsprod@gmail.com>2015-11-23 11:22:48 +0100
commit991e3b26fef334c2a21befb00a40f4c7e8fabf8b (patch)
treeb1ab1808f4a608995baddb76e1b280f9662a8f51
parent69bafa6ff924fbf9effe4275d6eb16be81a853ef (diff)
downloadcsv-991e3b26fef334c2a21befb00a40f4c7e8fabf8b.zip
csv-991e3b26fef334c2a21befb00a40f4c7e8fabf8b.tar.gz
csv-991e3b26fef334c2a21befb00a40f4c7e8fabf8b.tar.bz2
Introducing Reader::fetchPairs
In order to make League\Csv works better with huge CSV files we introduce two modes where some Reader::fetch* methods will return either an array or an iterator. The mode is defined for a single query and is by default reset to returning an array. The mode are added with the introduction of Reader::fetchPairs to returns data in an array of key-value pairs, as an associative array with a single entry per row. Adding Reader::fetchPairs requires dropping support for PHP5.4 as the method requires the use of PHP 5.5+ generators. The fetch* method callable function are also updated to ease their usage as prior to Reader::fetchPairs all callable had the same signature. Now the signature depends on the fetch* method.
-rw-r--r--.travis.yml3
-rw-r--r--README.md2
-rw-r--r--composer.json2
-rw-r--r--scrutinizer.yml2
-rw-r--r--src/AbstractCsv.php18
-rw-r--r--src/Config/Controls.php27
-rw-r--r--src/Reader.php211
-rw-r--r--test/ControlsTest.php19
-rw-r--r--test/FactoryTest.php9
-rw-r--r--test/ReaderTest.php175
10 files changed, 316 insertions, 152 deletions
diff --git a/.travis.yml b/.travis.yml
index 5798f9d..4235445 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,9 +4,6 @@ sudo: false
matrix:
include:
- - php: 5.4
- env:
- - COLLECT_COVERAGE=true
- php: 5.5
env:
- COLLECT_COVERAGE=true
diff --git a/README.md b/README.md
index 4a9d7bd..dfc0104 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ Full documentation can be found at [csv.thephpleague.com](http://csv.thephpleagu
System Requirements
-------
-You need **PHP >= 5.4.0** or **HHVM >= 3.2** and the `mbstring` extension to use `League\Csv` but the latest stable version of PHP/HHVM is recommended.
+You need **PHP >= 5.5.0** and the `mbstring` extension to use `League\Csv` but the latest stable version of PHP/HHVM is recommended.
Install
-------
diff --git a/composer.json b/composer.json
index 41cdf41..e23e011 100644
--- a/composer.json
+++ b/composer.json
@@ -37,7 +37,7 @@
}
},
"scripts": {
- "test": "vendor/bin/phpunit; vendor/bin/php-cs-fixer fix -v --diff --dry-run;"
+ "test": "phpunit; php-cs-fixer fix -v --diff --dry-run;"
},
"extra": {
"branch-alias": {
diff --git a/scrutinizer.yml b/scrutinizer.yml
index abd0a3d..a680ae9 100644
--- a/scrutinizer.yml
+++ b/scrutinizer.yml
@@ -20,4 +20,4 @@ checks:
tools:
external_code_coverage:
timeout: 1200
- runs: 3
+ runs: 2
diff --git a/src/AbstractCsv.php b/src/AbstractCsv.php
index bd07537..54cb538 100644
--- a/src/AbstractCsv.php
+++ b/src/AbstractCsv.php
@@ -97,7 +97,7 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
* a path to a file
*
* @param SplFileObject|string $path The file path
- * @param string $open_mode the file open mode flag
+ * @param string $open_mode The file open mode flag
*/
protected function __construct($path, $open_mode = 'r+')
{
@@ -172,7 +172,7 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
* @param mixed $path file path
* @param string $open_mode the file open mode flag
*
- * @throws InvalidArgumentException If $path is a \SplTempFileObject object
+ * @throws InvalidArgumentException If $path is a SplTempFileObject object
*
* @return static
*/
@@ -203,7 +203,6 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
if (is_string($str) || (is_object($str) && method_exists($str, '__toString'))) {
return (string) $str;
}
-
throw new InvalidArgumentException('Expected data must be a string or stringable');
}
@@ -237,8 +236,8 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
* The string must be an object that implements the `__toString` method,
* or a string
*
- * @param string $str the string
- * @param string $newline the newline character
+ * @param string|object $str the string
+ * @param string $newline the newline character
*
* @return static
*/
@@ -256,8 +255,8 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
/**
* Creates a {@link AbstractCsv} instance from another {@link AbstractCsv} object
*
- * @param string $class_name the class to be instantiated
- * @param string $open_mode the file open mode flag
+ * @param string $class the class to be instantiated
+ * @param string $open_mode the file open mode flag
*
* @return static
*/
@@ -285,7 +284,7 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
*/
public function newWriter($open_mode = 'r+')
{
- return $this->newInstance('\League\Csv\Writer', $open_mode);
+ return $this->newInstance(Writer::class, $open_mode);
}
/**
@@ -297,7 +296,7 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
*/
public function newReader($open_mode = 'r+')
{
- return $this->newInstance('\League\Csv\Reader', $open_mode);
+ return $this->newInstance(Reader::class, $open_mode);
}
/**
@@ -316,7 +315,6 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
if (false === ($int = filter_var($int, FILTER_VALIDATE_INT, ['options' => ['min_range' => $minValue]]))) {
throw new InvalidArgumentException($errorMessage);
}
-
return $int;
}
}
diff --git a/src/Config/Controls.php b/src/Config/Controls.php
index 5f2c362..3432974 100644
--- a/src/Config/Controls.php
+++ b/src/Config/Controls.php
@@ -103,33 +103,6 @@ trait Controls
}
/**
- * Detects the CSV file delimiters
- *
- * Returns a associative array where each key represents
- * the number of occurences and each value a delimiter with the
- * given occurence
- *
- * This method returns incorrect informations when two delimiters
- * have the same occurrence count
- *
- * DEPRECATION WARNING! This method will be removed in the next major point release
- *
- * @deprecated deprecated since version 7.2
- *
- * @param int $nb_rows
- * @param string[] $delimiters additional delimiters
- *
- * @return string[]
- */
- public function detectDelimiterList($nb_rows = 1, array $delimiters = [])
- {
- $delimiters = array_merge([$this->delimiter, ',', ';', "\t"], $delimiters);
- $stats = $this->fetchDelimitersOccurrence($delimiters, $nb_rows);
-
- return array_flip(array_filter($stats));
- }
-
- /**
* Detect Delimiters occurences in the CSV
*
* Returns a associative array where each key represents
diff --git a/src/Reader.php b/src/Reader.php
index e422d31..23c0e90 100644
--- a/src/Reader.php
+++ b/src/Reader.php
@@ -12,7 +12,7 @@
*/
namespace League\Csv;
-use CallbackFilterIterator;
+use Generator;
use InvalidArgumentException;
use Iterator;
use League\Csv\Modifier\MapIterator;
@@ -28,29 +28,52 @@ use SplFileObject;
*/
class Reader extends AbstractCsv
{
+ const FETCH_ARRAY = 1;
+
+ const FETCH_ITERATOR = 2;
+
/**
* @inheritdoc
*/
protected $stream_filter_mode = STREAM_FILTER_READ;
/**
- * Returns a Filtered Iterator
+ * Reader fetch mode
*
- * DEPRECATION WARNING! This method will be removed in the next major point release
+ * @var int
+ */
+ protected $fetchMode = self::FETCH_ARRAY;
+
+ /**
+ * returns the current fetch mode
*
- * @deprecated deprecated since version 7.2
+ * @return int
+ */
+ public function getFetchMode()
+ {
+ return $this->fetchMode;
+ }
+
+ /**
+ * Set the Reader fetch mode for the next call
*
- * @return Iterator
+ * @param static
*/
- public function query(callable $callable = null)
+ public function setFetchMode($mode)
{
- return $this->fetch($callable);
+ $modes = [static::FETCH_ARRAY => 1, static::FETCH_ITERATOR => 1];
+ if (!isset($modes[$mode])) {
+ throw new InvalidArgumentException('Unknown return type mode');
+ }
+ $this->fetchMode = $mode;
+
+ return $this;
}
/**
* Return a Filtered Iterator
*
- * @param callable $callable a callable function to be applied to each Iterator item
+ * @param callable|null $callable a callable function to be applied to each Iterator item
*
* @return Iterator
*/
@@ -72,6 +95,20 @@ class Reader extends AbstractCsv
}
/**
+ * Returns a sequential array of all CSV lines
+ *
+ * The callable function will be applied to each Iterator item
+ *
+ * @param callable $callable a callable function
+ *
+ * @return array
+ */
+ public function fetchAll(callable $callable = null)
+ {
+ return iterator_to_array($this->fetch($callable), false);
+ }
+
+ /**
* Applies a callback function on the CSV
*
* The callback function must return TRUE in order to continue
@@ -102,6 +139,8 @@ class Reader extends AbstractCsv
/**
* Returns a single row from the CSV
*
+ * By default if no offset is provided the first row of the CSV is selected
+ *
* @param int $offset
*
* @throws InvalidArgumentException If the $offset is not a valid Integer
@@ -119,49 +158,120 @@ class Reader extends AbstractCsv
}
/**
- * Returns a sequential array of all CSV lines
+ * Returns a single column from the CSV data
*
- * The callable function will be applied to each Iterator item
+ * The callable function will be applied to each value to be return
*
- * @param callable $callable a callable function
+ * By default if no column index is provided the first column of the CSV is selected
*
- * @return array
+ * @param int $column_index field Index
+ * @param callable|null $callable a callable function
+ *
+ * @throws InvalidArgumentException If the column index is not a positive integer or 0
+ *
+ * @return Iterator|array
*/
- public function fetchAll(callable $callable = null)
+ public function fetchColumn($columnIndex = 0, callable $callable = null)
{
- return iterator_to_array($this->fetch($callable), false);
+ $this->assertValidColumnIndex($columnIndex);
+
+ $filterColumn = function ($row) use ($columnIndex) {
+ return array_key_exists($columnIndex, $row);
+ };
+
+ $selectColumn = function ($row) use ($columnIndex) {
+ return $row[$columnIndex];
+ };
+
+ $this->addFilter($filterColumn);
+ $iterator = $this->fetch($selectColumn);
+ if (!is_null($callable)) {
+ $iterator = new MapIterator($iterator, $callable);
+ }
+
+ return $this->toArray($iterator, false);
}
/**
- * Returns a single column from the CSV data
+ * Convert the Iterator into an array depending on the class fetchMode
*
- * The callable function will be applied to each value to be return
+ * @param Iterator $iterator
+ * @param bool $use_keys Whether to use the iterator element keys as index
*
- * @param int $column_index field Index
- * @param callable $callable a callable function
+ * @return Iterator|array
+ */
+ protected function toArray(Iterator $iterator, $use_keys = true)
+ {
+ if (static::FETCH_ARRAY == $this->fetchMode) {
+ return iterator_to_array($iterator, $use_keys);
+ }
+ $this->fetchMode = static::FETCH_ARRAY;
+
+ return $iterator;
+ }
+
+ /**
+ * Validate a CSV row index
*
- * @throws InvalidArgumentException If the column index is not a positive integer or 0
+ * @param int $index
*
- * @return array
+ * @throws InvalidArgumentException If the column index is not a positive integer or 0
*/
- public function fetchColumn($column_index = 0, callable $callable = null)
+ protected function assertValidColumnIndex($index)
{
- if (false === filter_var($column_index, FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]])) {
- throw new InvalidArgumentException(
- 'the column index must be a positive integer or 0'
- );
+ if (false === filter_var($index, FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]])) {
+ throw new InvalidArgumentException('the column index must be a positive integer or 0');
}
- $filterColumn = function ($row) use ($column_index) {
- return array_key_exists($column_index, $row);
+ }
+
+ /**
+ * Retrive CSV data as pairs
+ *
+ * Fetches an associative array of all rows as key-value pairs (first
+ * column is the key, second column is the value).
+ *
+ * By default if no column index is provided:
+ * - the first CSV column is used to provide the keys
+ * - the second CSV column is used to provide the value
+ *
+ * @param int $offsetColumnIndex The column index to server as offset
+ * @param int $valueColumnIndex The column index to server as value
+ * @param callable|null $callable Callback function to run for each element in each array
+ *
+ * @return Generator|array
+ */
+ public function fetchPairs($offsetColumnIndex = 0, $valueColumnIndex = 1, callable $callable = null)
+ {
+ $this->assertValidColumnIndex($offsetColumnIndex);
+ $this->assertValidColumnIndex($valueColumnIndex);
+ $filterPairs = function ($row) use ($offsetColumnIndex, $valueColumnIndex) {
+ return array_key_exists($offsetColumnIndex, $row) && array_key_exists($valueColumnIndex, $row);
};
- $selectColumn = function ($row) use ($column_index) {
- return $row[$column_index];
+ $selectPairs = function ($row) use ($offsetColumnIndex, $valueColumnIndex) {
+ return [$row[$offsetColumnIndex], $row[$valueColumnIndex]];
};
+ $this->addFilter($filterPairs);
+ $iterator = $this->fetch($selectPairs);
- $iterator = $this->fetch($callable);
- $iterator = new CallbackFilterIterator($iterator, $filterColumn);
+ if (!is_null($callable)) {
+ $iterator = new MapIterator($iterator, $callable);
+ }
- return iterator_to_array(new MapIterator($iterator, $selectColumn), false);
+ return $this->toArray($this->fetchPairsGenerator($iterator), true);
+ }
+
+ /**
+ * Return the key/pairs as a PHP generator
+ *
+ * @param Iterator $iterator
+ *
+ * @return Generator
+ */
+ protected function fetchPairsGenerator(Iterator $iterator)
+ {
+ foreach ($iterator as $row) {
+ yield $row[0] => $row[1];
+ }
}
/**
@@ -177,7 +287,7 @@ class Reader extends AbstractCsv
*
* @throws InvalidArgumentException If the submitted keys are invalid
*
- * @return Iterator
+ * @return Iterator|array
*/
public function fetchAssoc($offset_or_keys = 0, callable $callable = null)
{
@@ -191,7 +301,7 @@ class Reader extends AbstractCsv
return array_combine($keys, $row);
};
- return iterator_to_array(new MapIterator($this->fetch($callable), $combineArray), false);
+ return $this->toArray(new MapIterator($this->fetch($callable), $combineArray), false);
}
/**
@@ -207,7 +317,9 @@ class Reader extends AbstractCsv
protected function getAssocKeys($offset_or_keys)
{
if (is_array($offset_or_keys)) {
- return $this->validateAssocKeys($offset_or_keys);
+ $this->assertValidAssocKeys($offset_or_keys);
+
+ return $offset_or_keys;
}
if (false === filter_var($offset_or_keys, FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]])) {
@@ -215,7 +327,7 @@ class Reader extends AbstractCsv
}
$keys = $this->getRow($offset_or_keys);
- $keys = $this->validateAssocKeys($keys);
+ $this->assertValidAssocKeys($keys);
$filterOutRow = function ($row, $rowIndex) use ($offset_or_keys) {
return is_array($row) && $rowIndex != $offset_or_keys;
};
@@ -231,22 +343,23 @@ class Reader extends AbstractCsv
*
* @throws InvalidArgumentException If the submitted array fails the assertion
*/
- protected function validateAssocKeys(array $keys)
+ protected function assertValidAssocKeys(array $keys)
{
- if (empty($keys)) {
- throw new InvalidArgumentException('The array can not be empty');
- }
-
- foreach ($keys as &$str) {
- $str = $this->validateString($str);
- }
- unset($str);
-
- if ($keys == array_unique($keys)) {
- return $keys;
+ if (empty($keys) || $keys !== array_unique(array_filter($keys, [$this, 'isValidString']))) {
+ throw new InvalidArgumentException('Use a flat array with unique string values');
}
+ }
- throw new InvalidArgumentException('The array must contain unique values');
+ /**
+ * Returns whether the submitted value can be used as string
+ *
+ * @param mixed $value
+ *
+ * @return bool
+ */
+ protected function isValidString($value)
+ {
+ return is_scalar($value) || (is_object($value) && method_exists($value, '__toString'));
}
/**
diff --git a/test/ControlsTest.php b/test/ControlsTest.php
index 4eebed7..35f6fe8 100644
--- a/test/ControlsTest.php
+++ b/test/ControlsTest.php
@@ -1,9 +1,10 @@
<?php
-namespace League\Csv\Test;
+namespace League\Csv\test;
use League\Csv\Reader;
use League\Csv\Writer;
+use PHPUnit_Framework_TestCase;
use SplFileObject;
use SplTempFileObject;
@@ -12,7 +13,7 @@ date_default_timezone_set('UTC');
/**
* @group controls
*/
-class ControlsTest extends AbstractTestCase
+class ControlsTest extends PHPUnit_Framework_TestCase
{
private $csv;
@@ -93,7 +94,7 @@ class ControlsTest extends AbstractTestCase
public function testDetectDelimiterList()
{
- $this->assertSame([4 => ','], $this->csv->detectDelimiterList());
+ $this->assertSame([',' => 4], $this->csv->fetchDelimitersOccurrence([',']));
}
/**
@@ -102,7 +103,7 @@ class ControlsTest extends AbstractTestCase
*/
public function testDetectDelimiterListWithInvalidRowLimit()
{
- $this->csv->detectDelimiterList(-4);
+ $this->csv->fetchDelimitersOccurrence([','], -4);
}
public function testDetectDelimiterListWithNoCSV()
@@ -110,7 +111,7 @@ class ControlsTest extends AbstractTestCase
$file = new SplTempFileObject();
$file->fwrite("How are you today ?\nI'm doing fine thanks!");
$csv = Writer::createFromFileObject($file);
- $this->assertSame([], $csv->detectDelimiterList(5, ['toto', '|']));
+ $this->assertSame(['|' => 0], $csv->fetchDelimitersOccurrence(['toto', '|'], 5));
}
public function testDetectDelimiterListWithInconsistentCSV()
@@ -124,7 +125,7 @@ class ControlsTest extends AbstractTestCase
$data->fputcsv(['toto', 'tata', 'tutu']);
$csv = Writer::createFromFileObject($data);
- $this->assertSame([12 => '|', 4 => ';'], $csv->detectDelimiterList(5, ['|']));
+ $this->assertSame(['|' => 12, ';' => 4], $csv->fetchDelimitersOccurrence(['|', ';'], 5));
}
/**
@@ -192,12 +193,14 @@ class ControlsTest extends AbstractTestCase
* @param $flag
* @param $line_count
* @dataProvider appliedFlagsProvider
- * @skipIfHHVM
*/
public function testAppliedFlags($flag, $line_count)
{
+ if (defined('HHVM_VERSION')) {
+ $this->markTestSkipped('HHVM CSV parsing is different');
+ }
$path = __DIR__.'/data/tmp.txt';
- $obj = new SplFileObject($path, 'w+');
+ $obj = new SplFileObject($path, 'w+');
$obj->fwrite("1st\n2nd\n");
$reader = Reader::createFromFileObject($obj);
$reader->setFlags($flag);
diff --git a/test/FactoryTest.php b/test/FactoryTest.php
index e35b402..377b1b9 100644
--- a/test/FactoryTest.php
+++ b/test/FactoryTest.php
@@ -2,7 +2,6 @@
namespace League\Csv\Test;
-use DateTime;
use League\Csv\Reader;
use SplFileInfo;
use SplFileObject;
@@ -42,14 +41,6 @@ class FactoryTest extends AbstractTestCase
Reader::createFromPath(new SplTempFileObject());
}
- /**
- * @expectedException InvalidArgumentException
- */
- public function testCreateFromPathWithUnStringableObject()
- {
- Reader::createFromPath(new DateTime());
- }
-
public function testCreateFromString()
{
$expected = 'john,doe,john.doe@example.com'.PHP_EOL
diff --git a/test/ReaderTest.php b/test/ReaderTest.php
index d650c51..4535dce 100644
--- a/test/ReaderTest.php
+++ b/test/ReaderTest.php
@@ -1,14 +1,16 @@
<?php
-namespace League\Csv\Test;
+namespace League\Csv\test;
use League\Csv\Reader;
+use League\Csv\Writer;
+use PHPUnit_Framework_TestCase;
use SplTempFileObject;
/**
* @group reader
*/
-class ReaderTest extends AbstractTestCase
+class ReaderTest extends PHPUnit_Framework_TestCase
{
private $csv;
@@ -151,10 +153,21 @@ class ReaderTest extends AbstractTestCase
$this->assertContains(['JANE', 'DOE', 'JANE.DOE@EXAMPLE.COM'], $res);
}
- public function testFetchAssoc()
+ public function testFetchAssocReturnsArray()
{
$keys = ['firstname', 'lastname', 'email'];
$res = $this->csv->fetchAssoc($keys);
+ $this->assertInternalType('array', $res);
+ foreach ($res as $offset => $row) {
+ $this->assertSame($keys, array_keys($row));
+ }
+ }
+
+ public function testFetchAssocReturnsIterator()
+ {
+ $keys = ['firstname', 'lastname', 'email'];
+ $res = $this->csv->setFetchMode(Reader::FETCH_ITERATOR)->fetchAssoc($keys);
+ $this->assertInstanceof('\Iterator', $res);
foreach ($res as $offset => $row) {
$this->assertSame($keys, array_keys($row));
}
@@ -216,15 +229,6 @@ class ReaderTest extends AbstractTestCase
}
/**
- * @expectedException \InvalidArgumentException
- */
- public function testFetchAssocThrowsExceptionWithNonUniqueAssocKeys()
- {
- $keys = ['firstname', 'lastname', 'firstname'];
- $this->csv->fetchAssoc($keys);
- }
-
- /**
* @param $expected
* @dataProvider validBOMSequences
*/
@@ -364,21 +368,19 @@ class ReaderTest extends AbstractTestCase
];
}
- public function testFetchCol()
+ public function testFetchColumn()
{
- $this->csv->addFilter(function ($row) {
- return $row != [null];
-
- });
- $this->assertSame(['john', 'jane'], $this->csv->fetchColumn(0));
- $this->csv->addFilter(function ($row) {
- return $row != [null];
+ $this->assertContains('john', $this->csv->fetchColumn(0));
+ $this->assertContains('jane', $this->csv->fetchColumn());
+ }
- });
- $this->assertSame(['john', 'jane'], $this->csv->fetchColumn());
+ public function testFetchColumnReturnsIterator()
+ {
+ $this->assertContains('john', $this->csv->setFetchMode(Reader::FETCH_ITERATOR)->fetchColumn(0));
+ $this->assertContains('jane', $this->csv->setFetchMode(Reader::FETCH_ITERATOR)->fetchColumn());
}
- public function testFetchColInconsistentColumnCSV()
+ public function testFetchColumnInconsistentColumnCSV()
{
$raw = [
['john', 'doe'],
@@ -390,16 +392,11 @@ class ReaderTest extends AbstractTestCase
$file->fputcsv($row);
}
$csv = Reader::createFromFileObject($file);
- $this->csv->addFilter(function ($row) {
- return $row != [null];
-
- });
$res = $csv->fetchColumn(2);
- $this->assertInternalType('array', $res);
$this->assertCount(1, $res);
}
- public function testFetchColEmptyCol()
+ public function testFetchColumnEmptyCol()
{
$raw = [
['john', 'doe'],
@@ -412,31 +409,23 @@ class ReaderTest extends AbstractTestCase
}
$csv = Reader::createFromFileObject($file);
$res = $csv->fetchColumn(2);
- $this->csv->addFilter(function ($row) {
- return $row != [null];
-
- });
- $this->assertInternalType('array', $res);
$this->assertCount(0, $res);
}
- public function testFetchColCallback()
+ public function testFetchColumnCallback()
{
$func = function ($value) {
- return array_map('strtoupper', $value);
+ return strtoupper($value);
};
- $this->csv->addFilter(function ($row) {
- return $row != [null];
-
- });
- $this->assertSame(['JOHN', 'JANE'], $this->csv->fetchColumn(0, $func));
+ $iterator = $this->csv->fetchColumn(0, $func);
+ $this->assertSame(['JOHN', 'JANE'], $iterator);
}
/**
* @expectedException \InvalidArgumentException
*/
- public function testFetchColFailure()
+ public function testFetchColumnFailure()
{
$this->csv->fetchColumn('toto');
}
@@ -482,6 +471,106 @@ class ReaderTest extends AbstractTestCase
public function testGetWriter()
{
- $this->assertInstanceOf('\League\Csv\Writer', $this->csv->newWriter());
+ $this->assertInstanceOf(Writer::class, $this->csv->newWriter());
+ }
+
+ /**
+ * @dataProvider fetchPairsDataProvider
+ */
+ public function testFetchPairsIteratorMode($key, $value, $callable, $expected)
+ {
+ $iterator = $this->csv->setFetchMode(Reader::FETCH_ITERATOR)->fetchPairs($key, $value, $callable);
+ foreach ($iterator as $key => $value) {
+ $res = current($expected);
+ $this->assertSame($value, $res[$key]);
+ next($expected);
+ }
+ }
+
+ public function fetchPairsDataProvider()
+ {
+ return [
+ 'default values' => [
+ 'key' => 0,
+ 'value' => 1,
+ 'callable' => null,
+ 'expected' => [
+ ['john' => 'doe'],
+ ['jane' => 'doe'],
+ ],
+ ],
+ 'changed key order' => [
+ 'key' => 1,
+ 'value' => 0,
+ 'callable' => null,
+ 'expected' => [
+ ['doe' => 'john'],
+ ['doe' => 'jane'],
+ ],
+ ],
+ 'with callback' => [
+ 'key' => 0,
+ 'value' => 1,
+ 'callable' => function ($row) {
+ return [
+ strtoupper($row[0]),
+ strtoupper($row[1]),
+ ];
+ },
+ 'expected' => [
+ ['JOHN' => 'DOE'],
+ ['JANE' => 'DOE'],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider fetchPairsArrayDataProvider
+ */
+ public function testFetchPairsArrayMode($key, $value, $callable, $expected)
+ {
+ $array = $this->csv->fetchPairs($key, $value, $callable);
+ $this->assertSame($expected, $array);
+ }
+
+ public function fetchPairsArrayDataProvider()
+ {
+ return [
+ 'default values' => [
+ 'key' => 0,
+ 'value' => 1,
+ 'callable' => null,
+ 'expected' => ['john' => 'doe', 'jane' => 'doe'],
+ ],
+ 'changed key order' => [
+ 'key' => 1,
+ 'value' => 0,
+ 'callable' => null,
+ 'expected' => ['doe' => 'jane'],
+ ],
+ 'with callback' => [
+ 'key' => 0,
+ 'value' => 1,
+ 'callable' => function ($row) {
+ return [
+ strtoupper($row[0]),
+ strtoupper($row[1]),
+ ];
+ },
+ 'expected' => ['JOHN' => 'DOE', 'JANE' => 'DOE'],
+ ],
+ ];
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testFetchMode()
+ {
+ $this->assertSame(Reader::FETCH_ARRAY, $this->csv->getFetchMode());
+ $this->csv->setFetchMode(Reader::FETCH_ITERATOR);
+ $this->assertSame(Reader::FETCH_ITERATOR, $this->csv->getFetchMode());
+ $this->csv->setFetchMode('toto');
}
}