diff --git a/README.md b/README.md index 35f599c7..dbcf1de7 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ System Requirements You need **PHP >= 5.4.0** and the `mbstring` extension to use `Bakame\Csv` but the latest stable version of PHP is recommended. -Install +Installation ------- You may install the Bakame.csv package with Composer (recommended) or manually. @@ -36,14 +36,36 @@ Download and extract the library in a specific directory, then add `'/path/to/Ba Usage ------- -**If you don't want to read the whole documentation just look at the [examples](examples/) directory to see how the library works.** +* [Downloading the CSV](examples/download.php) +* [Converting the CSV into a Json String](examples/json.php) +* [Converting the CSV into a HTML Table](examples/table.php) +* [Selecting specific rows in the CSV](examples/extract.php) +* [Filtering a CSV](examples/filtering.php) +* [Creating a CSV](examples/writing.php) +* [Switching between modes from Writer to Reader mode](examples/switchmode.php) -Manipulating a CSV +> The CSV file use for the examples is taken from [Paris Opendata](http://opendata.paris.fr/opendata/jsp/site/Portal.jsp?document_id=60&portlet_id=121) + +### Tips + +* 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 you may change the file cursor position and get unexpected results. + +* If you are dealing with non-unicode data, specify the encoding parameter using the `setEncoding` method otherwise your output conversions may no work. + +* **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 +if (! ini_get("auto_detect_line_endings")) { + ini_set("auto_detect_line_endings", true); +} +``` + +Documentation ------- The library is composed of two main classes: * `Bakame\Csv\Reader` to extract and filter data from a CSV -* `Bakame\Csv\Writer` to insert new data into a CSV. +* `Bakame\Csv\Writer` to insert new data into a CSV. Both classes share methods to instantiate, format and output the CSV. @@ -66,15 +88,11 @@ $writer = new Writer(new SpliFileObject('/path/to/your/csv/file.csv'), 'a+'); $writer = Writer::createFromString('john,doe,john.doe@example.com'); ``` -The static method `createFromString` is to be use if your data is a string. +Both classes constructors take one optional parameter `$open_mode` representing the file open mode used by the PHP [fopen](http://php.net/manual/en/function.fopen.php) function. +* The `Bakame\Csv\Writer` `$open_mode` default value is `w`. +* The `Bakame\Csv\Reader` `$open_mode` default value is `r`, and **no other value is possible**. So you don't need to explicitly set it. -Both classes can take one optional parameter `$open_mode` representing the file open mode used by the PHP [fopen][] function. -* In case of the `Bakame\Csv\Writer` class `$open_mode` default value is `w`, but you can change this value according to your needs. -* In case of the `Bakame\Csv\Reader` class `$open_mode` default value is `r`, and **no other value is possible**. So you don't need to explicitly set it. -* the `$open_mode` argument is not taken into account when creating a object from the static method `createFromString`. - - -[fopen]: http://php.net/manual/en/function.fopen.php +The static method `createFromString` is to be use if your data is a string. This method takes no optional `$open_mode` parameter. Once your object is created you can optionally set: @@ -105,21 +123,24 @@ foreach ($reader as $row) { ### Outputting the CSV +**Don't forget to set the CSV encoding format before using any outputting CSV method if your data is not `UTF-8` encoded.** + With both classes you can: #### show the CSV content: -You can directly use the `echo` construct on the instantiated object or use the `__toString` method +Use the `echo` construct on the instantiated object or use the `__toString` method. ```php echo $writer; //or echo $writer->__toString(); ``` -The CSV data can be formatted into an HTML table using the `toHTML` method. This methods accepts an optional argument `$classname` to help you customize the table rendering, by defaut the classname given to the table is `table-csv-data`. + +Use the `toHTML` method to format 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 -echo $writer->toHTML(); +echo $writer->toHTML('table table-bordered table-hover'); ``` #### convert the CSV into a Json string: @@ -141,13 +162,12 @@ header('Content-Disposition: attachment; filename="name-for-your-file.csv"'); $reader->output(); ``` - Extracting data from the CSV ------- -Extracting data is made easy using the following methods on a `Bakame\Csv\Reader` object: +To extract data use `Bakame\Csv\Reader` methods. -#### fetchAll +#### fetchAll($callable = null) `fetchAll` returns a sequential array of all rows. @@ -162,7 +182,7 @@ $data = $reader->fetchAll(); // ] // ``` -#### fetchAssoc +#### fetchAssoc([], $callable = null) `fetchAssoc` returns a sequential array of all rows. The rows themselves are associative arrays where the keys are given directly to the method using an one dimension array. This array should only contain unique `string` and/or `integer` values. @@ -181,7 +201,7 @@ $data = $reader->fetchAssoc(['firstname', 'lastname', 'email']); > * 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. -#### fetchCol +#### fetchCol($columnIndex, $callable = null) `fetchCol` returns a sequential array of all values in a given column from the CSV data. @@ -194,13 +214,13 @@ $data = $reader->fetchCol(2); ``` -The methods listed above (`fetchAll`, `fetchAssoc`, `fetchCol`) can all take a optional `callable` argument to further manipulate each row before being returned. This callable function can take three parameters at most: +The methods listed above (`fetchAll`, `fetchAssoc`, `fetchCol`) 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 (usually a `SplFileObject`) +* the current csv Iterator Object -#### fetchOne +#### fetchOne($offset) `fetchOne` return one single row from the CSV data. The required argument `$offset` represent the row index starting at 0. @@ -216,24 +236,24 @@ $data = $reader->fetchOne(3); ///accessing the 4th row (indexing starts at 0) You can further manipulate the CSV `fetch*` methods output by specifying filtering options using the following methods: -#### setFilter +#### setFilter($callable = null) `setFilter` method specifies an optional `callable` function to filter the CSV data. This function takes three parameters at most (see [CallbackFilterIterator][] for more informations) [CallbackFilterIterator]: http://php.net/manual/en/class.callbackfilteriterator.php#callbackfilteriterator.examples -#### setSortBy +#### setSortBy($callable = null) `setSortBy` method specifies an optional `callable` function to sort the CSV data. The function takes two parameters which will be filled by pairs of rows. **Beware when using this filter that you will be using `iterator_to_array` which could lead to performance penalty if you have a heavy CSV file to sort** -#### setOffset and setLimit +#### setOffset($offset) and setLimit($limit) * `setOffset` method specifies an optional offset for the return results. * `setLimit` method specifies an optional maximum rows count for the return results. -**Both methods are ignore by the `fetchOne` method.** +**Both methods have no effect on the `fetchOne` method output** Here's an example: @@ -302,7 +322,7 @@ $iterator = $reader Inserting data into the CSV ------- -To insert new data into a CSV use the following methods on a `Bakame\Csv\Writer` object: +To create or update a CSV use the following specific `Bakame\Csv\Writer` methods. #### insertOne @@ -346,9 +366,12 @@ $arr = [ $writer->insertAll($arr) //using an array $object = new ArrayIterator($arr); -$writer->insertMany($object); //using a Traversable object +$writer->insertAll($object); //using a Traversable object ``` +**When inserting strings don't forget to specify the CSV delimiter and enclosure characters that match those use in the string**. + + Switching from one class to the other ------- @@ -363,7 +386,6 @@ $newWriter = $reader->getWriter('a'); ``` **be careful the `$newWriter` object is not equal to the `$writer` object!!** - Testing ------- diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index bfe1c129..00000000 --- a/examples/README.md +++ /dev/null @@ -1,20 +0,0 @@ -Examples -========== - - -* [Converting the CSV into a HTML Table](example00.php) with the `toHTML` method -* [Converting the CSV into a Json String](example01.php) string -* [Downloading the CSV](example02.php) using the `output` method -* [Selecting specific rows in the CSV](example03.php) -* [Filtering a CSV](example04.php) using the `Bakame\Csv\Reader` class -* [Creating a CSV](example05.php) using the `Bakame\Csv\Writer` class -* [From writing mode to reader mode](example06.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) - -Tips ------- - -* When creating a file using the `Bakame\Csv\Writer` class, first use the `insert*` methods and manipulate your CSV afterwards. If you manipulate your data before you may change the file cursor position and get unexpected results. - -* If your are dealing with non-unicode data, please don't forger to specify the encoding parameter using the `setEncoding` method otherwise you json conversion may no work. \ No newline at end of file diff --git a/examples/example02.php b/examples/download.php similarity index 100% rename from examples/example02.php rename to examples/download.php diff --git a/examples/example.css b/examples/example.css new file mode 100644 index 00000000..9010a260 --- /dev/null +++ b/examples/example.css @@ -0,0 +1,53 @@ +html { + font:normal 1em/1.5 sans-serif; +} +/* taken and adapted from lea verou excellent blog theme */ +pre { + margin-bottom: 1em; + overflow: auto; + padding: .5em .8em; + border: 1px solid #aaa; + background-color: #e1e1e1; + color: #444; + font-size: 1.2em; + line-height: 1.5; + text-align: left; + -webkit-tab-size: 4; + -moz-tab-size: 4; + -ms-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; +} +body { + margin:0 auto; + width:50% +} +.table-csv-data { + width:98%; + margin:0 auto 1em; + border-collapse:collapse; + padding:0; + font:normal 1em/1.5 sans-serif; +} +.table-csv-data td { + border-bottom:1px solid #ccc; + padding:.3em; + color:#222; + vertical-align: top; + text-align:left; +} + +.table-csv-data tr:nth-child(even) td { + background-color:rgba(192, 192, 192, .2); +} + +.table-csv-data tr:hover td { + background-color:#d4e8fc; +} + +.with-header tbody tr:first-of-type td { + font-weight:bold; +} +.with-header tbody tr:first-of-type:hover td { + background-color:inherit; +} \ No newline at end of file diff --git a/examples/example05.php b/examples/example05.php deleted file mode 100644 index 33210d30..00000000 --- a/examples/example05.php +++ /dev/null @@ -1,55 +0,0 @@ -setDelimiter(';'); -$inputCsv->setEncoding("iso-8859-15"); - -//we filter only the least girl firstname given in 2010 -$filter = function ($row, $index) { - return $index > 0 //we don't take into account the header - && isset($row[1], $row[2], $row[3]) //we make sure the data are present - && 10 > $row[1] //the name is used less than 10 times - && 2010 == $row[3] //we are looking for the year 2010 - && 'F' == $row[2]; //we are only interested in girl firstname -}; - -//we order the result according to the number of firstname given -$sortBy = function ($row1, $row2) { - return strcmp($row1[1], $row2[1]); -}; - -$res = $inputCsv - ->setFilter($filter) - ->setSortBy($sortBy) - ->setLimit(20) //we just want the first 20 results - ->fetchAll(); - -$headers = $inputCsv->fetchOne(0); - -$writer = new Writer(new SplTempFileObject); //because we don't want to create the file -$writer->setDelimiter("\t"); //the delimiter will be the tab character -$writer->insertOne($headers); -$writer->insertAll($res); -?> - - - - - Example 2 - - -

