Compare commits

..

No commits in common. "master" and "v1" have entirely different histories.
master ... v1

19 changed files with 382 additions and 1143 deletions

3
.gitignore vendored
View file

@ -1 +1,4 @@
*.swp
tags
/vendor/

View file

@ -1,17 +0,0 @@
matrix:
PHP_VERSION:
- 7.3
- 7.4
- 8.0
- 8.1
pipeline:
dependencies:
image: gitnet.fr/deblan/php:${PHP_VERSION}
commands:
- php /usr/local/bin/composer install
- php /usr/local/bin/composer require --dev phpunit/phpunit
tests:
image: gitnet.fr/deblan/php:${PHP_VERSION}
commands:
- php ./vendor/bin/phpunit

View file

@ -20,5 +20,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

107
README.md
View file

@ -1,20 +1,12 @@
CSV parser/generator
====================
[![Build Status](https://ci.gitnet.fr/api/badges/deblan/csv/status.svg)](https://ci.gitnet.fr/deblan/csv)
A simple PHP library to:
* parse a CSV file
* parse a stream as CSV datas
* generate CSV files.
PHP >= 7.1 required.
A simple PHP library to parse and generate CSV files.
## Composer installation
```
$ composer require deblan/csv "~3"
$ composer require deblan/csv
```
Or in your composer.json:
@ -22,7 +14,8 @@ Or in your composer.json:
```
{
"require": {
"deblan/csv": "~3"
[...]
"deblan/csv": "dev-master"
}
}
```
@ -36,85 +29,33 @@ use Deblan\Csv\Csv;
$csv = new Csv();
// Defines the delimiter (default is ;)
$csv->setDelimiter(";");
$csv->addLine(array('Foo', '$1000'));
$csv->addLine(array('Bar', '$600'));
// Defines the enclosure (default is ")
$csv->setEnclosure('"');
// Defines the end of line (default is \n)
$csv->setEndOfLine("\n");
// Defines the charset (default is UTF-8)
$csv->setCharset("UTF-8");
// Add a new line at the end
$csv->addData(['Foo', '$1000'));
// Add a new line at the end
$csv->appendData(['Bar', '$600']);
// Add a new line at the beginning
$csv->prependData(['Boo', '$3000']);
// Defines all the datas
$csv->setDatas([[...], [...]]);
// Defines the header
$csv->setHeaders(['Product', 'Price']);
// Rendering
$result = $csv->render();
// Rendering to a file
$result = $csv->render('products.csv');
// Appending to a file
$result = $csv->render('products.csv', FILE_APPEND);
$result = $csv->compile();
```
### Parse a file
```php
use Deblan\Csv\Csv;
$csv = new Csv();
$csv->setLegend(array('product name', 'price'));
$csv->addLine(array('Foo', '$1000'));
$csv->addLine(array('Bar', '$600'));
$csv->compileToFile('products.csv');
```
### Parser
```php
use Deblan\Csv\CsvParser;
$csv = new CsvParser();
$csv = new CsvParser('products.csv');
$csv->setHasLegend(true);
$csv->parse();
// Defines the delimiter (default is ;)
$csv->setDelimiter(";");
// Defines the enclosure (default is ")
$csv->setEnclosure('"');
// Defines the end of line (default is \n)
$csv->setEndOfLine("\n");
// Headers?
$csv->setHasHeaders(true);
// Parse a file
$csv->parseFile('products.csv');
// Parse a string
$csv->parseString($myString);
// Headers and datas
$headers = $csv->getHeaders();
$legend = $csv->getLegend();
$products = $csv->getDatas();
```
### Parse a stream
```php
use Deblan\Csv\CsvStreamParser;
// CsvStreamParser is a CsvParser
$csv = new CsvStreamParser();
// Parse a stream
$csv->parseStream(fopen('products.csv', 'r'));
while ($data = $csv->getData()) {
// ...
}
```

View file

@ -7,11 +7,12 @@
convertWarningsToExceptions = "true"
processIsolation = "false"
stopOnFailure = "false"
syntaxCheck = "false"
bootstrap = "vendor/autoload.php" >
<testsuites>
<testsuite name="Deblan CSV Test Suite">
<directory>tests/</directory>
</testsuite>
</testsuites>
<testsuites>
<testsuite name="Deblan CSV Test Suite">
<directory>tests/</directory>
</testsuite>
</testsuites>
</phpunit>

View file

@ -2,340 +2,192 @@
namespace Deblan\Csv;
/**
* class Csv.
*
* @author Simon Vieille <simon@deblan.fr>
*/
use Deblan\Csv\Exception\CsvInvalidParameterException;
class Csv
{
/**
* @var string
*/
protected $delimiter = ';';
private $delimiter;
/**
* @var string
*/
protected $enclosure = '"';
private $enclosure;
/**
* @var string
*/
protected $endOfLine = "\n";
private $endline;
/**
* @var array
*/
protected $datas = [];
private $datas;
/**
* @var array
*/
protected $headers = [];
private $legend;
/**
* @var string
*/
protected $charset = 'UTF-8';
private $render;
/**
* @var bool
*/
protected $isModified = false;
private $encoding;
/**
* @var string
*/
protected $render;
private $hasLegend = false;
/**
* Set the value of "delimiter".
*
* @param string $delimiter
*
* @return Csv
*/
public function setDelimiter($delimiter)
public function __construct($delimiter = ';', $enclosure = '"', $endline = "\n", $encoding = 'UTF-8')
{
if ($this->delimiter !== $delimiter) {
$this->delimiter = $delimiter;
$this->isModified = true;
$this->setDelimiter($delimiter);
$this->setEnclosure($enclosure);
$this->setEndLine($endline);
$this->setEncoding($encoding);
$this->datas = array(0 => null);
$this->legend = array();
$this->render = "";
}
public function setFilename($v)
{
if (!is_string($v)) {
throw new CsvInvalidParameterException(sprintf('"%s" is not a valid string.', $v));
}
$this->filename = $v;
}
protected function setHasLegend($hasLegend)
{
$this->hasLegend = $hasLegend;
return $this;
}
/**
* Get the value of "delimiter".
*
* @return array
*/
public function getDelimiter()
public function getHasLegend()
{
return $this->delimiter;
return $this->hasLegend;
}
/**
* Set the value of "enclosure".
*
* @param string $enclosure
*
* @return Csv
*/
public function setEnclosure($enclosure)
public function hasLegend()
{
$enclosure = (string) $enclosure;
return $this->hasLegend;
}
if ($this->enclosure !== $enclosure) {
$this->enclosure = $enclosure;
$this->isModified = true;
public function setLegend(array $values)
{
$this->setHasLegend(true);
$this->legend = $values;
$this->addLine($values, 0);
}
public function addLine(array $values, $key = null)
{
if ($key !== null) {
$this->datas[$key] = $values;
return true;
}
$this->datas[] = $values;
}
public function setEncoding($encoding)
{
$this->encoding = $encoding;
return $this;
}
/**
* Get the value of "enclosure".
*
* @return string
*/
public function getEnclosure()
public function getEncoding()
{
return $this->enclosure;
return $this->encoding;
}
/**
* Set the value of "endOfLine".
*
* @param string $endOfLine
*
* @return Csv
*/
public function setEndOfLine($endOfLine)
public function setDelimiter($v)
{
if ($this->endOfLine !== $endOfLine) {
$this->endOfLine = (string) $endOfLine;
$this->isModified = true;
if (!is_string($v)) {
throw new CsvInvalidParameterException(sprintf('"%s" is not a valid string.', $v));
}
return $this;
$this->delimiter = $v;
}
/**
* Get the value of "endOfLine".
*
* @return string
*/
public function getEndOfLine()
public function setEndline($v)
{
return $this->endOfLine;
}
/**
* Set the value of "headers".
*
* @param array $headers
*
* @return Csv
*/
public function setHeaders(array $headers)
{
$this->headers = $headers;
if ($this->headers !== $headers) {
$this->headers = $headers;
$this->isModified = true;
if (!is_string($v)) {
throw new CsvInvalidParameterException(sprintf('"%s" is not a valid string.', $v));
}
return $this;
$this->endline = $v;
}
/**
* Get the value of "headers".
*
* @return array
*/
public function getHeaders()
public function setEnclosure($v)
{
return $this->headers;
}
/**
* Set the value of "charset".
*
* @param string $charset
*
* @return Csv
*/
public function setCharset($charset)
{
if ($this->charset !== $charset) {
$this->charset = (string) $charset;
$this->isModified = true;
if (!is_string($v)) {
throw new CsvInvalidParameterException(sprintf('"%s" is not a valid string.', $v));
}
return $this;
$this->enclose = $v;
}
/**
* Get the value of "charset".
*
* @return string
*/
public function getCharset()
public function getLegend()
{
return $this->charset;
return $this->legend;
}
/*
* Sets the value of "datas".
*
* @param array $datas
*
* @return Csv
*/
public function setDatas(array $datas)
{
if ($this->datas !== $datas) {
$this->datas = $datas;
$this->isModified = true;
}
return $this;
}
/**
* Get the value of "datas".
*
* @return array
*/
public function getDatas()
{
return $this->datas;
}
/*
* Appends data.
*
* @param array $data
*
* @return Csv
*/
public function appendData(array $data)
public function compile()
{
$this->datas[] = $data;
$this->isModified = true;
$this->render = "";
return $this;
}
/*
* Alias of "appendData()".
*
* {@inheritdoc self::appendData()}
*/
public function addData(array $data)
{
return $this->appendData($data);
}
/*
* Prepends data.
*
* @param array $data
*
* @return Csv
*/
public function preprendData(array $data)
{
array_unshift($this->datas, $data);
$this->isModified = true;
return $this;
}
/**
* Formats an array data to a CSV string.
*
* @param array $data
*
* @return array
*/
protected function formatData(array $data)
{
$columns = [];
foreach ($data as $value) {
$value = (string) $value;
if (!empty($this->enclosure)) {
$value = str_replace($this->enclosure, str_repeat($this->enclosure, 2), $value);
}
$value = sprintf('%1$s%2$s%1$s', $this->enclosure, (string) $value);
$columns[] = $value;
if ($this->datas[0] !== null) {
$this->append($this->datasToCsvLine($this->datas[0]));
}
$data = implode($this->delimiter, $columns);
$data = $this->encode($data);
unset($this->datas[0]);
return $data;
}
/*
* Changes the charset if needed.
*
* @param string $value
*
* @return string
*/
public function encode($value)
{
return mb_convert_encoding(
$value,
$this->charset,
mb_detect_encoding($value, mb_list_encodings())
);
}
/*
* Renders the CSV.
*
* @param string $filename @see file_put_contents
* @param int $flags @see file_put_contents
*
* @return string
*/
public function render($filename = null, $flags = null)
{
if ($this->isModified || empty($this->render)) {
$lines = [];
if (!empty($this->headers)) {
$lines[] = $this->formatData($this->headers);
}
foreach ($this->datas as $data) {
$lines[] = $this->formatData($data);
}
$this->render = implode($this->encode($this->endOfLine), $lines);
foreach ($this->datas as $v) {
$this->append($this->datasToCsvLine($v));
}
$this->isModified = false;
if ($filename !== null) {
$content = $this->render;
if ($flags === FILE_APPEND && file_exists($filename)) {
$content = $this->endOfLine.$content;
}
file_put_contents($filename, $content, $flags);
if ($this->encoding !== 'UTF-8') {
$this->render = iconv(
mb_detect_encoding($this->render),
$this->encoding,
$this->render
);
}
return $this->render;
}
public function hasDatas()
{
return count($this->datas) > 1;
}
protected function datasToCsvLine($datas)
{
foreach ($datas as $k => $v) {
$v = str_replace('\\', '\\\\', $v);
if ($this->enclose) {
$v = str_replace($this->enclose, '\\'.$this->enclose, $v);
} else {
$v = str_replace($this->delimiter, '\\'.$this->delimiter, $v);
}
$datas[$k] = $this->enclose.$v.$this->enclose;
}
$datas = implode($this->delimiter, $datas);
return $datas;
}
protected function append($line)
{
$this->render.= sprintf("%s%s", $line, $this->endline);
}
public function compileToFile($filename)
{
if (file_exists($filename)) {
unlink($filename);
}
file_put_contents($filename, $this->compile());
}
}

View file

@ -2,225 +2,149 @@
namespace Deblan\Csv;
/**
* class Csv.
*
* @author Simon Vieille <simon@deblan.fr>
*/
use Deblan\Csv\Exception\CsvParserInvalidParameterException;
use Deblan\Csv\Exception\CsvParserException;
class CsvParser
{
/**
* @var string
*/
protected $delimiter = ';';
private $filename;
/**
* @var string
*/
protected $enclosure = '"';
private $delimiter;
/**
* @var string
*/
protected $endOfLine = "\n";
private $enclosure;
/**
* @var array
*/
protected $datas = [];
private $escapeChar;
/**
* @var array
*/
protected $headers = [];
private $hasLegend;
/**
* @var bool
*/
protected $hasHeaders = false;
private $datas = array();
/**
* Set the value of "delimiter".
*
* @param string $delimiter
*
* @return Csv
*/
public function setDelimiter($delimiter)
private $legend = array();
private $nullValues = array();
public function __construct($filename, $delimiter = ';', $enclosure = '"', $escapeChar = '\\', $hasLegend = false, array $nullValues = array(''))
{
$this->delimiter = (string) $delimiter;
$this->setFilename($filename);
$this->setDelimiter($delimiter);
$this->setEnclosure($enclosure);
$this->setEscapeChar($escapeChar);
$this->setHasLegend($hasLegend);
$this->setNullValues($nullValues);
}
return $this;
public function setFilename($v)
{
if (!is_string($v)) {
throw new CsvParserInvalidParameterException(sprintf('"%s" is not a valid string.', $v));
}
if (!file_exists($v)) {
throw new CsvParserException(sprintf('"%s" does not exist.', $v));
}
if (!is_readable($v)) {
throw new CsvParserException(sprintf('"%s" is not readable.', $v));
}
$this->filename = $v;
}
public function setDelimiter($v)
{
if (!is_string($v)) {
throw new CsvParserInvalidParameterException(sprintf('"%s" is not a valid string.', $v));
}
$this->delimiter = $v;
}
public function setEnclosure($v)
{
if (!is_string($v)) {
throw new CsvParserInvalidParameterException(sprintf('"%s" is not a valid string.', $v));
}
$this->enclosure = $v;
}
public function setEscapeChar($v)
{
if (!is_string($v)) {
throw new CsvParserInvalidParameterException(sprintf('"%s" is not a valid string.', $v));
}
$this->escapeChar = $v;
}
public function setHasLegend($v)
{
if (!is_bool($v)) {
throw new CsvParserInvalidParameterException(sprintf('"%s" is not a valid bool.', $v));
}
$this->hasLegend = $v;
}
public function getHasLegend()
{
return $this->hasLegend;
}
public function getLegend()
{
return $this->legend;
}
public function setNullValues(array $v)
{
$this->nullValues = $v;
}
/**
* Get the value of "delimiter".
*
* @return array
* To improve...
*
*/
public function getDelimiter()
protected function cleanNullValues($line)
{
return $this->delimiter;
return str_replace($this->nullValues, '', $line);
}
/**
* Set the value of "enclosure".
*
* @param string $enclosure
*
* @return Csv
*/
public function setEnclosure($enclosure)
{
$this->enclosure = (string) $enclosure;
return $this;
}
/**
* Get the value of "enclosure".
*
* @return string
*/
public function getEnclosure()
{
return $this->enclosure;
}
/**
* Set the value of "endOfLine".
*
* @param string $endOfLine
*
* @return Csv
*/
public function setEndOfLine($endOfLine)
{
$this->endOfLine = (string) $endOfLine;
return $this;
}
/**
* Get the value of "endOfLine".
*
* @return string
*/
public function getEndOfLine()
{
return $this->endOfLine;
}
/**
* Get the value of "hasHeaders".
*
* @return bool
*/
public function getHasHeaders()
{
return $this->hasHeaders;
}
/**
* Set the value of "headers".
*
* @param bool $hasHeaders
*
* @return Csv
*/
public function setHasHeaders($hasHeaders)
{
$this->hasHeaders = (bool) $hasHeaders;
return $this;
}
/**
* Get the value of "headers".
*
* @return array
*/
public function getHeaders()
{
return $this->headers;
}
/**
* Get the value of "datas".
*
* @return array
*/
public function getDatas()
{
return $this->datas;
}
/*
* Parses a string.
*
* @param string $string
*
* @return CsvParser
*/
public function parseString($string)
public function parse()
{
$this->datas = [];
$this->headers = [];
$lines = str_getcsv($string, $this->endOfLine);
foreach ($lines as $key => $line) {
$data = $this->parseLine($line, $this->hasHeaders && $key === 0);
if ($data === null) {
continue;
}
if ($this->hasHeaders && $key === 0) {
$this->headers = $data;
} else {
$this->datas[] = $data;
}
if (!empty($this->datas)) {
return $this->datas;
}
return $this;
}
$lines = file($this->filename);
/*
* Parses a line.
*
* @param string $line
* @param bool $isHeaders
*
* @return array
*/
public function parseLine($line, $isHeaders = false)
{
$line = trim($line);
if (empty($line)) {
return null;
if (empty($lines)) {
return true;
}
$csv = str_getcsv($line, $this->delimiter, $this->enclosure);
if ($this->hasLegend) {
$this->legend = str_getcsv($lines[0], $this->delimiter, $this->enclosure, $this->escapeChar);
unset($lines[0]);
}
if (!$isHeaders && $this->hasHeaders && !empty($this->headers)) {
foreach ($this->headers as $key => $header) {
$csv[$header] = isset($csv[$key]) ? $csv[$key] : null;
foreach ($lines as $l => $line) {
$datas = str_getcsv($this->cleanNullValues($line), $this->delimiter, $this->enclosure, $this->escapeChar);
if ($this->hasLegend) {
foreach ($this->legend as $k => $v) {
$datas[$v] = isset($datas[$k]) ? $datas[$k] : null;
}
}
$this->datas[] = $datas;
}
return $csv;
}
/*
* Parses a file.
*
* @param string $filaname
*
* @return CsvParser
*/
public function parseFile($filename)
{
return $this->parseString(file_get_contents($filename));
return true;
}
}

View file

@ -1,69 +0,0 @@
<?php
namespace Deblan\Csv;
/**
* class Csv.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class CsvStreamParser extends CsvParser
{
/**
* @var resource
*/
protected $resource;
/**
* @var int
*/
protected $length;
/**
* Parse a stream.
*
* @param resource $resource
* @param int $length
*/
public function parseStream($resource, ? int $length = 0): void
{
if (!is_resource($resource)) {
throw new \InvalidArgumentException('First argument must be a valid resource.');
}
$this->resource = $resource;
$this->length = $length;
}
/**
* Get data of the stream parsing.
*
* @return null|array
*/
public function getData(): ? array
{
$csv = fgetcsv($this->resource, $this->length, $this->delimiter, $this->enclosure);
if ($csv === false) {
return null;
}
$isHeaders = $this->hasHeaders && empty($this->headers);
if ($isHeaders) {
$this->headers = $csv;
return $csv;
}
if (!$isHeaders && $this->hasHeaders && !empty($this->headers)) {
foreach ($this->headers as $key => $header) {
$csv[$header] = isset($csv[$key]) ? $csv[$key] : null;
}
}
$this->datas[] = $csv;
return $csv;
}
}

View file

@ -0,0 +1,7 @@
<?php
namespace Deblan\Csv\Exception;
class CsvException extends \Exception
{
}

View file

@ -0,0 +1,7 @@
<?php
namespace Deblan\Csv\Exception;
class CsvInvalidParameterException extends CsvException
{
}

View file

@ -0,0 +1,7 @@
<?php
namespace Deblan\Csv\Exception;
class CsvParserException extends \Exception
{
}

View file

@ -0,0 +1,7 @@
<?php
namespace Deblan\Csv\Exception;
class CsvParserInvalidParameterException extends CsvParserException
{
}

View file

@ -1,189 +1,8 @@
<?php
use Deblan\Csv\CsvParser;
use PHPUnit\Framework\TestCase;
class CsvParserTest extends TestCase
class CsvParserTest extends \PHPUnit_Framework_TestCase
{
public function testGettersAndSettersAndDefaultValues()
{
$parser = new CsvParser();
$this->assertEquals(';', $parser->getDelimiter());
$parser->setDelimiter('#');
$this->assertEquals('#', $parser->getDelimiter());
$parser = new CsvParser();
$this->assertEquals("\n", $parser->getEndOfLine());
$parser->setEndOfLine("\r\n");
$this->assertEquals("\r\n", $parser->getEndOfLine());
$parser = new CsvParser();
$this->assertEquals('"', $parser->getEnclosure());
$parser->setEnclosure("'");
$this->assertEquals("'", $parser->getEnclosure());
$parser = new CsvParser();
$this->assertEquals([], $parser->getDatas());
$this->assertEquals([], $parser->getHeaders());
$this->assertEquals(false, $parser->getHasHeaders());
$parser->setHasHeaders(true);
$this->assertEquals(true, $parser->getHasHeaders());
}
public function testParser()
{
$parser = new CsvParser();
$this->assertEquals(['foo', 'bar'], $parser->parseLine('"foo";"bar"'));
$this->assertEquals([], $parser->getDatas());
$this->assertEquals([], $parser->getHeaders());
$parser = new CsvParser();
$parser->parseString('"foo";"bar"');
$this->assertEquals([['foo', 'bar']], $parser->getDatas());
$this->assertEquals([], $parser->getHeaders());
$parser = new CsvParser();
$parser->parseString('"foo";"bar"'."\n".'"foo2";"bar2"');
$this->assertEquals([['foo', 'bar'], ['foo2', 'bar2']], $parser->getDatas());
$this->assertEquals([], $parser->getHeaders());
$parser = new CsvParser();
$parser->setHasHeaders(true);
$parser->parseString('"foo";"bar"'."\n".'"foo2";"bar2"');
$this->assertEquals([['foo2', 'bar2', 'foo' => 'foo2', 'bar' => 'bar2']], $parser->getDatas());
$this->assertEquals(['foo', 'bar'], $parser->getHeaders());
$parser = new CsvParser();
$parser->setHasHeaders(true);
$parser->setEnclosure(null);
$parser->parseString('foo;bar'."\n".'foo2;bar2;boo2');
$this->assertEquals([['foo2', 'bar2', 'boo2', 'foo' => 'foo2', 'bar' => 'bar2']], $parser->getDatas());
$this->assertEquals(['foo', 'bar'], $parser->getHeaders());
$parser = new CsvParser();
$parser->setHasHeaders(true);
$parser->parseString('foo;bar'."\n".'foo2');
$this->assertEquals([['foo2', 'foo' => 'foo2', 'bar' => null]], $parser->getDatas());
$this->assertEquals(['foo', 'bar'], $parser->getHeaders());
$parser = new CsvParser();
$parser->setHasHeaders(true);
$parser->parseFile(__DIR__.'/fixtures/example.csv');
$this->assertEquals(
[
[
'foo 1',
'bar 1',
'FOO' => 'foo 1',
'BAR' => 'bar 1',
],
[
'foo 2',
'bar 2',
'FOO' => 'foo 2',
'BAR' => 'bar 2',
],
[
'foo 3',
'bar 3',
'FOO' => 'foo 3',
'BAR' => 'bar 3',
],
],
$parser->getDatas()
);
$this->assertEquals(['FOO', 'BAR'], $parser->getHeaders());
$parser = new CsvParser();
$parser->setHasHeaders(false);
$parser->parseFile(__DIR__.'/fixtures/example2.csv');
$this->assertEquals(
[
[
'foo 1',
'bar 1',
],
[
'foo 2',
'ba"r 2',
],
[
'foo 3',
'bar 3',
],
],
$parser->getDatas()
);
$parser = new CsvParser();
$parser->setHasHeaders(true);
$parser->setEnclosure("'");
$parser->setDelimiter('#');
$parser->parseFile(__DIR__.'/fixtures/example3.csv');
$this->assertEquals(
[
[
'foo 1',
'',
"FO'O" => 'foo 1',
'BAR' => '',
],
[
'foo 1b',
"FO'O" => 'foo 1b',
'BAR' => null,
],
[
'foo 2',
'bar 2',
'unexpected 3',
"FO'O" => 'foo 2',
'BAR' => 'bar 2',
],
[
'foo 3',
'bar 3',
"FO'O" => 'foo 3',
'BAR' => 'bar 3',
],
],
$parser->getDatas()
);
$parser = new CsvParser();
$parser->setHasHeaders(true);
$parser->setEnclosure("'");
$parser->setDelimiter('#');
$parser->setEndOfLine("\r\n");
$parser->parseFile(__DIR__.'/fixtures/example4.csv');
$this->assertEquals(
[
[
'foo 1',
'',
"FO'O" => 'foo 1',
'BAR' => '',
],
[
'foo 1b',
"FO'O" => 'foo 1b',
'BAR' => null,
],
[
'foo 2',
'bar 2',
'unexpected 3',
"FO'O" => 'foo 2',
'BAR' => 'bar 2',
],
[
'foo 3',
'bar 3',
"FO'O" => 'foo 3',
'BAR' => 'bar 3',
],
],
$parser->getDatas()
);
}
public function testTest()
{
}
}

View file

@ -1,176 +0,0 @@
<?php
use Deblan\Csv\CsvParser;
use PHPUnit\Framework\TestCase;
use Deblan\Csv\CsvStreamParser;
class CsvParserParserTest extends CsvParserTest
{
public function testStreamParser()
{
$parser = new CsvStreamParser();
$this->assertEquals([], $parser->getDatas());
$this->assertEquals([], $parser->getHeaders());
$parser = new CsvStreamParser();
$this->expectException('\InvalidArgumentException');
$parser->parseStream(null);
}
public function testStreamParser2()
{
$parser = new CsvStreamParser();
$parser->setHasHeaders(true);
$parser->parseStream(fopen(__DIR__.'/fixtures/example.csv', 'r'));
$this->assertEquals([], $parser->getDatas());
$this->assertEquals([], $parser->getHeaders());
$this->assertEquals([
'FOO',
'BAR',
], $parser->getData());
$this->assertEquals([], $parser->getDatas());
$this->assertEquals(['FOO', 'BAR'], $parser->getHeaders());
$this->assertEquals([
'foo 1',
'bar 1',
'FOO' => 'foo 1',
'BAR' => 'bar 1',
], $parser->getData());
$this->assertEquals([
[
'foo 1',
'bar 1',
'FOO' => 'foo 1',
'BAR' => 'bar 1',
],
], $parser->getDatas());
$this->assertEquals(['FOO', 'BAR'], $parser->getHeaders());
$parser->getData();
$this->assertEquals([
[
'foo 1',
'bar 1',
'FOO' => 'foo 1',
'BAR' => 'bar 1',
],
[
'foo 2',
'bar 2',
'FOO' => 'foo 2',
'BAR' => 'bar 2',
],
], $parser->getDatas());
$this->assertEquals(['FOO', 'BAR'], $parser->getHeaders());
$parser->getData();
$this->assertEquals([
[
'foo 1',
'bar 1',
'FOO' => 'foo 1',
'BAR' => 'bar 1',
],
[
'foo 2',
'bar 2',
'FOO' => 'foo 2',
'BAR' => 'bar 2',
],
[
'foo 3',
'bar 3',
'FOO' => 'foo 3',
'BAR' => 'bar 3',
],
], $parser->getDatas());
$this->assertEquals(['FOO', 'BAR'], $parser->getHeaders());
}
public function testStreamParser3()
{
$parser = new CsvStreamParser();
$parser->setHasHeaders(false);
$parser->parseStream(fopen(__DIR__.'/fixtures/example.csv', 'r'));
$this->assertEquals([], $parser->getDatas());
$this->assertEquals([], $parser->getHeaders());
$this->assertEquals([
'FOO',
'BAR'
], $parser->getData());
$this->assertEquals([
[
'FOO',
'BAR'
]
], $parser->getDatas());
$this->assertEquals([], $parser->getHeaders());
$this->assertEquals([
'foo 1',
'bar 1',
], $parser->getData());
$this->assertEquals([
[
'FOO',
'BAR',
],
[
'foo 1',
'bar 1',
],
], $parser->getDatas());
$this->assertEquals([], $parser->getHeaders());
$this->assertEquals([
'foo 2',
'bar 2',
], $parser->getData());
$this->assertEquals([
[
'FOO',
'BAR',
],
[
'foo 1',
'bar 1',
],
[
'foo 2',
'bar 2',
],
], $parser->getDatas());
$this->assertEquals([], $parser->getHeaders());
$this->assertEquals([
'foo 3',
'bar 3',
], $parser->getData());
$this->assertEquals([
[
'FOO',
'BAR',
],
[
'foo 1',
'bar 1',
],
[
'foo 2',
'bar 2',
],
[
'foo 3',
'bar 3',
],
], $parser->getDatas());
$this->assertEquals([], $parser->getHeaders());
$this->assertEquals(null, $parser->getData());
}
}

View file

@ -1,143 +1,94 @@
<?php
use Deblan\Csv\Csv;
use PHPUnit\Framework\TestCase;
/**
* class CsvTest.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class CsvTest extends TestCase
class CsvTest extends \PHPUnit_Framework_TestCase
{
public function testGettersAndSettersAndDefaultValues()
public function testAddLine()
{
$csv = new Csv();
$this->assertEquals(';', $csv->getDelimiter());
$csv->setDelimiter('#');
$this->assertEquals('#', $csv->getDelimiter());
$csv->addLine(array('foo', 'bar'));
$this->assertEquals('"foo";"bar"'."\n", $csv->compile());
}
public function testSetLegend()
{
$csv = new Csv();
$this->assertEquals(false, $csv->getHasLegend());
$csv->setLegend($a = array('bim', 'bam'));
$this->assertEquals($a, $csv->getLegend());
$csv->addLine(array('foo', 'bar'));
$this->assertEquals(true, $csv->getHasLegend());
$this->assertEquals(
'"bim";"bam"'."\n".
'"foo";"bar"'."\n",
$csv->compile()
);
$csv = new Csv();
$csv->addLine(array('foo', 'bar'));
$csv->setLegend(array('bim', 'bam'));
$this->assertEquals(true, $csv->getHasLegend());
$this->assertEquals(
'"bim";"bam"'."\n".
'"foo";"bar"'."\n",
$csv->compile()
);
}
public function testHasDatas()
{
$csv = new Csv();
$this->assertEquals(false, $csv->hasDatas());
$csv->setLegend(array('bim', 'bam'));
$this->assertEquals(false, $csv->hasDatas());
$csv->addLine(array('foo', 'bar'));
$this->assertEquals(true, $csv->hasDatas());
$csv = new Csv();
$csv->addLine(array('foo', 'bar'));
$this->assertEquals(true, $csv->hasDatas());
}
public function testDatasToCsvLine()
{
$csv = new Csv();
$csv->addLine(array('fo\\o', 'bar'));
$this->assertEquals('"fo\\\\o";"bar"'."\n", $csv->compile());
$csv = new Csv();
$csv->setDelimiter(':');
$csv->addLine(array('foo', 'bar'));
$this->assertEquals('"foo":"bar"'."\n", $csv->compile());
$csv = new Csv();
$csv->setDelimiter(':');
$csv->addLine(array('fo:o', 'bar'));
$this->assertEquals('"fo:o":"bar"'."\n", $csv->compile());
$csv = new Csv();
$csv->setDelimiter(':');
$csv->setEnclosure('');
$csv->addLine(array('fo:o', 'bar'));
$this->assertEquals('fo\\:o:bar'."\n", $csv->compile());
$csv = new Csv();
$this->assertEquals('"', $csv->getEnclosure());
$csv->setEnclosure('#');
$this->assertEquals('#', $csv->getEnclosure());
$csv->addLine(array('foo', 'bar'));
$this->assertEquals('#foo#;#bar#'."\n", $csv->compile());
$csv = new Csv();
$this->assertEquals("\n", $csv->getEndOfLine());
$csv->setEndOfLine("\r\n");
$this->assertEquals("\r\n", $csv->getEndOfLine());
$csv = new Csv();
$this->assertEquals([], $csv->getDatas());
$csv->setDatas([['a', 'b', 'c'], ['d', 'e', 'f']]);
$this->assertEquals([['a', 'b', 'c'], ['d', 'e', 'f']], $csv->getDatas());
$csv = new Csv();
$this->assertEquals([], $csv->getHeaders());
$csv->setHeaders(['a', 'b', 'c']);
$this->assertEquals(['a', 'b', 'c'], $csv->getHeaders());
$csv = new Csv();
$this->assertEquals('UTF-8', $csv->getCharset());
$csv->setCharset('ISO-8859-1');
$this->assertEquals('ISO-8859-1', $csv->getCharset());
}
public function testRender()
{
$csv = new Csv();
$this->assertEquals(null, $csv->render());
$csv->addData(['foo', 'bar']);
$this->assertEquals('"foo";"bar"', $csv->render());
$csv = new Csv();
$csv->appendData(['foo', 'bar']);
$csv->appendData(['foo2', 'bar2']);
$this->assertEquals('"foo";"bar"'."\n".'"foo2";"bar2"', $csv->render());
$csv = new Csv();
$csv->preprendData(['foo2', 'bar2']);
$csv->preprendData(['foo', 'bar']);
$this->assertEquals('"foo";"bar"'."\n".'"foo2";"bar2"', $csv->render());
$csv = new Csv();
$csv->addData(['foo', 'bar']);
$csv->preprendData(['foo2', 'bar2']);
$csv->appendData(['foo3', 'bar3']);
$this->assertEquals('"foo2";"bar2"'."\n".'"foo";"bar"'."\n".'"foo3";"bar3"', $csv->render());
$csv = new Csv();
$csv->setHeaders(['a', 'b']);
$csv->addData(['foo', 'bar']);
$this->assertEquals('"a";"b"'."\n".'"foo";"bar"', $csv->render());
$csv = new Csv();
$csv->setHeaders(['a"b', 'cd"']);
$csv->addData(['f"oo', 'b""ar']);
$this->assertEquals('"a""b";"cd"""'."\n".'"f""oo";"b""""ar"', $csv->render());
$csv = new Csv();
$csv->addData(['foo', 'bar']);
$csv->setHeaders(['a', 'b']);
$this->assertEquals('"a";"b"'."\n".'"foo";"bar"', $csv->render());
$csv = new Csv();
$csv->addData(['foo', 'bar']);
$csv->addData(['foo2', 'bar2']);
$csv->setHeaders(['a', 'b']);
$csv->setEndOfLine("\r\n");
$this->assertEquals('"a";"b"'."\r\n".'"foo";"bar"'."\r\n".'"foo2";"bar2"', $csv->render());
$csv = new Csv();
$csv->setHeaders(['a', "b'd"]);
$csv->addData(["fo'o", 'bar']);
$csv->setEnclosure("'");
$this->assertEquals("'a';'b''d'"."\n"."'fo''o';'bar'", $csv->render());
$csv = new Csv();
$csv->setHeaders(['a', 'b']);
$csv->addData(['foo', 'bar']);
$csv->setDelimiter('#');
$this->assertEquals('"a"#"b"'."\n".'"foo"#"bar"', $csv->render());
$filename = tempnam(sys_get_temp_dir(), 'csvtests');
$csv = new Csv();
$csv->setHeaders(['a', 'b']);
$csv->addData(['foo', 'bar']);
$render = $csv->render($filename);
$this->assertEquals('"a";"b"'."\n".'"foo";"bar"', $render);
$this->assertEquals('"a";"b"'."\n".'"foo";"bar"', file_get_contents($filename));
$render = $csv->render($filename);
$this->assertEquals('"a";"b"'."\n".'"foo";"bar"', $render);
$this->assertEquals('"a";"b"'."\n".'"foo";"bar"', file_get_contents($filename));
unlink($filename);
$csv = new Csv();
$csv->setHeaders(['a', 'b']);
$csv->addData(['foo', 'bar']);
$csv->render($filename);
$csv = new Csv();
$csv->addData(['foo2', 'bar2']);
$render = $csv->render($filename, FILE_APPEND);
$this->assertEquals('"a";"b"'."\n".'"foo";"bar"'."\n".'"foo2";"bar2"', file_get_contents($filename));
unlink($filename);
}
public function testEncoding()
{
$csv = new Csv();
$csv->addData(['é']);
$render = $csv->render();
$this->assertEquals('"é"', $csv->render());
$csv = new Csv();
$csv->addData(['é']);
$csv->setCharset('ISO-8859-1');
$render = $csv->render();
$this->assertEquals('"é"', utf8_encode($csv->render()));
$csv->setEnclosure('#');
$csv->addLine(array('f#oo', 'bar'));
$this->assertEquals('#f\\#oo#;#bar#'."\n", $csv->compile());
}
}

View file

@ -1,4 +0,0 @@
"FOO";"BAR"
"foo 1";"bar 1"
"foo 2";"bar 2"
"foo 3";"bar 3"
1 FOO BAR
2 foo 1 bar 1
3 foo 2 bar 2
4 foo 3 bar 3

View file

@ -1,3 +0,0 @@
"foo 1";"bar 1"
"foo 2";"ba""r 2"
"foo 3";"bar 3"
1 foo 1 bar 1
2 foo 2 ba"r 2
3 foo 3 bar 3

View file

@ -1,5 +0,0 @@
'FO''O'#'BAR'
'foo 1'#
'foo 1b'
'foo 2'#'bar 2'#'unexpected 3'
'foo 3'#'bar 3'
1 'FO''O'#'BAR'
2 'foo 1'#
3 'foo 1b'
4 'foo 2'#'bar 2'#'unexpected 3'
5 'foo 3'#'bar 3'

View file

@ -1,5 +0,0 @@
'FO''O'#'BAR'
'foo 1'#
'foo 1b'
'foo 2'#'bar 2'#'unexpected 3'
'foo 3'#'bar 3'
1 'FO''O'#'BAR'
2 'foo 1'#
3 'foo 1b'
4 'foo 2'#'bar 2'#'unexpected 3'
5 'foo 3'#'bar 3'