Skip to content

Commit

Permalink
Code simplification
Browse files Browse the repository at this point in the history
- Removed Reader::select users must use Statement::process instead
- Exception message improved
- Improve v9 documentation
  • Loading branch information
nyamsprod committed Jun 6, 2017
1 parent 61b2185 commit b61a92c
Show file tree
Hide file tree
Showing 21 changed files with 73 additions and 74 deletions.
1 change: 0 additions & 1 deletion CHANGELOG.md
Expand Up @@ -8,7 +8,6 @@ All Notable changes to `Csv` will be documented in this file

- Improved CSV Records selection
- `League\Csv\Reader::getRecords` to access all CSV records
- `League\Csv\Reader::select` to enable CSV records selection
- `League\Csv\Statement` provides a constraint builder to select CSV records.
- `League\Csv\ResultSet` represents the result set of the selected CSV records.
- Improved CSV document header selection.
Expand Down
2 changes: 1 addition & 1 deletion docs/9.0/connections/index.md
Expand Up @@ -14,7 +14,7 @@ abstract class AbstractCsv implements ByteSequence
public function addStreamFilter(string $filtername, mixed $params = null): self
public function chunk(int $length): Generator
public static function createFromFileObject(SplFileObject $obj): self
public static function createFromPath(string $path, string $open_mode = 'r+'): self
public static function createFromPath(string $path, string $open_mode = 'r+', resource $context = null): self
public static function createFromStream(resource $stream): self
public static function createFromString(string $str): self
public function hasStreamFilter(string $filtername): bool
Expand Down
2 changes: 1 addition & 1 deletion docs/9.0/index.md
Expand Up @@ -34,7 +34,7 @@ $stmt = (new Statement())
->limit(25)
;

$res = $csv->select($stmt)->fetchAll();
$res = $stmt->process($csv)->fetchAll();
~~~

### Exporting a database table as a CSV document
Expand Down
15 changes: 3 additions & 12 deletions docs/9.0/reader/index.md
Expand Up @@ -20,7 +20,6 @@ class Reader extends AbstractCsv implements IteratorAggregate
public function getIterator(): Iterator
public function getRecords(): Iterator
public function getRecordPaddingValue(): mixed
public function select(Statement $stmt): ResultSet
public function setHeaderOffset(?int $offset): self
public function setRecordPaddingValue(mixed $padding_value): self
public function supportsHeaderAsRecordKeys(): bool
Expand Down Expand Up @@ -236,7 +235,7 @@ $reader->supportsHeaderAsRecordKeys(); //return false;
$reader->getRecords(); //throws a RuntimeException
~~~

### Improving iteration
### Iteration simplified

Because the `Reader` class implements the `IteratorAggregate` interface you can directly iterate over each record using the `foreach` construct and an instantiated `Reader` object. You will get the same results as if you had called `Reader::getRecords`.

Expand Down Expand Up @@ -291,13 +290,7 @@ $records = $reader->fetchColumn(2);

### Advanced Usage

~~~php
<?php

public Reader::select(Statement $stmt): ResultSet
~~~

If you require a more advance record selection, you may use the `Reader::select` method. This method uses a [Statement](/9.0/reader/statement/) object to process the `Reader` object. The found records are returned as a [ResultSet](/9.0/reader/resultset) object.
If you require a more advance record selection **or want to preserve the original record offset**, you should use a [Statement](/9.0/reader/statement/) object to process the `Reader` object. The found records are returned as a [ResultSet](/9.0/reader/resultset) object.

#### Example

Expand All @@ -313,8 +306,6 @@ $stmt = (new Statement())
->limit(5)
;

$records = $reader->select($stmt);
$records = $stmt->process($reader);
//$records is a League\Csv\ResultSet object
~~~

<p class="message-info">This method is equivalent of <a href="/9.0/reader/statement/#apply-the-constraints-to-a-csv-document">Statement::process</a>.</p>
2 changes: 1 addition & 1 deletion docs/9.0/reader/resultset.md
Expand Up @@ -22,7 +22,7 @@ class ResultSet implements Countable, IteratorAggregate
}
~~~