Example 4: Using Writer object

-

The table representation of the csv to be save

-toHTML();?> -

The Raw CSV as it will be saved

-
-
-
-

Notice that the delimiter have changed from ; to <tab>

- - diff --git a/examples/example03.php b/examples/extract.php similarity index 77% rename from examples/example03.php rename to examples/extract.php index 2eb08e2c..9e884fab 100644 --- a/examples/example03.php +++ b/examples/extract.php @@ -11,18 +11,19 @@ //get the header $headers = $inputCsv->fetchOne(0); -//get at maximum 40 rows starting from the second 801th row +//get at maximum 25 rows starting from the second 801th row $res = $inputCsv->setOffset(800)->setLimit(25)->fetchAll(); ?> - Example 1 + \Bakame\Csv\Reader simple usage + -

Example 1: Simple Reader class usage

- +

\Bakame\Csv\Reader simple usage

+
diff --git a/examples/example04.php b/examples/filtering.php similarity index 88% rename from examples/example04.php rename to examples/filtering.php index 213425f9..61fcb4dc 100644 --- a/examples/example04.php +++ b/examples/filtering.php @@ -36,11 +36,12 @@ -Example 3 + \Bakame\Csv\Reader filtering method + -

Example 3: Using the Reader class filtering capabilities

-
Part of the CSV from the 801th row with at most 25 rows
+

