The League of Extraordinary Packages

Our Packages:

Presented by The League of Extraordinary Packages

Getting Started

The API

Upgrading Guide

This is the documentation for the upcoming version 9.0. This is a work in progress.

Upgrading from 8.x to 9.x

League\Csv 9.0 is a new major version that comes with backward compatibility breaks.

This guide will help you migrate from a 8.x version to 9.0. It will only explain backward compatibility breaks, it will not present the new features (read the documentation for that).

Installation

If you are using composer then you should update the require section of your composer.json file.

composer require league/uri:^9.0

This will edit (or create) your composer.json file.

PHP version requirement

League\Csv 9.0 requires a PHP version greater or equal than 7.0.0 (was previously 5.5.0).

The library is not tested on HHVM

The Writer class

Stricter argument type

The Writer::insertOne and Writer::insertAll methods no longer accept string as possible CSV records

Before:

<?php

use League\Csv\Writer;

$writer = Writer::createFromFileObject(new SplTempFileObject());
$str = 'john,doe,john.doe@example.com';
$writer->insertOne($str);
$writer->insertAll([$str]);

After:

<?php

use League\Csv\Writer;

$writer = Writer::createFromFileObject(new SplTempFileObject());
$str = 'john,doe,john.doe@example.com';
$record = str_getcsv($str, ',', '"', '\\');
$writer->insertOne($record);
$writer->insertAll([$record]);

Reduced method chaining

The Writer::insertOne and Writer::insertAll methods are no longer chainable.

Before:

<?php

use League\Csv\Writer;

$writer = Writer::createFromFileObject(new SplTempFileObject());
$record = ['john', 'doe', 'john.doe@example.com'];
$writer
	->insertOne($record)
	->insertAll([$record])
    ->insertOne($record)
;

After:

<?php

use League\Csv\Writer;

$writer = Writer::createFromFileObject(new SplTempFileObject());
$record = ['john','doe','john.doe@example.com'];
$writer->insertOne($record);
$writer->insertAll([$record]);
$writer->insertOne($record);

Removed methods

Validators and Formatters can only be removed on object destruction.

You can no longer iterate over a Writer class, use the Reader class instead.

The Reader class

Reader::fetchAssoc is removed

The Reader::fetchAssoc is removed instead you are required to specify the header offset and use Reader::getRecords.

Before:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
foreach ($reader->fetchAssoc(0) as $records) {
    //The CSV first row is used as the CSV header
    //and as the index of each found record
    //the CSV header offset is removed from iteration
}

After:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
$reader->setHeaderOffset(0);
foreach ($reader->getRecords() as $records) {
    //The CSV first row is used as the CSV header
    //and as the index of each found record
    //the CSV header offset is removed from iteration
}

or use the optional $header argument from the Reader::getRecords method.

Before:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
$records = $reader->fetchAssoc(['firstname', 'lastname', 'email']);

After:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
$records = $reader->getRecords(['firstname', 'lastname', 'email']);

Last but not least if you are using query filters then use the optional $header argument from the Statement::process method.

Before:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
$records = $reader
    ->limit(5)
    ->offset(3)
    ->fetchAssoc(['firstname', 'lastname', 'email'])
;

After:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
$stmt = (new Statement())
    ->limit(5)
    ->offset(3)
;

$records = $stmt->process($reader, ['firstname', 'lastname', 'email']);

Reader::fetchAll is removed

The Reader::fetchAll method is removed in favor of the Reader::getRecords method and the IteratorAggregate interface.

Before:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
foreach ($reader->fetchAll() as $key => $value) {
    // do something here
}

After:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
foreach ($reader as $record) {
    // do something here
}

If you require the CSV to be returned as a sequential array of all rows you can simply convert the returned Iterator to an array using iterator_to_array.

Before:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
$csv_as_array = $reader->fetchAll();

After:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
$csv_as_array = iterator_to_array($reader, false);

Reader::fetch and Reader:each are removed

Reader::fetch and Reader:each are removed as the Reader and ResultSet classes implement the IteratorAggregate interface.

Before:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');

$func = function (array $record) {
    return array_map('strtoupper', $record);
};

$records = $reader
    ->setOffset(3)
    ->setLimit(2)
    ->fetch($func)
;

foreach ($records as $record) {
    // do something here
}

After:

<?php

use League\Csv\Reader;
use League\Csv\Statement;

$reader = Reader::createFromPath('/path/to/file.csv');
$stmt = (new Statement())
    ->offset(3)
    ->limit(2)
;
$records = $stmt->process($reader);
foreach ($records as $record) {
    $res = array_map('strtoupper', $record);
    // do something here
}

