add stream parser

This commit is contained in:
Simon Vieille 2020-02-10 16:24:43 +01:00
parent 33e15895d3
commit 9899e5bfbd
Signed by: deblan
GPG Key ID: 03383D15A1D31745
5 changed files with 273 additions and 6 deletions

View File

@ -3,12 +3,18 @@ CSV parser/generator
<a href="https://phpci.gitnet.fr/build-status/view/2">![](https://phpci.gitnet.fr/build-status/image/2?branch=master&label=PHPCensor&style=flat-square)</a>
A simple PHP library to parse and generate CSV files.
A simple PHP library to:
* parse a CSV file
* parse a stream as CSV datas
* generate CSV files.
PHP >= 7.1 required.
## Composer installation
```
$ composer require deblan/csv "~2"
$ composer require deblan/csv "~3"
```
Or in your composer.json:
@ -16,7 +22,7 @@ Or in your composer.json:
```
{
"require": {
"deblan/csv": "~2"
"deblan/csv": "~3"
}
}
```
@ -67,7 +73,7 @@ $result = $csv->render('products.csv');
$result = $csv->render('products.csv', FILE_APPEND);
```
### Parser
### Parse a file
```php
use Deblan\Csv\CsvParser;
@ -96,3 +102,19 @@ $csv->parseString($myString);
$headers = $csv->getHeaders();
$products = $csv->getDatas();
```
### Parse a stram
```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,7 +7,6 @@
convertWarningsToExceptions = "true"
processIsolation = "false"
stopOnFailure = "false"
syntaxCheck = "true"
bootstrap = "vendor/autoload.php" >
<testsuites>

View File

@ -0,0 +1,69 @@
<?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

@ -1,8 +1,9 @@
<?php
use Deblan\Csv\CsvParser;
use PHPUnit\Framework\TestCase;
class CsvParserParserTest extends \PHPUnit_Framework_TestCase
class CsvParserTest extends TestCase
{
public function testGettersAndSettersAndDefaultValues()
{

View File

@ -0,0 +1,176 @@
<?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());
}
}