Using the Bakame\Csv\Reader class filtering capabilities

+
diff --git a/examples/example01.php b/examples/json.php similarity index 100% rename from examples/example01.php rename to examples/json.php diff --git a/examples/example06.php b/examples/switchmode.php similarity index 86% rename from examples/example06.php rename to examples/switchmode.php index 6ddf30cb..df480ebc 100644 --- a/examples/example06.php +++ b/examples/switchmode.php @@ -56,10 +56,11 @@ - Example 2 + Bakame\Csv\Writer and Bakame\Csv\Reader switching mode + -

Example 4: Using Writer object with Strings

+

Using createFromString method and converting the Bakame\Csv\Writer into a Bakame\Csv\Reader

The table representation of the csv to be save

toHTML();?>

The Raw CSV as it will be saved

diff --git a/examples/example00.php b/examples/table.php similarity index 67% rename from examples/example00.php rename to examples/table.php index be353d0f..5c26ddbf 100644 --- a/examples/example00.php +++ b/examples/table.php @@ -12,9 +12,10 @@ - Example 2 + Using the toHTML() method + -toHTML();?> +toHTML('table-csv-data with-header');?> diff --git a/examples/writing.php b/examples/writing.php new file mode 100644 index 00000000..948008ac --- /dev/null +++ b/examples/writing.php @@ -0,0 +1,42 @@ +setDelimiter("\t"); //the delimiter will be the tab character +$writer->setEncoding("utf-8"); + +$headers = ["position" , "team", "played", "goals difference", "points"]; +$writer->insertOne($headers); + +$teams = [ + [1, "Chelsea", 26, 27, 57], + [2, "Arsenal", 26, 22, 56], + [3, "Manchester City", 25, 41, 54], + [4, "Liverpool", 26, 34, 53], + [5, "Tottenham", 26, 4, 50], + [6, "Everton", 25, 11, 45], + [7, "Manchester United", 26, 10, 42], +]; + +$writer->insertAll($teams); +?> + + + + + Using the \Bakame\Writer object + + + +

Example 4: Using Writer object

+

The table representation of the csv

+toHTML('table-csv-data with-header');?> +

The Raw CSV to be saved

+
+
+
+ +
Statistics for the 20 least used female name in the year 2010