Reader::fetchPairsWithoutDuplicates is removed

The fetchPairsWithoutDuplicates is removed as it is redundant with the fetchPairs method.

Before:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
$pairs_without_duplicates = $reader
    ->setOffset(3)
    ->setLimit(2)
    ->fetchPairsWithoutDuplicates()
;

foreach ($pairs_without_duplicates as $key => $value) {
    // do something here
}

After:

<?php

use League\Csv\Reader;
use League\Csv\Statement;

$reader = Reader::createFromPath('/path/to/file.csv');
$stmt = (new Statement())
    ->offset(3)
    ->limit(2)
;
$records = $stmt->process($reader);
$pairs_without_duplicates = iterator_to_array($records->fetchPairs(), true);
foreach ($pairs_without_duplicates as $record) {
    // do something here
}

Reader::fetchDelimitersOccurrence is removed

The Reader::fetchDelimitersOccurrence is removed instead you are required to use the League\Csv\delimiter_detect function with a Reader object.

Before:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
$stats = $reader->fetchDelimitersOccurrence([',', ';', "\t"], 10);

After:

<?php

use League\Csv\Reader;
use function League\Csv\delimiter_detect;

$reader = Reader::createFromPath('/path/to/file.csv');
$stats = delimiter_detect($reader, [',', ';', "\t"], 10);

Optional callable arguments are removed

The following methods no longer accept an optional callable as argument.

Before:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
$records = $reader->fetchColumn(0, function ($value) {
    return strtoupper($value);
});

After:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
foreach ($records->fetchColumn(0) as $value) {
    $value = strtoupper($value);
};

Miscellanous

Columns consistency Validator

Before:

<?php

use League\Csv\Plugin\ColumnConsistencyValidator;
use League\Csv\Writer;

$validator = new ColumnConsistencyValidator();
$validator->autodetectColumnCount();

$csv = Writer::createFromPath('/path/to/file.csv');
$csv->addValidator($validator, 'columns_consistency');

After:

<?php

use League\Csv\ColumnConsistency;
use League\Csv\Writer;

$csv = Writer::createFromPath('/path/to/file.csv');
$csv->addValidator(new ColumnConsistency(), 'columns_consistency');

Stream Filtering

To detect if a PHP stream filters are supported you neet to call AbstractCsv::supportsStreamFilter

Before:

<?php

use League\Csv\Writer;

$csv = Writer::createFromPath('/path/to/file.csv');
$csv->isActiveStreamFilter(); //true

After:

<?php

use League\Csv\Writer;

$csv = Writer::createFromPath('/path/to/file.csv');
$csv->supportsStreamFilter(); //true

The filtering mode is fixed and can not be changed:

Therefore AbstractCsv::setStreamFilterMode is removed.

To add a stream filter you will only need the AbstractCsv::addStreamFilter method.

Before:

<?php

use League\Csv\Writer;

$csv = Writer::createFromPath('/path/to/file.csv');
$csv->appendStreamFilter('string.toupper');
$csv->prependStreamFilter('string.rot13');

After:

<?php

use League\Csv\Writer;

$csv = Writer::createFromPath('/path/to/file.csv');
$csv->addStreamFilter('string.rot13');
$csv->addStreamFilter('string.toupper');
//the insertion order has changed

PHP Stream filters are removed once the CSV object is freed.

Before:

<?php

use League\Csv\Writer;

$csv = Writer::createFromPath('/path/to/file.csv');
$csv->appendStreamFilter('string.toupper');
$csv->prependStreamFilter('string.rot13');
$csv->removeStreamFilter('string.rot13');
$csv->clearStreamFilters();

After:

<?php

use League\Csv\Writer;

$csv = Writer::createFromPath('/path/to/file.csv');
$csv->addStreamFilter('string.rot13');
$csv->addStreamFilter('string.toupper');
$csv = null;

Conversion methods

All convertion methods are no longer attached to the Reader or the Writer classes you need a Converter object to convert your CSV. The following methods are removed

And you can no longer convert a Writer class.

Before:

<?php

use League\Csv\Writer;

$csv = Writer::createFromPath('/path/to/file.csv');
$dom = $csv->toXML(); //$dom is a DOMDocument

After:

<?php

use League\Csv\XMLConverter;
use League\Csv\Reader;

$csv = Reader::createFromPath('/path/to/file.csv');
$dom = (new XMLConverter())->convert($csv); //$dom is a DOMDocument

Switching between connections

You can no longer switch between connection. You are require to explicitly load a new Reader and/or Writer object.