A `League\Csv\ResultSet` object represents the associated result set of processing a [CSV document](/9.0/reader/) with a [constraint builder](/9.0/reader/statement/). This object is returned from [Reader::select](/9.0/reader/#selecting-csv-records) or [Statement::process](/9.0/reader/statement/#apply-the-constraints-to-a-csv-document) execution.
A `League\Csv\ResultSet` object represents the associated result set of processing a [CSV document](/9.0/reader/) with a [constraint builder](/9.0/reader/statement/). This object is returned from [Statement::process](/9.0/reader/statement/#apply-the-constraints-to-a-csv-document) execution.

## Result set informations

Expand Down
3 changes: 0 additions & 3 deletions docs/9.0/reader/statement.md
Expand Up @@ -129,6 +129,3 @@ $stmt = (new Statement())

$records = $stmt->process($reader);
~~~

<p class="message-info">This method is equivalent of <a href="/9.0/reader/#selecting-csv-records">Reader::select</a>.</p>

2 changes: 1 addition & 1 deletion docs/_data/project.yml
@@ -1,5 +1,5 @@
# Documentation website
title: Csv
title: CSV
tagline: "CSV data manipulation made easy in PHP."
description: "Working with CSV can often be much more difficult than you expect, with different types of delimiter and complicated structures. This makes it easy to read and write almost anything."
google_analytics_tracking_id: UA-46050814-6
Expand Down
8 changes: 4 additions & 4 deletions src/AbstractCsv.php
Expand Up @@ -265,7 +265,7 @@ public function __toString(): string
*/
public function chunk(int $length): Generator
{
$length = $this->filterMinRange($length, 1, 'The length must be a positive integer');
$length = $this->filterMinRange($length, 1, __METHOD__.'() expects the length to be a positive integer %s given');
$input_bom = $this->getInputBOM();
$this->document->rewind();
if ($input_bom != $this->output_bom) {
Expand Down Expand Up @@ -322,7 +322,7 @@ public function output(string $filename = null): int
*/
public function setDelimiter(string $delimiter): self
{
$char = $this->filterControl($delimiter, 'delimiter');
$char = $this->filterControl($delimiter, 'delimiter', __METHOD__);
if ($char != $this->delimiter) {
$this->delimiter = $char;
$this->resetProperties();
Expand All @@ -347,7 +347,7 @@ protected function resetProperties()
*/
public function setEnclosure(string $enclosure): self
{
$char = $this->filterControl($enclosure, 'enclosure');
$char = $this->filterControl($enclosure, 'enclosure', __METHOD__);
if ($char != $this->enclosure) {
$this->enclosure = $char;
$this->resetProperties();
Expand All @@ -365,7 +365,7 @@ public function setEnclosure(string $enclosure): self
*/
public function setEscape(string $escape): self
{
$char = $this->filterControl($escape, 'escape');
$char = $this->filterControl($escape, 'escape', __METHOD__);
if ($char != $this->escape) {
$this->escape = $char;
$this->resetProperties();
Expand Down
2 changes: 1 addition & 1 deletion src/CharsetConverter.php
Expand Up @@ -182,7 +182,7 @@ protected function encodeField(&$value, &$offset)
*/
public function convert($records): Iterator
{
$records = $this->filterIterable($records);
$records = $this->filterIterable($records, __METHOD__);
if (is_array($records)) {
$records = new ArrayIterator($records);
}
Expand Down
2 changes: 1 addition & 1 deletion src/ColumnConsistency.php
Expand Up @@ -40,7 +40,7 @@ class ColumnConsistency
*/
public function __construct(int $columns_count = -1)
{
$this->columns_count = $this->filterMinRange($columns_count, -1, 'The column count must be greater or equal to -1');
$this->columns_count = $this->filterMinRange($columns_count, -1, __METHOD__.'() expects the column count to be greater or equal to -1 %s given');
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/JsonConverter.php
Expand Up @@ -44,7 +44,7 @@ class JsonConverter
*/
public function options(int $options): self
{
$options = $this->filterMinRange($options, 0, 'The options must be a positive integer or 0');
$options = $this->filterMinRange($options, 0, __METHOD__.'() expectes the options to be a positive integer or 0, %s given');
$clone = clone $this;
$clone->options = $options;

Expand All @@ -62,7 +62,7 @@ public function options(int $options): self
*/
public function convert($records): string
{
$records = $this->filterIterable($records);
$records = $this->filterIterable($records, __METHOD__);
if (!is_array($records)) {
$records = iterator_to_array($records);
}
Expand Down
18 changes: 3 additions & 15 deletions src/Reader.php
Expand Up @@ -177,18 +177,6 @@ public function getRecordPaddingValue()
return $this->record_padding_value;
}

/**
* Returns a CSV records collection
*
* @param Statement $stmt
*
* @return ResultSet
*/
public function select(Statement $stmt): ResultSet
{
return $stmt->process($this);
}

/**
* @inheritdoc
*/
Expand All @@ -201,7 +189,7 @@ public function __call($method, array $arguments)
;
}

throw new BadMethodCallException(sprintf('Reader::%s does not exists', $method));
throw new BadMethodCallException(sprintf('Reader::%s does not exist', $method));
}

/**
Expand All @@ -221,7 +209,7 @@ public function fetchDelimitersOccurrence(array $delimiters, int $nb_records = 1
return 1 == strlen($value);
};

$nb_records = $this->filterMinRange($nb_records, 1, 'The number of records to consider must be a valid positive integer');
$nb_records = $this->filterMinRange($nb_records, 1, __METHOD__.'() expects the number of records to consider to be a valid positive integer, %s given');
$delimiters = array_unique(array_filter($delimiters, $filter));
$reducer = function (array $res, string $delimiter) use ($nb_records): array {
$res[$delimiter] = $this->getCellCount($delimiter, $nb_records);
Expand Down Expand Up @@ -367,7 +355,7 @@ protected function stripBOM(Iterator $iterator, string $bom): Iterator
public function setHeaderOffset($offset): self
{
if (null !== $offset) {
$offset = $this->filterMinRange($offset, 0, 'The header offset index must be a positive integer or 0');
$offset = $this->filterMinRange($offset, 0, __METHOD__.'() expects the header offset index to be a positive integer or 0, %s given');
}

if ($offset !== $this->header_offset) {
Expand Down
8 changes: 4 additions & 4 deletions src/ResultSet.php
Expand Up @@ -155,7 +155,7 @@ public function fetchOne(int $offset = 0): array
{
$iterator = new LimitIterator(
$this->iterator,
$this->filterMinRange($offset, 0, 'The submitted offset must be a positive integer or 0'),
$this->filterMinRange($offset, 0, __METHOD__.'() expects the submitted offset to be a positive integer or 0, %s given'),
1
);

Expand All @@ -175,7 +175,7 @@ public function fetchOne(int $offset = 0): array
*/
public function fetchColumn($index = 0): Generator
{
$offset = $this->getColumnIndex($index, 'The column index `%s` is invalid or does not exist');
$offset = $this->getColumnIndex($index, __METHOD__.'() expects the column index to be a valid string or integer, `%s` given');
$filter = function (array $record) use ($offset): bool {
return isset($record[$offset]);
};
Expand Down Expand Up @@ -266,8 +266,8 @@ protected function getColumnIndexByKey(int $index, string $error_message)
*/
public function fetchPairs($offset_index = 0, $value_index = 1): Generator
{
$offset = $this->getColumnIndex($offset_index, 'The offset index value `%s` is invalid');
$value = $this->getColumnIndex($value_index, 'The value index value `%s` is invalid');
$offset = $this->getColumnIndex($offset_index, __METHOD__.'() expects the offset index value to be a valid string or integer, `%s` given');
$value = $this->getColumnIndex($value_index, __METHOD__.'() expects the value index value to be a valid string or integer, `%s` given');

$filter = function (array $record) use ($offset): bool {
return isset($record[$offset]);
Expand Down
4 changes: 2 additions & 2 deletions src/Statement.php
Expand Up @@ -98,7 +98,7 @@ public function orderBy(callable $callable): self
*/
public function offset(int $offset): self
{
$offset = $this->filterMinRange($offset, 0, 'The Statement offset must be a positive integer or 0');
$offset = $this->filterMinRange($offset, 0, __METHOD__.'() expects the offset to be a positive integer or 0, %s given');
if ($offset === $this->offset) {
return $this;
}
Expand All @@ -118,7 +118,7 @@ public function offset(int $offset): self
*/
public function limit(int $limit): self
{
$limit = $this->filterMinRange($limit, -1, 'The Statement limit must an integer greater or equals to -1');
$limit = $this->filterMinRange($limit, -1, __METHOD__.'() expects the limit to be greater or equel to -1, %s given');
if ($limit === $this->limit) {
return $this;
}
Expand Down
16 changes: 11 additions & 5 deletions src/StreamIterator.php
Expand Up @@ -190,9 +190,9 @@ public static function createFromString(string $content): self
*/
public function setCsvControl(string $delimiter = ',', string $enclosure = '"', string $escape = '\\')
{
$this->delimiter = $this->filterControl($delimiter, 'delimiter');
$this->enclosure = $this->filterControl($enclosure, 'enclosure');
$this->escape = $this->filterControl($escape, 'escape');
$this->delimiter = $this->filterControl($delimiter, 'delimiter', __METHOD__);
$this->enclosure = $this->filterControl($enclosure, 'enclosure', __METHOD__);
$this->escape = $this->filterControl($escape, 'escape', __METHOD__);
}

/**
Expand Down Expand Up @@ -221,7 +221,13 @@ public function setFlags(int $flags)
*/
public function fputcsv(array $fields, string $delimiter = ',', string $enclosure = '"', string $escape = '\\')
{
return fputcsv($this->stream, $fields, $this->filterControl($delimiter, 'delimiter'), $this->filterControl($enclosure, 'enclosure'), $this->filterControl($escape, 'escape'));
return fputcsv(
$this->stream,
$fields,
$this->filterControl($delimiter, 'delimiter', __METHOD__),
$this->filterControl($enclosure, 'enclosure', __METHOD__),
$this->filterControl($escape, 'escape', __METHOD__)
);
}

/**
Expand Down Expand Up @@ -341,7 +347,7 @@ protected function getCurrentLine()
*/
public function seek($position)
{
$pos = $this->filterMinRange((int) $position, 0, 'Can\'t seek stream to negative line %d');
$pos = $this->filterMinRange((int) $position, 0, __METHOD__.'() Can\'t seek stream to negative line %d');
foreach ($this as $key => $value) {
if ($key === $pos || feof($this->stream)) {
$this->offset--;
Expand Down
14 changes: 8 additions & 6 deletions src/ValidatorTrait.php
Expand Up @@ -53,36 +53,38 @@ protected function filterMinRange(int $value, int $min_value, string $error_mess
* Validate the argument given is an iterable
*
* @param array|Traversable $iterable
* @param string $caller public API method calling the method
*
* @throws TypeError If the submitted value is not iterable
*
* @return array|Traversable
*/
protected function filterIterable($iterable)
protected function filterIterable($iterable, string $caller)
{
if (is_array($iterable) || $iterable instanceof Traversable) {
return $iterable;
}

throw new TypeError(sprintf('Argument passed must be iterable, %s given', gettype($iterable)));
throw new TypeError(sprintf('%s() expects argument passed to be iterable, %s given', $caller, gettype($iterable)));
}

/**
* Filter Csv control character
*
* @param string $char Csv control character
* @param string $type Csv control character type
* @param string $char Csv control character
* @param string $type Csv control character type
* @param string $caller public API method calling the method
*
* @throws InvalidArgumentException If the Csv control character is not one character only.
*
* @return string
*/
protected function filterControl(string $char, string $type): string
protected function filterControl(string $char, string $type, string $caller): string
{
if (1 == strlen($char)) {
return $char;
}

throw new InvalidArgumentException(sprintf('%s must be a single character', $type));
throw new InvalidArgumentException(sprintf('%s() expects %s to be a single character %s given', $caller, $type, $char));
}
}
4 changes: 2 additions & 2 deletions src/Writer.php
Expand Up @@ -99,7 +99,7 @@ public function getFlushThreshold()
public function insertAll($records): int
{
$bytes = 0;
foreach ($this->filterIterable($records) as $record) {
foreach ($this->filterIterable($records, __METHOD__) as $record) {
$bytes += $this->insertOne($record);
}

Expand Down Expand Up @@ -236,7 +236,7 @@ public function setNewline(string $newline): self
public function setFlushThreshold($threshold): self
{
if (null !== $threshold) {
$threshold = $this->filterMinRange($threshold, 1, 'The flush threshold must be a valid positive integer or null');
$threshold = $this->filterMinRange($threshold, 1, __METHOD__.'() expects 1 Argument to be null or a valid integer greater or equal to 1, %s given');
}

if ($threshold === $this->flush_threshold) {
Expand Down
2 changes: 1 addition & 1 deletion src/XMLConverter.php
Expand Up @@ -95,7 +95,7 @@ public function convert($records): DOMDocument
$record_encoder = $this->encoder['record']['' !== $this->offset_attr];
$doc = new DOMDocument('1.0');
$root = $doc->createElement($this->root_name);
foreach ($this->filterIterable($records) as $offset => $record) {
foreach ($this->filterIterable($records, __METHOD__) as $offset => $record) {
$node = $this->{$record_encoder}($doc, $record, $field_encoder, $offset);
$root->appendChild($node);
}
Expand Down
11 changes: 0 additions & 11 deletions tests/ReaderTest.php
Expand Up @@ -107,17 +107,6 @@ public function testGetHeader()
$this->assertSame([], $this->csv->getHeader());
}

/**
* @covers ::select
* @covers League\Csv\Statement
* @covers League\Csv\ResultSet
*/
public function testSelect()
{
$stmt = new Statement();
$this->assertEquals($stmt->process($this->csv), $this->csv->select($stmt));
}

/**
* @covers ::__call
*/
Expand Down
1 change: 1 addition & 0 deletions tests/ResultSetTest.php
Expand Up @@ -92,6 +92,7 @@ public function testSetLimitThrowException()

/**
* @covers League\Csv\Statement::offset
* @covers ::__construct
*/
public function testSetOffset()
{
Expand Down

0 comments on commit b61a92c

Please sign in to comment.