Skip to content

Commit

Permalink
Exceptions handling simplify
Browse files Browse the repository at this point in the history
- All CSV related exceptions are throw using League\Csv\Exception
- All non related exceptions (Converters) are thrown using SPL Exceptions or DOM Exception
  • Loading branch information
nyamsprod committed Aug 7, 2017
1 parent 869d3db commit 4b6f1b1
Show file tree
Hide file tree
Showing 37 changed files with 180 additions and 401 deletions.
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ matrix:
env: COLLECT_COVERAGE=true VALIDATE_CODING_STYLE=false
- php: 7.1
env: COLLECT_COVERAGE=true VALIDATE_CODING_STYLE=true
- php: master
env: COLLECT_COVERAGE=true VALIDATE_CODING_STYLE=false
allow_failures:
- php: master
fast_finish: true

cache:
Expand Down
8 changes: 2 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,8 @@ All Notable changes to `Csv` will be documented in this file
- `League\Csv\XMLConverter` converts CSV records into DOMDocument
- `League\Csv\HTMLConverter` converts CSV records into HTML table.
- Improved Exception handling
- `League\Csv\Exception` the default exception interface
- `League\Csv\Exception\InsertionException`
- `League\Csv\Exception\LengthException`
- `League\Csv\Exception\LogicException`
- `League\Csv\Exception\OutOfRangeException`
- `League\Csv\Exception\RuntimeException`
- `League\Csv\Exception` the default exception
- `League\Csv\Exception\CannotInsertRecord`
- Improved CSV document output
- `League\Csv\AbstractCsv::chunk` method to output the CSV document in chunk
- `League\Csv\bom_match` function to detect BOM sequence in a given string
Expand Down
2 changes: 1 addition & 1 deletion docs/9.0/connections/controls.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ title: Csv character controls

To correctly parse a CSV document you are required to set the character controls to be used by the `Reader` or the `Writer` object.

<p>On error the setter methods will throw a <code>LengthException</code> exception if the submitted string length is not equal to <code>1</code>.</p>
<p class="message-warning">On error the setter methods will throw a <code>Exception</code> exception if the submitted string length is not equal to <code>1</code>.</p>


## The delimiter character.
Expand Down
123 changes: 0 additions & 123 deletions docs/9.0/connections/exceptions.md

This file was deleted.

2 changes: 1 addition & 1 deletion docs/9.0/connections/filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ $writer->supportsStreamFilter(); //return false the API can not be use
$writer->getStreamFilterMode(); //return STREAM_FILTER_WRITE
~~~

<p class="message-warning">A <code>LogicException</code> exception will be thrown if you use the API on a object where <code>supportsStreamFilter</code> returns <code>false</code>.</p>
<p class="message-warning">A <code>League\Csv\Exception</code> exception will be thrown if you use the API on a object where <code>supportsStreamFilter</code> returns <code>false</code>.</p>

### Cheat sheet

