diff --git a/.gitattributes b/.gitattributes index 40409793..e9299e32 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,8 +7,8 @@ /.php_cs export-ignore /.scrutinizer.yml export-ignore /.travis.yml export-ignore +/docs export-ignore /README.md export-ignore -/scrutinizer.yml export-ignore /CHANGELOG.md export-ignore /CONDUCT.md export-ignore /phpunit.xml export-ignore diff --git a/.gitignore b/.gitignore index 104fbc01..abd86096 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ vendor build -docs composer.lock diff --git a/docs/7.0/basic-usage.md b/docs/7.0/basic-usage.md new file mode 100644 index 00000000..9d9f3fbf --- /dev/null +++ b/docs/7.0/basic-usage.md @@ -0,0 +1,67 @@ +--- +layout: default +title: Basic Usage +--- + +# Basic usage + +

Tips: Even though you can use the following methods with the League\Csv\Writer object. It is recommended to do so with the League\Csv\Reader class to avoid losing the file cursor position and getting unexpected results when inserting new data.

+ +Once your CSV object is [instantiated](/7.0/instantiation) and [configured](/7.0/properties/), you can start interacting with the data using a number of methods available to you. For starters, you can iterate over your newly object to extract each CSV row using the `foreach` construct. + +~~~php + $row) { + //do something meaningful here with $row !! + //$row is an array where each item represent a CSV data cell + //$index is the CSV row index +} +~~~ + +

You can do more complex iterations using the query methods available on the League\Csv\Reader class only.

+ +## Outputting the CSV + +### __toString() + +Use the `echo` construct on the instantiated object or use the `__toString` method to show the CSV full content. + +~~~php +__toString(); +~~~ + +### output($filename = null) + +If you only wish to make your CSV downloadable by forcing a file download just use the `output` method to force the use of the output buffer on the CSV content. + +

Since version 7.0, the method returns the number of characters read from the handle and passed through to the output.

+ +~~~php +output(); +~~~ + +The output method can take an optional argument `$filename`. When present you +can even remove more headers. + +~~~php +output("name-for-your-file.csv"); +~~~ + +The output methods **can only be affected by:** + +- the [library stream filtering mechanism](/7.0/filtering/) +- the [BOM property](/7.0/bom/) + +No other method or property have effect on them. diff --git a/docs/7.0/bom.md b/docs/7.0/bom.md new file mode 100644 index 00000000..b14da9b7 --- /dev/null +++ b/docs/7.0/bom.md @@ -0,0 +1,139 @@ +--- +layout: default +title: CSV and BOM character +--- + +# Managing the BOM character + +## Detecting the CSV BOM character + +To improve interoperability with programs interacting with CSV, you can now manage the presence of a BOM character in your CSV content. The character signals the endianness of the CSV and its value depends on the CSV encoding character. To help you work with `BOM`, we are adding the following constants to the `Reader` and the `Writer` class: + +* `BOM_UTF8` : `UTF-8` `BOM`; +* `BOM_UTF16_BE` : `UTF-16` `BOM` with Big-Endian; +* `BOM_UTF16_LE` : `UTF-16` `BOM` with Little-Endian; +* `BOM_UTF32_BE` : `UTF-32` `BOM` with Big-Endian; +* `BOM_UTF32_LE` : `UTF-32` `BOM` with Little-Endian; + +They each represent the `BOM` character for each encoding character. + +### getInputBOM() + +This method will detect and return the `BOM` character used in your CSV if any. + +~~~php +getInputBOM(); //$res equals null if no BOM is found + +$reader = new Reader::createFromPat('path/to/your/msexcel.csv'); +if (Reader::BOM_UTF16_LE == $reader->getInputBOM()) { + //the CSV file is encoded using UTF-16 LE +} +~~~ + +If you wish to remove the BOM character while processing your data, you can rely on the [query filters](/7.0/query-filtering/#stripbomstatus) to do so. + +## Adding the BOM character to your CSV + +### setOutputBOM($bom = null); + +This method will manage the addition of a BOM character in front of your outputted CSV when you are: + +- downloading a file using the `output` method +- ouputting the CSV directly using the `__toString()` method + +`$bom` is a string representing the BOM character. To remove the `BOM` character just set `$bom` to an empty value like `null` or an empty string. + +

To ease writing the sequence you should use the BOM_* constants.

+ +### getOutputBOM() + +This method will tell you at any given time what `BOM` character will be prepended to the CSV content. + +

For Backward compatibility by default getOutputBOM returns null.

+ +~~~php +getOutputBOM(); //$res equals null; +$reader->setOutputBOM(Reader::BOM_UTF16LE); +$res = $reader->getOutputBOM(); //$res equals "\xFF\xFE"; +echo $reader; //the BOM sequence is prepended to the CSV + +~~~ + +## Software dependency + +Depending on your operating system and on the software you are using to read/import your CSV you may need to adjust the encoding character and add its corresponding BOM character to your CSV. + +

Out of the box, League\Csv assumes that your are using a UTF-8 encoded CSV without any BOM character.

+ +In the examples below we will be using an existing CSV as a starting point. The code may vary if you are creating the CSV from scratch. + +### MS Excel on Windows + +On Windows, MS Excel, expects an UTF-8 encoded CSV with its corresponding `BOM` character. To fullfill this requirement, you simply need to add the `UTF-8` `BOM` character if needed as explained below: + +~~~php +setOutputBOM(Reader::BOM_UTF8); +//BOM detected and adjusted for the output +echo $reader->__toString(); + +~~~ + +### MS Excel on MacOS + +On a MacOS system, MS Excel requires a CSV encoded in `UTF-16 LE` using the `tab` character as delimiter. Here's an example on how to meet those requirements using the `League\Csv` package. + +~~~php +setDelimiter("\t"); + +//we insert csv data +$writer->insertAll($origin); + +//let's switch to the Reader object +//Writer::output will failed because of the open mode +$csv = $writer->newReader(); + +//we register a Stream Filter class to convert the CSV into the UTF-16 LE +stream_filter_register(FilterTranscode::FILTER_NAME."*", "\lib\FilterTranscode"); +$csv->appendStreamFilter(FilterTranscode::FILTER_NAME."UTF-8:UTF-16LE"); + +//we detect and adjust the output BOM to be used +$csv->setOutputBOM(Reader::BOM_UTF16_LE); +//all is good let's output the results +$csv->output('mycsvfile.csv'); + +~~~ + +Of note, we used the [filtering capability](/7.0/filtering) of the library to convert the CSV encoding character from `UTF-8` to `UTF-16 LE`. + +You can found the code and the associated filter class in the [examples directory](https://github.com/thephpleague/csv/tree/master/examples). \ No newline at end of file diff --git a/docs/7.0/converting.md b/docs/7.0/converting.md new file mode 100644 index 00000000..980f41b2 --- /dev/null +++ b/docs/7.0/converting.md @@ -0,0 +1,67 @@ +--- +layout: default +title: Converting your CSV +--- + +# Converting the CSV + +the `League\Csv` object can convert your CSV document into JSON, XML and HTML format. In order to do so, the conversion methods assume that your CSV is UTF-8 encoded. To properly transcode your document into an UTF-8 compatible charset the recommended way is to use the library stream filtering mechanism. + +When this is not possible/applicable you can fallback to using the `setEncodingFrom` and `getEncodingFrom` methods. + +If your CSV is not UTF-8 encoded some unexpected results and some errors could be thrown when trying to convert your data. + +

Starting with version 7.0, when used with the League\Csv\Reader class, the conversion methods behavior are affected by the query options methods. Please refer to the Query Filters page for more informations and examples.

+ +

Starting with version 7.1, query filters are also available for conversion methods when using the League\Csv\Writer class

+ +## Convert to JSON format + +Use the `json_encode` function directly on the instantiated object. + +~~~php +toXML('data', 'line', 'item'); +~~~ + +## Convert to HTML table + +Use the `toHTML` method to convert the CSV data into an HTML table. This method +accepts an optional argument `$classname` to help you customize the table +rendering, by defaut the classname given to the table is `table-csv-data`. + +~~~php +toHTML('table table-bordered table-hover'); +~~~ + +## Example using data transcode before conversion + +~~~php +setEncodingFrom('iso-8859-15'); +echo json_encode($reader); +//the CSV is transcoded from iso-8859-15 to UTF-8 +//before being converted to JSON format; +echo $reader; //outputting the data is not affected by the conversion +~~~ diff --git a/docs/7.0/examples.md b/docs/7.0/examples.md new file mode 100644 index 00000000..ec89c300 --- /dev/null +++ b/docs/7.0/examples.md @@ -0,0 +1,102 @@ +--- +layout: default +title: Examples +--- + +# Examples + +## Parsing a document + +A simple example to show you how to parse a CSV document. + +~~~php + +fetchOne(); + +//get 25 rows starting from the 11th row +$res = $csv->setOffset(10)->setLimit(25)->fetchAll(); +~~~ + +## Exporting a database table as a CSV document + +A simple example to show you how to create and download a CSV from a `PDOStatement` object + +~~~php + +prepare( + "SELECT firstname, lastname, email FROM users LIMIT 200" +); +//because we don't want to duplicate the data for each row +// PDO::FETCH_NUM could also have been used +$sth->setFetchMode(PDO::FETCH_ASSOC); +$sth->execute(); + +//we create the CSV into memory +$csv = Writer::createFromFileObject(new SplTempFileObject()); + +//we insert the CSV header +$csv->insertOne(['firstname', 'lastname', 'email']); + +// The PDOStatement Object implements the Traversable Interface +// that's why Writer::insertAll can directly insert +// the data into the CSV +$csv->insertAll($sth); + +// Because you are providing the filename you don't have to +// set the HTTP headers Writer::output can +// directly set them for you +// The file is downloadable +$csv->output('users.csv'); +die; +~~~ + +## Importing a CSV into a database table + +A simple example to show you how to import some CSV data into a database using a `PDOStatement` object + +~~~php +prepare( + "INSERT INTO users (firstname, lastname, email) VALUES (:firstname, :lastname, :email)" +); + +$csv = Reader::createFromPath('/path/to/your/csv/file.csv'); +$csv->setOffset(1); //because we don't want to insert the header +$nbInsert = $csv->each(function ($row) use (&$sth) { + //Do not forget to validate your data before inserting it in your database + $sth->bindValue(':firstname', $row[0], PDO::PARAM_STR); + $sth->bindValue(':lastname', $row[1], PDO::PARAM_STR); + $sth->bindValue(':email', $row[2], PDO::PARAM_STR); + + return $sth->execute(); //if the function return false then the iteration will stop +}); +~~~ + +## More Examples + +* [Selecting specific rows in the CSV](https://github.com/thephpleague/csv/blob/master/examples/extract.php) +* [Querying a CSV](https://github.com/thephpleague/csv/blob/master/examples/filtering.php) +* [Creating a CSV](https://github.com/thephpleague/csv/blob/master/examples/writing.php) +* [Merging 2 CSV documents](https://github.com/thephpleague/csv/blob/master/examples/merge.php) +* [Switching between modes from Writer to Reader mode](https://github.com/thephpleague/csv/blob/master/examples/switchmode.php) +* [Downloading the CSV](https://github.com/thephpleague/csv/blob/master/examples/download.php) +* [Converting the CSV into a Json String](https://github.com/thephpleague/csv/blob/master/examples/json.php) +* [Converting the CSV into a XML file](https://github.com/thephpleague/csv/blob/master/examples/xml.php) +* [Converting the CSV into a HTML Table](https://github.com/thephpleague/csv/blob/master/examples/table.php) +* [Using stream Filter on the CSV](https://github.com/thephpleague/csv/blob/master/examples/stream.php) + +> The CSV data use for the examples are taken from [Paris Opendata](http://opendata.paris.fr/opendata/jsp/site/Portal.jsp?document_id=60&portlet_id=121) \ No newline at end of file diff --git a/docs/7.0/filtering.md b/docs/7.0/filtering.md new file mode 100644 index 00000000..16e15848 --- /dev/null +++ b/docs/7.0/filtering.md @@ -0,0 +1,163 @@ +--- +layout: default +title: Stream Filtering +--- + +# Stream Filtering + +To ease performing operations on the CSV as it is being read from or written to, the `Reader` and `Writer` classes now include methods to ease PHP stream filtering usage. + + +## Stream Filter API + +While in PHP the stream filter mode is attached to its associated filter, in `League\Csv` the filter mode is attached to the CSV object. This means that when you change the filter mode, you also clear all previously attached stream filters. + +To be able to use the stream filtering mechanism you need to: + +* validate that the stream filter API is active; +* set the class filtering mode; +* attached your stream filters to the CSV object; + +### Detecting if the API is active + +To be sure that the Stream Filter API is available it is recommend to use the method `isActiveStreamFilter`, which returns `true` if you can safely use the API: + +~~~php +isActiveStreamFilter(); //return true + +$writer = Writer::createFromFileObject(new SplTempFileObject()); +$writer->isActiveStreamFilter(); //return false the API can not be use +~~~ + +

Warning: A LogicException exception may be thrown if you try to use the API under certain circumstances without prior validation using isActiveStreamFilter

+ +### Setting and getting the object stream filter mode + +The stream filter mode property is set using PHP internal stream filter constant `STREAM_FILTER_*`, but unlike `fopen`, the mode is attached to the object and not to a stream filter. + +* `setStreamFilterMode($mode)`: set the object stream filter mode **and** remove all previously attached stream filters; +* `getStreamFilterMode()`: returns the current stream filter mode; + +By default: + +- when using the `Reader` class the property is equal to `STREAM_FILTER_READ`; +- when using the `Writer` class the property is equal to `STREAM_FILTER_WRITE`; +- If you instantiate the class using a PHP filter meta wrapper (ie: `php://filter/`), the mode will be the one used by the meta wrapper; + +~~~php +isActiveStreamFilter()) { + $current_mode = $reader->getStreamFilterMode(); //returns STREAM_FILTER_READ + $reader->setStreamFilterMode(STREAM_FILTER_WRITE); + //this means that any filter you will set will have no effect when reading the CSV + //all previously attached stream filters if they existed have been removed + $current_mode = $reader->getStreamFilterMode(); //returns STREAM_FILTER_WRITE +} +~~~ + +### Managing Stream filter + +To manage your registered stream filter collection you can use the following methods + +- `appendStreamFilter($filtername)` : adds a stream filter at the bottom of the collection +- `prependStreamFilter($filtername)` : adds a stream filter at the top of the collection +- `removeStreamFilter($filtername)` : removes a stream filter from the collection +- `hasStreamFilter($filtername)` : check the presence of a stream filter in the collection +- `clearStreamFilter()`: removes all the currently attached filters. + +The `$filtername` parameter is a string that represents the filter as registered using php `stream_filter_register` function or one of PHP internal stream filter. + +Since the stream filters are attached to the CSV object: + +* The filters will not be cleared between method calls unless specified +* The filters will not be copied to the new class when using `newReader` or `newWriter` methods + +The filters are automatically applied when the stream filter mode matches the method you are using. + +See below an example using `League\Csv\Reader` to illustrate: + +~~~php +isActiveStreamFilter()) { + $reader->appendStreamFilter('string.toupper'); + $reader->appendStreamFilter('string.rot13'); + $reader->prependStreamFilter('convert.utf8decode'); + $reader->removeStreamFilter('string.rot13'); +} +foreach ($reader as $row) { + // each row cell now contains strings that have been: + // first UTF8 decoded and then uppercased +} +~~~ + +

Warning: If your filter contains / characters, to be sure that it will be taken into account and won't trigger any exception or error, you should URL encode it prior to adding it to the filter collections.

+ +~~~php +appendStreamFilter($filter); +var_dump($reader->fetchAll()); +~~~ + +## Limitations + +### Writer class on Editing Mode + +

Warning: To preserve file cursor position during editing the stream filter mode and the stream filter collection are frozen after the first insert is made using any of the insert* method. Any attempt to modify the stream filter status will fail silently.

+ +~~~php +setDelimiter(','); +if ($writer->isActiveStreamFilter()) { + $writer->addStreamFilter('string.toupper'); +} +//first insert -> file.csv will contain uppercased data. +$writer->insertOne(['bill', 'gates', 'bill@microsoft.com']); +if ($writer->isActiveStreamFilter()) { + //isActiveStreamFilter returns false so this code is never executed + $writer->addStreamFilter('string.rot13'); +} +//this filter is added to the collection but will never be applied!! +$writer->addStreamFilter('string.rot13'); +//The inserted array will only be uppercased!! +$writer->insertOne('steve,job,job@apple.com'); + +echo $writer; //the newly added rows are all uppercased +~~~ + +## Example + +Please review the stream filtering example and the attached FilterTranscode Class to understand how to use the filtering mechanism to convert a CSV into another charset. + +The `FilterTranscode` class is not attached to the Library because converting you CSV may depend on the extension you choose, in PHP you can use the following extensions : + + \ No newline at end of file diff --git a/docs/7.0/index.md b/docs/7.0/index.md new file mode 100644 index 00000000..dc683b85 --- /dev/null +++ b/docs/7.0/index.md @@ -0,0 +1,44 @@ +--- +layout: default +--- + +# Introduction + +[![Author](http://img.shields.io/badge/author-@nyamsprod-blue.svg?style=flat-square)](https://twitter.com/nyamsprod) +[![Source Code](http://img.shields.io/badge/source-league/csv-blue.svg?style=flat-square)](https://github.com/thephpleague/csv) +[![Latest Version](https://img.shields.io/github/release/thephpleague/csv.svg?style=flat-square)](https://github.com/thephpleague/csv/releases) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md)
+[![Build Status](https://img.shields.io/travis/thephpleague/csv/master.svg?style=flat-square)](https://travis-ci.org/thephpleague/csv) +[![HHVM Status](https://img.shields.io/hhvm/league/csv.svg?style=flat-square)](http://hhvm.h4cc.de/package/league/csv) +[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/csv.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/csv/code-structure) +[![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/csv.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/csv) +[![Total Downloads](https://img.shields.io/packagist/dt/league/csv.svg?style=flat-square)](https://packagist.org/packages/league/csv) + +`League\Csv` is a simple library to ease CSV parsing, writing and filtering in +PHP. The goal of the library is to be as powerful while remaining lightweight, +by utilizing PHP native classes whenever possible. + +`League\Csv` was designed for developers who want to deal with CSV data using +modern code and without the high levels of bootstrap and low-levels of +usefulness provided by existing core functions or third party-code. + +[CSV on Packagist](https://packagist.org/packages/league/csv) + +## Highlights + +* Simple API +* Read and Write to CSV documents in a memory efficient and scalable way +* Use SPL to interact with the CSV documents +* Support PHP Stream filtering capabilities +* Transform CSV documents into popular format (JSON, XML or HTML) +* Fully documented +* Fully Unit tested +* Framework-agnostic +* Composer ready, [PSR-2] and [PSR-4] compliant + +## Questions? + +`League\Csv` was created by Ignace Nyamagana Butera. Find him on Twitter at [@nyamsprod](https://twitter.com/nyamsprod). + +[PSR-2]: http://www.php-fig.org/psr/psr-2/ +[PSR-4]: http://www.php-fig.org/psr/psr-4/ \ No newline at end of file diff --git a/docs/7.0/inserting.md b/docs/7.0/inserting.md new file mode 100644 index 00000000..2d8075f6 --- /dev/null +++ b/docs/7.0/inserting.md @@ -0,0 +1,212 @@ +--- +layout: default +title: Inserting new data into a CSV +--- + +# Inserting Data + +To create or update a CSV use the following `League\Csv\Writer` methods. + +

The class has been rewritten for scalability and speed. Some previous supported features have been removed. Please refer to the upgrade section to securely migrate from previous version to 7.0 .

+ +

When creating a file using the library, first insert all the data that need to be inserted before starting manipulating the CSV. If you manipulate your data before insertion, you may change the file cursor position and get unexpected results.

+ +## Adding new data + +The `Writer` class performs a number of actions while inserting your data into the CSV. When submitting data for insertion the class will proceed as describe below for each row. + +The `Writer` class will: + +- See if the row is an `array`, if not it will try to convert it into a proper `array`; +- If supplied, formatters will further format the given `array`; +- If supplied, validators will validate the formatted `array` according to their rules; +- While writing the data to your CSV document, if supplied, stream filters will apply further formatting to the inserted row; +- If needed the newline sequence will be updated; + +To add new data to your CSV the `Writer` class uses the following methods + +### insertOne($row) + +`insertOne` inserts a single row. This method can take an `array`, a `string` or +an `object` implementing the `__toString` method. + +~~~php +str = $str; + } + + public function __toString() + { + return $this->str; + } +} + +$writer->insertOne(['john', 'doe', 'john.doe@example.com']); +$writer->insertOne("'john','doe','john.doe@example.com'"); +$writer->insertOne(new ToStringEnabledClass("john,doe,john.doe@example.com")) +~~~ + +### insertAll($rows) + +`insertAll` inserts multiple rows. This method can take an `array` or a +`Traversable` object to add several rows to the CSV data. + +~~~php +insertAll($rows); //using an array + +$writer->insertAll(new ArrayIterator($rows)); //using a Traversable object +~~~ + +## Row formatting + +

New to version 7.0

+ +A formatter is a `callable` which accepts an `array` on input and returns the same array formatted according to its inner rules. + +You can attach as many formatters as you want to the `Writer` class to manipulate your data prior to its insertion. The formatters follow the *First In First Out* rule when inserted, deleted and/or applied. + + The formatter API comes with the following public API: + +### addFormatter(callable $callable) + +Adds a formatter to the formatter collection; + +### removeFormatter(callable $callable) + +Removes an already registered formatter. If the formatter was registered multiple times, you will have to call `removeFormatter` as often as the formatter was registered. **The first registered copy will be the first to be removed.** + +### hasFormatter(callable $callable) + +Checks if the formatter is already registered + +### clearFormatters() + +removes all registered formatters. + +~~~php +addFormatter(function ($row) { + return array_map('strtoupper', $row); +}); +$writer->insertOne(['john', 'doe', 'john.doe@example.com']); + +$writer->__toString(); +//will display something like JOHN,DOE,JOHN.DOE@EXAMPLE.COM +~~~ + +If you are relying on the **removed** null handling feature the library comes bundle with the following classes to help you migrate to the new version. + +- `League\Csv\Plugin\SkipNullValuesFormatter` to format `null` values + +Please refers to the migration guide for more information. + +## Row validation + +

New to version 7.0

+ +A validator is a `callable` which takes a `array` as its sole argument and returns a boolean. The validator **must** return `true` to validate the submitted row. Any other expression, including thruthy ones like `yes`, `1`,... will make the `insertOne` method throw an `League\Csv\Exception\InvalidRowException`. + +As with the new formatter capabilities, you can attach as many validators as you want to your data prior to its insertion. The row data is checked against your supplied validators **after being formatted**. + +The validator API comes with the following public API: + +### addValidator(callable $callable, $validator_name) + +Adds a validator each time it is called. The method takes two parameters: + +- A `callable` which takes an `array` as its unique parameter; +- The validator name which is **required**. If another validator was already registered with the given name, it will be overriden. + +### removeValidator($validator_name) + +Removes an already registered validator by using the validator registrated name + +### hasValidator($validator_name) + +Checks if the validator is already registered + +### clearValidators() + +Removes all registered validators + +## Validation failed + +If the validation failed a `League\Csv\Exception\InvalidRowException` is thrown by the `Writer` object. +This exception extends PHP's `InvalidArgumentException` by adding two public getter methods + +### InvalidRowException::getName + +returns the name of the failed validator + +### InvalidRowException::getData + +returns the invalid data submitted to the validator + +## Validation example + +~~~php +addValidator(function (array $row) { + return 10 == count($row); +}, 'row_must_contain_10_cells'); +try { + $writer->insertOne(['john', 'doe', 'john.doe@example.com']); +} catch (InvalidRowException $e) { + echo $e->getName(); //display 'row_must_contain_10_cells' + $e->getData();//will return the invalid data ['john', 'doe', 'john.doe@example.com'] +} +~~~ + +If you are relying on the **removed features** null handling and the column consistency, the library comes bundle with the following classes to help you migrate to the new version. + +- `League\Csv\Plugin\ForbiddenNullValuesValidator` to validate the absence of the `null` value; +- `League\Csv\Plugin\ColumnConsistencyValidator` to validate the CSV column consistency; + +Please refers to the migration guide for more information. + +## Stream filtering + +Some data formatting can still occur while writing the data to the CSV document after validation using the [Stream Filters capabilities](/7.0/fitering/). + +## Handling newline + +Because the php `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 CSV newly inserted line. + +At any given time you can get and modify the `$newline` property using the `getNewline` and `setNewline` methods described in CSV properties documentation page. + +~~~php +getNewline(); // equals "\n"; +$writer->setNewline("\r\n"); +$newline = $writer->getNewline(); // equals "\r\n"; +$writer->insertOne(["one", "two"]); +echo $writer; // displays "one,two\r\n"; +~~~ + +

Please refer to the BOM character dedicated documentation page for more informations on how the library manage the BOM character.

+ diff --git a/docs/7.0/installation.md b/docs/7.0/installation.md new file mode 100644 index 00000000..932b0264 --- /dev/null +++ b/docs/7.0/installation.md @@ -0,0 +1,22 @@ +--- +layout: default +title: Installation +--- + +# Installation + +## System Requirements + +You need **PHP >= 5.4.0** or **HHVM >= 3.2** and the `mbstring` extension to use `League\Csv` but the latest stable version of PHP/HHVM is recommended. + +## Composer + +`League\Csv` is available on [Packagist](https://packagist.org/packages/league/csv) and can be installed using [Composer](https://getcomposer.org/): + +~~~ +$ composer require league/csv:^7.0 +~~~ + +## Going Solo + +You can also use `League\Csv` without using Composer by downloading the library and using any other [PSR-4](http://www.php-fig.org/psr/psr-4/) compatible autoloader. diff --git a/docs/7.0/instantiation.md b/docs/7.0/instantiation.md new file mode 100644 index 00000000..74abf9fb --- /dev/null +++ b/docs/7.0/instantiation.md @@ -0,0 +1,119 @@ +--- +layout: default +title: Instantiation using named constructors +--- + +# Instantiation + +The library is composed of two main classes: + +* `League\Csv\Reader` to read data from a CSV +* `League\Csv\Writer` to write new data into a CSV + +Both classes extend the `League\Csv\AbstractCsv` class and as such share methods for instantiation. + +## Mac OS Server + +**If you are on a Mac OS X Server**, add the following lines before using the library to help [PHP detect line ending in Mac OS X](http://php.net/manual/en/function.fgetcsv.php#refsect1-function.fgetcsv-returnvalues). + +~~~php +Warning: The method throws an InvalidArgumentException if a SplTempFileObject is given as no path can be retrieve from such object.

+* The `$open_mode` parameter which defaults to `r+` if none is supplied. + +The resulting string and `$open_mode` parameters are used to lazy load internally a `SplFileObject` object. + +~~~php +The $newline argument was added in version 7.0

+ +If you have a raw CSV string use the `createFromString` named constructor. This method accepts two parameters: + +- the raw CSV string; +- the newline sequence to be added at the end of the raw CSV string; + +If no newline sequence is specified, the newline sequence used will be `\n` to match the one added by PHP `fputcsv` function. + +

The $newline argument is deprecated since version 7.2 and will be removed in the next major release.

+ +~~~php +Starting with version 7.0 directly using the default constructor is no longer possible.

+ +## Switching from one class to the other + +At any given time you can switch or create a new `League\Csv\Writer` or a new `League\Csv\Reader` from the current object. to do so you can use the following methods. + +* the `newReader` to create a new `League\Csv\Reader` object; +* the `newWriter` to create a new `League\Csv\Writer` object; + +Both methods accept an optional `$open_mode` parameter. + +* When not explicitly set, the `$open_mode` default value is `r+` for both methods. +* If the initial object `$open_mode` parameter was not taken into account any new CSV object created with these methods won't take into account the given `$open_mode`. + +~~~php +newReader('r+'); +$newWriter = $reader->newWriter('a'); +$anotherWriter = $newWriter->newWriter('r+'); +~~~ + +

Warning: be careful the $newWriter and $anotherWriter object are not the same as the $writer object!

\ No newline at end of file diff --git a/docs/7.0/properties.md b/docs/7.0/properties.md new file mode 100644 index 00000000..047eadf8 --- /dev/null +++ b/docs/7.0/properties.md @@ -0,0 +1,219 @@ +--- +layout: default +title: Setting and Accessing CSV settings +--- + +# CSV properties + +Once your object is [instantiated](/7.0/instantiation/) you can optionally set several CSV properties. The following methods works on both the `Reader` and the `Writer` class. + +## Accessing and Setting CSV properties + +### The delimiter character + +~~~php +setDelimiter(';'); +$delimiter = $csv->getDelimiter(); //returns ";" +~~~ +The default delimiter character is `,`. + +### The enclosure character + +~~~php +setEnclosure('|'); +$enclosure = $csv->getEnclosure(); //returns "|" +~~~ +The default enclosure character is `"`. + +### The escape character + +

Warning: The library depends on PHP SplFileObject class. Since this class exhibits a reported bug, Data using the escape character a correctly escaped but the escape character is not removed from the CSV content.
+A possible workaround to this issue while waiting for a PHP bug fix is to register a callable that will format your content.

+ +~~~php +setEscape('\\'); +$escape = $csv->getEscape(); //returns "\" +~~~ +The default escape character is `\`. + +### The SplFileObject flags + +`League\Csv` objects rely internally on the `SplFileObject` class. In order to fine tune the class behavior you can adjust the [SplFileObject flags](http://php.net/manual/en/class.splfileobject.php#splfileobject.constants) used. + +~~~php +setFlags(SplFileObject::READ_AHEAD|SplFileObject::SKIP_EMPTY); +$flags = $csv->getFlags(); //returns an integer +~~~ + +

Since version 7.0.1, the setFlags method has been fixed to prevent a bug in SplFileObject.

+ +

Since version 7.2.0, the flags on instantiaton are have been changed to correct a bug when parsing row cells with multiple lines

+ +- On instantiation the flags set are : + - `SplFileObject::READ_CSV` + - `SplFileObject::READ_AHEAD` + - `SplFileObject::SKIP_EMPTY` + +- On update you can add or remove any `SplFileObject` flags except for the `SplFileObject::READ_CSV` flag. + +## Detecting CSV delimiter + +### fetchDelimitersOccurrence(array $delimiters, $nbRows = 1) + +

This method is introduced in version 7.2.0

+ +The method takes two arguments: + +* an array containing the delimiters to check; +* an integer which represents the number of rows to scan (default to `1`); + +~~~php +setEnclosure('"'); +$reader->setEscape('\\'); + +$delimiters_list = $reader->fetchDelimitersOccurrence([' ', '|'], 10); +// $delimiters_list can be the following +// [ +// '|' => 20, +// ' ' => 0, +// ] +// This seems to be a consistent CSV with: +// - the delimiter "|" appearing 20 times in the 10 first rows +// - the delimiter " " never appearing +~~~ + +

This method only test the delimiters you gave it.

+ +### detectDelimiterList($nbRows = 1, array $delimiters = []) + +

This method is deprecated since version 7.2.0 and will be remove in the next major release

+ +

If multiple delimiters share the same occurrences count only the last found delimiter will be returned in the response array.

+ +

This method will only give you a hint, a better approach is to ask the CSV provider for the document controls properties.

+ +If you are no sure about the delimiter you can ask the library to detect it for you using the `detectDelimiterList` method. + +The method takes two arguments: + +* the number of rows to scan (default to `1`); +* the possible delimiters to check (you don't need to specify the following delimiters as they are already checked by the method: `",", ";", "\t"`); + +~~~php +setEnclosure('"'); +$reader->setEscape('\\'); +$reader->setFlags(SplFileObject::READ_AHEAD|SplFileObject::SKIP_EMPTY); + +$delimiters_list = $reader->detectDelimiterList(10, [' ', '|']); +// $delimiters_list can be the following +// [ +// 20 => '|', +// 3 => ';' +// ] +// This is a inconsistent CSV with: +// - the delimiter "|" appearing 20 times in the 10 first rows +// - the delimiter ";" appearing 3 times in the 10 first rows +~~~ + +The more rows and delimiters you add, the more time and memory consuming the operation will be. The method returns an `array` of the delimiters found. + +* If a single delimiter is found the array will contain only one delimiter; +* If multiple delimiters are found the array will contain the found delimiters sorted descendingly according to their occurences in the defined rows set; +* If no delimiter is found or your CSV is composed of a single column, the array will be empty; + +

BC Break: Starting with version 7.0, the index of each found delimiter represents the occurence of the found delimiter in the selected rows.

+ +Whenever a user creates a new CSV object using the `newWriter` or the `newReader` methods, the current CSV object properties are copied to the new instance. + +## Writing mode only properties + +The following properties only affect the CSV when you are writing or saving data to it. + +### The newline sequence + +The newline sequence is appended to each CSV newly inserted line. To improve interoperability with programs interacting with CSV and because the php `fputcsv` implementation has a hardcoded `"\n"`, we need to be able to replace this last `LF` code with one supplied by the developer. + +~~~php +setNewline("\r\n"); +$newline = $csv->getNewline(); //returns "\r\n" +~~~ +The default newline sequence is `\n`; + +

Since version 7.0, the $newline getter and setter methods are also available on the Reader class.

+ +### The BOM character + +To improve interoperability with programs interacting with CSV, you can now manage the presence of a BOM character in your CSV content. + +Detect the current BOM character is done using the `getInputBOM` method. This method returns the currently used BOM character or `null` if none is found or recognized. + +~~~php +getInputBOM(); +~~~ + +You can of course set the outputting BOM you want your CSV to be associated with. + +~~~php +setOutputBOM(Reader::BOM_UTF8); +$bom = $csv->getOutputBOM(); //returns "\xEF\xBB\xBF" +~~~ +The default output `BOM` character is set to `null`. + +

Please refer to the BOM character dedicated documentation page for more informations on how the library helps you manage this feature.

+ +## Conversion only properties + +The following properties and method only works when converting CSV document into other available format. + +### The encoding charset + +To convert your CSV document into another format it must be encoded in UTF-8. + +When this is not the case, you should transcode it using the library stream filtering mechanism. + +When this is not applicable you can fallback by providing the CSV original encoding charset to the CSV class using the following method: + +~~~php +setEncodingFrom('iso-8859-15'); +echo $reader->getEncodingFrom(); //returns iso-8859-15; +~~~ + +By default `getEncodingFrom` returns `UTF-8` if `setEncodingFrom` was not used. + +
The encoding properties have no effect when reading or writing to a CSV document. You should instead use the Stream Filter API or the Writing Formatter API.
+ +~~~php +setEncodingFrom('iso-8859-15'); +echo json_encode($reader); +//the CSV is transcoded from iso-8859-15 to UTF-8 +//before being converted to JSON format; +echo $reader; //outputting the data is not affected by the conversion +~~~ \ No newline at end of file diff --git a/docs/7.0/query-filtering.md b/docs/7.0/query-filtering.md new file mode 100644 index 00000000..072db049 --- /dev/null +++ b/docs/7.0/query-filtering.md @@ -0,0 +1,165 @@ +--- +layout: default +title: Query Filtering +--- + +# Query Filtering + +## Query Filters + +You can restrict [extract methods](/7.0/reading/) and [conversion methods](/7.0/converting/) output by setting query options. To set those options you will need to use the methods described below. But keep in mind that: + +* The query options methods are all chainable *except when they have to return a boolean*; +* The query options methods can be call in any sort of order before any extract/conversion method; +* After an extract/conversion method call, all query options are cleared; +* The optional extract method callable function is called after all query options have been applied; + +

The options methods are described in the same order as they are applied on the CSV iterator. The order is similar to one found in SQL statement construct.

+ +

Starting with version 7.0 The query options can be use to modify the output from the jsonSerialize, toXML and toHTML methods.

+ +

Starting with version 7.1 The query options are also available for conversion methods on the League\Csv\Writer class.

+ +## Modifying content methods + +### stripBOM($status) + +

Introduced in version 7.1

+ +`stripBom` only argument `$status` must be a `boolean`. This method specifies if the [BOM sequence](/7.0/bom/) must be removed or not from the CSV's first cell of the first row. The actual stripping will take place only if a BOM sequence is detected and the first row is selected in the resultset **or** if its offset is used as the first argument of the `Reader::fetchAssoc` method. + +

For backward compatibility, if the method is not called no BOM sequence will be stripped from the CSV document.

+ +

The BOM sequence is never removed from the CSV document, it is only stripped from the resultset.

+ +## Filtering methods + +The filtering options **are the first settings applied to the CSV before anything else**. The filters follow the *First In First Out* rule. + +### addFilter(callable $callable) + +The `addFilter` method adds a callable filter function each time it is called. The function can take up to three parameters: + +* the current csv row data; +* the current csv key; +* the current csv iterator object; + +### removeFilter(callable $callable) + +`removeFilter` method removes an already registered filter function. If the function was registered multiple times, you will have to call `removeFilter` as often as the filter was registered. **The first registered copy will be the first to be removed.** + +### hasFilter(callable $callable) + +`hasFilter` method checks if the filter function is already registered + +### clearFilter() + +`clearFilter` method removes all registered filter functions. + +## Sorting methods + +The sorting options are applied **after the CSV filtering options**. The sorting follow the *First In First Out* rule. + +

To sort the data iterator_to_array is used which could lead to performance penalty if you have a heavy CSV file to sort +

+ +### addSortBy(callable $callable) + +`addSortBy` method adds a sorting function each time it is called. The function takes exactly two parameters which will be filled by pairs of rows. + +### removeSortBy(callable $callable) + +`removeSortBy` method removes an already registered sorting function. If the function was registered multiple times, you will have to call `removeSortBy` as often as the function was registered. **The first registered copy will be the first to be removed.** + +### hasSortBy(callable $callable) + +`hasSortBy` method checks if the sorting function is already registered + +### clearSortBy() + +`clearSortBy` method removes all registered sorting functions. + +## Interval methods + +The methods enable returning a specific interval of CSV rows. When called more than once, only the last filtering settings is taken into account. The interval is calculated **after filtering and/or sorting but before extracting the data**. + +### setOffset($offset = 0) + +`setOffset` method specifies an optional offset for the return data. By default the offset equals `0`. + +### setLimit($limit = -1) + +`setLimit` method specifies an optional maximum rows count for the return data. By default the offset equals `-1`, which translate to all rows. + +

Both methods have no effect on the fetchOne method output.

+ +## Examples + +### Modifying extract methods output + +Here's an example on how to use the query features of the `Reader` class to restrict the `fetchAssoc` result: + +~~~php +stripBom(false) + ->setOffset(3) + ->setLimit(2) + ->addFilter('filterByEmail') + ->addSortBy('sortByLastName') + ->fetchAssoc(['firstname', 'lastname', 'email'], function ($value) { + return array_map('strtoupper', $value); +}); +// data length will be equals or lesser that 2 starting from the row index 3. +// will return something like this : +// +// [ +// ['firstname' => 'JANE', 'lastname' => 'RAMANOV', 'email' => 'JANE.RAMANOV@EXAMPLE.COM'], +// ['firstname' => 'JOHN', 'lastname' => 'DOE', 'email' => 'JOHN.DOE@EXAMPLE.COM'], +// ] +// +~~~ + +### Modifying conversion methods output + +Starting with `version 7.0`, the query options can also modify the output from the conversion methods as shown below with the `toHTML` method. + +~~~php +stripBom(true) + ->setOffset(3) + ->setLimit(2) + ->addFilter('filterByEmail') + ->addSortBy('sortByLastName') + ->toHTML("simple-table"); +// $data contains the HTML table code equivalent to: +// +// +// +// +//
JANERAMANOVJANE.RAMANOV@EXAMPLE.COM
JOHNDOEJOHN.DOE@EXAMPLE.COM
+// +~~~ diff --git a/docs/7.0/reading.md b/docs/7.0/reading.md new file mode 100644 index 00000000..3b7c493f --- /dev/null +++ b/docs/7.0/reading.md @@ -0,0 +1,201 @@ +--- +layout: default +title: Extracting data from a CSV +--- + +# Extracting data + +To extract data from a CSV document use `League\Csv\Reader` methods. + +## Fetching CSV data + +### query(callable $callable = null) + +

This method is deprecated since version 7.2.0 and will be remove in the next major release

+ +The `query` method prepares and issues queries on the CSV data. It returns an `Iterator` that represents the result that you can further manipulate as you wish. + +~~~php +query(); +foreach ($data as $lineIndex => $row) { + //do something here +} +~~~ + +### fetch(callable $callable = null) + +

This method is introduced in version 7.2.0

+ +The `fetch` method returns an `Iterator`. + +~~~php +fetch() as $row) { + //do something here +} +~~~ + +### fetchAll(callable $callable = null) + +`fetchAll` returns a sequential array of all rows. + +~~~php +fetchAll(); +// will return something like this : +// +// [ +// ['john', 'doe', 'john.doe@example.com'], +// ['jane', 'doe', 'jane.doe@example.com'], +// ... +// ] +// +$nb_rows = count($data); +~~~ + +### fetchAssoc($offset_or_keys = 0, callable $callable = null) + +`fetchAssoc` returns a sequential array of all rows. The rows themselves are associative arrays where the keys are an one dimension array. This array must only contain unique `string` and/or `integer` values. + +This array keys can be specified as the first argument as + +- a specific CSV row by providing its offset; **(since version 6.1)** +- a non empty array directly provided; + +Using a non empty array: + +~~~php +fetchAssoc(['firstname', 'lastname', 'email']); +// will return something like this : +// +// [ +// ['firstname' => 'john', 'lastname' => 'doe', 'email' => 'john.doe@example.com'], +// ['firstname' => 'jane', 'lastname' => 'doe', 'email' => 'jane.doe@example.com'], +// ['firstname' => 'fred', 'lastname' => 'doe', 'email' => 'fred.doe@example.com'], +// ... +// ] +// +~~~ + +Using a specific offset: + +~~~php +fetchAssoc(); +// will return something like this : +// +// [ +// ['john' => 'jane', 'doe' => 'doe', 'john.doe@example.com' => 'jane.doe@example.com'], +// ['john' => 'fred', 'doe' => 'doe', 'john.doe@example.com' => 'fred.doe@example.com'], +// ... +// ] +// +~~~ + +Of note: + +- If the number of values in a CSV row is lesser than the number of named keys, the method will add `null` values to compensate for the missing values. +- If the number of values in a CSV row is greater that the number of named keys the exceeding values will be drop from the result set. +- If no argument is provided, the first row from the CSV data will be used +- If an offset is used, its content will be skipped in the result set. + +### fetchColumn($columnIndex = 0, callable $callable = null) + +`fetchColumn` returns a sequential array of all values in a given column from the CSV data. + +If for a given row the column does not exist, the row will be skipped. + +~~~php +fetchColumn(2); +// will return something like this : +// +// ['john.doe@example.com', 'jane.doe@example.com', ...] +// +~~~ + +
+BC break starting with version 7.0 : + +
+ +### Using a callable to modify the returned resultset + +The methods listed above (`query`, `fetchAll`, `fetchAssoc`, `fetchColumn`) can all take a optional `callable` argument to further manipulate each row before being returned. This callable function can take up to three parameters: + +* the current csv row data +* the current csv key +* the current csv iterator object + +~~~php +fetchAll(function ($row) { + return array_map('strtoupper', $row); +}); +// will return something like this : +// +// [ +// ['JOHN', 'DOE', 'JOHN.DOE@EXAMPLE.COM'], +// ['JANE', 'DOE', 'JANE.DOE@EXAMPLE.COM'], +// ... +// ] +// +$nb_rows = count($data); +~~~ + +

In case of the fetchAssoc method, it's the callable result which is combine to the array key.

+ +### fetchOne($offset = 0) + +`fetchOne` return one single row from the CSV data. The required argument $offset represent the row index starting at 0. If no argument is given to the method it will return the first row from the CSV data. + +~~~php +fetchOne(3); ///accessing the 4th row (indexing starts at 0) +// will return something like this : +// +// ['john', 'doe', 'john.doe@example.com'] +// +~~~ + +### each(callable $callable) + +`each` apply a callable function on each CSV row. The callable function: + +* **must** return `true` to continue iterating over the CSV; +* can take up to three parameters: + * the current csv row data; + * the current csv key; + * the current csv iterator object; + +The method returns the number of successful iterations. + +~~~php +each(function ($row, $index, $iterator) use (&$res, $func)) { + if (is_callable($func)) { + $res[] = $func($row, $index, $iterator); + return true; + } + $res[] = $row; + return true; +}); +~~~ diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 00000000..1eb0ff8f --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +csv.thephpleague.com \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 00000000..99010eb8 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,4 @@ +--- +permalink: pretty +gems: + - jekyll-redirect-from \ No newline at end of file diff --git a/docs/_data/images.yml b/docs/_data/images.yml new file mode 100644 index 00000000..7d475040 --- /dev/null +++ b/docs/_data/images.yml @@ -0,0 +1,8 @@ +# Path to project specific favicon.ico, leave blank to use default +favicon: + +# Path to project specific apple-touch-icon-precomposed.png, leave blank to use default +apple_touch: + +# Path to project logo +logo: \ No newline at end of file diff --git a/docs/_data/menu.yml b/docs/_data/menu.yml new file mode 100644 index 00000000..62f56518 --- /dev/null +++ b/docs/_data/menu.yml @@ -0,0 +1,42 @@ +'8.0': + Getting Started: + Introduction: '/' + Examples: '/examples/' + Installation: '/installation/' + The API: + Instantiation: '/instantiation/' + CSV Properties: '/properties/' + Basic Usage: '/basic-usage/' + Extracting Data: '/reading/' + Inserting Data: '/inserting/' + Converting Data: '/converting/' + Query Filters: '/query-filtering/' + Stream Filters: '/filtering/' + BOM Handling: '/bom/' + Upgrading Guide: + Introduction: '/upgrading/' + Changelog: '/changelog/' + 5.x to 6.x: '/upgrading/6.0/' + 6.x to 7.x: '/upgrading/7.0/' + 7.x to 8.x: '/upgrading/8.0/' +'7.0': + Getting Started: + Introduction: '/7.0/' + Examples: '/7.0/examples/' + Installation: '/7.0/installation/' + The API: + Instantiation: '/7.0/instantiation/' + CSV Properties: '/7.0/properties/' + Basic Usage: '/7.0/basic-usage/' + Extracting Data: '/7.0/reading/' + Inserting Data: '/7.0/inserting/' + Converting Data: '/7.0/converting/' + Query Filters: '/7.0/query-filtering/' + Stream Filters: '/7.0/filtering/' + BOM Handling: '/7.0/bom/' + Upgrading Guide: + Introduction: '/upgrading/' + Changelog: '/changelog/' + 7.x to 8.x: '/upgrading/8.0/' + 6.x to 7.x: '/upgrading/7.0/' + 5.x to 6.x: '/upgrading/6.0/' diff --git a/docs/_data/project.yml b/docs/_data/project.yml new file mode 100644 index 00000000..b9b083ad --- /dev/null +++ b/docs/_data/project.yml @@ -0,0 +1,5 @@ +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 +default_version: "8.0" \ No newline at end of file diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100644 index 00000000..61aed21e --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,127 @@ + + + + + + + {% assign version = page.url | remove_first: "/" | split: "/"" | first %} + {% assign upgrading_pages = version %} + + {% if version != '8.0' %} + {% if version != '7.0' %} + {% assign version = site.data.project.default_version %} + {% endif %} + {% endif %} + + {% capture version_home %}/{{ version }}/{% endcapture %} + + {% if page.url == '/' or page.url == version_home %} + {{ site.data.project.title }} - {{ site.data.project.tagline }} + {% else %} + {{ page.title }} - {{ site.data.project.title }} + {% endif %} + + {% if site.github.url %} + + {% else %} + + {% endif %} + + {% if site.data.project.description %} + + {% endif %} + + {% if site.data.images.favicon %} + + {% else %} + + {% endif %} + + {% if site.data.images.apple_touch %} + + {% else %} + + {% endif %} + + + + + +
+ + The League of Extraordinary Packages + +

Our Packages:

+ +
+ +
+ + + Presented by The League of Extraordinary Packages + +
+ + + + +
+ + + + {% for section in site.data.menu[version] %} +

{{ section[0] }}

+ + {% endfor %} +
+
+ {{ content }} +
+
+ + + + + + + +{% if site.data.project.google_analytics_tracking_id %} + +{% endif %} + + + \ No newline at end of file diff --git a/docs/basic-usage.md b/docs/basic-usage.md new file mode 100644 index 00000000..12b4c150 --- /dev/null +++ b/docs/basic-usage.md @@ -0,0 +1,113 @@ +--- +layout: default +title: Basic Usage +--- + +# Basic usage + +

Tips: Even though you can use the following methods with the League\Csv\Writer object. It is recommended to do so with the League\Csv\Reader class to avoid losing the file cursor position and getting unexpected results when inserting new data.

+ +Once your CSV object is [instantiated](/instantiation) and [configured](/properties/), you can start interacting with the data using a number of methods available to you. + + +## Iterating over the CSV rows + +The CSV object implements PHP's `IteratorAggregate` interface + +~~~php + $row) { + //do something meaningful here with $row !! + //$row is an array where each item represent a CSV data cell + //$index is the CSV row index +} +~~~ + +

You can do more complex iterations using the query methods available on the League\Csv\Reader class only.

+ +## Outputting the CSV + +### __toString + +Returns the string representation of the CSV document + +~~~php +__toString(); +~~~ + +### output + +If you only wish to make your CSV downloadable by forcing a file download just use the `output` method to force the use of the output buffer on the CSV content. + +~~~php +output(); +~~~ + +#### Example 2 - using the $filename argument + +~~~php +output("name-for-your-file.csv"); +~~~ + +#### Notes + +The output methods **can only be affected by:** + +- the [library stream filtering mechanism](/filtering/) +- the [BOM property](/bom/) + +No other method or property have effect on them. diff --git a/docs/bom.md b/docs/bom.md new file mode 100644 index 00000000..36859877 --- /dev/null +++ b/docs/bom.md @@ -0,0 +1,157 @@ +--- +layout: default +title: CSV and BOM character +--- + +# Managing the BOM character + +## Detecting the CSV BOM character + +To improve interoperability with programs interacting with CSV, you can now manage the presence of a BOM character in your CSV content. The character signals the endianness of the CSV and its value depends on the CSV encoding character. To help you work with `BOM`, we are adding the following constants to the `Reader` and the `Writer` class: + +* `BOM_UTF8` : `UTF-8` `BOM`; +* `BOM_UTF16_BE` : `UTF-16` `BOM` with Big-Endian; +* `BOM_UTF16_LE` : `UTF-16` `BOM` with Little-Endian; +* `BOM_UTF32_BE` : `UTF-32` `BOM` with Big-Endian; +* `BOM_UTF32_LE` : `UTF-32` `BOM` with Little-Endian; + +They each represent the `BOM` character for each encoding character. + +### AbstractCsv::getInputBOM + +This method will detect and return the `BOM` character used in your CSV if any. + +~~~php +getInputBOM(); //$res equals '' if no BOM is found + +$reader = new Reader::createFromPath('path/to/your/msexcel.csv'); +if (Reader::BOM_UTF16_LE == $reader->getInputBOM()) { + //the CSV file is encoded using UTF-16 LE +} +~~~ + +If you wish to remove the BOM character while processing your data, you can rely on the [query filters](/query-filtering/#stripbomstatus) to do so. + +## Adding the BOM character to your CSV + +### AbstractCsv::setOutputBOM; + +This method will manage the addition of a BOM character in front of your outputted CSV when you are: + +- downloading a file using the `output` method +- ouputting the CSV directly using the `__toString()` method + +~~~php +To ease writing the sequence you should use the BOM_* constants.

+ +### AbstractCsv::getOutputBOM + +This method will tell you at any given time what `BOM` character will be prepended to the CSV content. + +~~~php +BC Break: by default getOutputBOM returns an empty string.

+ +~~~php +getOutputBOM(); //$res equals null; +$reader->setOutputBOM(Reader::BOM_UTF16_LE); +$res = $reader->getOutputBOM(); //$res equals "\xFF\xFE"; +echo $reader; //the BOM sequence is prepended to the CSV + +~~~ + +## Software dependency + +Depending on your operating system and on the software you are using to read/import your CSV you may need to adjust the encoding character and add its corresponding BOM character to your CSV. + +

Out of the box, League\Csv assumes that your are using a UTF-8 encoded CSV without any BOM character.

+ +In the examples below we will be using an existing CSV as a starting point. The code may vary if you are creating the CSV from scratch. + +### MS Excel on Windows + +On Windows, MS Excel, expects an UTF-8 encoded CSV with its corresponding `BOM` character. To fullfill this requirement, you simply need to add the `UTF-8` `BOM` character if needed as explained below: + +~~~php +setOutputBOM(Reader::BOM_UTF8); +//BOM detected and adjusted for the output +echo $reader->__toString(); + +~~~ + +### MS Excel on MacOS + +On a MacOS system, MS Excel requires a CSV encoded in `UTF-16 LE` using the `tab` character as delimiter. Here's an example on how to meet those requirements using the `League\Csv` package. + +~~~php +setDelimiter("\t"); + +//we insert csv data +$writer->insertAll($origin); + +//let's switch to the Reader object +//Writer::output will failed because of the open mode +$csv = $writer->newReader(); + +//we register a Stream Filter class to convert the CSV into the UTF-16 LE +stream_filter_register(FilterTranscode::FILTER_NAME."*", "\lib\FilterTranscode"); +$csv->appendStreamFilter(FilterTranscode::FILTER_NAME."UTF-8:UTF-16LE"); + +//we detect and adjust the output BOM to be used +$csv->setOutputBOM(Reader::BOM_UTF16_LE); +//all is good let's output the results +$csv->output('mycsvfile.csv'); + +~~~ + +Of note, we used the [filtering capability](/filtering) of the library to convert the CSV encoding character from `UTF-8` to `UTF-16 LE`. + +You can found the code and the associated filter class in the [examples directory](https://github.com/thephpleague/csv/tree/master/examples). \ No newline at end of file diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 00000000..409b50af --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,13 @@ +--- +layout: default +title: Changelog +--- + +# Changelog + +All Notable changes to `Csv` will be documented in this file + +{% for release in site.github.releases %} +## {{ release.name }} +{{ release.body | replace:'```':'~~~' | markdownify }} +{% endfor %} \ No newline at end of file diff --git a/docs/converting.md b/docs/converting.md new file mode 100644 index 00000000..3355fccf --- /dev/null +++ b/docs/converting.md @@ -0,0 +1,89 @@ +--- +layout: default +title: Converting your CSV +--- + +# Converting the CSV + +The `League\Csv` object can convert your CSV document into JSON, XML and HTML formats. In order to do so, the conversion methods assume that your CSV is UTF-8 encoded. To properly transcode your document into an UTF-8 compatible charset, it's recommended to use the library stream filtering mechanism. + +When this is not possible/applicable you can fallback to using the `setEncodingFrom` and `getEncodingFrom` methods. + +If your CSV is not UTF-8 encoded some unexpected results and some errors may be thrown when trying to convert your data. + +## Convert to JSON format + +`AbstractCsv` implements the `JsonSerializable` interface. As such you can use the `json_encode` function directly on the instantiated object. + +~~~php +toXML('data', 'line', 'item'); +~~~ + +## Convert to HTML table + +Use the `toHTML` method to convert the CSV data into an HTML table. + +~~~php +toHTML('table table-bordered table-hover'); +~~~ + +## Example using data transcode before conversion + +~~~php +setEncodingFrom('iso-8859-15'); +echo json_encode($reader); +//the CSV is transcoded from iso-8859-15 to UTF-8 +//before being converted to JSON format; +echo $reader; //outputting the data is not affected by the conversion +~~~ diff --git a/docs/custom.css b/docs/custom.css new file mode 100644 index 00000000..b4b565f5 --- /dev/null +++ b/docs/custom.css @@ -0,0 +1,29 @@ +menu .versions { + margin: 15px 0 0 50px; +} + +@media screen and (max-width: 549px) { + menu { + text-align: center; + } + menu .versions { + margin: 15px 0 0 0; + display: inline-block; + } +} + +@media screen and (min-width: 550px) and (max-width: 849px) { + menu .versions { + margin: 15px 0 0 30px; + } +} + +blockquote { + border-left: 4px solid #ccc; + font-style:italic; +} + +blockquote { + box-sizing: border-box; + padding:0 10px; +} \ No newline at end of file diff --git a/docs/custom.js b/docs/custom.js new file mode 100644 index 00000000..c1b5ea1e --- /dev/null +++ b/docs/custom.js @@ -0,0 +1,5 @@ +$(function() { + $('.versions').change(function (e) { + location.href = $(this).find('option:selected').data('url'); + }); +}); \ No newline at end of file diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 00000000..810677f4 --- /dev/null +++ b/docs/examples.md @@ -0,0 +1,125 @@ +--- +layout: default +title: Examples +--- + +# Examples + +## Parsing a document + +A simple example to show you how to parse a CSV document. + +~~~php +fetchOne(); + +//get 25 rows starting from the 11th row +$res = $csv->setOffset(10)->setLimit(25)->fetchAll(); +~~~ + +## Exporting a database table as a CSV document + +A simple example to show you how to create and download a CSV from a `PDOStatement` object + +~~~php +prepare( + "SELECT firstname, lastname, email FROM users LIMIT 200" +); +//because we don't want to duplicate the data for each row +// PDO::FETCH_NUM could also have been used +$sth->setFetchMode(PDO::FETCH_ASSOC); +$sth->execute(); + +//we create the CSV into memory +$csv = Writer::createFromFileObject(new SplTempFileObject()); + +//we insert the CSV header +$csv->insertOne(['firstname', 'lastname', 'email']); + +// The PDOStatement Object implements the Traversable Interface +// that's why Writer::insertAll can directly insert +// the data into the CSV +$csv->insertAll($sth); + +// Because you are providing the filename you don't have to +// set the HTTP headers Writer::output can +// directly set them for you +// The file is downloadable +$csv->output('users.csv'); +die; +~~~ + +## Importing a CSV into a database table + +A simple example to show you how to import some CSV data into a database using a `PDOStatement` object + +~~~php +prepare( + "INSERT INTO users (firstname, lastname, email) VALUES (:firstname, :lastname, :email)" +); + +$csv = Reader::createFromPath('/path/to/your/csv/file.csv'); +$csv->setOffset(1); //because we don't want to insert the header +$nbInsert = $csv->each(function ($row) use (&$sth) { + //Do not forget to validate your data before inserting it in your database + $sth->bindValue(':firstname', $row[0], PDO::PARAM_STR); + $sth->bindValue(':lastname', $row[1], PDO::PARAM_STR); + $sth->bindValue(':email', $row[2], PDO::PARAM_STR); + + return $sth->execute(); //if the function return false then the iteration will stop +}); +~~~ + +## Converting a UTF-16 CSV file contents to UTF-8 + +When importing csv files, you don't know whether the file is encoded with `UTF-8`, `UTF-16` or anything else. +The below example tries to determine the encoding and convert to `UTF-8` using the iconv extension. + +~~~php +getInputBOM(); + +if ($input_bom === Reader::BOM_UTF16_LE || $input_bom === Reader::BOM_UTF16_BE) { + $reader->appendStreamFilter('convert.iconv.UTF-16/UTF-8'); +} + +foreach ($reader->fetchAssoc(0) as $row) { + echo json_encode($row, JSON_PRETTY_PRINT), PHP_EOL; +} +~~~ + +## More Examples + +* [Selecting specific rows in the CSV](https://github.com/thephpleague/csv/blob/master/examples/extract.php) +* [Querying a CSV](https://github.com/thephpleague/csv/blob/master/examples/filtering.php) +* [Creating a CSV](https://github.com/thephpleague/csv/blob/master/examples/writing.php) +* [Merging 2 CSV documents](https://github.com/thephpleague/csv/blob/master/examples/merge.php) +* [Switching between modes from Writer to Reader mode](https://github.com/thephpleague/csv/blob/master/examples/switchmode.php) +* [Downloading the CSV](https://github.com/thephpleague/csv/blob/master/examples/download.php) +* [Converting the CSV into a Json String](https://github.com/thephpleague/csv/blob/master/examples/json.php) +* [Converting the CSV into a XML file](https://github.com/thephpleague/csv/blob/master/examples/xml.php) +* [Converting the CSV into a HTML Table](https://github.com/thephpleague/csv/blob/master/examples/table.php) +* [Using stream Filter on the CSV](https://github.com/thephpleague/csv/blob/master/examples/stream.php) + +> The CSV data use for the examples are taken from [Paris Opendata](http://opendata.paris.fr/opendata/jsp/site/Portal.jsp?document_id=60&portlet_id=121) diff --git a/docs/filtering.md b/docs/filtering.md new file mode 100644 index 00000000..35002c32 --- /dev/null +++ b/docs/filtering.md @@ -0,0 +1,188 @@ +--- +layout: default +title: Stream Filtering +--- + +# Stream Filtering + +To ease performing operations on the CSV as it is being read from or written to, the `Reader` and `Writer` classes now include methods to ease PHP stream filtering usage. + +## Stream Filter API + +While in PHP the stream filter mode is attached to its associated filter, in `League\Csv` the filter mode is attached to the CSV object. This means that when you change the filter mode, you also clear all previously attached stream filters. + +To be able to use the stream filtering mechanism you need to: + +* validate that the stream filter API is active; +* set the class filtering mode; +* attached your stream filters to the CSV object; + +### Detecting if the API is active + +To be sure that the Stream Filter API is available it is recommend to use the method `isActiveStreamFilter`. + +~~~php +isActiveStreamFilter(); //return true + +$writer = Writer::createFromFileObject(new SplTempFileObject()); +$writer->isActiveStreamFilter(); //return false the API can not be use +~~~ + +

Warning: A LogicException exception may be thrown if you try to use the API under certain circumstances without prior validation using isActiveStreamFilter

+ +### Setting and getting the object stream filter mode + +The stream filter mode property is set using PHP internal stream filter constant `STREAM_FILTER_*`. + +~~~php +isActiveStreamFilter()) { + $current_mode = $reader->getStreamFilterMode(); //returns STREAM_FILTER_READ + $reader->setStreamFilterMode(STREAM_FILTER_WRITE); + //this means that any filter you will set will have no effect when reading the CSV + //all previously attached stream filters if they existed have been removed + $current_mode = $reader->getStreamFilterMode(); //returns STREAM_FILTER_WRITE +} +~~~ + +### Managing Stream filter + +To manage your registered stream filter collection you can use the following methods: + +~~~php +isActiveStreamFilter()) { + $reader->appendStreamFilter('string.toupper'); + $reader->appendStreamFilter('string.rot13'); + $reader->prependStreamFilter('convert.utf8decode'); + $reader->removeStreamFilter('string.rot13'); +} +foreach ($reader as $row) { + // each row cell now contains strings that have been: + // first UTF8 decoded and then uppercased +} +~~~ + +

Starting with version 8.1.0 you no longer need to URL encode your filter prior to attach it to the CSV object.

+ +~~~php +appendStreamFilter('convert.iconv.UTF-8/ASCII//TRANSLIT'); +var_dump($reader->fetchAll()); +~~~ + +## Limitations + +### Writer class on Editing Mode + +

Warning: To preserve file cursor position during editing the stream filter mode and the stream filter collection are frozen after the first insert is made using any of the insert* method. Any attempt to modify the stream filter status will fail silently.

+ +~~~php +setDelimiter(','); +if ($writer->isActiveStreamFilter()) { + $writer->addStreamFilter('string.toupper'); +} +//first insert -> file.csv will contain uppercased data. +$writer->insertOne(['bill', 'gates', 'bill@microsoft.com']); +if ($writer->isActiveStreamFilter()) { + //isActiveStreamFilter returns false so this code is never executed + $writer->addStreamFilter('string.rot13'); +} +//this filter is added to the collection but will never be applied!! +$writer->addStreamFilter('string.rot13'); +//The inserted array will only be uppercased!! +$writer->insertOne('steve,job,job@apple.com'); + +echo $writer; //the newly added rows are all uppercased +~~~ + +## Example + +Please review the stream filtering example and the attached FilterTranscode Class to understand how to use the filtering mechanism to convert a CSV into another charset. + +The `FilterTranscode` class is not attached to the Library because converting your CSV may depend on the extension you choose, in PHP you can use the following extensions : + + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..28696b80 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,43 @@ +--- +layout: default +--- + +# Introduction + +[![Author](http://img.shields.io/badge/author-@nyamsprod-blue.svg?style=flat-square)](https://twitter.com/nyamsprod) +[![Source Code](http://img.shields.io/badge/source-league/csv-blue.svg?style=flat-square)](https://github.com/thephpleague/csv) +[![Latest Version](https://img.shields.io/github/release/thephpleague/csv.svg?style=flat-square)](https://github.com/thephpleague/csv/releases) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md)
+[![Build Status](https://img.shields.io/travis/thephpleague/csv/master.svg?style=flat-square)](https://travis-ci.org/thephpleague/csv) +[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/csv.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/csv/code-structure) +[![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/csv.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/csv) +[![Total Downloads](https://img.shields.io/packagist/dt/league/csv.svg?style=flat-square)](https://packagist.org/packages/league/csv) + +`Csv` is a simple library to ease CSV parsing, writing and filtering in +PHP. The goal of the library is to be powerful while remaining lightweight, +by utilizing PHP native classes whenever possible. + +`Csv` was designed for developers who want to deal with CSV data using +modern code and without the high levels of bootstrap and low-levels of +usefulness provided by existing core functions or third party-code. + +[CSV on Packagist](https://packagist.org/packages/league/csv) + +## Highlights + +* Simple API +* Read and Write to CSV documents in a memory efficient and scalable way +* Use SPL to interact with the CSV documents +* Support PHP Stream filtering capabilities +* Transform CSV documents into popular formats (JSON, XML or HTML) +* Fully documented +* Fully Unit tested +* Framework-agnostic +* Composer ready, [PSR-2] and [PSR-4] compliant + +## Questions? + +`Csv` was created by Ignace Nyamagana Butera. Find him on Twitter at [@nyamsprod](https://twitter.com/nyamsprod). + +[PSR-2]: http://www.php-fig.org/psr/psr-2/ +[PSR-4]: http://www.php-fig.org/psr/psr-4/ diff --git a/docs/inserting.md b/docs/inserting.md new file mode 100644 index 00000000..76c85630 --- /dev/null +++ b/docs/inserting.md @@ -0,0 +1,250 @@ +--- +layout: default +title: Inserting new data into a CSV +--- + +# Inserting Data + +To create or update a CSV use the following `League\Csv\Writer` methods. + +

When creating a file using the library, first insert all the data that need to be inserted before starting manipulating the CSV. If you manipulate your data before insertion, you may change the file cursor position and get unexpected results.

+ +## Adding new data + +The `Writer` class performs a number of actions while inserting your data into the CSV. When submitting data for insertion the class will proceed as describe below for each row. + +The `Writer` class will: + +- See if the row is an `array`, if not it will try to convert it into a proper `array`; +- If supplied, formatters will further format the given `array`; +- If supplied, validators will validate the formatted `array` according to their rules; +- While writing the data to your CSV document, if supplied, stream filters will apply further formatting to the inserted row; +- If needed the newline sequence will be updated; + +To add new data to your CSV the `Writer` class uses the following methods + +### Writer::insertOne + +`insertOne` inserts a single row. + +~~~php +str = $str; + } + + public function __toString() + { + return $this->str; + } +} + +$writer = Writer::createFromFileObject(new SplTempFileObject()); +$writer->insertOne(['john', 'doe', 'john.doe@example.com']); +$writer->insertOne("'john','doe','john.doe@example.com'"); +$writer->insertOne(new ToStringEnabledClass("john,doe,john.doe@example.com")) +~~~ + +### Writer::insertAll + +`insertAll` inserts multiple rows. + +~~~php +insertAll($rows); //using an array +$writer->insertAll(new ArrayIterator($rows)); //using a Traversable object +~~~ + +## Row formatting + +### CSV Formatter + +A formatter is a `callable` which accepts an `array` on input and returns the same array formatted according to its inner rules. + +~~~php +addFormatter($formatter); +$writer->insertOne(['john', 'doe', 'john.doe@example.com']); + +$writer->__toString(); +//will display something like JOHN,DOE,JOHN.DOE@EXAMPLE.COM +~~~ + +## Row validation + +### CSV validator + +A validator is a `callable` which takes a `array` as its sole argument and returns a boolean. + +~~~php +addValidator(function (array $row) { + return 10 == count($row); +}, 'row_must_contain_10_cells'); +try { + $writer->insertOne(['john', 'doe', 'john.doe@example.com']); +} catch (InvalidRowException $e) { + echo $e->getName(); //display 'row_must_contain_10_cells' + $e->getData();//will return the invalid data ['john', 'doe', 'john.doe@example.com'] +} +~~~ + +## Stream filtering + +Some data formatting can still occur while writing the data to the CSV document after validation using the [Stream Filters capabilities](/fitering/). + +## Handling newline + +Because the php `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 CSV newly inserted line. + +At any given time you can get and modify the `$newline` property using the `getNewline` and `setNewline` methods described in CSV properties documentation page. + +~~~php +getNewline(); // equals "\n"; +$writer->setNewline("\r\n"); +$newline = $writer->getNewline(); // equals "\r\n"; +$writer->insertOne(["one", "two"]); +echo $writer; // displays "one,two\r\n"; +~~~ + +

Please refer to the BOM character dedicated documentation page for more informations on how the library manage the BOM character.

+ diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 00000000..4579a705 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,22 @@ +--- +layout: default +title: Installation +--- + +# Installation + +## System Requirements + +You need **PHP >= 5.5.0** and the `mbstring` extension to use `Csv` but the latest stable version of PHP is recommended. + +## Composer + +`Csv` is available on [Packagist](https://packagist.org/packages/league/csv) and can be installed using [Composer](https://getcomposer.org/): + +~~~ +$ composer require league/csv:^8.0 +~~~ + +## Going Solo + +You can also use `Csv` without using Composer by downloading the library and using any other [PSR-4](http://www.php-fig.org/psr/psr-4/) compatible autoloader. diff --git a/docs/instantiation.md b/docs/instantiation.md new file mode 100644 index 00000000..b26e7a28 --- /dev/null +++ b/docs/instantiation.md @@ -0,0 +1,166 @@ +--- +layout: default +title: Instantiation using named constructors +--- + +# Instantiation + +The library is composed of two main classes: + +* `League\Csv\Reader` to read data from a CSV +* `League\Csv\Writer` to write new data into a CSV + +Both classes extend the `League\Csv\AbstractCsv` class and as such share methods for instantiation. + +## Csv and Macintosh + +If your CSV document was created or is read on a Macintosh computer, add the following lines before using the library to help [PHP detect line ending in Mac OS X](http://php.net/manual/en/function.fgetcsv.php#refsect1-function.fgetcsv-returnvalues). + +~~~php +Warning: The method throws an InvalidArgumentException if a SplTempFileObject is given as no path can be retrieve from such object.

+* The `$open_mode` parameter which defaults to `r+` if none is supplied. + +The resulting string and `$open_mode` parameters are used to lazy load internally a `SplFileObject` object. + +~~~php +New since version 8.2.0

+ + +This named constructor will create a new object from a stream resource. + +~~~php +MUST be seekable otherwise a `InvalidArgumentException` will be thrown. + +~~~php +newReader('r+'); +$newWriter = $reader->newWriter('a'); +$anotherWriter = $newWriter->newWriter('r+'); +~~~ + +

Warning: be careful the $newWriter and $anotherWriter object are not the same as the $writer object!

\ No newline at end of file diff --git a/docs/properties.md b/docs/properties.md new file mode 100644 index 00000000..9f613afb --- /dev/null +++ b/docs/properties.md @@ -0,0 +1,308 @@ +--- +layout: default +title: Setting and Accessing CSV settings +--- + +# CSV properties + +Once your object is [instantiated](/instantiation/) you can optionally set several CSV properties. The following methods works on both the `Reader` and the `Writer` class. + +

Since version 8.1.1 The underlying CSV controls from the submitted CSV are inherited by the return AbstractCsv object.

+ + +~~~php +setFlags(SplFileObject::READ_CSV); +$file->setCsvControl('|'); + +$csv = Reader::createFromFileObject($file); + +echo $csv->getDelimiter(); //display '|' +~~~ + +

Of note, The escape character is only inherited starting with PHP 5.6.25 in the PHP5 line and 7.0.10 in the PHP7 version.

+ + +## Accessing and Setting CSV properties + +### The CSV delimiter character. + +#### Description + +~~~php +setDelimiter(';'); +$delimiter = $csv->getDelimiter(); //returns ";" +~~~ + +#### Notes + +The default delimiter character is `,`. + +### The enclosure character + +#### Description + +~~~php +setEnclosure('|'); +$enclosure = $csv->getEnclosure(); //returns "|" +~~~ + +#### Notes + +The default enclosure character is `"`. + +### The escape character + +

Warning: The library depends on PHP SplFileObject class. Since this class exhibits a reported bug, Data using the escape character are correctly escaped but the escape character is not removed from the CSV content.
+A possible workaround to this issue while waiting for a PHP bug fix is to register a callable to your extracting method when possible.

+ + +#### Description + +~~~php +setEscape('\\'); +$escape = $csv->getEscape(); //returns "\" +~~~ + +#### Notes + +The default escape character is `\`. + +### fetchDelimitersOccurrence + +This method allow you to find the occurences of some delimiters in a given CSV object. + +~~~php +setEnclosure('"'); +$reader->setEscape('\\'); + +$delimiters_list = $reader->fetchDelimitersOccurrence([' ', '|'], 10); +// $delimiters_list can be the following +// [ +// '|' => 20, +// ' ' => 0, +// ] +// This seems to be a consistent CSV with: +// - the delimiter "|" appearing 20 times in the 10 first rows +// - the delimiter " " never appearing +~~~ + +

Warning: This method only test the delimiters you gave it.

+ +## Writing mode only properties + +The following properties only affect the CSV object when you are writing and/or saving data to it. + +

The Reader class still have access to them.

+ + +### The newline sequence + +To improve interoperability with programs interacting with CSV, the newline sequence is appended to each CSV newly inserted line. + +#### Description + +~~~php +setNewline("\r\n"); +$newline = $csv->getNewline(); //returns "\r\n" +~~~ + +#### Notes + +The default newline sequence is `\n`; + +### The BOM sequence + +To improve interoperability with programs interacting with CSV, you can manage the presence of the BOM sequence in your CSV content. + +#### Detect the currently used BOM sequence + +

BC Break: getInputBOM always return a string

+ +~~~php +getInputBOM(); +~~~ + +#### Set the outputting BOM sequence + +~~~php +BC Break: getOutputBOM always return a string

+ +~~~php +setOutputBOM(Reader::BOM_UTF8); +$bom = $csv->getOutputBOM(); //returns "\xEF\xBB\xBF" +~~~ + +#### Notes + +- The default output `BOM` character is set to an empty string. +- The `AbstractCsv` class provide constants to ease BOM sequence manipulation. + +

Please refer to the BOM character dedicated documentation page for more informations on how the library helps you manage this feature.

+ +## Conversion only properties + +

The following properties and method only works when converting your CSV document into other available formats.

+ +To convert your CSV document into another format it must be encoded in `UTF-8`. + +When this is not the case, you should transcode it first using the library stream filtering mechanism. When this is not applicable you should provide the CSV original encoding charset to the CSV object using the following methods. + +### methods + +

These methods are introduced in version 8.1.0

+ +~~~php +The following methods are deprecated since version 8.1.0 and will be remove in the next major release

+ +~~~php +setInputEncoding('iso-8859-15'); +echo $csv->getInputEncoding(); //returns iso-8859-15; +~~~ + +#### Notes + +By default `getInputEncoding` returns `UTF-8` if `setInputEncoding` was not used. + +
The encoding properties have no effect when reading or writing to a CSV document. You should instead use the Stream Filter API or the Writing Formatter API.
+ +~~~php +setInputEncoding('iso-8859-15'); +echo json_encode($reader); +//the CSV is transcoded from iso-8859-15 to UTF-8 +//before being converted to JSON format; +echo $reader; //outputting the data is not affected by the conversion +~~~ diff --git a/docs/query-filtering.md b/docs/query-filtering.md new file mode 100644 index 00000000..b1968ef7 --- /dev/null +++ b/docs/query-filtering.md @@ -0,0 +1,184 @@ +--- +layout: default +title: Query Filtering +--- + +# Query Filtering + +## Query Filters + +You can restrict [extract methods](/reading/) and [conversion methods](/converting/) output by setting query options. To set those options you will need to use the methods described below. But keep in mind that: + +* The query options methods are all chainable *except when they have to return a boolean*; +* The query options methods can be called in any sort of order before any extract/conversion method; +* After an extract/conversion method call, all query options are cleared; + +## Modifying content methods + +### AbstractCsv::stripBOM + + This method specifies if the [BOM sequence](/bom/) must be removed or not from the CSV's first cell of the first row. + +~~~php +The BOM sequence is never removed from the CSV document, it is only stripped from the resultset.

+ +## Filtering methods + +The filtering options **are the first settings applied to the CSV before anything else**. The filters follow the *First In First Out* rule. + +### AbstractCsv::addFilter + +The `addFilter` method adds a callable filter function each time it is called. + +~~~php +To sort the data iterator_to_array is used, which could lead to a performance penalty if you have a heavy CSV file to sort +

+ +### AbstractCsv::addSortBy + +`addSortBy` method adds a sorting function each time it is called. + +~~~php +Both methods have no effect on the fetchOne method output.

+ +## Examples + +### Modifying extract methods output + +Here's an example on how to use the query features of the `Reader` class to restrict the `fetchAssoc` result: + +~~~php +stripBom(false) + ->setOffset(3) + ->setLimit(2) + ->addFilter('filterByEmail') + ->addSortBy('sortByLastName') + ->fetchAssoc(['firstname', 'lastname', 'email'], function ($value) { + return array_map('strtoupper', $value); +}); +// data length will be equals or lesser that 2 starting from the row index 3. +// will return something like this : +// +// [ +// ['firstname' => 'JANE', 'lastname' => 'RAMANOV', 'email' => 'JANE.RAMANOV@EXAMPLE.COM'], +// ['firstname' => 'JOHN', 'lastname' => 'DOE', 'email' => 'JOHN.DOE@EXAMPLE.COM'], +// ] +// +~~~ + +### Modifying conversion methods output + +The query options can also modify the output from the conversion methods as shown below with the `toHTML` method. + +~~~php +stripBom(true) + ->setOffset(3) + ->setLimit(2) + ->addFilter('filterByEmail') + ->addSortBy('sortByLastName') + ->toHTML("simple-table"); +// $data contains the HTML table code equivalent to: +// +// +// +// +//
JANERAMANOVJANE.RAMANOV@EXAMPLE.COM
JOHNDOEJOHN.DOE@EXAMPLE.COM
+// +~~~ diff --git a/docs/reading.md b/docs/reading.md new file mode 100644 index 00000000..b747dadc --- /dev/null +++ b/docs/reading.md @@ -0,0 +1,446 @@ +--- +layout: default +title: Extracting data from a CSV +--- + +# Extracting data + +To extract data from a CSV document use `League\Csv\Reader` methods. + +## Reader::fetch + +The `fetch` method fetches the next row from the `Iterator` result set. + +~~~php +fetch(); +foreach ($results as $row) { + //do something here +} +~~~ + +### Example 2 - with a callable + +~~~php +fetch($func); +foreach ($results as $row) { + //each row member will be uppercased +} +~~~ + +## Reader::fetchAll + +`fetchAll` returns a sequential `array` of all rows. + +~~~php +fetchOne(3); ///accessing the 4th row (indexing starts at 0) +// will return something like this : +// +// ['john', 'doe', 'john.doe@example.com'] +// +~~~ + +## Reader::each + +`each` applies a callable function on each CSV row. + +~~~php +each(function ($row) { + return true; +}); +~~~ + +## Reader::fetchAssoc + +

BC Break: Starting with version 8.0.0 This method returns an Iterator.

+ +`fetchAssoc` returns an `Iterator` of all rows. The rows themselves are associative arrays where the keys are a one dimension array. This array must only contain unique `string` and/or `scalar` values. + +~~~php +fetchAssoc($keys); +// $results is an iterator +foreach ($results as $row) { +// each row will have the following data +// [ +// 'firstname' => 'john', +// 'lastname' => 'doe', +// 'email' => 'john.doe@example.com', +// ]; +// +} +~~~ + +### Example 2 - Using a CSV offset + +~~~php +fetchAssoc($offset); +// $results is an iterator +foreach ($results as $row) { +// each row will have the following data +// [ +// 'john' => 'jane', +// 'doe' => 'doe', +// 'john.doe@example.com' => 'jane.doe@example.com', +// ]; +// +} +~~~ + +### Notes + +- If the number of values in a CSV row is lesser than the number of named keys, the method will add `null` values to compensate for the missing values. +- If the number of values in a CSV row is greater that the number of named keys the exceeding values will be drop from the result set. +- If an offset is used, its content will be skipped in the result set. +- If no argument is provided, the first row from the CSV data will be used + +### The optional callable argument + +

BC Break: The callable expects a row with the indexes already applied to it.

+ +The method takes an optional callable which signature is as follow: + +~~~php +function(array $row [, int $rowOffset [, Iterator $iterator]]): array +~~~ + +- `$row`: the CSV current row combined with the submitted indexes **(new in version 8.0.0)** +- `$rowOffset`: the CSV current row offset +- `$iterator`: the current CSV iterator + +### Example 3 - Using a callable + +~~~php +fetchAssoc($keys, $func) as $row) { + $row['date']->format('Y-m-d H:i:s'); + //because this cell contain a `DateTimeInterface` object +} +~~~ + +## Reader::fetchColumn + +

BC Break: Starting with version 8.0.0 This method returns a Iterator.

+ +`fetchColumn` returns a `Iterator` of all values in a given column from the CSV data. + +~~~php +fetchColumn(2); +$data = iterator_to_array($result, false); +// will return something like this : +// +// ['john.doe@example.com', 'jane.doe@example.com', ...] +// +~~~ + +### The optional callable argument + +

BC Break: The callable expects the column value as its first parameter

+ +The method takes an optional callable which signature is as follow: + +~~~php +fetchColumn(2, 'strtoupper') as $value) { + echo $value; //display 'JOHN.DOE@EXAMPLE.COM' +} +~~~ + +## Reader::fetchPairs + +

new feature introduced in version 8.0

+ +The `fetchPairs` method returns a `Generator` of key-value pairs. + +~~~php +fetchPairs() as $firstname => $lastname) { + // - first iteration + // echo $firstname; -> 'john' + // echo $lastname; -> 'doe' + // - second iteration + // echo $firstname; -> 'jane' + // echo $lastname; -> 'doe' + // - third iteration + // echo $firstname; -> 'foo' + // echo $lastname; -> 'bar' +} +~~~ + +### Notes + +- If no `$offsetIndex` is provided it default to `0`; +- If no `$valueIndex` is provided it default to `1`; +- 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; + +### The optional callable argument + +The method takes an optional callable which signature is as follow: + +~~~php +fetchPairs(1, 0, $func) as $lastname => $firstname) { + // - first iteration + // echo $lastname; -> 'DOE' + // echo $firstname; -> 'john' + // - second iteration + // echo $lastname; -> 'DOE' + // echo $firstname; -> 'jane' + // - third iteration + // echo $lastname; -> 'BAR' + // echo $firstname; -> 'foo' +} +~~~ + +## Reader::fetchPairsWithoutDuplicates + +

new feature introduced in version 8.0

+ +The `fetchPairsWithoutDuplicates` method returns data in an `array` of key-value pairs, as an associative array with a single entry per row. + +~~~php +fetchPairsWithoutDuplicates(1, 0); +// will return ['doe' => 'jane', 'foo' => 'bar']; +// the 'john' value has been overwritten by 'jane' +~~~ diff --git a/docs/upgrading/index.md b/docs/upgrading/index.md new file mode 100644 index 00000000..000ed85d --- /dev/null +++ b/docs/upgrading/index.md @@ -0,0 +1,10 @@ +--- +layout: default +title: Upgrading +permalink: upgrading/ +--- + +# Upgrading + +Welcome to the upgrade guide for `Csv`. We've tried to cover all backward compatible breaks from 5.0 through to the current MAJOR stable release. If we've missed anything, feel free to create an issue, or send a pull request. You can also refer to the information found in the [CHANGELOG.md](https://github.com/thephpleague/csv/blob/master/CHANGELOG.md) file attached to the library. + diff --git a/docs/upgrading/upgrading-6.0.md b/docs/upgrading/upgrading-6.0.md new file mode 100644 index 00000000..2ee3f121 --- /dev/null +++ b/docs/upgrading/upgrading-6.0.md @@ -0,0 +1,163 @@ +--- +layout: default +title: Upgrading from 5.x to 6.x +permalink: upgrading/6.0/ +--- + +# Upgrading from 5.x to 6.x + +## Installation + +If you are using composer then you should update the require section of your `composer.json` file. + +~~~ +composer require league/csv:~6.0 +~~~ + +This will edit (or create) your `composer.json` file. + +## New Features + +### Stream Filter API + +The Stream Filter API is introduced. Please [refer to the documentation](/filtering/) for more information + +## Added Methods + +### Named Constructors + +The new preferred way to instantiate a CSV object is to use the [named constructors](/overview/#instantiation): + +Two new named constructors are added to complement the already present `createFromString` method. + +* `createFromPath`; +* `createFromFileObject`; + +You can still use the class constructor for backward compatibility. + +## Backward Incompatible Changes + +### Detecting CSV Delimiters + +The `detectDelimiter` method is removed and replaced by the `detectDelimiterList` method. + +The difference between both methods is that the latter always return an `array` as the former was throwing `RuntimeException` when multiple delimiters where found (*ie.*: the CSV was inconsistent) + +Old code: + +~~~php +detectDelimiter(10, [' ', '|']); + if (is_null($delimiter)) { + //no delimiter found + } +} catch(RuntimeException $e) { + //inconsistent CSV the found delimiters were given in $e->getMessage(); +} + +~~~ + +New code: + +~~~php +detectDelimiterList(10, [' ', '|']); +if (! $delimiters_list) { + //no delimiter found +} elseif (1 == count($delimiters_list)) { + $delimiter = array_shift($delimiters); // the found delimiter +} else { + //inconsistent CSV + var_dump($delimiters_list); // all the delimiters found +} + +~~~ + +### Transcoding Charset Property + +`setEncoding`/`getEnconding`: the `$encondingFrom` property setter and getter are renamed `setEncodingFrom`/`getEncondingFrom` to avoid any ambiguity. + +**The library always assume that the output is in `UTF-8`** so when transcoding your CSV you should always transcode from the `$encondingFrom` charset into an UTF-8 compatible charset. + +You need to upgrade your code accordingly. + +Old code: + +~~~php +setEncoding('SJIS'); +$charset = $reader->getEncoding(); //returns 'SJIS' +$reader->output(); + +~~~ + +New code: + +~~~php +setEncodingFrom('SJIS'); +$charset = $reader->getEncodingFrom(); //returns 'SJIS' +$reader->output(); + +~~~ + +### Creating New Instances From Existing CSV Objects + +`League\Csv\Writer::getReader` and `League\Csv\Reader::getWriter` are removed. + +The new methods `newWriter` and `newReader` are available on **both** classes. This means you can create a CSV reader and/or a CSV writer object from any given object. + +* `newWriter` behaves exactly like `getWriter`; +* `newReader` behaves exactly like `getReader`; + +Old code: + +~~~php +getWriter('a+'); + +$another_reader = $writer->getReader(); +~~~ + +New code: + +~~~php +newWriter('a+'); + +$another_writer = $writer->newWriter('rb+'); +$another_reader1 = $writer->newReader(); +$another_reader2 = $reader->newReader(); +~~~ + +## Already deprecated methods in 5.0 series, removed in 6.0 + +- `setSortBy`: deprecated since version 5.2 and replaced by `addSortBy`. +- `setFilter`: deprecated since version 5.1 and replaced by `addFilter`. diff --git a/docs/upgrading/upgrading-7.0.md b/docs/upgrading/upgrading-7.0.md new file mode 100644 index 00000000..a507b8fc --- /dev/null +++ b/docs/upgrading/upgrading-7.0.md @@ -0,0 +1,301 @@ +--- +layout: default +title: Upgrading from 6.x to 7.x +permalink: upgrading/7.0/ +--- + +# Upgrading from 6.x to 7.x + +## Installation + +If you are using composer then you should update the require section of your `composer.json` file. + +~~~ +$ composer require league/csv:~7.0 +~~~ + +This will edit (or create) your `composer.json` file. + +## Added features + +To improving writing speed you can now control data formatting and validation insertion prior to CSV addition: + +Please [refer to the documentation](/inserting/) for more information. + +## Improved features + +### newline + +The newline feature introduced during the 6.X series is completed by + +- adding the setter and getter methods to the `Reader` class. +- adding the `$newline` character as a second argument of the `createFromString` named constructor. When set, the method internally use the `setNewline` method to make sure the property is correctly set for future use. + +### newReader and newWriter + +All the CSV properties are now copied to the new instance when using both methods. + +### BOM + +When using the `__toString` or `output` methods the input BOM if it exists is stripped from the output. + +## Backward Incompatible Changes + +### PHP ini settings + +**If you are on a Mac OS X Server**, add the following lines before using the library to help [PHP detect line ending in Mac OS X](http://php.net/manual/en/function.fgetcsv.php#refsect1-function.fgetcsv-returnvalues). + +~~~php +insertOne(["foo", null, "bar"]); //will throw an RuntimeException +~~~ + +**New code:** + +~~~php +addValidator($validator, 'null_as_exception'); +$writer->insertOne(["foo", null, "bar"]); //will throw an League\Csv\Exception\InvalidRowException +~~~ + +#### Example 2 : Null value formatting + +**Old code:** + +~~~php +setNullHandlingMode(Writer::NULL_AS_SKIP_CELL); +$writer->insertOne(["foo", null, "bar"]); +//the actual inserted row will be ["foo", "bar"] +~~~ + +**New code:** + +~~~php +addFormatter($formatter); +$writer->insertOne(["foo", null, "bar"]); +//the actual inserted row will be ["foo", "bar"] +~~~ + +### Row consistency check + +Directly checking row consistency has been removed from the `Writer` class. If your code relied on it you can use the new validation and formatting capabilities of the `Writer` class and: + +- the `League\Csv\Plugin\ColumnConsistencyValidator` class. + +**Old code:** + +~~~php +setNullHandlingMode(Writer::NULL_AS_EMPTY); +$writer->autodetectColumnsCount(); +$writer->getColumnsCount(); //returns -1 + +$writer->insertOne(["foo", null, "bar"]); +$nb_column_count = $writer->getColumnsCount(); //returns 3 +~~~ + +**New code:** + +~~~php +autodetectColumnsCount(); +$validator->getColumnsCount(); //returns -1 + +$writer = Writer::createFromPath('/path/to/your/csv/file.csv'); +$writer->addValidator($validator, 'column_consistency'); + +$writer->insertOne(["foo", null, "bar"]); +$nb_column_count = $validator->getColumnsCount(); //returns 3 +~~~ + +### CSV conversion methods + +`jsonSerialize`, `toXML` and `toHTML` methods returns data is affected by the `Reader` query options methods. You can directly narrow the CSV conversion into a json string, a `DOMDocument` object or a HTML table if you filter your data prior to using the conversion method. + +As with any other `Reader` extract method, the query options are resetted after a call to the above methods. + +Because prior to version 7.0 the conversion methods were not affected, you may have to update your code accordingly. + +**Old behavior:** + +~~~php +setOffset(1); +$reader->setLimit(5); +$reader->toHTML(); //would convert the full CSV +~~~ + +**New behavior:** + +~~~php +setOffset(1); +$reader->setLimit(5); +$reader->toHTML(); //will only convert the 5 specified rows +~~~ + +Of course, since the query options methods do not exist on the `Writer` class. The changed behavior does not affect the latter class. + +### CSV Instantiation + +You can no longer use `Reader` and `Writer` default constructors. You are required to use the named constructors. This is done in order to clarify `$open_mode` argument usage on instantiation. See below for a concrete example. + +**Removed behavior:** + +~~~php +detectDelimiterList(10, [' ', '|']); +foreach ($delimiters_list as $occurences => $delimiter) { + echo "$delimiter appeared $occurences times in 10 CSV row", PHP_EOL; +} +//$occurences can not be less than 1 +//since it would mean that the delimiter is not used +//if you are only interested in getting +// the most use delimiter you can still do as follow +if (count($delimiters_list)) { + $delimiter = array_shift($delimiters); +} +~~~ + +### Reader::fetchColumn + +Prior to version 7.0 when, if the column did not exist in the csv data the method returned an array full of null values. + +**Old behavior:** + +~~~php +fetchColumn(3); +//$arr is a array containing only null values; +~~~ + +**New behavior:** + +~~~php +fetchColumn(3); +//$arr is empty +~~~ + +Row with non existing values are skipped from the result set. \ No newline at end of file diff --git a/docs/upgrading/upgrading-8.0.md b/docs/upgrading/upgrading-8.0.md new file mode 100644 index 00000000..95b9b777 --- /dev/null +++ b/docs/upgrading/upgrading-8.0.md @@ -0,0 +1,215 @@ +--- +layout: default +title: Upgrading from 7.x to 8.x +permalink: upgrading/8.0/ +--- + +# Upgrading from 7.x to 8.x + +## Installation + +If you are using composer then you should update the require section of your `composer.json` file. + +~~~ +$ composer require league/csv:^8.0 +~~~ + +This will edit (or create) your `composer.json` file. + +## Added features + +### Reader::fetchPairs and Reader::fetchPairsWithoutDuplicates + +To complements the Reader extract methods the following methods are added: + +- `Reader:fetchPairs` +- `Reader:fetchPairsWithoutDuplicates` + +Please [refer to the documentation](/reading/) for more information. + +## Backward Incompatible Changes + +### PHP required version + +`Csv` 8.0.0 is the first major version to remove support for `PHP 5.4`. + +### Remove optional argument to createFromString + +In version 8.0 the optional second argument from `createFromString` is removed. If your code relied on it you can use the following snippet: + +**Old code:** + +~~~php +insertOne(["foo", null, "bar"]); +~~~ + +**New code:** + +~~~php +setNewline("\r\n") +$writer->insertOne(["foo", null, "bar"]); +~~~ + +### Remove SplFileObject flags usage + +In version 8.0 you can no longer set `SplFileObject` flags the following methods are remove: + +- `setFlags` +- `getFlags` + +The `SplFileObject` flags are normalized to have a normalized CSV filtering independent of the underlying PHP engine use (`HHVM` or `Zend`). + +**Old code:** + +~~~php +setFlags(SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY); +$csv->fetchAssoc(); //empty lines where removed +~~~ + +**New code:** + +~~~php +fetchAssoc(); //empty lines are automatically removed +~~~ + +### fetchAssoc and fetchColumn return Iterator + +`Reader::fetchAssoc` and `Reader::fetchColumn` no longer return an array but instead an `Iterator`. + +**Old code:** + +~~~php +fetchAssoc(['lastname', 'firstname']); + +echo $res[0]['lastname']; //would return the first row 'lastname' index +~~~ + +**New code:** + +~~~php +fetchAssoc(['lastname', 'firstname']); + +echo iterator_to_array($res, false)[0]['lastname']; +~~~ + +### fetchAssoc callable argument + +The optional callable argument from `Reader::fetchAssoc` now expects its first argument to be an `array` indexed by the submitted array keys. In all previous versions, the indexation was made after the callable had manipulated the CSV row. + +**Old code:** + +~~~php +fetchAssoc(['lastname', 'firstname'], $func); +~~~ + +**New code:** + +~~~php +fetchAssoc(['lastname', 'firstname'], $func); +~~~ + +### fetchColumn callable argument + +The optional callable argument from `Reader::fetchColumn` now expects its first argument to be the selected column value. In all previous versions, the callable first argument was an array. + +**Old code:** + +~~~php +fetchColumn(2, $func); +~~~ + +**New code:** + +~~~php +fetchColum(2, $func); +~~~ + +## Deprecated methods in 7.0 series, removed in 8.0 + +- `Controls::detectDelimiterList` replaced by `Controls::fetchDelimitersOccurence` +- `Reader::query` replaced by `Reader::fetch` + +## Removed methods in 8.0.0 + +- `Controls::setFlags` +- `Controls::getFlags` +- `QueryFilter::hasFilter` +- `QueryFilter::removeFilter` +- `QueryFilter::clearFilter` +- `QueryFilter::hasSortBy` +- `QueryFilter::removeSortBy` +- `QueryFilter::clearSortBy` \ No newline at end of file diff --git a/src/AbstractCsv.php b/src/AbstractCsv.php index 3a875001..33a23365 100644 --- a/src/AbstractCsv.php +++ b/src/AbstractCsv.php @@ -4,7 +4,7 @@ * * @license http://opensource.org/licenses/MIT * @link https://github.com/thephpleague/csv/ -* @version 8.1.1 +* @version 8.2.0 * @package League.csv * * For the full copyright and license information, please view the LICENSE @@ -67,11 +67,11 @@ abstract class AbstractCsv implements JsonSerializable, IteratorAggregate const BOM_UTF32_LE = "\xFF\xFE\x00\x00"; /** - * The constructor path + * The path * - * can be a SplFileInfo object or the string path to a file + * can be a StreamIterator object, a SplFileObject object or the string path to a file * - * @var SplFileObject|string + * @var StreamIterator|SplFileObject|string */ protected $path; @@ -155,7 +155,7 @@ public static function createFromStream($stream) * The string must be an object that implements the `__toString` method, * or a string * - * @param string|object $str the string + * @param string $str the string * * @return static */ diff --git a/src/Config/Controls.php b/src/Config/Controls.php index a8593e76..69d7799a 100644 --- a/src/Config/Controls.php +++ b/src/Config/Controls.php @@ -4,7 +4,7 @@ * * @license http://opensource.org/licenses/MIT * @link https://github.com/thephpleague/csv/ -* @version 8.1.1 +* @version 8.2.0 * @package League.csv * * For the full copyright and license information, please view the LICENSE diff --git a/src/Config/Output.php b/src/Config/Output.php index 7672c360..59f673dc 100644 --- a/src/Config/Output.php +++ b/src/Config/Output.php @@ -4,7 +4,7 @@ * * @license http://opensource.org/licenses/MIT * @link https://github.com/thephpleague/csv/ -* @version 8.1.1 +* @version 8.2.0 * @package League.csv * * For the full copyright and license information, please view the LICENSE diff --git a/src/Exception/InvalidRowException.php b/src/Exception/InvalidRowException.php index 8473202c..c19d3db8 100644 --- a/src/Exception/InvalidRowException.php +++ b/src/Exception/InvalidRowException.php @@ -4,7 +4,7 @@ * * @license http://opensource.org/licenses/MIT * @link https://github.com/thephpleague/csv/ -* @version 8.1.1 +* @version 8.2.0 * @package League.csv * * For the full copyright and license information, please view the LICENSE diff --git a/src/Modifier/MapIterator.php b/src/Modifier/MapIterator.php index d892b551..92c0c051 100644 --- a/src/Modifier/MapIterator.php +++ b/src/Modifier/MapIterator.php @@ -4,7 +4,7 @@ * * @license http://opensource.org/licenses/MIT * @link https://github.com/thephpleague/csv/ -* @version 8.1.1 +* @version 8.2.0 * @package League.csv * * For the full copyright and license information, please view the LICENSE diff --git a/src/Modifier/QueryFilter.php b/src/Modifier/QueryFilter.php index 582440c9..35eeba40 100644 --- a/src/Modifier/QueryFilter.php +++ b/src/Modifier/QueryFilter.php @@ -4,7 +4,7 @@ * * @license http://opensource.org/licenses/MIT * @link https://github.com/thephpleague/csv/ -* @version 8.1.1 +* @version 8.2.0 * @package League.csv * * For the full copyright and license information, please view the LICENSE diff --git a/src/Modifier/RowFilter.php b/src/Modifier/RowFilter.php index e489c6d2..786410fc 100644 --- a/src/Modifier/RowFilter.php +++ b/src/Modifier/RowFilter.php @@ -4,7 +4,7 @@ * * @license http://opensource.org/licenses/MIT * @link https://github.com/thephpleague/csv/ -* @version 8.1.1 +* @version 8.2.0 * @package League.csv * * For the full copyright and license information, please view the LICENSE diff --git a/src/Modifier/StreamFilter.php b/src/Modifier/StreamFilter.php index 76c5059f..691be711 100644 --- a/src/Modifier/StreamFilter.php +++ b/src/Modifier/StreamFilter.php @@ -4,7 +4,7 @@ * * @license http://opensource.org/licenses/MIT * @link https://github.com/thephpleague/csv/ -* @version 8.1.1 +* @version 8.2.0 * @package League.csv * * For the full copyright and license information, please view the LICENSE @@ -14,6 +14,7 @@ use LogicException; use OutOfBoundsException; +use SplFileObject; /** * A Trait to ease PHP Stream Filters manipulation @@ -66,7 +67,7 @@ trait StreamFilter * an object that implements the `__toString` method * a path to a file * - * @param \SplFileObject|string $path The file path + * @param StreamIterator|SplFileObject|string $path The file path */ protected function initStreamFilter($path) { diff --git a/src/Plugin/ColumnConsistencyValidator.php b/src/Plugin/ColumnConsistencyValidator.php index 8cc1c4a9..6bf905e5 100644 --- a/src/Plugin/ColumnConsistencyValidator.php +++ b/src/Plugin/ColumnConsistencyValidator.php @@ -4,7 +4,7 @@ * * @license http://opensource.org/licenses/MIT * @link https://github.com/thephpleague/csv/ -* @version 8.1.1 +* @version 8.2.0 * @package League.csv * * For the full copyright and license information, please view the LICENSE diff --git a/src/Plugin/ForbiddenNullValuesValidator.php b/src/Plugin/ForbiddenNullValuesValidator.php index 1670b53d..586a5768 100644 --- a/src/Plugin/ForbiddenNullValuesValidator.php +++ b/src/Plugin/ForbiddenNullValuesValidator.php @@ -4,7 +4,7 @@ * * @license http://opensource.org/licenses/MIT * @link https://github.com/thephpleague/csv/ -* @version 8.1.1 +* @version 8.2.0 * @package League.csv * * For the full copyright and license information, please view the LICENSE diff --git a/src/Plugin/SkipNullValuesFormatter.php b/src/Plugin/SkipNullValuesFormatter.php index a738982a..906ad42f 100644 --- a/src/Plugin/SkipNullValuesFormatter.php +++ b/src/Plugin/SkipNullValuesFormatter.php @@ -4,7 +4,7 @@ * * @license http://opensource.org/licenses/MIT * @link https://github.com/thephpleague/csv/ -* @version 8.1.1 +* @version 8.2.0 * @package League.csv * * For the full copyright and license information, please view the LICENSE diff --git a/src/Reader.php b/src/Reader.php index e29afdf1..79efc749 100644 --- a/src/Reader.php +++ b/src/Reader.php @@ -4,7 +4,7 @@ * * @license http://opensource.org/licenses/MIT * @link https://github.com/thephpleague/csv/ -* @version 8.1.1 +* @version 8.2.0 * @package League.csv * * For the full copyright and license information, please view the LICENSE diff --git a/src/Writer.php b/src/Writer.php index 521ddef9..449f7264 100644 --- a/src/Writer.php +++ b/src/Writer.php @@ -4,7 +4,7 @@ * * @license http://opensource.org/licenses/MIT * @link https://github.com/thephpleague/csv/ -* @version 8.1.1 +* @version 8.2.0 * @package League.csv * * For the full copyright and license information, please view the LICENSE