Compare commits
21 commits
Author | SHA1 | Date | |
---|---|---|---|
Simon Vieille | e1cb3d8b9a | ||
Simon Vieille | c2e570f966 | ||
Simon Vieille | 0c34dce1cf | ||
Simon Vieille | 9cfbebabd6 | ||
Simon Vieille | ec870e287c | ||
Simon Vieille | cfb04db402 | ||
Simon Vieille | 7719bd7202 | ||
Simon Vieille | 0f413d06b9 | ||
Simon Vieille | 9899e5bfbd | ||
Simon Vieille | 33e15895d3 | ||
Simon Vieille | 1ac6c03c1c | ||
Simon Vieille | f8731f6fbe | ||
Simon Vieille | 237290aba9 | ||
Simon Vieille | 496221566a | ||
Simon Vieille | 4809f0157b | ||
Simon Vieille | 37be0f572f | ||
Simon Vieille | 022c31a703 | ||
Simon Vieille | 6c4a535ecd | ||
Simon Vieille | 2c25ffd751 | ||
Simon Vieille | ae1176ce78 | ||
Simon Vieille | db680faa97 |
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1 @@
|
|||
*.swp
|
||||
tags
|
||||
|
||||
/vendor/
|
||||
|
|
17
.woodpecker.yml
Normal file
17
.woodpecker.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
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
|
1
LICENSE
1
LICENSE
|
@ -21,3 +21,4 @@ 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.
|
||||
|
||||
|
|
107
README.md
107
README.md
|
@ -1,12 +1,20 @@
|
|||
CSV parser/generator
|
||||
====================
|
||||
|
||||
A simple PHP library to parse and generate CSV files.
|
||||
[![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.
|
||||
|
||||
## Composer installation
|
||||
|
||||
```
|
||||
$ composer require deblan/csv
|
||||
$ composer require deblan/csv "~3"
|
||||
```
|
||||
|
||||
Or in your composer.json:
|
||||
|
@ -14,8 +22,7 @@ Or in your composer.json:
|
|||
```
|
||||
{
|
||||
"require": {
|
||||
[...]
|
||||
"deblan/csv": "dev-master"
|
||||
"deblan/csv": "~3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -29,33 +36,85 @@ use Deblan\Csv\Csv;
|
|||
|
||||
$csv = new Csv();
|
||||
|
||||
$csv->addLine(array('Foo', '$1000'));
|
||||
$csv->addLine(array('Bar', '$600'));
|
||||
// Defines the delimiter (default is ;)
|
||||
$csv->setDelimiter(";");
|
||||
|
||||
$result = $csv->compile();
|
||||
// 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);
|
||||
```
|
||||
|
||||
```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
|
||||
### Parse a file
|
||||
|
||||
```php
|
||||
use Deblan\Csv\CsvParser;
|
||||
|
||||
$csv = new CsvParser('products.csv');
|
||||
$csv->setHasLegend(true);
|
||||
$csv->parse();
|
||||
$csv = new CsvParser();
|
||||
|
||||
$legend = $csv->getLegend();
|
||||
// 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();
|
||||
$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()) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
|
11
phpunit.xml
11
phpunit.xml
|
@ -7,12 +7,11 @@
|
|||
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>
|
||||
|
|
|
@ -2,192 +2,340 @@
|
|||
|
||||
namespace Deblan\Csv;
|
||||
|
||||
use Deblan\Csv\Exception\CsvInvalidParameterException;
|
||||
|
||||
/**
|
||||
* class Csv.
|
||||
*
|
||||
* @author Simon Vieille <simon@deblan.fr>
|
||||
*/
|
||||
class Csv
|
||||
{
|
||||
private $delimiter;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $delimiter = ';';
|
||||
|
||||
private $enclosure;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $enclosure = '"';
|
||||
|
||||
private $endline;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $endOfLine = "\n";
|
||||
|
||||
private $datas;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $datas = [];
|
||||
|
||||
private $legend;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $headers = [];
|
||||
|
||||
private $render;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $charset = 'UTF-8';
|
||||
|
||||
private $encoding;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isModified = false;
|
||||
|
||||
private $hasLegend = false;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $render;
|
||||
|
||||
public function __construct($delimiter = ';', $enclosure = '"', $endline = "\n", $encoding = 'UTF-8')
|
||||
/**
|
||||
* Set the value of "delimiter".
|
||||
*
|
||||
* @param string $delimiter
|
||||
*
|
||||
* @return Csv
|
||||
*/
|
||||
public function setDelimiter($delimiter)
|
||||
{
|
||||
$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));
|
||||
if ($this->delimiter !== $delimiter) {
|
||||
$this->delimiter = $delimiter;
|
||||
$this->isModified = true;
|
||||
}
|
||||
|
||||
$this->filename = $v;
|
||||
}
|
||||
|
||||
protected function setHasLegend($hasLegend)
|
||||
{
|
||||
$this->hasLegend = $hasLegend;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHasLegend()
|
||||
/**
|
||||
* Get the value of "delimiter".
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDelimiter()
|
||||
{
|
||||
return $this->hasLegend;
|
||||
return $this->delimiter;
|
||||
}
|
||||
|
||||
public function hasLegend()
|
||||
/**
|
||||
* Set the value of "enclosure".
|
||||
*
|
||||
* @param string $enclosure
|
||||
*
|
||||
* @return Csv
|
||||
*/
|
||||
public function setEnclosure($enclosure)
|
||||
{
|
||||
return $this->hasLegend;
|
||||
}
|
||||
$enclosure = (string) $enclosure;
|
||||
|
||||
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;
|
||||
if ($this->enclosure !== $enclosure) {
|
||||
$this->enclosure = $enclosure;
|
||||
$this->isModified = true;
|
||||
}
|
||||
|
||||
$this->datas[] = $values;
|
||||
}
|
||||
|
||||
public function setEncoding($encoding)
|
||||
{
|
||||
$this->encoding = $encoding;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEncoding()
|
||||
/**
|
||||
* Get the value of "enclosure".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEnclosure()
|
||||
{
|
||||
return $this->encoding;
|
||||
return $this->enclosure;
|
||||
}
|
||||
|
||||
public function setDelimiter($v)
|
||||
/**
|
||||
* Set the value of "endOfLine".
|
||||
*
|
||||
* @param string $endOfLine
|
||||
*
|
||||
* @return Csv
|
||||
*/
|
||||
public function setEndOfLine($endOfLine)
|
||||
{
|
||||
if (!is_string($v)) {
|
||||
throw new CsvInvalidParameterException(sprintf('"%s" is not a valid string.', $v));
|
||||
if ($this->endOfLine !== $endOfLine) {
|
||||
$this->endOfLine = (string) $endOfLine;
|
||||
$this->isModified = true;
|
||||
}
|
||||
|
||||
$this->delimiter = $v;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setEndline($v)
|
||||
/**
|
||||
* Get the value of "endOfLine".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEndOfLine()
|
||||
{
|
||||
if (!is_string($v)) {
|
||||
throw new CsvInvalidParameterException(sprintf('"%s" is not a valid string.', $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;
|
||||
}
|
||||
|
||||
$this->endline = $v;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setEnclosure($v)
|
||||
/**
|
||||
* Get the value of "headers".
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHeaders()
|
||||
{
|
||||
if (!is_string($v)) {
|
||||
throw new CsvInvalidParameterException(sprintf('"%s" is not a valid string.', $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;
|
||||
}
|
||||
|
||||
$this->enclose = $v;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLegend()
|
||||
/**
|
||||
* Get the value of "charset".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCharset()
|
||||
{
|
||||
return $this->legend;
|
||||
return $this->charset;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
public function compile()
|
||||
/*
|
||||
* Appends data.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return Csv
|
||||
*/
|
||||
public function appendData(array $data)
|
||||
{
|
||||
$this->render = "";
|
||||
$this->datas[] = $data;
|
||||
$this->isModified = true;
|
||||
|
||||
if ($this->datas[0] !== null) {
|
||||
$this->append($this->datasToCsvLine($this->datas[0]));
|
||||
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;
|
||||
}
|
||||
|
||||
unset($this->datas[0]);
|
||||
$data = implode($this->delimiter, $columns);
|
||||
$data = $this->encode($data);
|
||||
|
||||
foreach ($this->datas as $v) {
|
||||
$this->append($this->datasToCsvLine($v));
|
||||
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);
|
||||
}
|
||||
|
||||
if ($this->encoding !== 'UTF-8') {
|
||||
$this->render = iconv(
|
||||
mb_detect_encoding($this->render),
|
||||
$this->encoding,
|
||||
$this->render
|
||||
);
|
||||
$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);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,149 +2,225 @@
|
|||
|
||||
namespace Deblan\Csv;
|
||||
|
||||
use Deblan\Csv\Exception\CsvParserInvalidParameterException;
|
||||
use Deblan\Csv\Exception\CsvParserException;
|
||||
|
||||
/**
|
||||
* class Csv.
|
||||
*
|
||||
* @author Simon Vieille <simon@deblan.fr>
|
||||
*/
|
||||
class CsvParser
|
||||
{
|
||||
private $filename;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $delimiter = ';';
|
||||
|
||||
private $delimiter;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $enclosure = '"';
|
||||
|
||||
private $enclosure;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $endOfLine = "\n";
|
||||
|
||||
private $escapeChar;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $datas = [];
|
||||
|
||||
private $hasLegend;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $headers = [];
|
||||
|
||||
private $datas = array();
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $hasHeaders = false;
|
||||
|
||||
private $legend = array();
|
||||
|
||||
private $nullValues = array();
|
||||
|
||||
public function __construct($filename, $delimiter = ';', $enclosure = '"', $escapeChar = '\\', $hasLegend = false, array $nullValues = array(''))
|
||||
/**
|
||||
* Set the value of "delimiter".
|
||||
*
|
||||
* @param string $delimiter
|
||||
*
|
||||
* @return Csv
|
||||
*/
|
||||
public function setDelimiter($delimiter)
|
||||
{
|
||||
$this->setFilename($filename);
|
||||
$this->setDelimiter($delimiter);
|
||||
$this->setEnclosure($enclosure);
|
||||
$this->setEscapeChar($escapeChar);
|
||||
$this->setHasLegend($hasLegend);
|
||||
$this->setNullValues($nullValues);
|
||||
}
|
||||
$this->delimiter = (string) $delimiter;
|
||||
|
||||
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;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of "delimiter".
|
||||
*
|
||||
* To improve...
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function cleanNullValues($line)
|
||||
public function getDelimiter()
|
||||
{
|
||||
return str_replace($this->nullValues, '', $line);
|
||||
return $this->delimiter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
public function parse()
|
||||
/*
|
||||
* Parses a string.
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return CsvParser
|
||||
*/
|
||||
public function parseString($string)
|
||||
{
|
||||
if (!empty($this->datas)) {
|
||||
return $this->datas;
|
||||
}
|
||||
$this->datas = [];
|
||||
$this->headers = [];
|
||||
$lines = str_getcsv($string, $this->endOfLine);
|
||||
|
||||
$lines = file($this->filename);
|
||||
foreach ($lines as $key => $line) {
|
||||
$data = $this->parseLine($line, $this->hasHeaders && $key === 0);
|
||||
|
||||
if (empty($lines)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->hasLegend) {
|
||||
$this->legend = str_getcsv($lines[0], $this->delimiter, $this->enclosure, $this->escapeChar);
|
||||
unset($lines[0]);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if ($data === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->datas[] = $datas;
|
||||
if ($this->hasHeaders && $key === 0) {
|
||||
$this->headers = $data;
|
||||
} else {
|
||||
$this->datas[] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
$csv = str_getcsv($line, $this->delimiter, $this->enclosure);
|
||||
|
||||
if (!$isHeaders && $this->hasHeaders && !empty($this->headers)) {
|
||||
foreach ($this->headers as $key => $header) {
|
||||
$csv[$header] = isset($csv[$key]) ? $csv[$key] : null;
|
||||
}
|
||||
}
|
||||
|
||||
return $csv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses a file.
|
||||
*
|
||||
* @param string $filaname
|
||||
*
|
||||
* @return CsvParser
|
||||
*/
|
||||
public function parseFile($filename)
|
||||
{
|
||||
return $this->parseString(file_get_contents($filename));
|
||||
}
|
||||
}
|
||||
|
|
69
src/Deblan/Csv/CsvStreamParser.php
Normal file
69
src/Deblan/Csv/CsvStreamParser.php
Normal 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;
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Deblan\Csv\Exception;
|
||||
|
||||
class CsvException extends \Exception
|
||||
{
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Deblan\Csv\Exception;
|
||||
|
||||
class CsvInvalidParameterException extends CsvException
|
||||
{
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Deblan\Csv\Exception;
|
||||
|
||||
class CsvParserException extends \Exception
|
||||
{
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Deblan\Csv\Exception;
|
||||
|
||||
class CsvParserInvalidParameterException extends CsvParserException
|
||||
{
|
||||
}
|
|
@ -1,8 +1,189 @@
|
|||
<?php
|
||||
|
||||
class CsvParserTest extends \PHPUnit_Framework_TestCase
|
||||
use Deblan\Csv\CsvParser;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CsvParserTest extends TestCase
|
||||
{
|
||||
public function testTest()
|
||||
{
|
||||
}
|
||||
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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
176
tests/CsvStreamParserTest.php
Normal file
176
tests/CsvStreamParserTest.php
Normal 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());
|
||||
}
|
||||
}
|
|
@ -1,94 +1,143 @@
|
|||
<?php
|
||||
|
||||
use Deblan\Csv\Csv;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CsvTest extends \PHPUnit_Framework_TestCase
|
||||
/**
|
||||
* class CsvTest.
|
||||
*
|
||||
* @author Simon Vieille <simon@deblan.fr>
|
||||
*/
|
||||
class CsvTest extends TestCase
|
||||
{
|
||||
public function testAddLine()
|
||||
public function testGettersAndSettersAndDefaultValues()
|
||||
{
|
||||
$csv = new Csv();
|
||||
$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());
|
||||
$this->assertEquals(';', $csv->getDelimiter());
|
||||
$csv->setDelimiter('#');
|
||||
$this->assertEquals('#', $csv->getDelimiter());
|
||||
|
||||
$csv = new Csv();
|
||||
$this->assertEquals('"', $csv->getEnclosure());
|
||||
$csv->setEnclosure('#');
|
||||
$csv->addLine(array('foo', 'bar'));
|
||||
$this->assertEquals('#foo#;#bar#'."\n", $csv->compile());
|
||||
$this->assertEquals('#', $csv->getEnclosure());
|
||||
|
||||
$csv = new Csv();
|
||||
$csv->setEnclosure('#');
|
||||
$csv->addLine(array('f#oo', 'bar'));
|
||||
$this->assertEquals('#f\\#oo#;#bar#'."\n", $csv->compile());
|
||||
$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()));
|
||||
}
|
||||
}
|
||||
|
|
4
tests/fixtures/example.csv
vendored
Normal file
4
tests/fixtures/example.csv
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
"FOO";"BAR"
|
||||
"foo 1";"bar 1"
|
||||
"foo 2";"bar 2"
|
||||
"foo 3";"bar 3"
|
|
3
tests/fixtures/example2.csv
vendored
Normal file
3
tests/fixtures/example2.csv
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
"foo 1";"bar 1"
|
||||
"foo 2";"ba""r 2"
|
||||
"foo 3";"bar 3"
|
|
5
tests/fixtures/example3.csv
vendored
Normal file
5
tests/fixtures/example3.csv
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
'FO''O'#'BAR'
|
||||
'foo 1'#
|
||||
'foo 1b'
|
||||
'foo 2'#'bar 2'#'unexpected 3'
|
||||
'foo 3'#'bar 3'
|
|
5
tests/fixtures/example4.csv
vendored
Normal file
5
tests/fixtures/example4.csv
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
'FO''O'#'BAR'
|
||||
'foo 1'#
|
||||
'foo 1b'
|
||||
'foo 2'#'bar 2'#'unexpected 3'
|
||||
'foo 3'#'bar 3'
|
|
Loading…
Reference in a new issue