Expand Down
19 changes: 19 additions & 0 deletions docs/9.0/connections/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,22 @@ if (!ini_get("auto_detect_line_endings")) {

//the rest of the code continues here...
~~~

## Exceptions

The default exception class thrown while using this library is `League\Csv\Exception` which extends PHP `Exception` class.

~~~php
<?php

use League\Csv\Exception;
use League\Csv\Reader;

try {
$csv = Reader::createFromPath('/path/to/file.csv');
$csv->setDelimiter('toto');
} catch (Exception $e) {
echo $e->getMessage(), PHP_EOL;
}
~~~

2 changes: 1 addition & 1 deletion docs/9.0/connections/instantiation.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ $reader = Reader::createFromStream(fopen('/path/to/the/file.csv', 'r+'));
$writer = Writer::createFromStream(tmpfile());
~~~

<p class="message-warning"> The resource stream <strong>MUST</strong> be seekable otherwise an <code>RuntimeException</code> exception is thrown.</p>
<p class="message-warning"> The resource stream <strong>MUST</strong> be seekable otherwise an <code>League\Csv\Exception</code> exception is thrown.</p>

## Loading from a SplFileObject object

Expand Down
6 changes: 5 additions & 1 deletion docs/9.0/converter/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ The package provides classes which convert any collection of CSV records into:

Before conversion, you may want to configure your converter object. Each provided converter exposes additional methods to correctly convert your records.

When building a converter object, the methods do not need to be called in any particular order, and may be called multiple times. Because all provided converters are immutable, each time their setter methods are called they will return a new object without modifying the current one.
When building a converter object, the methods do not need to be called in any particular order, and may be called multiple times. Because all provided converters are immutable, each time their setter methods are called they will return a new object without modifying the current one.

## Converters exceptions

Because converters do not directly deals with CSV document but with their contents. On error theses classes trigger PHP's Exceptions instead of `League\Csv\Exception` exception.
2 changes: 1 addition & 1 deletion docs/9.0/converter/xml.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class XMLConverter

Prior to converting your records collection into XML, you may wish to configure the element and its associated attribute names. To do so `XMLConverter` provides methods to setup theses settings.

<p class="message-warning">Because we are building a <code>DOMDocument</code> object, the <code>XMLConverter</code> object throws <code>DOMException</code> exceptions that do not implements <a href="/9.0/connections/exceptions/">CsvException</a>.</p>
<p class="message-warning">Because we are building a <code>DOMDocument</code> object, the <code>XMLConverter</code> object throws <code>DOMException</code> insted of <code>League\Csv\Exception</code>.</p>

### XMLConverter::rootElement

Expand Down
6 changes: 3 additions & 3 deletions docs/9.0/reader/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ If no header offset is set:

<p class="message-info">By default no header offset is set.</p>

<p class="message-warning">Because the header is lazy loaded, if you provide a positive offset for an invalid record a <code>RuntimeException</code> will be triggered when trying to access the invalid record.</p>
<p class="message-warning">Because the header is lazy loaded, if you provide a positive offset for an invalid record a <code>Exception</code> exception will be triggered when trying to access the invalid record.</p>

~~~php
<?php
Expand All @@ -78,7 +78,7 @@ use League\Csv\Reader;
$csv = Reader::createFromPath('/path/to/file.csv');
$csv->setHeaderOffset(1000); //valid offset but the CSV does not contain 1000 records
$header_offset = $csv->getHeaderOffset(); //returns 1000
$header = $csv->getHeader(); //triggers a RuntimeException exception
$header = $csv->getHeader(); //triggers a Exception exception
~~~

## CSV records
Expand Down Expand Up @@ -183,7 +183,7 @@ foreach ($records as $offset => $record) {
//the first record will still be skip!!
~~~

<p class="message-warning">In both cases, if the header record contains non unique string values, a <code>RuntimeException</code> exception is triggered.</p>
<p class="message-warning">In both cases, if the header record contains non unique string values, a <code>Exception</code> exception is triggered.</p>

### Using the IteratorAggregate interface

Expand Down
12 changes: 3 additions & 9 deletions docs/9.0/reader/resultset.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ count(iterator_to_array($records->fetchColumn(2), false)); //returns 5
//5 records were skipped because the column value is null
~~~

<p class="message-warning">If the <code>ResultSet</code> contains column names and the <code>$columnIndex</code> is not found a <code>RuntimeException</code> is thrown.</p>
<p class="message-warning">If the <code>ResultSet</code> contains column names and the <code>$columnIndex</code> is not found an <code>Exception</code> exception is thrown.</p>

~~~php
<?php
Expand All @@ -244,7 +244,7 @@ $reader->setHeaderOffset(0);

$records = (new Statement())->process($reader);
foreach ($records->fetchColumn('foobar') as $record) {
//throw an RuntimeException if
//throw an Exception exception if
//no `foobar` column name is found
//in $records->getHeader() result
}
Expand Down Expand Up @@ -308,18 +308,12 @@ foreach ($records->fetchPairs() as $firstname => $lastname) {
- If no cell is found corresponding to `$offsetIndex` the row is skipped;
- If no cell is found corresponding to `$valueIndex` the `null` value is used;

<p class="message-warning">If the <code>ResultSet</code> contains column names and the submitted arguments are not found a <code>RuntimeException</code> is thrown.</p>
<p class="message-warning">If the <code>ResultSet</code> contains column names and the submitted arguments are not found an <code>Exception</code> exception is thrown.</p>

## Conversions

### Json serialization

~~~php
<?php

public ResultSet::jsonPreserveOffset(bool $status): self
~~~

The `ResultSet` class implements the `JsonSerializable` interface. As such you can use the `json_encode` function directly on the instantiated object. The interface is implemented using PHP's `iterator_array` on the `ResultSet::getRecords` method. As such, the returned `JSON` string data is affected by the presence or absence of column names.

~~~php
Expand Down
6 changes: 3 additions & 3 deletions docs/9.0/writer/helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ class ColumnConsistency

The `League\Csv\ColumnConsistency` class validates the inserted record column count consistency.

This class constructor accepts a single argument `$column_count` which sets the column count value and validate each record length against the given value. If the value differs an `InsertionException` will be thrown.
This class constructor accepts a single argument `$column_count` which sets the column count value and validate each record length against the given value. If the value differs an `CannotInsertRecord` will be thrown.

if `$column_count` equals `-1`, the object will lazy set the column count value according to the next inserted record and therefore will also validate it. On the next insert, if the given value differs a `InsertionException` exception is triggered.
if `$column_count` equals `-1`, the object will lazy set the column count value according to the next inserted record and therefore will also validate it. On the next insert, if the given value differs a `CannotInsertRecord` exception is triggered.
At any given time you can retrieve the column count value using the `ColumnConsistency::getColumnCount` method.

~~~php
Expand All @@ -38,7 +38,7 @@ $writer->addValidator($validator, 'column_consistency');
$validator->getColumnCount(); //returns -1
$writer->insertOne(["foo", "bar", "baz"]);
$validator->getColumnCount(); //returns 3
$writer->insertOne(["foo", "bar"]); //will trigger a InsertionException exception
$writer->insertOne(["foo", "bar"]); //will trigger a CannotInsertRecord exception
~~~

<p class="message-info">The default column count is set to <code>-1</code>.</p>
Expand Down
37 changes: 32 additions & 5 deletions docs/9.0/writer/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public Writer::insertOne(array $record): int
public Writer::insertAll(iterable $records): int
~~~

`Writer::insertOne` inserts a single record into the CSV document while `Writer::insertAll` adds several records. Both methods returns the length of the written data or throw an [League\Csv\Exception\InsertionException](/9.0/connections/exceptions/#runtime-exceptions) on error.
`Writer::insertOne` inserts a single record into the CSV document while `Writer::insertAll` adds several records. Both methods returns the length of the written data.

`Writer::insertOne` takes a single argument, an `array` which represents a single CSV record.
`Writer::insertAll` takes a single argument a PHP iterable which contains a collection of CSV records.
Expand All @@ -58,6 +58,28 @@ $writer->insertAll(new ArrayIterator($records)); //using a Traversable object

In the above example, all CSV records are saved to `/path/to/saved/file.csv`

If the record can not be inserted into the CSV document a `League\Csv\CannotInsertRecord` exception is thrown. This exception extends `League\Csv\Exception` and adds the ability to get the record on which the insertion failed.

~~~php
<?php

use League\Csv\CannotInsertRecord;
use League\Csv\Writer;

$records = [
[1, 2, 3],
['foo', 'bar', 'baz'],
['john', 'doe', '[email protected]'],
];

try {
$writer = Writer::createFromPath('/path/to/saved/file.csv', 'r');
$writer->insertAll($records);
} catch (CannotInsertRecord $e) {
$e->getRecords(); //returns [1, 2, 3]
}
~~~

## Handling newline

Because PHP's `fputcsv` implementation has a hardcoded `\n`, we need to be able to replace the last `LF` code with one supplied by the developper for more interoperability between CSV packages on different platforms. The newline sequence will be appended to each newly inserted CSV record.
Expand Down Expand Up @@ -165,7 +187,7 @@ function(array $record): bool

The validator **must** return `true` to validate the submitted record.

Any other expression, including thruthy ones like `yes`, `1`,... will make the `insertOne` method throw an `League\Csv\Exception\InsertionException`.
Any other expression, including thruthy ones like `yes`, `1`,... will make the `insertOne` method throw an `League\Csv\CannotInsertRecord`.

#### Adding a Validator to a Writer object

Expand All @@ -178,20 +200,25 @@ As with the formatter capabilities, you can attach as many validators as you wan
- A validator `callable`;
- A validator name. If another validator was already registered with the given name, it will be overriden.

On failure a [League\Csv\Exception\InsertionException](/9.0/connections/exceptions/#runtime-exceptions) exception is thrown by the `Writer` object.
On failure a `League\Csv\CannotInsertRecord` exception is thrown.
This exception will give access to:

- the validator name;
- the record which failed the validation;

~~~php
<?php

use League\Csv\Writer;
use League\Csv\Exception\InsertionException;
use League\Csv\CannotInsertRecord;

$writer->addValidator(function (array $row): bool {
return 10 == count($row);
}, 'row_must_contain_10_cells');

try {
$writer->insertOne(['john', 'doe', '[email protected]']);
} catch (InsertionException $e) {
} catch (CannotInsertRecord $e) {
echo $e->getName(); //display 'row_must_contain_10_cells'
$e->getData();//will return the invalid data ['john', 'doe', '[email protected]']
}
Expand Down
1 change: 0 additions & 1 deletion docs/_data/menu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ version:
BOM Sequences: '/9.0/connections/bom/'
Stream Filters: '/9.0/connections/filters/'
Document output: '/9.0/connections/output/'
Exceptions: '/9.0/connections/exceptions/'
Inserting Records:
Writer Connection: '/9.0/writer/'
Bundled Helpers: '/9.0/writer/helpers/'
Expand Down
Loading

0 comments on commit 4b6f1b1

Please sign in to comment.