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\Reader;
use League\Csv\Writer;

$writer = Writer::createFromFileObject(new SplTempFileObject());
$reader = Reader::createFromString('john,doe,john.doe@example.com');
$writer->insertOne($reader->fetchOne());
$writer->insertAll($reader);

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

Removed methods

Reader::fetchAssoc

The Reader::fetchAssoc features are now accessible using the new Reader::getRecords.

You are required to specify the CSV header using Reader::setHeaderOffset.

Before:

<?php

use League\Csv\Reader;

$reader = Reader::createFromPath('/path/to/file.csv');
foreach ($reader->fetchAssoc() as $records) {
    //The CSV first row is implicitly 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); //explicitly sets the CSV document header record
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 you can 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, Reader::fetch, Reader::each

Theses methods are removed because the Reader and the ResultSet implements 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
}

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

The Reader::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

Use the League\Csv\delimiter_detect function instead 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 because they return a iterable object.

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);
};

Stream Filtering

Stream support detection

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

Stream mode

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

stream filter removal

PHP Stream filters will only be removed on CSV object destruction.

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

Miscellanous

Switching between connections

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

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');