Version Description
- Fix category cleanup bug
Download this release
Release Info
Developer | dvkob |
Plugin | CSV Importer |
Version | 0.3.6 |
Comparing to | |
See all releases |
Version 0.3.6
- File_CSV_DataSource/DataSource.php +2265 -0
- File_CSV_DataSource/docs/LICENSE +23 -0
- File_CSV_DataSource/docs/README +19 -0
- File_CSV_DataSource/docs/examples/EXAMPLES +72 -0
- File_CSV_DataSource/docs/examples/documentation.wiki +2058 -0
- File_CSV_DataSource/tests/File_CSV_DataSourceTest.php +508 -0
- File_CSV_DataSource/tests/data/another_symmetric.csv +4 -0
- File_CSV_DataSource/tests/data/asymmetric.csv +10 -0
- File_CSV_DataSource/tests/data/empty.csv +0 -0
- File_CSV_DataSource/tests/data/escape_ng.csv +3 -0
- File_CSV_DataSource/tests/data/escape_ok.csv +3 -0
- File_CSV_DataSource/tests/data/longer_headers.csv +4 -0
- File_CSV_DataSource/tests/data/multcased.CsV +0 -0
- File_CSV_DataSource/tests/data/non_csv_extension.txt +0 -0
- File_CSV_DataSource/tests/data/one_row_only.csv +2 -0
- File_CSV_DataSource/tests/data/only_headers.csv +1 -0
- File_CSV_DataSource/tests/data/raw.csv +5 -0
- File_CSV_DataSource/tests/data/symmetric.csv +10 -0
- File_CSV_DataSource/tests/data/symmetric_with_empty_lines.csv +20 -0
- File_CSV_DataSource/tests/data/symmetric_with_empty_records.csv +28 -0
- File_CSV_DataSource/tests/data/symmetric_with_trailing_spaces.csv +10 -0
- File_CSV_DataSource/tests/data/uppercased.CSV +0 -0
- File_CSV_DataSource/tests/fixtures/csv.php +999 -0
- LICENSE +21 -0
- TODO +6 -0
- csv_importer.php +540 -0
- examples/comments.csv +2 -0
- examples/custom-taxonomies.csv +7 -0
- examples/functions.inc.php +19 -0
- examples/sample-advanced.csv +9 -0
- examples/sample.csv +20 -0
- readme.txt +339 -0
- screenshot-1.png +0 -0
File_CSV_DataSource/DataSource.php
ADDED
@@ -0,0 +1,2265 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
4 |
+
|
5 |
+
/**
|
6 |
+
* contains a few csv file data access tools.
|
7 |
+
*
|
8 |
+
* PHP VERSION 5
|
9 |
+
*
|
10 |
+
* LICENSE: The MIT License
|
11 |
+
*
|
12 |
+
* Copyright (c) <2008> <Kazuyoshi Tlacaelel>
|
13 |
+
*
|
14 |
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
15 |
+
* of this software and associated documentation files (the "Software"), to deal
|
16 |
+
* in the Software without restriction, including without limitation the rights
|
17 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
18 |
+
* copies of the Software, and to permit persons to whom the Software is
|
19 |
+
* furnished to do so, subject to the following conditions:
|
20 |
+
*
|
21 |
+
* The above copyright notice and this permission notice shall be included in
|
22 |
+
* all copies or substantial portions of the Software.
|
23 |
+
*
|
24 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
25 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
26 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
27 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
28 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
29 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
30 |
+
* THE SOFTWARE.
|
31 |
+
*
|
32 |
+
* @category File
|
33 |
+
* @package File_CSV_DataSource
|
34 |
+
* @author Kazuyoshi Tlacaelel <kazu.dev@gmail.com>
|
35 |
+
* @copyright 2008 Kazuyoshi Tlacaelel
|
36 |
+
* @license The MIT License
|
37 |
+
* @version SVN: $Id: DataSource.php 285574 2009-03-09 15:22:24Z ktlacaelel $
|
38 |
+
* @link http://code.google.com/p/php-csv-parser/
|
39 |
+
*/
|
40 |
+
|
41 |
+
/**
|
42 |
+
* csv data fetcher
|
43 |
+
*
|
44 |
+
* Sample snippets refer to this csv file for demonstration.
|
45 |
+
* <code>
|
46 |
+
* name,age,skill
|
47 |
+
* john,13,knows magic
|
48 |
+
* tanaka,8,makes sushi
|
49 |
+
* jose,5,dances salsa
|
50 |
+
* </code>
|
51 |
+
*
|
52 |
+
* @category File
|
53 |
+
* @package File_CSV_DataSource
|
54 |
+
* @author Kazuyoshi Tlacaelel <kazu.dev@gmail.com>
|
55 |
+
* @copyright 2008 Kazuyoshi Tlacaelel
|
56 |
+
* @license The MIT License
|
57 |
+
* @link http://code.google.com/p/php-csv-parser/
|
58 |
+
*/
|
59 |
+
class File_CSV_DataSource
|
60 |
+
{
|
61 |
+
public
|
62 |
+
|
63 |
+
/**
|
64 |
+
* csv parsing default-settings
|
65 |
+
*
|
66 |
+
* @var array
|
67 |
+
* @access public
|
68 |
+
*/
|
69 |
+
$settings = array(
|
70 |
+
'delimiter' => ',',
|
71 |
+
'eol' => ";",
|
72 |
+
'length' => 999999,
|
73 |
+
'escape' => '"'
|
74 |
+
);
|
75 |
+
|
76 |
+
protected
|
77 |
+
|
78 |
+
/**
|
79 |
+
* imported data from csv
|
80 |
+
*
|
81 |
+
* @var array
|
82 |
+
* @access protected
|
83 |
+
*/
|
84 |
+
$rows = array(),
|
85 |
+
|
86 |
+
/**
|
87 |
+
* csv file to parse
|
88 |
+
*
|
89 |
+
* @var string
|
90 |
+
* @access protected
|
91 |
+
*/
|
92 |
+
$_filename = '',
|
93 |
+
|
94 |
+
/**
|
95 |
+
* csv headers to parse
|
96 |
+
*
|
97 |
+
* @var array
|
98 |
+
* @access protected
|
99 |
+
*/
|
100 |
+
$headers = array();
|
101 |
+
|
102 |
+
/**
|
103 |
+
* data load initialize
|
104 |
+
*
|
105 |
+
* @param mixed $filename please look at the load() method
|
106 |
+
*
|
107 |
+
* @access public
|
108 |
+
* @see load()
|
109 |
+
* @return void
|
110 |
+
*/
|
111 |
+
public function __construct($filename = null)
|
112 |
+
{
|
113 |
+
$this->load($filename);
|
114 |
+
}
|
115 |
+
|
116 |
+
/**
|
117 |
+
* csv file loader
|
118 |
+
*
|
119 |
+
* indicates the object which file is to be loaded
|
120 |
+
*
|
121 |
+
* <code>
|
122 |
+
*
|
123 |
+
* require_once 'File/CSV/DataSource.php';
|
124 |
+
*
|
125 |
+
* $csv = new File_CSV_DataSource;
|
126 |
+
* $csv->load('my_cool.csv');
|
127 |
+
* var_export($csv->connect());
|
128 |
+
*
|
129 |
+
* array (
|
130 |
+
* 0 =>
|
131 |
+
* array (
|
132 |
+
* 'name' => 'john',
|
133 |
+
* 'age' => '13',
|
134 |
+
* 'skill' => 'knows magic',
|
135 |
+
* ),
|
136 |
+
* 1 =>
|
137 |
+
* array (
|
138 |
+
* 'name' => 'tanaka',
|
139 |
+
* 'age' => '8',
|
140 |
+
* 'skill' => 'makes sushi',
|
141 |
+
* ),
|
142 |
+
* 2 =>
|
143 |
+
* array (
|
144 |
+
* 'name' => 'jose',
|
145 |
+
* 'age' => '5',
|
146 |
+
* 'skill' => 'dances salsa',
|
147 |
+
* ),
|
148 |
+
* )
|
149 |
+
*
|
150 |
+
* </code>
|
151 |
+
*
|
152 |
+
* @param string $filename the csv filename to load
|
153 |
+
*
|
154 |
+
* @access public
|
155 |
+
* @return boolean true if file was loaded successfully
|
156 |
+
* @see isSymmetric(), getAsymmetricRows(), symmetrize()
|
157 |
+
*/
|
158 |
+
public function load($filename)
|
159 |
+
{
|
160 |
+
$this->_filename = $filename;
|
161 |
+
$this->flush();
|
162 |
+
return $this->parse();
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* settings alterator
|
167 |
+
*
|
168 |
+
* lets you define different settings for scanning
|
169 |
+
*
|
170 |
+
* Given array will override the internal settings
|
171 |
+
*
|
172 |
+
* <code>
|
173 |
+
* $settings = array(
|
174 |
+
* 'delimiter' => ',',
|
175 |
+
* 'eol' => ";",
|
176 |
+
* 'length' => 999999,
|
177 |
+
* 'escape' => '"'
|
178 |
+
* );
|
179 |
+
* </code>
|
180 |
+
*
|
181 |
+
* @param mixed $array containing settings to use
|
182 |
+
*
|
183 |
+
* @access public
|
184 |
+
* @return boolean true if changes where applyed successfully
|
185 |
+
* @see $settings
|
186 |
+
*/
|
187 |
+
public function settings($array)
|
188 |
+
{
|
189 |
+
$this->settings = array_merge($this->settings, $array);
|
190 |
+
}
|
191 |
+
|
192 |
+
/**
|
193 |
+
* header fetcher
|
194 |
+
*
|
195 |
+
* gets csv headers into an array
|
196 |
+
*
|
197 |
+
* <code>
|
198 |
+
*
|
199 |
+
* var_export($csv->getHeaders());
|
200 |
+
*
|
201 |
+
* array (
|
202 |
+
* 0 => 'name',
|
203 |
+
* 1 => 'age',
|
204 |
+
* 2 => 'skill',
|
205 |
+
* )
|
206 |
+
*
|
207 |
+
* </code>
|
208 |
+
*
|
209 |
+
* @access public
|
210 |
+
* @return array
|
211 |
+
*/
|
212 |
+
public function getHeaders()
|
213 |
+
{
|
214 |
+
return $this->headers;
|
215 |
+
}
|
216 |
+
|
217 |
+
/**
|
218 |
+
* header counter
|
219 |
+
*
|
220 |
+
* retrives the total number of loaded headers
|
221 |
+
*
|
222 |
+
* @access public
|
223 |
+
* @return integer gets the length of headers
|
224 |
+
*/
|
225 |
+
public function countHeaders()
|
226 |
+
{
|
227 |
+
return count($this->headers);
|
228 |
+
}
|
229 |
+
|
230 |
+
/**
|
231 |
+
* header and row relationship builder
|
232 |
+
*
|
233 |
+
* Attempts to create a relationship for every single cell that
|
234 |
+
* was captured and its corresponding header. The sample below shows
|
235 |
+
* how a connection/relationship is built.
|
236 |
+
*
|
237 |
+
* sample of a csv file "my_cool.csv"
|
238 |
+
*
|
239 |
+
* <code>
|
240 |
+
* name,age,skill
|
241 |
+
* john,13,knows magic
|
242 |
+
* tanaka,8,makes sushi
|
243 |
+
* jose,5,dances salsa
|
244 |
+
* </code>
|
245 |
+
*
|
246 |
+
* php implementation
|
247 |
+
*
|
248 |
+
* <code>
|
249 |
+
*
|
250 |
+
* $csv = new File_CSV_DataSource;
|
251 |
+
* $csv->load('my_cool.csv');
|
252 |
+
*
|
253 |
+
* if (!$csv->isSymmetric()) {
|
254 |
+
* die('file has headers and rows with different lengths
|
255 |
+
* cannot connect');
|
256 |
+
* }
|
257 |
+
*
|
258 |
+
* var_export($csv->connect());
|
259 |
+
*
|
260 |
+
* array (
|
261 |
+
* 0 =>
|
262 |
+
* array (
|
263 |
+
* 'name' => 'john',
|
264 |
+
* 'age' => '13',
|
265 |
+
* 'skill' => 'knows magic',
|
266 |
+
* ),
|
267 |
+
* 1 =>
|
268 |
+
* array (
|
269 |
+
* 'name' => 'tanaka',
|
270 |
+
* 'age' => '8',
|
271 |
+
* 'skill' => 'makes sushi',
|
272 |
+
* ),
|
273 |
+
* 2 =>
|
274 |
+
* array (
|
275 |
+
* 'name' => 'jose',
|
276 |
+
* 'age' => '5',
|
277 |
+
* 'skill' => 'dances salsa',
|
278 |
+
* ),
|
279 |
+
* )
|
280 |
+
*
|
281 |
+
* </code>
|
282 |
+
*
|
283 |
+
*
|
284 |
+
* You can pass a collection of headers in an array to build
|
285 |
+
* a connection for those columns only!
|
286 |
+
*
|
287 |
+
* <code>
|
288 |
+
*
|
289 |
+
* var_export($csv->connect(array('age')));
|
290 |
+
*
|
291 |
+
* array (
|
292 |
+
* 0 =>
|
293 |
+
* array (
|
294 |
+
* 'age' => '13',
|
295 |
+
* ),
|
296 |
+
* 1 =>
|
297 |
+
* array (
|
298 |
+
* 'age' => '8',
|
299 |
+
* ),
|
300 |
+
* 2 =>
|
301 |
+
* array (
|
302 |
+
* 'age' => '5',
|
303 |
+
* ),
|
304 |
+
* )
|
305 |
+
*
|
306 |
+
* </code>
|
307 |
+
*
|
308 |
+
* @param array $columns the columns to connect, if nothing
|
309 |
+
* is given all headers will be used to create a connection
|
310 |
+
*
|
311 |
+
* @access public
|
312 |
+
* @return array If the data is not symmetric an empty array
|
313 |
+
* will be returned instead
|
314 |
+
* @see isSymmetric(), getAsymmetricRows(), symmetrize(), getHeaders()
|
315 |
+
*/
|
316 |
+
public function connect($columns = array())
|
317 |
+
{
|
318 |
+
if (!$this->isSymmetric()) {
|
319 |
+
return array();
|
320 |
+
}
|
321 |
+
if (!is_array($columns)) {
|
322 |
+
return array();
|
323 |
+
}
|
324 |
+
if ($columns === array()) {
|
325 |
+
$columns = $this->headers;
|
326 |
+
}
|
327 |
+
|
328 |
+
$ret_arr = array();
|
329 |
+
|
330 |
+
foreach ($this->rows as $record) {
|
331 |
+
$item_array = array();
|
332 |
+
foreach ($record as $column => $value) {
|
333 |
+
$header = $this->headers[$column];
|
334 |
+
if (in_array($header, $columns)) {
|
335 |
+
$item_array[$header] = $value;
|
336 |
+
}
|
337 |
+
}
|
338 |
+
|
339 |
+
// do not append empty results
|
340 |
+
if ($item_array !== array()) {
|
341 |
+
array_push($ret_arr, $item_array);
|
342 |
+
}
|
343 |
+
}
|
344 |
+
|
345 |
+
return $ret_arr;
|
346 |
+
}
|
347 |
+
|
348 |
+
/**
|
349 |
+
* data length/symmetry checker
|
350 |
+
*
|
351 |
+
* tells if the headers and all of the contents length match.
|
352 |
+
* Note: there is a lot of methods that won't work if data is not
|
353 |
+
* symmetric this method is very important!
|
354 |
+
*
|
355 |
+
* @access public
|
356 |
+
* @return boolean
|
357 |
+
* @see symmetrize(), getAsymmetricRows(), isSymmetric()
|
358 |
+
*/
|
359 |
+
public function isSymmetric()
|
360 |
+
{
|
361 |
+
$hc = count($this->headers);
|
362 |
+
foreach ($this->rows as $row) {
|
363 |
+
if (count($row) != $hc) {
|
364 |
+
return false;
|
365 |
+
}
|
366 |
+
}
|
367 |
+
return true;
|
368 |
+
}
|
369 |
+
|
370 |
+
/**
|
371 |
+
* asymmetric data fetcher
|
372 |
+
*
|
373 |
+
* finds the rows that do not match the headers length
|
374 |
+
*
|
375 |
+
* lets assume that we add one more row to our csv file.
|
376 |
+
* that has only two values. Something like
|
377 |
+
*
|
378 |
+
* <code>
|
379 |
+
* name,age,skill
|
380 |
+
* john,13,knows magic
|
381 |
+
* tanaka,8,makes sushi
|
382 |
+
* jose,5,dances salsa
|
383 |
+
* niki,6
|
384 |
+
* </code>
|
385 |
+
*
|
386 |
+
* Then in our php code
|
387 |
+
*
|
388 |
+
* <code>
|
389 |
+
* $csv->load('my_cool.csv');
|
390 |
+
* var_export($csv->getAsymmetricRows());
|
391 |
+
* </code>
|
392 |
+
*
|
393 |
+
* The result
|
394 |
+
*
|
395 |
+
* <code>
|
396 |
+
*
|
397 |
+
* array (
|
398 |
+
* 0 =>
|
399 |
+
* array (
|
400 |
+
* 0 => 'niki',
|
401 |
+
* 1 => '6',
|
402 |
+
* ),
|
403 |
+
* )
|
404 |
+
*
|
405 |
+
* </code>
|
406 |
+
*
|
407 |
+
* @access public
|
408 |
+
* @return array filled with rows that do not match headers
|
409 |
+
* @see getHeaders(), symmetrize(), isSymmetric(),
|
410 |
+
* getAsymmetricRows()
|
411 |
+
*/
|
412 |
+
public function getAsymmetricRows()
|
413 |
+
{
|
414 |
+
$ret_arr = array();
|
415 |
+
$hc = count($this->headers);
|
416 |
+
foreach ($this->rows as $row) {
|
417 |
+
if (count($row) != $hc) {
|
418 |
+
$ret_arr[] = $row;
|
419 |
+
}
|
420 |
+
}
|
421 |
+
return $ret_arr;
|
422 |
+
}
|
423 |
+
|
424 |
+
/**
|
425 |
+
* all rows length equalizer
|
426 |
+
*
|
427 |
+
* makes the length of all rows and headers the same. If no $value is given
|
428 |
+
* all unexistent cells will be filled with empty spaces
|
429 |
+
*
|
430 |
+
* @param mixed $value the value to fill the unexistent cells
|
431 |
+
*
|
432 |
+
* @access public
|
433 |
+
* @return array
|
434 |
+
* @see isSymmetric(), getAsymmetricRows(), symmetrize()
|
435 |
+
*/
|
436 |
+
public function symmetrize($value = '')
|
437 |
+
{
|
438 |
+
$max_length = 0;
|
439 |
+
$headers_length = count($this->headers);
|
440 |
+
|
441 |
+
foreach ($this->rows as $row) {
|
442 |
+
$row_length = count($row);
|
443 |
+
if ($max_length < $row_length) {
|
444 |
+
$max_length = $row_length;
|
445 |
+
}
|
446 |
+
}
|
447 |
+
|
448 |
+
if ($max_length < $headers_length) {
|
449 |
+
$max_length = $headers_length;
|
450 |
+
}
|
451 |
+
|
452 |
+
foreach ($this->rows as $key => $row) {
|
453 |
+
$this->rows[$key] = array_pad($row, $max_length, $value);
|
454 |
+
}
|
455 |
+
|
456 |
+
$this->headers = array_pad($this->headers, $max_length, $value);
|
457 |
+
}
|
458 |
+
|
459 |
+
/**
|
460 |
+
* grid walker
|
461 |
+
*
|
462 |
+
* travels through the whole dataset executing a callback per each
|
463 |
+
* cell
|
464 |
+
*
|
465 |
+
* Note: callback functions get the value of the cell as an
|
466 |
+
* argument, and whatever that callback returns will be used to
|
467 |
+
* replace the current value of that cell.
|
468 |
+
*
|
469 |
+
* @param string $callback the callback function to be called per
|
470 |
+
* each cell in the dataset.
|
471 |
+
*
|
472 |
+
* @access public
|
473 |
+
* @return void
|
474 |
+
* @see walkColumn(), walkRow(), fillColumn(), fillRow(), fillCell()
|
475 |
+
*/
|
476 |
+
public function walkGrid($callback)
|
477 |
+
{
|
478 |
+
foreach (array_keys($this->getRows()) as $key) {
|
479 |
+
if (!$this->walkRow($key, $callback)) {
|
480 |
+
return false;
|
481 |
+
}
|
482 |
+
}
|
483 |
+
return true;
|
484 |
+
}
|
485 |
+
|
486 |
+
/**
|
487 |
+
* column fetcher
|
488 |
+
*
|
489 |
+
* gets all the data for a specific column identified by $name
|
490 |
+
*
|
491 |
+
* Note $name is the same as the items returned by getHeaders()
|
492 |
+
*
|
493 |
+
* sample of a csv file "my_cool.csv"
|
494 |
+
*
|
495 |
+
* <code>
|
496 |
+
* name,age,skill
|
497 |
+
* john,13,knows magic
|
498 |
+
* tanaka,8,makes sushi
|
499 |
+
* jose,5,dances salsa
|
500 |
+
* </code>
|
501 |
+
*
|
502 |
+
* php implementation
|
503 |
+
*
|
504 |
+
* <code>
|
505 |
+
* $csv = new File_CSV_DataSource;
|
506 |
+
* $csv->load('my_cool.csv');
|
507 |
+
* var_export($csv->getColumn('name'));
|
508 |
+
* </code>
|
509 |
+
*
|
510 |
+
* the above example outputs something like
|
511 |
+
*
|
512 |
+
* <code>
|
513 |
+
*
|
514 |
+
* array (
|
515 |
+
* 0 => 'john',
|
516 |
+
* 1 => 'tanaka',
|
517 |
+
* 2 => 'jose',
|
518 |
+
* )
|
519 |
+
*
|
520 |
+
* </code>
|
521 |
+
*
|
522 |
+
* @param string $name the name of the column to fetch
|
523 |
+
*
|
524 |
+
* @access public
|
525 |
+
* @return array filled with values of a column
|
526 |
+
* @see getHeaders(), fillColumn(), appendColumn(), getCell(), getRows(),
|
527 |
+
* getRow(), hasColumn()
|
528 |
+
*/
|
529 |
+
public function getColumn($name)
|
530 |
+
{
|
531 |
+
if (!in_array($name, $this->headers)) {
|
532 |
+
return array();
|
533 |
+
}
|
534 |
+
$ret_arr = array();
|
535 |
+
$key = array_search($name, $this->headers, true);
|
536 |
+
foreach ($this->rows as $data) {
|
537 |
+
$ret_arr[] = $data[$key];
|
538 |
+
}
|
539 |
+
return $ret_arr;
|
540 |
+
}
|
541 |
+
|
542 |
+
/**
|
543 |
+
* column existance checker
|
544 |
+
*
|
545 |
+
* checks if a column exists, columns are identified by their
|
546 |
+
* header name.
|
547 |
+
*
|
548 |
+
* sample of a csv file "my_cool.csv"
|
549 |
+
*
|
550 |
+
* <code>
|
551 |
+
* name,age,skill
|
552 |
+
* john,13,knows magic
|
553 |
+
* tanaka,8,makes sushi
|
554 |
+
* jose,5,dances salsa
|
555 |
+
* </code>
|
556 |
+
*
|
557 |
+
* php implementation
|
558 |
+
*
|
559 |
+
* <code>
|
560 |
+
* $csv = new File_CSV_DataSource;
|
561 |
+
* $csv->load('my_cool.csv');
|
562 |
+
* $headers = $csv->getHeaders();
|
563 |
+
* </code>
|
564 |
+
*
|
565 |
+
* now lets check if the columns exist
|
566 |
+
*
|
567 |
+
* <code>
|
568 |
+
* var_export($csv->hasColumn($headers[0])); // true
|
569 |
+
* var_export($csv->hasColumn('age')); // true
|
570 |
+
* var_export($csv->hasColumn('I dont exist')); // false
|
571 |
+
* </code>
|
572 |
+
*
|
573 |
+
* @param string $string an item returned by getHeaders()
|
574 |
+
*
|
575 |
+
* @access public
|
576 |
+
* @return boolean
|
577 |
+
* @see getHeaders()
|
578 |
+
*/
|
579 |
+
public function hasColumn($string)
|
580 |
+
{
|
581 |
+
return in_array($string, $this->headers);
|
582 |
+
}
|
583 |
+
|
584 |
+
/**
|
585 |
+
* column appender
|
586 |
+
*
|
587 |
+
* Appends a column and each or all values in it can be
|
588 |
+
* dinamically filled. Only when the $values argument is given.
|
589 |
+
* <code>
|
590 |
+
*
|
591 |
+
*
|
592 |
+
* var_export($csv->fillColumn('age', 99));
|
593 |
+
* true
|
594 |
+
*
|
595 |
+
* var_export($csv->appendColumn('candy_ownership', array(99, 44, 65)));
|
596 |
+
* true
|
597 |
+
*
|
598 |
+
* var_export($csv->appendColumn('import_id', 111111111));
|
599 |
+
* true
|
600 |
+
*
|
601 |
+
* var_export($csv->connect());
|
602 |
+
*
|
603 |
+
* array (
|
604 |
+
* 0 =>
|
605 |
+
* array (
|
606 |
+
* 'name' => 'john',
|
607 |
+
* 'age' => 99,
|
608 |
+
* 'skill' => 'knows magic',
|
609 |
+
* 'candy_ownership' => 99,
|
610 |
+
* 'import_id' => 111111111,
|
611 |
+
* ),
|
612 |
+
* 1 =>
|
613 |
+
* array (
|
614 |
+
* 'name' => 'tanaka',
|
615 |
+
* 'age' => 99,
|
616 |
+
* 'skill' => 'makes sushi',
|
617 |
+
* 'candy_ownership' => 44,
|
618 |
+
* 'import_id' => 111111111,
|
619 |
+
* ),
|
620 |
+
* 2 =>
|
621 |
+
* array (
|
622 |
+
* 'name' => 'jose',
|
623 |
+
* 'age' => 99,
|
624 |
+
* 'skill' => 'dances salsa',
|
625 |
+
* 'candy_ownership' => 65,
|
626 |
+
* 'import_id' => 111111111,
|
627 |
+
* ),
|
628 |
+
* )
|
629 |
+
*
|
630 |
+
* </code>
|
631 |
+
*
|
632 |
+
* @param string $column an item returned by getHeaders()
|
633 |
+
* @param mixed $values same as fillColumn()
|
634 |
+
*
|
635 |
+
* @access public
|
636 |
+
* @return boolean
|
637 |
+
* @see getHeaders(), fillColumn(), fillCell(), createHeaders(),
|
638 |
+
* setHeaders()
|
639 |
+
*/
|
640 |
+
public function appendColumn($column, $values = null)
|
641 |
+
{
|
642 |
+
if ($this->hasColumn($column)) {
|
643 |
+
return false;
|
644 |
+
}
|
645 |
+
$this->headers[] = $column;
|
646 |
+
$length = $this->countHeaders();
|
647 |
+
$rows = array();
|
648 |
+
|
649 |
+
foreach ($this->rows as $row) {
|
650 |
+
$rows[] = array_pad($row, $length, '');
|
651 |
+
}
|
652 |
+
|
653 |
+
$this->rows = $rows;
|
654 |
+
|
655 |
+
if ($values === null) {
|
656 |
+
$values = '';
|
657 |
+
}
|
658 |
+
|
659 |
+
return $this->fillColumn($column, $values);
|
660 |
+
}
|
661 |
+
|
662 |
+
/**
|
663 |
+
* collumn data injector
|
664 |
+
*
|
665 |
+
* fills alll the data in the given column with $values
|
666 |
+
*
|
667 |
+
* sample of a csv file "my_cool.csv"
|
668 |
+
*
|
669 |
+
* <code>
|
670 |
+
* name,age,skill
|
671 |
+
* john,13,knows magic
|
672 |
+
* tanaka,8,makes sushi
|
673 |
+
* jose,5,dances salsa
|
674 |
+
* </code>
|
675 |
+
*
|
676 |
+
* php implementation
|
677 |
+
*
|
678 |
+
* <code>
|
679 |
+
* $csv = new File_CSV_DataSource;
|
680 |
+
* $csv->load('my_cool.csv');
|
681 |
+
*
|
682 |
+
* // if the csv file loads
|
683 |
+
* if ($csv->load('my_cool.csv')) {
|
684 |
+
*
|
685 |
+
* // grab all data within the age column
|
686 |
+
* var_export($csv->getColumn('age'));
|
687 |
+
*
|
688 |
+
* // rename all values in it with the number 99
|
689 |
+
* var_export($csv->fillColumn('age', 99));
|
690 |
+
*
|
691 |
+
* // grab all data within the age column
|
692 |
+
* var_export($csv->getColumn('age'));
|
693 |
+
*
|
694 |
+
* // rename each value in a column independently
|
695 |
+
* $data = array(1, 2, 3);
|
696 |
+
* $csv->fillColumn('age', $data);
|
697 |
+
*
|
698 |
+
* var_export($csv->getColumn('age'));
|
699 |
+
* }
|
700 |
+
* </code>
|
701 |
+
*
|
702 |
+
* standard output
|
703 |
+
*
|
704 |
+
* <code>
|
705 |
+
* array (
|
706 |
+
* 0 => '13',
|
707 |
+
* 1 => '8',
|
708 |
+
* 2 => '5',
|
709 |
+
* )
|
710 |
+
* </code>
|
711 |
+
*
|
712 |
+
* <code>
|
713 |
+
* true
|
714 |
+
* </code>
|
715 |
+
*
|
716 |
+
* <code>
|
717 |
+
* array (
|
718 |
+
* 0 => 99,
|
719 |
+
* 1 => 99,
|
720 |
+
* 2 => 99,
|
721 |
+
* )
|
722 |
+
* </code>
|
723 |
+
*
|
724 |
+
* <code>
|
725 |
+
* array (
|
726 |
+
* 0 => 1,
|
727 |
+
* 1 => 2,
|
728 |
+
* 2 => 3,
|
729 |
+
* )
|
730 |
+
* </code>
|
731 |
+
*
|
732 |
+
* @param mixed $column the column identified by a string
|
733 |
+
* @param mixed $values ither one of the following
|
734 |
+
* - (Number) will fill the whole column with the value of number
|
735 |
+
* - (String) will fill the whole column with the value of string
|
736 |
+
* - (Array) will fill the while column with the values of array
|
737 |
+
* the array gets ignored if it does not match the length of rows
|
738 |
+
*
|
739 |
+
* @access public
|
740 |
+
* @return void
|
741 |
+
*/
|
742 |
+
public function fillColumn($column, $values = null)
|
743 |
+
{
|
744 |
+
if (!$this->hasColumn($column)) {
|
745 |
+
return false;
|
746 |
+
}
|
747 |
+
|
748 |
+
if ($values === null) {
|
749 |
+
return false;
|
750 |
+
}
|
751 |
+
|
752 |
+
if (!$this->isSymmetric()) {
|
753 |
+
return false;
|
754 |
+
}
|
755 |
+
|
756 |
+
$y = array_search($column, $this->headers);
|
757 |
+
|
758 |
+
if (is_numeric($values) || is_string($values)) {
|
759 |
+
foreach (range(0, $this->countRows() -1) as $x) {
|
760 |
+
$this->fillCell($x, $y, $values);
|
761 |
+
}
|
762 |
+
return true;
|
763 |
+
}
|
764 |
+
|
765 |
+
if ($values === array()) {
|
766 |
+
return false;
|
767 |
+
}
|
768 |
+
|
769 |
+
$length = $this->countRows();
|
770 |
+
if (is_array($values) && $length == count($values)) {
|
771 |
+
for ($x = 0; $x < $length; $x++) {
|
772 |
+
$this->fillCell($x, $y, $values[$x]);
|
773 |
+
}
|
774 |
+
return true;
|
775 |
+
}
|
776 |
+
|
777 |
+
return false;
|
778 |
+
}
|
779 |
+
|
780 |
+
/**
|
781 |
+
* column remover
|
782 |
+
*
|
783 |
+
* Completly removes a whole column identified by $name
|
784 |
+
* Note: that this function will only work if data is symmetric.
|
785 |
+
*
|
786 |
+
* sample of a csv file "my_cool.csv"
|
787 |
+
*
|
788 |
+
* <code>
|
789 |
+
* name,age,skill
|
790 |
+
* john,13,knows magic
|
791 |
+
* tanaka,8,makes sushi
|
792 |
+
* jose,5,dances salsa
|
793 |
+
* </code>
|
794 |
+
*
|
795 |
+
* load the library and csv file
|
796 |
+
*
|
797 |
+
* <code>
|
798 |
+
* require_once 'File/CSV/DataSource.php';
|
799 |
+
* $csv = new File_CSV_DataSource;
|
800 |
+
* $csv->load('my_cool.csv');
|
801 |
+
* </code>
|
802 |
+
*
|
803 |
+
* lets dump currently loaded data
|
804 |
+
* <code>
|
805 |
+
* var_export($csv->connect());
|
806 |
+
* </code>
|
807 |
+
*
|
808 |
+
* output
|
809 |
+
*
|
810 |
+
* <code>
|
811 |
+
* array (
|
812 |
+
* 0 =>
|
813 |
+
* array (
|
814 |
+
* 'name' => 'john',
|
815 |
+
* 'age' => '13',
|
816 |
+
* 'skill' => 'knows magic',
|
817 |
+
* ),
|
818 |
+
* 1 =>
|
819 |
+
* array (
|
820 |
+
* 'name' => 'tanaka',
|
821 |
+
* 'age' => '8',
|
822 |
+
* 'skill' => 'makes sushi',
|
823 |
+
* ),
|
824 |
+
* 2 =>
|
825 |
+
* array (
|
826 |
+
* 'name' => 'jose',
|
827 |
+
* 'age' => '5',
|
828 |
+
* 'skill' => 'dances salsa',
|
829 |
+
* ),
|
830 |
+
* )
|
831 |
+
* </code>
|
832 |
+
*
|
833 |
+
* and now let's remove the second column
|
834 |
+
*
|
835 |
+
* <code>
|
836 |
+
* var_export($csv->removeColumn('age'));
|
837 |
+
* </code>
|
838 |
+
*
|
839 |
+
* output
|
840 |
+
*
|
841 |
+
* <code>
|
842 |
+
* true
|
843 |
+
* </code>
|
844 |
+
*
|
845 |
+
* those changes made let's dump the data again and see what we got
|
846 |
+
*
|
847 |
+
* <code>
|
848 |
+
* array (
|
849 |
+
* 0 =>
|
850 |
+
* array (
|
851 |
+
* 'name' => 'john',
|
852 |
+
* 'skill' => 'knows magic',
|
853 |
+
* ),
|
854 |
+
* 1 =>
|
855 |
+
* array (
|
856 |
+
* 'name' => 'tanaka',
|
857 |
+
* 'skill' => 'makes sushi',
|
858 |
+
* ),
|
859 |
+
* 2 =>
|
860 |
+
* array (
|
861 |
+
* 'name' => 'jose',
|
862 |
+
* 'skill' => 'dances salsa',
|
863 |
+
* ),
|
864 |
+
* )
|
865 |
+
* </code>
|
866 |
+
*
|
867 |
+
* @param string $name same as the ones returned by getHeaders();
|
868 |
+
*
|
869 |
+
* @access public
|
870 |
+
* @return boolean
|
871 |
+
* @see hasColumn(), getHeaders(), createHeaders(), setHeaders(),
|
872 |
+
* isSymmetric(), getAsymmetricRows()
|
873 |
+
*/
|
874 |
+
public function removeColumn($name)
|
875 |
+
{
|
876 |
+
if (!in_array($name, $this->headers)) {
|
877 |
+
return false;
|
878 |
+
}
|
879 |
+
|
880 |
+
if (!$this->isSymmetric()) {
|
881 |
+
return false;
|
882 |
+
}
|
883 |
+
|
884 |
+
$key = array_search($name, $this->headers);
|
885 |
+
unset($this->headers[$key]);
|
886 |
+
$this->resetKeys($this->headers);
|
887 |
+
|
888 |
+
foreach ($this->rows as $target => $row) {
|
889 |
+
unset($this->rows[$target][$key]);
|
890 |
+
$this->resetKeys($this->rows[$target]);
|
891 |
+
}
|
892 |
+
|
893 |
+
return $this->isSymmetric();
|
894 |
+
}
|
895 |
+
|
896 |
+
/**
|
897 |
+
* column walker
|
898 |
+
*
|
899 |
+
* goes through the whole column and executes a callback for each
|
900 |
+
* one of the cells in it.
|
901 |
+
*
|
902 |
+
* Note: callback functions get the value of the cell as an
|
903 |
+
* argument, and whatever that callback returns will be used to
|
904 |
+
* replace the current value of that cell.
|
905 |
+
*
|
906 |
+
* @param string $name the header name used to identify the column
|
907 |
+
* @param string $callback the callback function to be called per
|
908 |
+
* each cell value
|
909 |
+
*
|
910 |
+
* @access public
|
911 |
+
* @return boolean
|
912 |
+
* @see getHeaders(), fillColumn(), appendColumn()
|
913 |
+
*/
|
914 |
+
public function walkColumn($name, $callback)
|
915 |
+
{
|
916 |
+
if (!$this->isSymmetric()) {
|
917 |
+
return false;
|
918 |
+
}
|
919 |
+
|
920 |
+
if (!$this->hasColumn($name)) {
|
921 |
+
return false;
|
922 |
+
}
|
923 |
+
|
924 |
+
if (!function_exists($callback)) {
|
925 |
+
return false;
|
926 |
+
}
|
927 |
+
|
928 |
+
$column = $this->getColumn($name);
|
929 |
+
foreach ($column as $key => $cell) {
|
930 |
+
$column[$key] = $callback($cell);
|
931 |
+
}
|
932 |
+
return $this->fillColumn($name, $column);
|
933 |
+
}
|
934 |
+
|
935 |
+
/**
|
936 |
+
* cell fetcher
|
937 |
+
*
|
938 |
+
* gets the value of a specific cell by given coordinates
|
939 |
+
*
|
940 |
+
* Note: That indexes start with zero, and headers are not
|
941 |
+
* searched!
|
942 |
+
*
|
943 |
+
* For example if we are trying to grab the cell that is in the
|
944 |
+
* second row and the third column
|
945 |
+
*
|
946 |
+
* <code>
|
947 |
+
* name,age,skill
|
948 |
+
* john,13,knows magic
|
949 |
+
* tanaka,8,makes sushi
|
950 |
+
* jose,5,dances salsa
|
951 |
+
* </code>
|
952 |
+
*
|
953 |
+
* we would do something like
|
954 |
+
* <code>
|
955 |
+
* var_export($csv->getCell(1, 2));
|
956 |
+
* </code>
|
957 |
+
*
|
958 |
+
* and get the following results
|
959 |
+
* <code>
|
960 |
+
* 'makes sushi'
|
961 |
+
* </code>
|
962 |
+
*
|
963 |
+
* @param integer $x the row to fetch
|
964 |
+
* @param integer $y the column to fetch
|
965 |
+
*
|
966 |
+
* @access public
|
967 |
+
* @return mixed|false the value of the cell or false if the cell does
|
968 |
+
* not exist
|
969 |
+
* @see getHeaders(), hasCell(), getRow(), getRows(), getColumn()
|
970 |
+
*/
|
971 |
+
public function getCell($x, $y)
|
972 |
+
{
|
973 |
+
if ($this->hasCell($x, $y)) {
|
974 |
+
$row = $this->getRow($x);
|
975 |
+
return $row[$y];
|
976 |
+
}
|
977 |
+
return false;
|
978 |
+
}
|
979 |
+
|
980 |
+
/**
|
981 |
+
* cell value filler
|
982 |
+
*
|
983 |
+
* replaces the value of a specific cell
|
984 |
+
*
|
985 |
+
* sample of a csv file "my_cool.csv"
|
986 |
+
*
|
987 |
+
* <code>
|
988 |
+
* name,age,skill
|
989 |
+
* john,13,knows magic
|
990 |
+
* tanaka,8,makes sushi
|
991 |
+
* jose,5,dances salsa
|
992 |
+
* </code>
|
993 |
+
*
|
994 |
+
* php implementation
|
995 |
+
*
|
996 |
+
* <code>
|
997 |
+
*
|
998 |
+
* $csv = new File_CSV_DataSource;
|
999 |
+
*
|
1000 |
+
* // load the csv file
|
1001 |
+
* $csv->load('my_cool.csv');
|
1002 |
+
*
|
1003 |
+
* // find out if the given coordinate is valid
|
1004 |
+
* if($csv->hasCell(1, 1)) {
|
1005 |
+
*
|
1006 |
+
* // if so grab that cell and dump it
|
1007 |
+
* var_export($csv->getCell(1, 1)); // '8'
|
1008 |
+
*
|
1009 |
+
* // replace the value of that cell
|
1010 |
+
* $csv->fillCell(1, 1, 'new value'); // true
|
1011 |
+
*
|
1012 |
+
* // output the new value of the cell
|
1013 |
+
* var_export($csv->getCell(1, 1)); // 'new value'
|
1014 |
+
*
|
1015 |
+
* }
|
1016 |
+
* </code>
|
1017 |
+
*
|
1018 |
+
* now lets try to grab the whole row
|
1019 |
+
*
|
1020 |
+
* <code>
|
1021 |
+
* // show the whole row
|
1022 |
+
* var_export($csv->getRow(1));
|
1023 |
+
* </code>
|
1024 |
+
*
|
1025 |
+
* standard output
|
1026 |
+
*
|
1027 |
+
* <code>
|
1028 |
+
* array (
|
1029 |
+
* 0 => 'tanaka',
|
1030 |
+
* 1 => 'new value',
|
1031 |
+
* 2 => 'makes sushi',
|
1032 |
+
* )
|
1033 |
+
* </code>
|
1034 |
+
*
|
1035 |
+
* @param integer $x the row to fetch
|
1036 |
+
* @param integer $y the column to fetch
|
1037 |
+
* @param mixed $value the value to fill the cell with
|
1038 |
+
*
|
1039 |
+
* @access public
|
1040 |
+
* @return boolean
|
1041 |
+
* @see hasCell(), getRow(), getRows(), getColumn()
|
1042 |
+
*/
|
1043 |
+
public function fillCell($x, $y, $value)
|
1044 |
+
{
|
1045 |
+
if (!$this->hasCell($x, $y)) {
|
1046 |
+
return false;
|
1047 |
+
}
|
1048 |
+
$row = $this->getRow($x);
|
1049 |
+
$row[$y] = $value;
|
1050 |
+
$this->rows[$x] = $row;
|
1051 |
+
return true;
|
1052 |
+
}
|
1053 |
+
|
1054 |
+
/**
|
1055 |
+
* checks if a coordinate is valid
|
1056 |
+
*
|
1057 |
+
* sample of a csv file "my_cool.csv"
|
1058 |
+
*
|
1059 |
+
* <code>
|
1060 |
+
* name,age,skill
|
1061 |
+
* john,13,knows magic
|
1062 |
+
* tanaka,8,makes sushi
|
1063 |
+
* jose,5,dances salsa
|
1064 |
+
* </code>
|
1065 |
+
*
|
1066 |
+
* load the csv file
|
1067 |
+
*
|
1068 |
+
* <code>
|
1069 |
+
* $csv = new File_CSV_DataSource;
|
1070 |
+
* var_export($csv->load('my_cool.csv')); // true if file is
|
1071 |
+
* // loaded
|
1072 |
+
* </code>
|
1073 |
+
*
|
1074 |
+
* find out if a coordinate is valid
|
1075 |
+
*
|
1076 |
+
* <code>
|
1077 |
+
* var_export($csv->hasCell(99, 3)); // false
|
1078 |
+
* </code>
|
1079 |
+
*
|
1080 |
+
* check again for a know valid coordinate and grab that cell
|
1081 |
+
*
|
1082 |
+
* <code>
|
1083 |
+
* var_export($csv->hasCell(1, 1)); // true
|
1084 |
+
* var_export($csv->getCell(1, 1)); // '8'
|
1085 |
+
* </code>
|
1086 |
+
*
|
1087 |
+
* @param mixed $x the row to fetch
|
1088 |
+
* @param mixed $y the column to fetch
|
1089 |
+
*
|
1090 |
+
* @access public
|
1091 |
+
* @return void
|
1092 |
+
*/
|
1093 |
+
public function hasCell($x, $y)
|
1094 |
+
{
|
1095 |
+
$has_x = array_key_exists($x, $this->rows);
|
1096 |
+
$has_y = array_key_exists($y, $this->headers);
|
1097 |
+
return ($has_x && $has_y);
|
1098 |
+
}
|
1099 |
+
|
1100 |
+
/**
|
1101 |
+
* row fetcher
|
1102 |
+
*
|
1103 |
+
* Note: first row is zero
|
1104 |
+
*
|
1105 |
+
* sample of a csv file "my_cool.csv"
|
1106 |
+
*
|
1107 |
+
* <code>
|
1108 |
+
* name,age,skill
|
1109 |
+
* john,13,knows magic
|
1110 |
+
* tanaka,8,makes sushi
|
1111 |
+
* jose,5,dances salsa
|
1112 |
+
* </code>
|
1113 |
+
*
|
1114 |
+
* load the library and csv file
|
1115 |
+
*
|
1116 |
+
* <code>
|
1117 |
+
* require_once 'File/CSV/DataSource.php';
|
1118 |
+
* $csv = new File_CSV_DataSource;
|
1119 |
+
* $csv->load('my_cool.csv');
|
1120 |
+
* </code>
|
1121 |
+
*
|
1122 |
+
* lets dump currently loaded data
|
1123 |
+
* <code>
|
1124 |
+
* var_export($csv->connect());
|
1125 |
+
* </code>
|
1126 |
+
*
|
1127 |
+
* output
|
1128 |
+
*
|
1129 |
+
* <code>
|
1130 |
+
* array (
|
1131 |
+
* 0 =>
|
1132 |
+
* array (
|
1133 |
+
* 'name' => 'john',
|
1134 |
+
* 'age' => '13',
|
1135 |
+
* 'skill' => 'knows magic',
|
1136 |
+
* ),
|
1137 |
+
* 1 =>
|
1138 |
+
* array (
|
1139 |
+
* 'name' => 'tanaka',
|
1140 |
+
* 'age' => '8',
|
1141 |
+
* 'skill' => 'makes sushi',
|
1142 |
+
* ),
|
1143 |
+
* 2 =>
|
1144 |
+
* array (
|
1145 |
+
* 'name' => 'jose',
|
1146 |
+
* 'age' => '5',
|
1147 |
+
* 'skill' => 'dances salsa',
|
1148 |
+
* ),
|
1149 |
+
* )
|
1150 |
+
* </code>
|
1151 |
+
*
|
1152 |
+
* Now let's fetch the second row
|
1153 |
+
*
|
1154 |
+
* <code>
|
1155 |
+
* var_export($csv->getRow(1));
|
1156 |
+
* </code>
|
1157 |
+
*
|
1158 |
+
* output
|
1159 |
+
*
|
1160 |
+
* <code>
|
1161 |
+
* array (
|
1162 |
+
* 0 => 'tanaka',
|
1163 |
+
* 1 => '8',
|
1164 |
+
* 2 => 'makes sushi',
|
1165 |
+
* )
|
1166 |
+
* </code>
|
1167 |
+
*
|
1168 |
+
* @param integer $number the row number to fetch
|
1169 |
+
*
|
1170 |
+
* @access public
|
1171 |
+
* @return array the row identified by number, if $number does
|
1172 |
+
* not exist an empty array is returned instead
|
1173 |
+
*/
|
1174 |
+
public function getRow($number)
|
1175 |
+
{
|
1176 |
+
$raw = $this->rows;
|
1177 |
+
if (array_key_exists($number, $raw)) {
|
1178 |
+
return $raw[$number];
|
1179 |
+
}
|
1180 |
+
return array();
|
1181 |
+
}
|
1182 |
+
|
1183 |
+
/**
|
1184 |
+
* multiple row fetcher
|
1185 |
+
*
|
1186 |
+
* Extracts a rows in the following fashion
|
1187 |
+
* - all rows if no $range argument is given
|
1188 |
+
* - a range of rows identified by their key
|
1189 |
+
* - if rows in range are not found nothing is retrived instead
|
1190 |
+
* - if no rows were found an empty array is returned
|
1191 |
+
*
|
1192 |
+
* sample of a csv file "my_cool.csv"
|
1193 |
+
*
|
1194 |
+
* <code>
|
1195 |
+
* name,age,skill
|
1196 |
+
* john,13,knows magic
|
1197 |
+
* tanaka,8,makes sushi
|
1198 |
+
* jose,5,dances salsa
|
1199 |
+
* </code>
|
1200 |
+
*
|
1201 |
+
* load the library and csv file
|
1202 |
+
*
|
1203 |
+
* <code>
|
1204 |
+
* require_once 'File/CSV/DataSource.php';
|
1205 |
+
* $csv = new File_CSV_DataSource;
|
1206 |
+
* $csv->load('my_cool.csv');
|
1207 |
+
* </code>
|
1208 |
+
*
|
1209 |
+
* lets dump currently loaded data
|
1210 |
+
* <code>
|
1211 |
+
* var_export($csv->connect());
|
1212 |
+
* </code>
|
1213 |
+
*
|
1214 |
+
* output
|
1215 |
+
*
|
1216 |
+
* <code>
|
1217 |
+
* array (
|
1218 |
+
* 0 =>
|
1219 |
+
* array (
|
1220 |
+
* 'name' => 'john',
|
1221 |
+
* 'age' => '13',
|
1222 |
+
* 'skill' => 'knows magic',
|
1223 |
+
* ),
|
1224 |
+
* 1 =>
|
1225 |
+
* array (
|
1226 |
+
* 'name' => 'tanaka',
|
1227 |
+
* 'age' => '8',
|
1228 |
+
* 'skill' => 'makes sushi',
|
1229 |
+
* ),
|
1230 |
+
* 2 =>
|
1231 |
+
* array (
|
1232 |
+
* 'name' => 'jose',
|
1233 |
+
* 'age' => '5',
|
1234 |
+
* 'skill' => 'dances salsa',
|
1235 |
+
* ),
|
1236 |
+
* )
|
1237 |
+
* </code>
|
1238 |
+
*
|
1239 |
+
* now get the second and thirdh row
|
1240 |
+
*
|
1241 |
+
* <code>
|
1242 |
+
* var_export($csv->getRows(array(1, 2)));
|
1243 |
+
* </code>
|
1244 |
+
*
|
1245 |
+
* output
|
1246 |
+
*
|
1247 |
+
* <code>
|
1248 |
+
* array (
|
1249 |
+
* 0 =>
|
1250 |
+
* array (
|
1251 |
+
* 0 => 'tanaka',
|
1252 |
+
* 1 => '8',
|
1253 |
+
* 2 => 'makes sushi',
|
1254 |
+
* ),
|
1255 |
+
* 1 =>
|
1256 |
+
* array (
|
1257 |
+
* 0 => 'jose',
|
1258 |
+
* 1 => '5',
|
1259 |
+
* 2 => 'dances salsa',
|
1260 |
+
* ),
|
1261 |
+
* )
|
1262 |
+
* </code>
|
1263 |
+
*
|
1264 |
+
* now lets try something odd and the goodie third row
|
1265 |
+
*
|
1266 |
+
* <code>
|
1267 |
+
* var_export($csv->getRows(array(9, 2)));
|
1268 |
+
* </code>
|
1269 |
+
*
|
1270 |
+
* output
|
1271 |
+
*
|
1272 |
+
* <code>
|
1273 |
+
* array (
|
1274 |
+
* 0 =>
|
1275 |
+
* array (
|
1276 |
+
* 0 => 'jose',
|
1277 |
+
* 1 => '5',
|
1278 |
+
* 2 => 'dances salsa',
|
1279 |
+
* ),
|
1280 |
+
* )
|
1281 |
+
* </code>
|
1282 |
+
*
|
1283 |
+
* @param array $range a list of rows to retrive
|
1284 |
+
*
|
1285 |
+
* @access public
|
1286 |
+
* @return array
|
1287 |
+
*/
|
1288 |
+
public function getRows($range = array())
|
1289 |
+
{
|
1290 |
+
if (is_array($range) && ($range === array())) {
|
1291 |
+
return $this->rows;
|
1292 |
+
}
|
1293 |
+
|
1294 |
+
if (!is_array($range)) {
|
1295 |
+
return $this->rows;
|
1296 |
+
}
|
1297 |
+
|
1298 |
+
$ret_arr = array();
|
1299 |
+
foreach ($this->rows as $key => $row) {
|
1300 |
+
if (in_array($key, $range)) {
|
1301 |
+
$ret_arr[] = $row;
|
1302 |
+
}
|
1303 |
+
}
|
1304 |
+
return $ret_arr;
|
1305 |
+
}
|
1306 |
+
|
1307 |
+
/**
|
1308 |
+
* row counter
|
1309 |
+
*
|
1310 |
+
* This function will exclude the headers
|
1311 |
+
*
|
1312 |
+
* sample of a csv file "my_cool.csv"
|
1313 |
+
*
|
1314 |
+
* <code>
|
1315 |
+
* name,age,skill
|
1316 |
+
* john,13,knows magic
|
1317 |
+
* tanaka,8,makes sushi
|
1318 |
+
* jose,5,dances salsa
|
1319 |
+
* </code>
|
1320 |
+
*
|
1321 |
+
* php implementation
|
1322 |
+
*
|
1323 |
+
* <code>
|
1324 |
+
* $csv = new File_CSV_DataSource;
|
1325 |
+
* $csv->load('my_cool.csv');
|
1326 |
+
* var_export($csv->countRows()); // returns 3
|
1327 |
+
* </code>
|
1328 |
+
*
|
1329 |
+
* @access public
|
1330 |
+
* @return integer
|
1331 |
+
*/
|
1332 |
+
public function countRows()
|
1333 |
+
{
|
1334 |
+
return count($this->rows);
|
1335 |
+
}
|
1336 |
+
|
1337 |
+
/**
|
1338 |
+
* row appender
|
1339 |
+
*
|
1340 |
+
* Aggregates one more row to the currently loaded dataset
|
1341 |
+
*
|
1342 |
+
* sample of a csv file "my_cool.csv"
|
1343 |
+
*
|
1344 |
+
* <code>
|
1345 |
+
* name,age,skill
|
1346 |
+
* john,13,knows magic
|
1347 |
+
* tanaka,8,makes sushi
|
1348 |
+
* jose,5,dances salsa
|
1349 |
+
* </code>
|
1350 |
+
*
|
1351 |
+
*
|
1352 |
+
* first let's load the file and output whatever was retrived.
|
1353 |
+
*
|
1354 |
+
* <code>
|
1355 |
+
* require_once 'File/CSV/DataSource.php';
|
1356 |
+
* $csv = new File_CSV_DataSource;
|
1357 |
+
* $csv->load('my_cool.csv');
|
1358 |
+
* var_export($csv->connect());
|
1359 |
+
* </code>
|
1360 |
+
*
|
1361 |
+
* output
|
1362 |
+
*
|
1363 |
+
* <code>
|
1364 |
+
*
|
1365 |
+
* array (
|
1366 |
+
* 0 =>
|
1367 |
+
* array (
|
1368 |
+
* 'name' => 'john',
|
1369 |
+
* 'age' => '13',
|
1370 |
+
* 'skill' => 'knows magic',
|
1371 |
+
* ),
|
1372 |
+
* 1 =>
|
1373 |
+
* array (
|
1374 |
+
* 'name' => 'tanaka',
|
1375 |
+
* 'age' => '8',
|
1376 |
+
* 'skill' => 'makes sushi',
|
1377 |
+
* ),
|
1378 |
+
* 2 =>
|
1379 |
+
* array (
|
1380 |
+
* 'name' => 'jose',
|
1381 |
+
* 'age' => '5',
|
1382 |
+
* 'skill' => 'dances salsa',
|
1383 |
+
* ),
|
1384 |
+
* )
|
1385 |
+
* </code>
|
1386 |
+
*
|
1387 |
+
* now lets do some modifications, let's try adding three rows.
|
1388 |
+
*
|
1389 |
+
* <code>
|
1390 |
+
* var_export($csv->appendRow(1));
|
1391 |
+
* var_export($csv->appendRow('2'));
|
1392 |
+
* var_export($csv->appendRow(array(3, 3, 3)));
|
1393 |
+
* </code>
|
1394 |
+
*
|
1395 |
+
* output
|
1396 |
+
*
|
1397 |
+
* <code>
|
1398 |
+
* true
|
1399 |
+
* true
|
1400 |
+
* true
|
1401 |
+
* </code>
|
1402 |
+
*
|
1403 |
+
* and now let's try to see what has changed
|
1404 |
+
*
|
1405 |
+
* <code>
|
1406 |
+
* var_export($csv->connect());
|
1407 |
+
* </code>
|
1408 |
+
*
|
1409 |
+
* output
|
1410 |
+
*
|
1411 |
+
* <code>
|
1412 |
+
* array (
|
1413 |
+
* 0 =>
|
1414 |
+
* array (
|
1415 |
+
* 'name' => 'john',
|
1416 |
+
* 'age' => '13',
|
1417 |
+
* 'skill' => 'knows magic',
|
1418 |
+
* ),
|
1419 |
+
* 1 =>
|
1420 |
+
* array (
|
1421 |
+
* 'name' => 'tanaka',
|
1422 |
+
* 'age' => '8',
|
1423 |
+
* 'skill' => 'makes sushi',
|
1424 |
+
* ),
|
1425 |
+
* 2 =>
|
1426 |
+
* array (
|
1427 |
+
* 'name' => 'jose',
|
1428 |
+
* 'age' => '5',
|
1429 |
+
* 'skill' => 'dances salsa',
|
1430 |
+
* ),
|
1431 |
+
* 3 =>
|
1432 |
+
* array (
|
1433 |
+
* 'name' => 1,
|
1434 |
+
* 'age' => 1,
|
1435 |
+
* 'skill' => 1,
|
1436 |
+
* ),
|
1437 |
+
* 4 =>
|
1438 |
+
* array (
|
1439 |
+
* 'name' => '2',
|
1440 |
+
* 'age' => '2',
|
1441 |
+
* 'skill' => '2',
|
1442 |
+
* ),
|
1443 |
+
* 5 =>
|
1444 |
+
* array (
|
1445 |
+
* 'name' => 3,
|
1446 |
+
* 'age' => 3,
|
1447 |
+
* 'skill' => 3,
|
1448 |
+
* ),
|
1449 |
+
* )
|
1450 |
+
* </code>
|
1451 |
+
*
|
1452 |
+
* @param array $values the values to be appended to the row
|
1453 |
+
*
|
1454 |
+
* @access public
|
1455 |
+
* @return boolean
|
1456 |
+
*/
|
1457 |
+
public function appendRow($values)
|
1458 |
+
{
|
1459 |
+
$this->rows[] = array();
|
1460 |
+
$this->symmetrize();
|
1461 |
+
return $this->fillRow($this->countRows() - 1, $values);
|
1462 |
+
}
|
1463 |
+
|
1464 |
+
/**
|
1465 |
+
* fillRow
|
1466 |
+
*
|
1467 |
+
* Replaces the contents of cells in one given row with $values.
|
1468 |
+
*
|
1469 |
+
* sample of a csv file "my_cool.csv"
|
1470 |
+
*
|
1471 |
+
* <code>
|
1472 |
+
* name,age,skill
|
1473 |
+
* john,13,knows magic
|
1474 |
+
* tanaka,8,makes sushi
|
1475 |
+
* jose,5,dances salsa
|
1476 |
+
* </code>
|
1477 |
+
*
|
1478 |
+
* if we load the csv file and fill the second row with new data?
|
1479 |
+
*
|
1480 |
+
* <code>
|
1481 |
+
* // load the library
|
1482 |
+
* require_once 'File/CSV/DataSource.php';
|
1483 |
+
* $csv = new File_CSV_DataSource;
|
1484 |
+
*
|
1485 |
+
* // load csv file
|
1486 |
+
* $csv->load('my_cool.csv');
|
1487 |
+
*
|
1488 |
+
* // fill exitent row
|
1489 |
+
* var_export($csv->fillRow(1, 'x'));
|
1490 |
+
* </code>
|
1491 |
+
*
|
1492 |
+
* output
|
1493 |
+
*
|
1494 |
+
* <code>
|
1495 |
+
* true
|
1496 |
+
* </code>
|
1497 |
+
*
|
1498 |
+
* now let's dump whatever we have changed
|
1499 |
+
*
|
1500 |
+
* <code>
|
1501 |
+
* var_export($csv->connect());
|
1502 |
+
* </code>
|
1503 |
+
*
|
1504 |
+
* output
|
1505 |
+
*
|
1506 |
+
* <code>
|
1507 |
+
* array (
|
1508 |
+
* 0 =>
|
1509 |
+
* array (
|
1510 |
+
* 'name' => 'john',
|
1511 |
+
* 'age' => '13',
|
1512 |
+
* 'skill' => 'knows magic',
|
1513 |
+
* ),
|
1514 |
+
* 1 =>
|
1515 |
+
* array (
|
1516 |
+
* 'name' => 'x',
|
1517 |
+
* 'age' => 'x',
|
1518 |
+
* 'skill' => 'x',
|
1519 |
+
* ),
|
1520 |
+
* 2 =>
|
1521 |
+
* array (
|
1522 |
+
* 'name' => 'jose',
|
1523 |
+
* 'age' => '5',
|
1524 |
+
* 'skill' => 'dances salsa',
|
1525 |
+
* ),
|
1526 |
+
* )
|
1527 |
+
* </code>
|
1528 |
+
*
|
1529 |
+
* now lets try to fill the row with specific data for each cell
|
1530 |
+
*
|
1531 |
+
* <code>
|
1532 |
+
* var_export($csv->fillRow(1, array(1, 2, 3)));
|
1533 |
+
* </code>
|
1534 |
+
*
|
1535 |
+
* output
|
1536 |
+
*
|
1537 |
+
* <code>
|
1538 |
+
* true
|
1539 |
+
* </code>
|
1540 |
+
*
|
1541 |
+
* and dump the results
|
1542 |
+
*
|
1543 |
+
* <code>
|
1544 |
+
* var_export($csv->connect());
|
1545 |
+
* </code>
|
1546 |
+
*
|
1547 |
+
* output
|
1548 |
+
*
|
1549 |
+
* <code>
|
1550 |
+
*
|
1551 |
+
* array (
|
1552 |
+
* 0 =>
|
1553 |
+
* array (
|
1554 |
+
* 'name' => 'john',
|
1555 |
+
* 'age' => '13',
|
1556 |
+
* 'skill' => 'knows magic',
|
1557 |
+
* ),
|
1558 |
+
* 1 =>
|
1559 |
+
* array (
|
1560 |
+
* 'name' => 1,
|
1561 |
+
* 'age' => 2,
|
1562 |
+
* 'skill' => 3,
|
1563 |
+
* ),
|
1564 |
+
* 2 =>
|
1565 |
+
* array (
|
1566 |
+
* 'name' => 'jose',
|
1567 |
+
* 'age' => '5',
|
1568 |
+
* 'skill' => 'dances salsa',
|
1569 |
+
* ),
|
1570 |
+
* )
|
1571 |
+
* </code>
|
1572 |
+
*
|
1573 |
+
* @param integer $row the row to fill identified by its key
|
1574 |
+
* @param mixed $values the value to use, if a string or number
|
1575 |
+
* is given the whole row will be replaced with this value.
|
1576 |
+
* if an array is given instead the values will be used to fill
|
1577 |
+
* the row. Only when the currently loaded dataset is symmetric
|
1578 |
+
*
|
1579 |
+
* @access public
|
1580 |
+
* @return boolean
|
1581 |
+
* @see isSymmetric(), getAsymmetricRows(), symmetrize(), fillColumn(),
|
1582 |
+
* fillCell(), appendRow()
|
1583 |
+
*/
|
1584 |
+
public function fillRow($row, $values)
|
1585 |
+
{
|
1586 |
+
if (!$this->hasRow($row)) {
|
1587 |
+
return false;
|
1588 |
+
}
|
1589 |
+
|
1590 |
+
if (is_string($values) || is_numeric($values)) {
|
1591 |
+
foreach ($this->rows[$row] as $key => $cell) {
|
1592 |
+
$this->rows[$row][$key] = $values;
|
1593 |
+
}
|
1594 |
+
return true;
|
1595 |
+
}
|
1596 |
+
|
1597 |
+
$eql_to_headers = ($this->countHeaders() == count($values));
|
1598 |
+
if (is_array($values) && $this->isSymmetric() && $eql_to_headers) {
|
1599 |
+
$this->rows[$row] = $values;
|
1600 |
+
return true;
|
1601 |
+
}
|
1602 |
+
|
1603 |
+
return false;
|
1604 |
+
}
|
1605 |
+
|
1606 |
+
/**
|
1607 |
+
* row existance checker
|
1608 |
+
*
|
1609 |
+
* Scans currently loaded dataset and
|
1610 |
+
* checks if a given row identified by $number exists
|
1611 |
+
*
|
1612 |
+
* sample of a csv file "my_cool.csv"
|
1613 |
+
*
|
1614 |
+
* <code>
|
1615 |
+
* name,age,skill
|
1616 |
+
* john,13,knows magic
|
1617 |
+
* tanaka,8,makes sushi
|
1618 |
+
* jose,5,dances salsa
|
1619 |
+
* </code>
|
1620 |
+
*
|
1621 |
+
* load library and csv file
|
1622 |
+
*
|
1623 |
+
* <code>
|
1624 |
+
* require_once 'File/CSV/DataSource.php';
|
1625 |
+
* $csv = new File_CSV_DataSource;
|
1626 |
+
* $csv->load('my_cool.csv');
|
1627 |
+
* </code>
|
1628 |
+
*
|
1629 |
+
* build a relationship and dump it so we can see the rows we will
|
1630 |
+
* be working with
|
1631 |
+
*
|
1632 |
+
* <code>
|
1633 |
+
* var_export($csv->connect());
|
1634 |
+
* </code>
|
1635 |
+
*
|
1636 |
+
* output
|
1637 |
+
*
|
1638 |
+
* <code>
|
1639 |
+
* array (
|
1640 |
+
* 0 =>
|
1641 |
+
* array (
|
1642 |
+
* 'name' => 'john',
|
1643 |
+
* 'age' => '13',
|
1644 |
+
* 'skill' => 'knows magic',
|
1645 |
+
* ),
|
1646 |
+
* 1 => // THIS ROW EXISTS!!!
|
1647 |
+
* array (
|
1648 |
+
* 'name' => 'tanaka',
|
1649 |
+
* 'age' => '8',
|
1650 |
+
* 'skill' => 'makes sushi',
|
1651 |
+
* ),
|
1652 |
+
* 2 =>
|
1653 |
+
* array (
|
1654 |
+
* 'name' => 'jose',
|
1655 |
+
* 'age' => '5',
|
1656 |
+
* 'skill' => 'dances salsa',
|
1657 |
+
* ),
|
1658 |
+
* )
|
1659 |
+
* </code>
|
1660 |
+
*
|
1661 |
+
* now lets check for row existance
|
1662 |
+
*
|
1663 |
+
* <code>
|
1664 |
+
* var_export($csv->hasRow(1));
|
1665 |
+
* var_export($csv->hasRow(-1));
|
1666 |
+
* var_export($csv->hasRow(9999));
|
1667 |
+
* </code>
|
1668 |
+
*
|
1669 |
+
* output
|
1670 |
+
*
|
1671 |
+
* <code>
|
1672 |
+
* true
|
1673 |
+
* false
|
1674 |
+
* false
|
1675 |
+
* </code>
|
1676 |
+
*
|
1677 |
+
* @param mixed $number a numeric value that identifies the row
|
1678 |
+
* you are trying to fetch.
|
1679 |
+
*
|
1680 |
+
* @access public
|
1681 |
+
* @return boolean
|
1682 |
+
* @see getRow(), getRows(), appendRow(), fillRow()
|
1683 |
+
*/
|
1684 |
+
public function hasRow($number)
|
1685 |
+
{
|
1686 |
+
return (in_array($number, array_keys($this->rows)));
|
1687 |
+
}
|
1688 |
+
|
1689 |
+
/**
|
1690 |
+
* row remover
|
1691 |
+
*
|
1692 |
+
* removes one row from the current data set.
|
1693 |
+
*
|
1694 |
+
* sample of a csv file "my_cool.csv"
|
1695 |
+
*
|
1696 |
+
* <code>
|
1697 |
+
* name,age,skill
|
1698 |
+
* john,13,knows magic
|
1699 |
+
* tanaka,8,makes sushi
|
1700 |
+
* jose,5,dances salsa
|
1701 |
+
* </code>
|
1702 |
+
*
|
1703 |
+
* first let's load the file and output whatever was retrived.
|
1704 |
+
*
|
1705 |
+
* <code>
|
1706 |
+
* require_once 'File/CSV/DataSource.php';
|
1707 |
+
* $csv = new File_CSV_DataSource;
|
1708 |
+
* $csv->load('my_cool.csv');
|
1709 |
+
* var_export($csv->connect());
|
1710 |
+
* </code>
|
1711 |
+
*
|
1712 |
+
* output
|
1713 |
+
*
|
1714 |
+
* <code>
|
1715 |
+
*
|
1716 |
+
* array (
|
1717 |
+
* 0 =>
|
1718 |
+
* array (
|
1719 |
+
* 'name' => 'john',
|
1720 |
+
* 'age' => '13',
|
1721 |
+
* 'skill' => 'knows magic',
|
1722 |
+
* ),
|
1723 |
+
* 1 =>
|
1724 |
+
* array (
|
1725 |
+
* 'name' => 'tanaka',
|
1726 |
+
* 'age' => '8',
|
1727 |
+
* 'skill' => 'makes sushi',
|
1728 |
+
* ),
|
1729 |
+
* 2 =>
|
1730 |
+
* array (
|
1731 |
+
* 'name' => 'jose',
|
1732 |
+
* 'age' => '5',
|
1733 |
+
* 'skill' => 'dances salsa',
|
1734 |
+
* ),
|
1735 |
+
* )
|
1736 |
+
* </code>
|
1737 |
+
*
|
1738 |
+
* now lets remove the second row
|
1739 |
+
*
|
1740 |
+
* <code>
|
1741 |
+
* var_export($csv->removeRow(1));
|
1742 |
+
* </code>
|
1743 |
+
*
|
1744 |
+
* output
|
1745 |
+
*
|
1746 |
+
* <code>
|
1747 |
+
* true
|
1748 |
+
* </code>
|
1749 |
+
*
|
1750 |
+
* now lets dump again the data and see what changes have been
|
1751 |
+
* made
|
1752 |
+
*
|
1753 |
+
* <code>
|
1754 |
+
* var_export($csv->connect());
|
1755 |
+
* </code>
|
1756 |
+
*
|
1757 |
+
* output
|
1758 |
+
*
|
1759 |
+
* <code>
|
1760 |
+
* array (
|
1761 |
+
* 0 =>
|
1762 |
+
* array (
|
1763 |
+
* 'name' => 'john',
|
1764 |
+
* 'age' => '13',
|
1765 |
+
* 'skill' => 'knows magic',
|
1766 |
+
* ),
|
1767 |
+
* 1 =>
|
1768 |
+
* array (
|
1769 |
+
* 'name' => 'jose',
|
1770 |
+
* 'age' => '5',
|
1771 |
+
* 'skill' => 'dances salsa',
|
1772 |
+
* ),
|
1773 |
+
* )
|
1774 |
+
* </code>
|
1775 |
+
*
|
1776 |
+
* @param mixed $number the key that identifies that row
|
1777 |
+
*
|
1778 |
+
* @access public
|
1779 |
+
* @return boolean
|
1780 |
+
* @see hasColumn(), getHeaders(), createHeaders(), setHeaders(),
|
1781 |
+
* isSymmetric(), getAsymmetricRows()
|
1782 |
+
*/
|
1783 |
+
public function removeRow($number)
|
1784 |
+
{
|
1785 |
+
$cnt = $this->countRows();
|
1786 |
+
$row = $this->getRow($number);
|
1787 |
+
if (is_array($row) && ($row != array())) {
|
1788 |
+
unset($this->rows[$number]);
|
1789 |
+
} else {
|
1790 |
+
return false;
|
1791 |
+
}
|
1792 |
+
$this->resetKeys($this->rows);
|
1793 |
+
return ($cnt == ($this->countRows() + 1));
|
1794 |
+
}
|
1795 |
+
|
1796 |
+
/**
|
1797 |
+
* row walker
|
1798 |
+
*
|
1799 |
+
* goes through one full row of data and executes a callback
|
1800 |
+
* function per each cell in that row.
|
1801 |
+
*
|
1802 |
+
* Note: callback functions get the value of the cell as an
|
1803 |
+
* argument, and whatever that callback returns will be used to
|
1804 |
+
* replace the current value of that cell.
|
1805 |
+
*
|
1806 |
+
* @param string|integer $row anything that is numeric is a valid row
|
1807 |
+
* identificator. As long as it is within the range of the currently
|
1808 |
+
* loaded dataset
|
1809 |
+
*
|
1810 |
+
* @param string $callback the callback function to be executed
|
1811 |
+
* per each cell in a row
|
1812 |
+
*
|
1813 |
+
* @access public
|
1814 |
+
* @return boolean
|
1815 |
+
* - false if callback does not exist
|
1816 |
+
* - false if row does not exits
|
1817 |
+
*/
|
1818 |
+
public function walkRow($row, $callback)
|
1819 |
+
{
|
1820 |
+
if (!function_exists($callback)) {
|
1821 |
+
return false;
|
1822 |
+
}
|
1823 |
+
if ($this->hasRow($row)) {
|
1824 |
+
foreach ($this->getRow($row) as $key => $value) {
|
1825 |
+
$this->rows[$row][$key] = $callback($value);
|
1826 |
+
}
|
1827 |
+
return true;
|
1828 |
+
}
|
1829 |
+
return false;
|
1830 |
+
}
|
1831 |
+
|
1832 |
+
/**
|
1833 |
+
* raw data as array
|
1834 |
+
*
|
1835 |
+
* Gets the data that was retrived from the csv file as an array
|
1836 |
+
*
|
1837 |
+
* Note: that changes and alterations made to rows, columns and
|
1838 |
+
* values will also reflect on what this function retrives.
|
1839 |
+
*
|
1840 |
+
* @access public
|
1841 |
+
* @return array
|
1842 |
+
* @see connect(), getHeaders(), getRows(), isSymmetric(), getAsymmetricRows(),
|
1843 |
+
* symmetrize()
|
1844 |
+
*/
|
1845 |
+
public function getRawArray()
|
1846 |
+
{
|
1847 |
+
$ret_arr = array();
|
1848 |
+
$ret_arr[] = $this->headers;
|
1849 |
+
foreach ($this->rows as $row) {
|
1850 |
+
$ret_arr[] = $row;
|
1851 |
+
}
|
1852 |
+
return $ret_arr;
|
1853 |
+
}
|
1854 |
+
|
1855 |
+
/**
|
1856 |
+
* header creator
|
1857 |
+
*
|
1858 |
+
* uses prefix and creates a header for each column suffixed by a
|
1859 |
+
* numeric value
|
1860 |
+
*
|
1861 |
+
* by default the first row is interpreted as headers but if we
|
1862 |
+
* have a csv file with data only and no headers it becomes really
|
1863 |
+
* annoying to work with the current loaded data.
|
1864 |
+
*
|
1865 |
+
* this function will create a set dinamically generated headers
|
1866 |
+
* and make the current headers accessable with the row handling
|
1867 |
+
* functions
|
1868 |
+
*
|
1869 |
+
* Note: that the csv file contains only data but no headers
|
1870 |
+
* sample of a csv file "my_cool.csv"
|
1871 |
+
*
|
1872 |
+
* <code>
|
1873 |
+
* john,13,knows magic
|
1874 |
+
* tanaka,8,makes sushi
|
1875 |
+
* jose,5,dances salsa
|
1876 |
+
* </code>
|
1877 |
+
*
|
1878 |
+
* checks if the csv file was loaded
|
1879 |
+
*
|
1880 |
+
* <code>
|
1881 |
+
* $csv = new File_CSV_DataSource;
|
1882 |
+
* if (!$csv->load('my_cool.csv')) {
|
1883 |
+
* die('can not load csv file');
|
1884 |
+
* }
|
1885 |
+
* </code>
|
1886 |
+
*
|
1887 |
+
* dump current headers
|
1888 |
+
*
|
1889 |
+
* <code>
|
1890 |
+
* var_export($csv->getHeaders());
|
1891 |
+
* </code>
|
1892 |
+
*
|
1893 |
+
* standard output
|
1894 |
+
*
|
1895 |
+
* <code>
|
1896 |
+
* array (
|
1897 |
+
* 0 => 'john',
|
1898 |
+
* 1 => '13',
|
1899 |
+
* 2 => 'knows magic',
|
1900 |
+
* )
|
1901 |
+
* </code>
|
1902 |
+
*
|
1903 |
+
* generate headers named 'column' suffixed by a number and interpret
|
1904 |
+
* the previous headers as rows.
|
1905 |
+
*
|
1906 |
+
* <code>
|
1907 |
+
* $csv->createHeaders('column')
|
1908 |
+
* </code>
|
1909 |
+
*
|
1910 |
+
* dump current headers
|
1911 |
+
*
|
1912 |
+
* <code>
|
1913 |
+
* var_export($csv->getHeaders());
|
1914 |
+
* </code>
|
1915 |
+
*
|
1916 |
+
* standard output
|
1917 |
+
*
|
1918 |
+
* <code>
|
1919 |
+
* array (
|
1920 |
+
* 0 => 'column_1',
|
1921 |
+
* 1 => 'column_2',
|
1922 |
+
* 2 => 'column_3',
|
1923 |
+
* )
|
1924 |
+
* </code>
|
1925 |
+
*
|
1926 |
+
* build a relationship and dump it
|
1927 |
+
*
|
1928 |
+
* <code>
|
1929 |
+
* var_export($csv->connect());
|
1930 |
+
* </code>
|
1931 |
+
*
|
1932 |
+
* output
|
1933 |
+
*
|
1934 |
+
* <code>
|
1935 |
+
*
|
1936 |
+
* array (
|
1937 |
+
* 0 =>
|
1938 |
+
* array (
|
1939 |
+
* 'column_1' => 'john',
|
1940 |
+
* 'column_2' => '13',
|
1941 |
+
* 'column_3' => 'knows magic',
|
1942 |
+
* ),
|
1943 |
+
* 1 =>
|
1944 |
+
* array (
|
1945 |
+
* 'column_1' => 'tanaka',
|
1946 |
+
* 'column_2' => '8',
|
1947 |
+
* 'column_3' => 'makes sushi',
|
1948 |
+
* ),
|
1949 |
+
* 2 =>
|
1950 |
+
* array (
|
1951 |
+
* 'column_1' => 'jose',
|
1952 |
+
* 'column_2' => '5',
|
1953 |
+
* 'column_3' => 'dances salsa',
|
1954 |
+
* ),
|
1955 |
+
* )
|
1956 |
+
* </code>
|
1957 |
+
*
|
1958 |
+
* @param string $prefix string to use as prefix for each
|
1959 |
+
* independent header
|
1960 |
+
*
|
1961 |
+
* @access public
|
1962 |
+
* @return boolean fails if data is not symmetric
|
1963 |
+
* @see isSymmetric(), getAsymmetricRows()
|
1964 |
+
*/
|
1965 |
+
public function createHeaders($prefix)
|
1966 |
+
{
|
1967 |
+
if (!$this->isSymmetric()) {
|
1968 |
+
return false;
|
1969 |
+
}
|
1970 |
+
|
1971 |
+
$length = count($this->headers) + 1;
|
1972 |
+
$this->moveHeadersToRows();
|
1973 |
+
|
1974 |
+
$ret_arr = array();
|
1975 |
+
for ($i = 1; $i < $length; $i ++) {
|
1976 |
+
$ret_arr[] = $prefix . "_$i";
|
1977 |
+
}
|
1978 |
+
$this->headers = $ret_arr;
|
1979 |
+
return $this->isSymmetric();
|
1980 |
+
}
|
1981 |
+
|
1982 |
+
/**
|
1983 |
+
* header injector
|
1984 |
+
*
|
1985 |
+
* uses a $list of values which wil be used to replace current
|
1986 |
+
* headers.
|
1987 |
+
*
|
1988 |
+
* Note: that given $list must match the length of all rows.
|
1989 |
+
* known as symmetric. see isSymmetric() and getAsymmetricRows() methods
|
1990 |
+
*
|
1991 |
+
* Also, that current headers will be used as first row of data
|
1992 |
+
* and consecuently all rows order will change with this action.
|
1993 |
+
*
|
1994 |
+
* sample of a csv file "my_cool.csv"
|
1995 |
+
*
|
1996 |
+
* <code>
|
1997 |
+
* name,age,skill
|
1998 |
+
* john,13,knows magic
|
1999 |
+
* tanaka,8,makes sushi
|
2000 |
+
* jose,5,dances salsa
|
2001 |
+
* </code>
|
2002 |
+
*
|
2003 |
+
* load the library and csv file
|
2004 |
+
*
|
2005 |
+
* <code>
|
2006 |
+
* require_once 'File/CSV/DataSource.php';
|
2007 |
+
* $csv = new File_CSV_DataSource;
|
2008 |
+
* $csv->load('my_cool.csv');
|
2009 |
+
* </code>
|
2010 |
+
*
|
2011 |
+
* lets dump currently loaded data
|
2012 |
+
* <code>
|
2013 |
+
* var_export($csv->connect());
|
2014 |
+
* </code>
|
2015 |
+
*
|
2016 |
+
* output
|
2017 |
+
*
|
2018 |
+
* <code>
|
2019 |
+
* array (
|
2020 |
+
* 0 =>
|
2021 |
+
* array (
|
2022 |
+
* 'name' => 'john',
|
2023 |
+
* 'age' => '13',
|
2024 |
+
* 'skill' => 'knows magic',
|
2025 |
+
* ),
|
2026 |
+
* 1 =>
|
2027 |
+
* array (
|
2028 |
+
* 'name' => 'tanaka',
|
2029 |
+
* 'age' => '8',
|
2030 |
+
* 'skill' => 'makes sushi',
|
2031 |
+
* ),
|
2032 |
+
* 2 =>
|
2033 |
+
* array (
|
2034 |
+
* 'name' => 'jose',
|
2035 |
+
* 'age' => '5',
|
2036 |
+
* 'skill' => 'dances salsa',
|
2037 |
+
* ),
|
2038 |
+
* )
|
2039 |
+
* </code>
|
2040 |
+
*
|
2041 |
+
* And now lets create a new set of headers and attempt to inject
|
2042 |
+
* them into the current loaded dataset
|
2043 |
+
*
|
2044 |
+
* <code>
|
2045 |
+
* $new_headers = array('a', 'b', 'c');
|
2046 |
+
* var_export($csv->setHeaders($new_headers));
|
2047 |
+
* </code>
|
2048 |
+
*
|
2049 |
+
* output
|
2050 |
+
*
|
2051 |
+
* <code>
|
2052 |
+
* true
|
2053 |
+
* </code>
|
2054 |
+
*
|
2055 |
+
* Now lets try the same with some headers that do not match the
|
2056 |
+
* current headers length. (this should fail)
|
2057 |
+
*
|
2058 |
+
* <code>
|
2059 |
+
* $new_headers = array('a', 'b');
|
2060 |
+
* var_export($csv->setHeaders($new_headers));
|
2061 |
+
* </code>
|
2062 |
+
*
|
2063 |
+
* output
|
2064 |
+
*
|
2065 |
+
* <code>
|
2066 |
+
* false
|
2067 |
+
* </code>
|
2068 |
+
*
|
2069 |
+
* now let's dump whatever we have changed
|
2070 |
+
*
|
2071 |
+
* <code>
|
2072 |
+
* var_export($csv->connect());
|
2073 |
+
* </code>
|
2074 |
+
*
|
2075 |
+
* output
|
2076 |
+
*
|
2077 |
+
* <code>
|
2078 |
+
* array (
|
2079 |
+
* 0 =>
|
2080 |
+
* array (
|
2081 |
+
* 'a' => 'name',
|
2082 |
+
* 'b' => 'age',
|
2083 |
+
* 'c' => 'skill',
|
2084 |
+
* ),
|
2085 |
+
* 1 =>
|
2086 |
+
* array (
|
2087 |
+
* 'a' => 'john',
|
2088 |
+
* 'b' => '13',
|
2089 |
+
* 'c' => 'knows magic',
|
2090 |
+
* ),
|
2091 |
+
* 2 =>
|
2092 |
+
* array (
|
2093 |
+
* 'a' => 'tanaka',
|
2094 |
+
* 'b' => '8',
|
2095 |
+
* 'c' => 'makes sushi',
|
2096 |
+
* ),
|
2097 |
+
* 3 =>
|
2098 |
+
* array (
|
2099 |
+
* 'a' => 'jose',
|
2100 |
+
* 'b' => '5',
|
2101 |
+
* 'c' => 'dances salsa',
|
2102 |
+
* ),
|
2103 |
+
* )
|
2104 |
+
* </code>
|
2105 |
+
*
|
2106 |
+
* @param array $list a collection of names to use as headers,
|
2107 |
+
*
|
2108 |
+
* @access public
|
2109 |
+
* @return boolean fails if data is not symmetric
|
2110 |
+
* @see isSymmetric(), getAsymmetricRows(), getHeaders(), createHeaders()
|
2111 |
+
*/
|
2112 |
+
public function setHeaders($list)
|
2113 |
+
{
|
2114 |
+
if (!$this->isSymmetric()) {
|
2115 |
+
return false;
|
2116 |
+
}
|
2117 |
+
if (!is_array($list)) {
|
2118 |
+
return false;
|
2119 |
+
}
|
2120 |
+
if (count($list) != count($this->headers)) {
|
2121 |
+
return false;
|
2122 |
+
}
|
2123 |
+
$this->moveHeadersToRows();
|
2124 |
+
$this->headers = $list;
|
2125 |
+
return true;
|
2126 |
+
}
|
2127 |
+
|
2128 |
+
/**
|
2129 |
+
* csv parser
|
2130 |
+
*
|
2131 |
+
* reads csv data and transforms it into php-data
|
2132 |
+
*
|
2133 |
+
* @access protected
|
2134 |
+
* @return boolean
|
2135 |
+
*/
|
2136 |
+
protected function parse()
|
2137 |
+
{
|
2138 |
+
if (!$this->validates()) {
|
2139 |
+
return false;
|
2140 |
+
}
|
2141 |
+
|
2142 |
+
$c = 0;
|
2143 |
+
$d = $this->settings['delimiter'];
|
2144 |
+
$e = $this->settings['escape'];
|
2145 |
+
$l = $this->settings['length'];
|
2146 |
+
|
2147 |
+
$res = fopen($this->_filename, 'r');
|
2148 |
+
|
2149 |
+
while ($keys = fgetcsv($res, $l, $d, $e)) {
|
2150 |
+
|
2151 |
+
if ($c == 0) {
|
2152 |
+
$this->headers = $keys;
|
2153 |
+
} else {
|
2154 |
+
array_push($this->rows, $keys);
|
2155 |
+
}
|
2156 |
+
|
2157 |
+
$c ++;
|
2158 |
+
}
|
2159 |
+
|
2160 |
+
fclose($res);
|
2161 |
+
$this->removeEmpty();
|
2162 |
+
return true;
|
2163 |
+
}
|
2164 |
+
|
2165 |
+
/**
|
2166 |
+
* empty row remover
|
2167 |
+
*
|
2168 |
+
* removes all records that have been defined but have no data.
|
2169 |
+
*
|
2170 |
+
* @access protected
|
2171 |
+
* @return array containing only the rows that have data
|
2172 |
+
*/
|
2173 |
+
protected function removeEmpty()
|
2174 |
+
{
|
2175 |
+
$ret_arr = array();
|
2176 |
+
foreach ($this->rows as $row) {
|
2177 |
+
$line = trim(join('', $row));
|
2178 |
+
if (!empty($line)) {
|
2179 |
+
$ret_arr[] = $row;
|
2180 |
+
}
|
2181 |
+
}
|
2182 |
+
$this->rows = $ret_arr;
|
2183 |
+
}
|
2184 |
+
|
2185 |
+
/**
|
2186 |
+
* csv file validator
|
2187 |
+
*
|
2188 |
+
* checks wheather if the given csv file is valid or not
|
2189 |
+
*
|
2190 |
+
* @access protected
|
2191 |
+
* @return boolean
|
2192 |
+
*/
|
2193 |
+
protected function validates()
|
2194 |
+
{
|
2195 |
+
// file existance
|
2196 |
+
if (!file_exists($this->_filename)) {
|
2197 |
+
return false;
|
2198 |
+
}
|
2199 |
+
|
2200 |
+
// file readability
|
2201 |
+
if (!is_readable($this->_filename)) {
|
2202 |
+
return false;
|
2203 |
+
}
|
2204 |
+
|
2205 |
+
return true;
|
2206 |
+
}
|
2207 |
+
|
2208 |
+
/**
|
2209 |
+
* header relocator
|
2210 |
+
*
|
2211 |
+
* @access protected
|
2212 |
+
* @return void
|
2213 |
+
*/
|
2214 |
+
protected function moveHeadersToRows()
|
2215 |
+
{
|
2216 |
+
$arr = array();
|
2217 |
+
$arr[] = $this->headers;
|
2218 |
+
foreach ($this->rows as $row) {
|
2219 |
+
$arr[] = $row;
|
2220 |
+
}
|
2221 |
+
$this->rows = $arr;
|
2222 |
+
$this->headers = array();
|
2223 |
+
}
|
2224 |
+
|
2225 |
+
/**
|
2226 |
+
* array key reseter
|
2227 |
+
*
|
2228 |
+
* makes sure that an array's keys are setted in a correct numerical order
|
2229 |
+
*
|
2230 |
+
* Note: that this function does not return anything, all changes
|
2231 |
+
* are made to the original array as a reference
|
2232 |
+
*
|
2233 |
+
* @param array &$array any array, if keys are strings they will
|
2234 |
+
* be replaced with numeric values
|
2235 |
+
*
|
2236 |
+
* @access protected
|
2237 |
+
* @return void
|
2238 |
+
*/
|
2239 |
+
protected function resetKeys(&$array)
|
2240 |
+
{
|
2241 |
+
$arr = array();
|
2242 |
+
foreach ($array as $item) {
|
2243 |
+
$arr[] = $item;
|
2244 |
+
}
|
2245 |
+
$array = $arr;
|
2246 |
+
}
|
2247 |
+
|
2248 |
+
/**
|
2249 |
+
* object data flusher
|
2250 |
+
*
|
2251 |
+
* tells this object to forget all data loaded and start from
|
2252 |
+
* scratch
|
2253 |
+
*
|
2254 |
+
* @access protected
|
2255 |
+
* @return void
|
2256 |
+
*/
|
2257 |
+
protected function flush()
|
2258 |
+
{
|
2259 |
+
$this->rows = array();
|
2260 |
+
$this->headers = array();
|
2261 |
+
}
|
2262 |
+
|
2263 |
+
}
|
2264 |
+
|
2265 |
+
?>
|
File_CSV_DataSource/docs/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
The MIT License
|
3 |
+
|
4 |
+
Copyright (c) <2008> <Kazuyoshi Tlacaelel>
|
5 |
+
|
6 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 |
+
of this software and associated documentation files (the "Software"), to deal
|
8 |
+
in the Software without restriction, including without limitation the rights
|
9 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 |
+
copies of the Software, and to permit persons to whom the Software is
|
11 |
+
furnished to do so, subject to the following conditions:
|
12 |
+
|
13 |
+
The above copyright notice and this permission notice shall be included in
|
14 |
+
all copies or substantial portions of the Software.
|
15 |
+
|
16 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 |
+
THE SOFTWARE.
|
23 |
+
|
File_CSV_DataSource/docs/README
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
|
3 |
+
EXAMPLES
|
4 |
+
located in the file "docs/examples/EXAMPLES"
|
5 |
+
|
6 |
+
LICENSE
|
7 |
+
located in the file "LICENSE"
|
8 |
+
|
9 |
+
PROJECT
|
10 |
+
http://code.google.com/p/php-csv-parser/
|
11 |
+
|
12 |
+
TESTS
|
13 |
+
located in the folder "tests"
|
14 |
+
|
15 |
+
AUTHOR
|
16 |
+
Kazuyoshi Tlacaelel
|
17 |
+
|
18 |
+
DOCUMENTATION
|
19 |
+
http://code.google.com/p/php-csv-parser/
|
File_CSV_DataSource/docs/examples/EXAMPLES
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#summary Quick sample!
|
2 |
+
#labels Featured
|
3 |
+
|
4 |
+
Lets get started with quick samples
|
5 |
+
|
6 |
+
= Quick Samples =
|
7 |
+
*my_file.csv*
|
8 |
+
{{{
|
9 |
+
name, age
|
10 |
+
john, 13
|
11 |
+
takaka, 8
|
12 |
+
}}}
|
13 |
+
|
14 |
+
*php script*
|
15 |
+
{{{
|
16 |
+
<?php
|
17 |
+
|
18 |
+
$csv = new File_CSV_DataSource;
|
19 |
+
|
20 |
+
$csv->load('my_file.csv'); // boolean
|
21 |
+
|
22 |
+
$csv->getHeaders(); // array('name', 'age');
|
23 |
+
|
24 |
+
$csv->getColumn('name'); // array('john', 'tanaka');
|
25 |
+
|
26 |
+
$csv->row(1); // array('john', '13');
|
27 |
+
|
28 |
+
$csv->connect(); // array(
|
29 |
+
// array('name' => 'john', 'age' => 13),
|
30 |
+
// array('name' => 'tanaka', 'age' => 8)
|
31 |
+
// );
|
32 |
+
|
33 |
+
?>
|
34 |
+
|
35 |
+
}}}
|
36 |
+
|
37 |
+
|
38 |
+
= Detailed Usage =
|
39 |
+
|
40 |
+
{{{
|
41 |
+
<?php
|
42 |
+
|
43 |
+
// usage sample
|
44 |
+
$csv = new File_CSV_DataSource;
|
45 |
+
|
46 |
+
// tell the object to parse a specific file
|
47 |
+
if ($csv->load('my_file.csv')) {
|
48 |
+
|
49 |
+
// execute the following if given file is usable
|
50 |
+
|
51 |
+
// get the headers found in file
|
52 |
+
$array = $csv->getHeaders();
|
53 |
+
|
54 |
+
// get a specific column from csv file
|
55 |
+
$csv->getColumn($array[2]);
|
56 |
+
|
57 |
+
// get each record with its related header
|
58 |
+
// ONLY if all records length match the number
|
59 |
+
// of headers
|
60 |
+
if ($csv->isSymmetric()) {
|
61 |
+
$array = $csv->connect();
|
62 |
+
} else {
|
63 |
+
// fetch records that dont match headers length
|
64 |
+
$array = $csv->getAsymmetricRows();
|
65 |
+
}
|
66 |
+
|
67 |
+
// ignore everything and simply get the data as an array
|
68 |
+
$array = $csv->getrawArray();
|
69 |
+
}
|
70 |
+
|
71 |
+
?>
|
72 |
+
}}}
|
File_CSV_DataSource/docs/examples/documentation.wiki
ADDED
@@ -0,0 +1,2058 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
= Method:__construct =
|
3 |
+
|
4 |
+
_ data load initialize _
|
5 |
+
|
6 |
+
# *Argument* _mixed_ $filename please look at the load() method
|
7 |
+
|
8 |
+
* *Visibility* public
|
9 |
+
* *Also see* load()
|
10 |
+
* *Returns* void
|
11 |
+
|
12 |
+
|
13 |
+
----
|
14 |
+
|
15 |
+
= Method:appendColumn =
|
16 |
+
|
17 |
+
_ column appender _
|
18 |
+
|
19 |
+
Appends a column and each or all values in it can be
|
20 |
+
dinamically filled. Only when the $values argument is given.
|
21 |
+
|
22 |
+
|
23 |
+
{{{
|
24 |
+
|
25 |
+
|
26 |
+
var_export($csv->fillColumn('age', 99));
|
27 |
+
true
|
28 |
+
|
29 |
+
var_export($csv->appendColumn('candy_ownership', array(99, 44, 65)));
|
30 |
+
true
|
31 |
+
|
32 |
+
var_export($csv->appendColumn('import_id', 111111111));
|
33 |
+
true
|
34 |
+
|
35 |
+
var_export($csv->connect());
|
36 |
+
|
37 |
+
array (
|
38 |
+
0 =>
|
39 |
+
array (
|
40 |
+
'name' => 'john',
|
41 |
+
'age' => 99,
|
42 |
+
'skill' => 'knows magic',
|
43 |
+
'candy_ownership' => 99,
|
44 |
+
'import_id' => 111111111,
|
45 |
+
),
|
46 |
+
1 =>
|
47 |
+
array (
|
48 |
+
'name' => 'tanaka',
|
49 |
+
'age' => 99,
|
50 |
+
'skill' => 'makes sushi',
|
51 |
+
'candy_ownership' => 44,
|
52 |
+
'import_id' => 111111111,
|
53 |
+
),
|
54 |
+
2 =>
|
55 |
+
array (
|
56 |
+
'name' => 'jose',
|
57 |
+
'age' => 99,
|
58 |
+
'skill' => 'dances salsa',
|
59 |
+
'candy_ownership' => 65,
|
60 |
+
'import_id' => 111111111,
|
61 |
+
),
|
62 |
+
)
|
63 |
+
|
64 |
+
}}}
|
65 |
+
|
66 |
+
|
67 |
+
# *Argument* _string_ $column an item returned by getHeaders()
|
68 |
+
# *Argument* _mixed_ $values same as fillColumn()
|
69 |
+
|
70 |
+
* *Visibility* public
|
71 |
+
* *Returns* boolean
|
72 |
+
* *Also see* getHeaders(), fillColumn(), fillCell(), createHeaders(),
|
73 |
+
setHeaders()
|
74 |
+
|
75 |
+
|
76 |
+
----
|
77 |
+
|
78 |
+
= Method:appendRow =
|
79 |
+
|
80 |
+
_ row appender _
|
81 |
+
|
82 |
+
Aggregates one more row to the currently loaded dataset
|
83 |
+
|
84 |
+
sample of a csv file "my_cool.csv"
|
85 |
+
|
86 |
+
|
87 |
+
|
88 |
+
{{{
|
89 |
+
name,age,skill
|
90 |
+
john,13,knows magic
|
91 |
+
tanaka,8,makes sushi
|
92 |
+
jose,5,dances salsa
|
93 |
+
}}}
|
94 |
+
|
95 |
+
|
96 |
+
|
97 |
+
first let's load the file and output whatever was retrived.
|
98 |
+
|
99 |
+
|
100 |
+
|
101 |
+
{{{
|
102 |
+
require_once 'File/CSV/DataSource.php';
|
103 |
+
$csv = new File_CSV_DataSource;
|
104 |
+
$csv->load('my_cool.csv');
|
105 |
+
var_export($csv->connect());
|
106 |
+
}}}
|
107 |
+
|
108 |
+
|
109 |
+
output
|
110 |
+
|
111 |
+
|
112 |
+
|
113 |
+
{{{
|
114 |
+
|
115 |
+
array (
|
116 |
+
0 =>
|
117 |
+
array (
|
118 |
+
'name' => 'john',
|
119 |
+
'age' => '13',
|
120 |
+
'skill' => 'knows magic',
|
121 |
+
),
|
122 |
+
1 =>
|
123 |
+
array (
|
124 |
+
'name' => 'tanaka',
|
125 |
+
'age' => '8',
|
126 |
+
'skill' => 'makes sushi',
|
127 |
+
),
|
128 |
+
2 =>
|
129 |
+
array (
|
130 |
+
'name' => 'jose',
|
131 |
+
'age' => '5',
|
132 |
+
'skill' => 'dances salsa',
|
133 |
+
),
|
134 |
+
)
|
135 |
+
}}}
|
136 |
+
|
137 |
+
|
138 |
+
now lets do some modifications, let's try adding three rows.
|
139 |
+
|
140 |
+
|
141 |
+
|
142 |
+
{{{
|
143 |
+
var_export($csv->appendRow(1));
|
144 |
+
var_export($csv->appendRow('2'));
|
145 |
+
var_export($csv->appendRow(array(3, 3, 3)));
|
146 |
+
}}}
|
147 |
+
|
148 |
+
|
149 |
+
output
|
150 |
+
|
151 |
+
|
152 |
+
|
153 |
+
{{{
|
154 |
+
true
|
155 |
+
true
|
156 |
+
true
|
157 |
+
}}}
|
158 |
+
|
159 |
+
|
160 |
+
and now let's try to see what has changed
|
161 |
+
|
162 |
+
|
163 |
+
|
164 |
+
{{{
|
165 |
+
var_export($csv->connect());
|
166 |
+
}}}
|
167 |
+
|
168 |
+
|
169 |
+
output
|
170 |
+
|
171 |
+
|
172 |
+
|
173 |
+
{{{
|
174 |
+
array (
|
175 |
+
0 =>
|
176 |
+
array (
|
177 |
+
'name' => 'john',
|
178 |
+
'age' => '13',
|
179 |
+
'skill' => 'knows magic',
|
180 |
+
),
|
181 |
+
1 =>
|
182 |
+
array (
|
183 |
+
'name' => 'tanaka',
|
184 |
+
'age' => '8',
|
185 |
+
'skill' => 'makes sushi',
|
186 |
+
),
|
187 |
+
2 =>
|
188 |
+
array (
|
189 |
+
'name' => 'jose',
|
190 |
+
'age' => '5',
|
191 |
+
'skill' => 'dances salsa',
|
192 |
+
),
|
193 |
+
3 =>
|
194 |
+
array (
|
195 |
+
'name' => 1,
|
196 |
+
'age' => 1,
|
197 |
+
'skill' => 1,
|
198 |
+
),
|
199 |
+
4 =>
|
200 |
+
array (
|
201 |
+
'name' => '2',
|
202 |
+
'age' => '2',
|
203 |
+
'skill' => '2',
|
204 |
+
),
|
205 |
+
5 =>
|
206 |
+
array (
|
207 |
+
'name' => 3,
|
208 |
+
'age' => 3,
|
209 |
+
'skill' => 3,
|
210 |
+
),
|
211 |
+
)
|
212 |
+
}}}
|
213 |
+
|
214 |
+
|
215 |
+
# *Argument* _array_ $values the values to be appended to the row
|
216 |
+
|
217 |
+
* *Visibility* public
|
218 |
+
* *Returns* boolean
|
219 |
+
|
220 |
+
|
221 |
+
----
|
222 |
+
|
223 |
+
= Method:connect =
|
224 |
+
|
225 |
+
_ header and row relationship builder _
|
226 |
+
|
227 |
+
Attempts to create a relationship for every single cell that
|
228 |
+
was captured and its corresponding header. The sample below shows
|
229 |
+
how a connection/relationship is built.
|
230 |
+
|
231 |
+
sample of a csv file "my_cool.csv"
|
232 |
+
|
233 |
+
|
234 |
+
|
235 |
+
{{{
|
236 |
+
name,age,skill
|
237 |
+
john,13,knows magic
|
238 |
+
tanaka,8,makes sushi
|
239 |
+
jose,5,dances salsa
|
240 |
+
}}}
|
241 |
+
|
242 |
+
|
243 |
+
php implementation
|
244 |
+
|
245 |
+
|
246 |
+
|
247 |
+
{{{
|
248 |
+
|
249 |
+
$csv = new File_CSV_DataSource;
|
250 |
+
$csv->load('my_cool.csv');
|
251 |
+
|
252 |
+
if (!$csv->isSymmetric()) {
|
253 |
+
die('file has headers and rows with different lengths
|
254 |
+
cannot connect');
|
255 |
+
}
|
256 |
+
|
257 |
+
var_export($csv->connect());
|
258 |
+
|
259 |
+
array (
|
260 |
+
0 =>
|
261 |
+
array (
|
262 |
+
'name' => 'john',
|
263 |
+
'age' => '13',
|
264 |
+
'skill' => 'knows magic',
|
265 |
+
),
|
266 |
+
1 =>
|
267 |
+
array (
|
268 |
+
'name' => 'tanaka',
|
269 |
+
'age' => '8',
|
270 |
+
'skill' => 'makes sushi',
|
271 |
+
),
|
272 |
+
2 =>
|
273 |
+
array (
|
274 |
+
'name' => 'jose',
|
275 |
+
'age' => '5',
|
276 |
+
'skill' => 'dances salsa',
|
277 |
+
),
|
278 |
+
)
|
279 |
+
|
280 |
+
}}}
|
281 |
+
|
282 |
+
|
283 |
+
|
284 |
+
You can pass a collection of headers in an array to build
|
285 |
+
a connection for those columns only!
|
286 |
+
|
287 |
+
|
288 |
+
|
289 |
+
{{{
|
290 |
+
|
291 |
+
var_export($csv->connect(array('age')));
|
292 |
+
|
293 |
+
array (
|
294 |
+
0 =>
|
295 |
+
array (
|
296 |
+
'age' => '13',
|
297 |
+
),
|
298 |
+
1 =>
|
299 |
+
array (
|
300 |
+
'age' => '8',
|
301 |
+
),
|
302 |
+
2 =>
|
303 |
+
array (
|
304 |
+
'age' => '5',
|
305 |
+
),
|
306 |
+
)
|
307 |
+
|
308 |
+
}}}
|
309 |
+
|
310 |
+
|
311 |
+
# *Argument* _array_ $columns the columns to connect, if nothing
|
312 |
+
is given all headers will be used to create a connection
|
313 |
+
|
314 |
+
* *Visibility* public
|
315 |
+
* *Returns* array If the data is not symmetric an empty array
|
316 |
+
will be returned instead
|
317 |
+
* *Also see* isSymmetric(), getAsymmetricRows(), symmetrize(), getHeaders()
|
318 |
+
|
319 |
+
|
320 |
+
----
|
321 |
+
|
322 |
+
= Method:countHeaders =
|
323 |
+
|
324 |
+
_ header counter _
|
325 |
+
|
326 |
+
retrives the total number of loaded headers
|
327 |
+
|
328 |
+
* *Visibility* public
|
329 |
+
* *Returns* integer gets the length of headers
|
330 |
+
|
331 |
+
|
332 |
+
----
|
333 |
+
|
334 |
+
= Method:countRows =
|
335 |
+
|
336 |
+
_ row counter _
|
337 |
+
|
338 |
+
This function will exclude the headers
|
339 |
+
|
340 |
+
sample of a csv file "my_cool.csv"
|
341 |
+
|
342 |
+
|
343 |
+
|
344 |
+
{{{
|
345 |
+
name,age,skill
|
346 |
+
john,13,knows magic
|
347 |
+
tanaka,8,makes sushi
|
348 |
+
jose,5,dances salsa
|
349 |
+
}}}
|
350 |
+
|
351 |
+
|
352 |
+
php implementation
|
353 |
+
|
354 |
+
|
355 |
+
|
356 |
+
{{{
|
357 |
+
$csv = new File_CSV_DataSource;
|
358 |
+
$csv->load('my_cool.csv');
|
359 |
+
var_export($csv->countRows()); // returns 3
|
360 |
+
}}}
|
361 |
+
|
362 |
+
|
363 |
+
* *Visibility* public
|
364 |
+
* *Returns* integer
|
365 |
+
|
366 |
+
|
367 |
+
----
|
368 |
+
|
369 |
+
= Method:createHeaders =
|
370 |
+
|
371 |
+
_ header creator _
|
372 |
+
|
373 |
+
uses prefix and creates a header for each column suffixed by a
|
374 |
+
numeric value
|
375 |
+
|
376 |
+
by default the first row is interpreted as headers but if we
|
377 |
+
have a csv file with data only and no headers it becomes really
|
378 |
+
annoying to work with the current loaded data.
|
379 |
+
|
380 |
+
this function will create a set dinamically generated headers
|
381 |
+
and make the current headers accessable with the row handling
|
382 |
+
functions
|
383 |
+
|
384 |
+
Note: that the csv file contains only data but no headers
|
385 |
+
sample of a csv file "my_cool.csv"
|
386 |
+
|
387 |
+
|
388 |
+
|
389 |
+
{{{
|
390 |
+
john,13,knows magic
|
391 |
+
tanaka,8,makes sushi
|
392 |
+
jose,5,dances salsa
|
393 |
+
}}}
|
394 |
+
|
395 |
+
|
396 |
+
checks if the csv file was loaded
|
397 |
+
|
398 |
+
|
399 |
+
|
400 |
+
{{{
|
401 |
+
$csv = new File_CSV_DataSource;
|
402 |
+
if (!$csv->load('my_cool.csv')) {
|
403 |
+
die('can not load csv file');
|
404 |
+
}
|
405 |
+
}}}
|
406 |
+
|
407 |
+
|
408 |
+
dump current headers
|
409 |
+
|
410 |
+
|
411 |
+
|
412 |
+
{{{
|
413 |
+
var_export($csv->getHeaders());
|
414 |
+
}}}
|
415 |
+
|
416 |
+
|
417 |
+
standard output
|
418 |
+
|
419 |
+
|
420 |
+
|
421 |
+
{{{
|
422 |
+
array (
|
423 |
+
0 => 'john',
|
424 |
+
1 => '13',
|
425 |
+
2 => 'knows magic',
|
426 |
+
)
|
427 |
+
}}}
|
428 |
+
|
429 |
+
|
430 |
+
generate headers named 'column' suffixed by a number and interpret
|
431 |
+
the previous headers as rows.
|
432 |
+
|
433 |
+
|
434 |
+
|
435 |
+
{{{
|
436 |
+
$csv->createHeaders('column')
|
437 |
+
}}}
|
438 |
+
|
439 |
+
|
440 |
+
dump current headers
|
441 |
+
|
442 |
+
|
443 |
+
|
444 |
+
{{{
|
445 |
+
var_export($csv->getHeaders());
|
446 |
+
}}}
|
447 |
+
|
448 |
+
|
449 |
+
standard output
|
450 |
+
|
451 |
+
|
452 |
+
|
453 |
+
{{{
|
454 |
+
array (
|
455 |
+
0 => 'column_1',
|
456 |
+
1 => 'column_2',
|
457 |
+
2 => 'column_3',
|
458 |
+
)
|
459 |
+
}}}
|
460 |
+
|
461 |
+
|
462 |
+
build a relationship and dump it
|
463 |
+
|
464 |
+
|
465 |
+
|
466 |
+
{{{
|
467 |
+
var_export($csv->connect());
|
468 |
+
}}}
|
469 |
+
|
470 |
+
|
471 |
+
output
|
472 |
+
|
473 |
+
|
474 |
+
|
475 |
+
{{{
|
476 |
+
|
477 |
+
array (
|
478 |
+
0 =>
|
479 |
+
array (
|
480 |
+
'column_1' => 'john',
|
481 |
+
'column_2' => '13',
|
482 |
+
'column_3' => 'knows magic',
|
483 |
+
),
|
484 |
+
1 =>
|
485 |
+
array (
|
486 |
+
'column_1' => 'tanaka',
|
487 |
+
'column_2' => '8',
|
488 |
+
'column_3' => 'makes sushi',
|
489 |
+
),
|
490 |
+
2 =>
|
491 |
+
array (
|
492 |
+
'column_1' => 'jose',
|
493 |
+
'column_2' => '5',
|
494 |
+
'column_3' => 'dances salsa',
|
495 |
+
),
|
496 |
+
)
|
497 |
+
}}}
|
498 |
+
|
499 |
+
|
500 |
+
# *Argument* _string_ $prefix string to use as prefix for each
|
501 |
+
independent header
|
502 |
+
|
503 |
+
* *Visibility* public
|
504 |
+
* *Returns* boolean fails if data is not symmetric
|
505 |
+
* *Also see* isSymmetric(), getAsymmetricRows()
|
506 |
+
|
507 |
+
|
508 |
+
----
|
509 |
+
|
510 |
+
= Method:fillCell =
|
511 |
+
|
512 |
+
_ cell value filler _
|
513 |
+
|
514 |
+
replaces the value of a specific cell
|
515 |
+
|
516 |
+
sample of a csv file "my_cool.csv"
|
517 |
+
|
518 |
+
|
519 |
+
|
520 |
+
{{{
|
521 |
+
name,age,skill
|
522 |
+
john,13,knows magic
|
523 |
+
tanaka,8,makes sushi
|
524 |
+
jose,5,dances salsa
|
525 |
+
}}}
|
526 |
+
|
527 |
+
|
528 |
+
php implementation
|
529 |
+
|
530 |
+
|
531 |
+
|
532 |
+
{{{
|
533 |
+
|
534 |
+
$csv = new File_CSV_DataSource;
|
535 |
+
|
536 |
+
// load the csv file
|
537 |
+
$csv->load('my_cool.csv');
|
538 |
+
|
539 |
+
// find out if the given coordinate is valid
|
540 |
+
if($csv->hasCell(1, 1)) {
|
541 |
+
|
542 |
+
// if so grab that cell and dump it
|
543 |
+
var_export($csv->getCell(1, 1)); // '8'
|
544 |
+
|
545 |
+
// replace the value of that cell
|
546 |
+
$csv->fillCell(1, 1, 'new value'); // true
|
547 |
+
|
548 |
+
// output the new value of the cell
|
549 |
+
var_export($csv->getCell(1, 1)); // 'new value'
|
550 |
+
|
551 |
+
}
|
552 |
+
}}}
|
553 |
+
|
554 |
+
|
555 |
+
now lets try to grab the whole row
|
556 |
+
|
557 |
+
|
558 |
+
|
559 |
+
{{{
|
560 |
+
// show the whole row
|
561 |
+
var_export($csv->getRow(1));
|
562 |
+
}}}
|
563 |
+
|
564 |
+
|
565 |
+
standard output
|
566 |
+
|
567 |
+
|
568 |
+
|
569 |
+
{{{
|
570 |
+
array (
|
571 |
+
0 => 'tanaka',
|
572 |
+
1 => 'new value',
|
573 |
+
2 => 'makes sushi',
|
574 |
+
)
|
575 |
+
}}}
|
576 |
+
|
577 |
+
|
578 |
+
# *Argument* _integer_ $x the row to fetch
|
579 |
+
# *Argument* _integer_ $y the column to fetch
|
580 |
+
# *Argument* _mixed_ $value the value to fill the cell with
|
581 |
+
|
582 |
+
* *Visibility* public
|
583 |
+
* *Returns* boolean
|
584 |
+
* *Also see* hasCell(), getRow(), getRows(), getColumn()
|
585 |
+
|
586 |
+
|
587 |
+
----
|
588 |
+
|
589 |
+
= Method:fillColumn =
|
590 |
+
|
591 |
+
_ collumn data injector _
|
592 |
+
|
593 |
+
fills alll the data in the given column with $values
|
594 |
+
|
595 |
+
sample of a csv file "my_cool.csv"
|
596 |
+
|
597 |
+
|
598 |
+
|
599 |
+
{{{
|
600 |
+
name,age,skill
|
601 |
+
john,13,knows magic
|
602 |
+
tanaka,8,makes sushi
|
603 |
+
jose,5,dances salsa
|
604 |
+
}}}
|
605 |
+
|
606 |
+
|
607 |
+
php implementation
|
608 |
+
|
609 |
+
|
610 |
+
|
611 |
+
{{{
|
612 |
+
$csv = new File_CSV_DataSource;
|
613 |
+
$csv->load('my_cool.csv');
|
614 |
+
|
615 |
+
// if the csv file loads
|
616 |
+
if ($csv->load('my_cool.csv')) {
|
617 |
+
|
618 |
+
// grab all data within the age column
|
619 |
+
var_export($csv->getColumn('age'));
|
620 |
+
|
621 |
+
// rename all values in it with the number 99
|
622 |
+
var_export($csv->fillColumn('age', 99));
|
623 |
+
|
624 |
+
// grab all data within the age column
|
625 |
+
var_export($csv->getColumn('age'));
|
626 |
+
|
627 |
+
// rename each value in a column independently
|
628 |
+
$data = array(1, 2, 3);
|
629 |
+
$csv->fillColumn('age', $data);
|
630 |
+
|
631 |
+
var_export($csv->getColumn('age'));
|
632 |
+
}
|
633 |
+
}}}
|
634 |
+
|
635 |
+
|
636 |
+
standard output
|
637 |
+
|
638 |
+
|
639 |
+
|
640 |
+
{{{
|
641 |
+
array (
|
642 |
+
0 => '13',
|
643 |
+
1 => '8',
|
644 |
+
2 => '5',
|
645 |
+
)
|
646 |
+
}}}
|
647 |
+
|
648 |
+
|
649 |
+
|
650 |
+
|
651 |
+
{{{
|
652 |
+
true
|
653 |
+
}}}
|
654 |
+
|
655 |
+
|
656 |
+
|
657 |
+
|
658 |
+
{{{
|
659 |
+
array (
|
660 |
+
0 => 99,
|
661 |
+
1 => 99,
|
662 |
+
2 => 99,
|
663 |
+
)
|
664 |
+
}}}
|
665 |
+
|
666 |
+
|
667 |
+
|
668 |
+
|
669 |
+
{{{
|
670 |
+
array (
|
671 |
+
0 => 1,
|
672 |
+
1 => 2,
|
673 |
+
2 => 3,
|
674 |
+
)
|
675 |
+
}}}
|
676 |
+
|
677 |
+
|
678 |
+
# *Argument* _mixed_ $column the column identified by a string
|
679 |
+
# *Argument* _mixed_ $values ither one of the following
|
680 |
+
# (Number) will fill the whole column with the value of number
|
681 |
+
# (String) will fill the whole column with the value of string
|
682 |
+
# (Array) will fill the while column with the values of array
|
683 |
+
the array gets ignored if it does not match the length of rows
|
684 |
+
|
685 |
+
* *Visibility* public
|
686 |
+
* *Returns* void
|
687 |
+
|
688 |
+
|
689 |
+
----
|
690 |
+
|
691 |
+
= Method:fillRow =
|
692 |
+
|
693 |
+
_ fillRow _
|
694 |
+
|
695 |
+
Replaces the contents of cells in one given row with $values.
|
696 |
+
|
697 |
+
sample of a csv file "my_cool.csv"
|
698 |
+
|
699 |
+
|
700 |
+
|
701 |
+
{{{
|
702 |
+
name,age,skill
|
703 |
+
john,13,knows magic
|
704 |
+
tanaka,8,makes sushi
|
705 |
+
jose,5,dances salsa
|
706 |
+
}}}
|
707 |
+
|
708 |
+
|
709 |
+
if we load the csv file and fill the second row with new data?
|
710 |
+
|
711 |
+
|
712 |
+
|
713 |
+
{{{
|
714 |
+
// load the library
|
715 |
+
require_once 'File/CSV/DataSource.php';
|
716 |
+
$csv = new File_CSV_DataSource;
|
717 |
+
|
718 |
+
// load csv file
|
719 |
+
$csv->load('my_cool.csv');
|
720 |
+
|
721 |
+
// fill exitent row
|
722 |
+
var_export($csv->fillRow(1, 'x'));
|
723 |
+
}}}
|
724 |
+
|
725 |
+
|
726 |
+
output
|
727 |
+
|
728 |
+
|
729 |
+
|
730 |
+
{{{
|
731 |
+
true
|
732 |
+
}}}
|
733 |
+
|
734 |
+
|
735 |
+
now let's dump whatever we have changed
|
736 |
+
|
737 |
+
|
738 |
+
|
739 |
+
{{{
|
740 |
+
var_export($csv->connect());
|
741 |
+
}}}
|
742 |
+
|
743 |
+
|
744 |
+
output
|
745 |
+
|
746 |
+
|
747 |
+
|
748 |
+
{{{
|
749 |
+
array (
|
750 |
+
0 =>
|
751 |
+
array (
|
752 |
+
'name' => 'john',
|
753 |
+
'age' => '13',
|
754 |
+
'skill' => 'knows magic',
|
755 |
+
),
|
756 |
+
1 =>
|
757 |
+
array (
|
758 |
+
'name' => 'x',
|
759 |
+
'age' => 'x',
|
760 |
+
'skill' => 'x',
|
761 |
+
),
|
762 |
+
2 =>
|
763 |
+
array (
|
764 |
+
'name' => 'jose',
|
765 |
+
'age' => '5',
|
766 |
+
'skill' => 'dances salsa',
|
767 |
+
),
|
768 |
+
)
|
769 |
+
}}}
|
770 |
+
|
771 |
+
|
772 |
+
now lets try to fill the row with specific data for each cell
|
773 |
+
|
774 |
+
|
775 |
+
|
776 |
+
{{{
|
777 |
+
var_export($csv->fillRow(1, array(1, 2, 3)));
|
778 |
+
}}}
|
779 |
+
|
780 |
+
|
781 |
+
output
|
782 |
+
|
783 |
+
|
784 |
+
|
785 |
+
{{{
|
786 |
+
true
|
787 |
+
}}}
|
788 |
+
|
789 |
+
|
790 |
+
and dump the results
|
791 |
+
|
792 |
+
|
793 |
+
|
794 |
+
{{{
|
795 |
+
var_export($csv->connect());
|
796 |
+
}}}
|
797 |
+
|
798 |
+
|
799 |
+
output
|
800 |
+
|
801 |
+
|
802 |
+
|
803 |
+
{{{
|
804 |
+
|
805 |
+
array (
|
806 |
+
0 =>
|
807 |
+
array (
|
808 |
+
'name' => 'john',
|
809 |
+
'age' => '13',
|
810 |
+
'skill' => 'knows magic',
|
811 |
+
),
|
812 |
+
1 =>
|
813 |
+
array (
|
814 |
+
'name' => 1,
|
815 |
+
'age' => 2,
|
816 |
+
'skill' => 3,
|
817 |
+
),
|
818 |
+
2 =>
|
819 |
+
array (
|
820 |
+
'name' => 'jose',
|
821 |
+
'age' => '5',
|
822 |
+
'skill' => 'dances salsa',
|
823 |
+
),
|
824 |
+
)
|
825 |
+
}}}
|
826 |
+
|
827 |
+
|
828 |
+
# *Argument* _integer_ $row the row to fill identified by its key
|
829 |
+
# *Argument* _mixed_ $values the value to use, if a string or number
|
830 |
+
is given the whole row will be replaced with this value.
|
831 |
+
if an array is given instead the values will be used to fill
|
832 |
+
the row. Only when the currently loaded dataset is symmetric
|
833 |
+
|
834 |
+
* *Visibility* public
|
835 |
+
* *Returns* boolean
|
836 |
+
* *Also see* isSymmetric(), getAsymmetricRows(), symmetrize(), fillColumn(),
|
837 |
+
fillCell(), appendRow()
|
838 |
+
|
839 |
+
|
840 |
+
----
|
841 |
+
|
842 |
+
= Method:getAsymmetricRows =
|
843 |
+
|
844 |
+
_ asymmetric data fetcher _
|
845 |
+
|
846 |
+
finds the rows that do not match the headers length
|
847 |
+
|
848 |
+
lets assume that we add one more row to our csv file.
|
849 |
+
that has only two values. Something like
|
850 |
+
|
851 |
+
|
852 |
+
|
853 |
+
{{{
|
854 |
+
name,age,skill
|
855 |
+
john,13,knows magic
|
856 |
+
tanaka,8,makes sushi
|
857 |
+
jose,5,dances salsa
|
858 |
+
niki,6
|
859 |
+
}}}
|
860 |
+
|
861 |
+
|
862 |
+
Then in our php code
|
863 |
+
|
864 |
+
|
865 |
+
|
866 |
+
{{{
|
867 |
+
$csv->load('my_cool.csv');
|
868 |
+
var_export($csv->getAsymmetricRows());
|
869 |
+
}}}
|
870 |
+
|
871 |
+
|
872 |
+
The result
|
873 |
+
|
874 |
+
|
875 |
+
|
876 |
+
{{{
|
877 |
+
|
878 |
+
array (
|
879 |
+
0 =>
|
880 |
+
array (
|
881 |
+
0 => 'niki',
|
882 |
+
1 => '6',
|
883 |
+
),
|
884 |
+
)
|
885 |
+
|
886 |
+
}}}
|
887 |
+
|
888 |
+
|
889 |
+
* *Visibility* public
|
890 |
+
* *Returns* array filled with rows that do not match headers
|
891 |
+
* *Also see* getHeaders(), symmetrize(), isSymmetric(),
|
892 |
+
getAsymmetricRows()
|
893 |
+
|
894 |
+
|
895 |
+
----
|
896 |
+
|
897 |
+
= Method:getCell =
|
898 |
+
|
899 |
+
_ cell fetcher _
|
900 |
+
|
901 |
+
gets the value of a specific cell by given coordinates
|
902 |
+
|
903 |
+
Note: That indexes start with zero, and headers are not
|
904 |
+
searched!
|
905 |
+
|
906 |
+
For example if we are trying to grab the cell that is in the
|
907 |
+
second row and the third column
|
908 |
+
|
909 |
+
|
910 |
+
|
911 |
+
{{{
|
912 |
+
name,age,skill
|
913 |
+
john,13,knows magic
|
914 |
+
tanaka,8,makes sushi
|
915 |
+
jose,5,dances salsa
|
916 |
+
}}}
|
917 |
+
|
918 |
+
|
919 |
+
we would do something like
|
920 |
+
|
921 |
+
|
922 |
+
{{{
|
923 |
+
var_export($csv->getCell(1, 2));
|
924 |
+
}}}
|
925 |
+
|
926 |
+
|
927 |
+
and get the following results
|
928 |
+
|
929 |
+
|
930 |
+
{{{
|
931 |
+
'makes sushi'
|
932 |
+
}}}
|
933 |
+
|
934 |
+
|
935 |
+
# *Argument* _integer_ $x the row to fetch
|
936 |
+
# *Argument* _integer_ $y the column to fetch
|
937 |
+
|
938 |
+
* *Visibility* public
|
939 |
+
* *Returns* mixed|false the value of the cell or false if the cell does
|
940 |
+
not exist
|
941 |
+
* *Also see* getHeaders(), hasCell(), getRow(), getRows(), getColumn()
|
942 |
+
|
943 |
+
|
944 |
+
----
|
945 |
+
|
946 |
+
= Method:getColumn =
|
947 |
+
|
948 |
+
_ column fetcher _
|
949 |
+
|
950 |
+
gets all the data for a specific column identified by $name
|
951 |
+
|
952 |
+
Note $name is the same as the items returned by getHeaders()
|
953 |
+
|
954 |
+
sample of a csv file "my_cool.csv"
|
955 |
+
|
956 |
+
|
957 |
+
|
958 |
+
{{{
|
959 |
+
name,age,skill
|
960 |
+
john,13,knows magic
|
961 |
+
tanaka,8,makes sushi
|
962 |
+
jose,5,dances salsa
|
963 |
+
}}}
|
964 |
+
|
965 |
+
|
966 |
+
php implementation
|
967 |
+
|
968 |
+
|
969 |
+
|
970 |
+
{{{
|
971 |
+
$csv = new File_CSV_DataSource;
|
972 |
+
$csv->load('my_cool.csv');
|
973 |
+
var_export($csv->getColumn('name'));
|
974 |
+
}}}
|
975 |
+
|
976 |
+
|
977 |
+
the above example outputs something like
|
978 |
+
|
979 |
+
|
980 |
+
|
981 |
+
{{{
|
982 |
+
|
983 |
+
array (
|
984 |
+
0 => 'john',
|
985 |
+
1 => 'tanaka',
|
986 |
+
2 => 'jose',
|
987 |
+
)
|
988 |
+
|
989 |
+
}}}
|
990 |
+
|
991 |
+
|
992 |
+
# *Argument* _string_ $name the name of the column to fetch
|
993 |
+
|
994 |
+
* *Visibility* public
|
995 |
+
* *Returns* array filled with values of a column
|
996 |
+
* *Also see* getHeaders(), fillColumn(), appendColumn(), getCell(), getRows(),
|
997 |
+
getRow(), hasColumn()
|
998 |
+
|
999 |
+
|
1000 |
+
----
|
1001 |
+
|
1002 |
+
= Method:getHeaders =
|
1003 |
+
|
1004 |
+
_ header fetcher _
|
1005 |
+
|
1006 |
+
gets csv headers into an array
|
1007 |
+
|
1008 |
+
|
1009 |
+
|
1010 |
+
{{{
|
1011 |
+
|
1012 |
+
var_export($csv->getHeaders());
|
1013 |
+
|
1014 |
+
array (
|
1015 |
+
0 => 'name',
|
1016 |
+
1 => 'age',
|
1017 |
+
2 => 'skill',
|
1018 |
+
)
|
1019 |
+
|
1020 |
+
}}}
|
1021 |
+
|
1022 |
+
|
1023 |
+
* *Visibility* public
|
1024 |
+
* *Returns* array
|
1025 |
+
|
1026 |
+
|
1027 |
+
----
|
1028 |
+
|
1029 |
+
= Method:getRawArray =
|
1030 |
+
|
1031 |
+
_ raw data as array _
|
1032 |
+
|
1033 |
+
Gets the data that was retrived from the csv file as an array
|
1034 |
+
|
1035 |
+
Note: that changes and alterations made to rows, columns and
|
1036 |
+
values will also reflect on what this function retrives.
|
1037 |
+
|
1038 |
+
* *Visibility* public
|
1039 |
+
* *Returns* array
|
1040 |
+
* *Also see* connect(), getHeaders(), getRows(), isSymmetric(), getAsymmetricRows(),
|
1041 |
+
symmetrize()
|
1042 |
+
|
1043 |
+
|
1044 |
+
----
|
1045 |
+
|
1046 |
+
= Method:getRow =
|
1047 |
+
|
1048 |
+
_ row fetcher _
|
1049 |
+
|
1050 |
+
Note: first row is zero
|
1051 |
+
|
1052 |
+
sample of a csv file "my_cool.csv"
|
1053 |
+
|
1054 |
+
|
1055 |
+
|
1056 |
+
{{{
|
1057 |
+
name,age,skill
|
1058 |
+
john,13,knows magic
|
1059 |
+
tanaka,8,makes sushi
|
1060 |
+
jose,5,dances salsa
|
1061 |
+
}}}
|
1062 |
+
|
1063 |
+
|
1064 |
+
load the library and csv file
|
1065 |
+
|
1066 |
+
|
1067 |
+
|
1068 |
+
{{{
|
1069 |
+
require_once 'File/CSV/DataSource.php';
|
1070 |
+
$csv = new File_CSV_DataSource;
|
1071 |
+
$csv->load('my_cool.csv');
|
1072 |
+
}}}
|
1073 |
+
|
1074 |
+
|
1075 |
+
lets dump currently loaded data
|
1076 |
+
|
1077 |
+
|
1078 |
+
{{{
|
1079 |
+
var_export($csv->connect());
|
1080 |
+
}}}
|
1081 |
+
|
1082 |
+
|
1083 |
+
output
|
1084 |
+
|
1085 |
+
|
1086 |
+
|
1087 |
+
{{{
|
1088 |
+
array (
|
1089 |
+
0 =>
|
1090 |
+
array (
|
1091 |
+
'name' => 'john',
|
1092 |
+
'age' => '13',
|
1093 |
+
'skill' => 'knows magic',
|
1094 |
+
),
|
1095 |
+
1 =>
|
1096 |
+
array (
|
1097 |
+
'name' => 'tanaka',
|
1098 |
+
'age' => '8',
|
1099 |
+
'skill' => 'makes sushi',
|
1100 |
+
),
|
1101 |
+
2 =>
|
1102 |
+
array (
|
1103 |
+
'name' => 'jose',
|
1104 |
+
'age' => '5',
|
1105 |
+
'skill' => 'dances salsa',
|
1106 |
+
),
|
1107 |
+
)
|
1108 |
+
}}}
|
1109 |
+
|
1110 |
+
|
1111 |
+
Now let's fetch the second row
|
1112 |
+
|
1113 |
+
|
1114 |
+
|
1115 |
+
{{{
|
1116 |
+
var_export($csv->getRow(1));
|
1117 |
+
}}}
|
1118 |
+
|
1119 |
+
|
1120 |
+
output
|
1121 |
+
|
1122 |
+
|
1123 |
+
|
1124 |
+
{{{
|
1125 |
+
array (
|
1126 |
+
0 => 'tanaka',
|
1127 |
+
1 => '8',
|
1128 |
+
2 => 'makes sushi',
|
1129 |
+
)
|
1130 |
+
}}}
|
1131 |
+
|
1132 |
+
|
1133 |
+
# *Argument* _integer_ $number the row number to fetch
|
1134 |
+
|
1135 |
+
* *Visibility* public
|
1136 |
+
* *Returns* array the row identified by number, if $number does
|
1137 |
+
not exist an empty array is returned instead
|
1138 |
+
|
1139 |
+
|
1140 |
+
----
|
1141 |
+
|
1142 |
+
= Method:getRows =
|
1143 |
+
|
1144 |
+
_ multiple row fetcher _
|
1145 |
+
|
1146 |
+
Extracts a rows in the following fashion
|
1147 |
+
# all rows if no $range argument is given
|
1148 |
+
# a range of rows identified by their key
|
1149 |
+
# if rows in range are not found nothing is retrived instead
|
1150 |
+
# if no rows were found an empty array is returned
|
1151 |
+
|
1152 |
+
sample of a csv file "my_cool.csv"
|
1153 |
+
|
1154 |
+
|
1155 |
+
|
1156 |
+
{{{
|
1157 |
+
name,age,skill
|
1158 |
+
john,13,knows magic
|
1159 |
+
tanaka,8,makes sushi
|
1160 |
+
jose,5,dances salsa
|
1161 |
+
}}}
|
1162 |
+
|
1163 |
+
|
1164 |
+
load the library and csv file
|
1165 |
+
|
1166 |
+
|
1167 |
+
|
1168 |
+
{{{
|
1169 |
+
require_once 'File/CSV/DataSource.php';
|
1170 |
+
$csv = new File_CSV_DataSource;
|
1171 |
+
$csv->load('my_cool.csv');
|
1172 |
+
}}}
|
1173 |
+
|
1174 |
+
|
1175 |
+
lets dump currently loaded data
|
1176 |
+
|
1177 |
+
|
1178 |
+
{{{
|
1179 |
+
var_export($csv->connect());
|
1180 |
+
}}}
|
1181 |
+
|
1182 |
+
|
1183 |
+
output
|
1184 |
+
|
1185 |
+
|
1186 |
+
|
1187 |
+
{{{
|
1188 |
+
array (
|
1189 |
+
0 =>
|
1190 |
+
array (
|
1191 |
+
'name' => 'john',
|
1192 |
+
'age' => '13',
|
1193 |
+
'skill' => 'knows magic',
|
1194 |
+
),
|
1195 |
+
1 =>
|
1196 |
+
array (
|
1197 |
+
'name' => 'tanaka',
|
1198 |
+
'age' => '8',
|
1199 |
+
'skill' => 'makes sushi',
|
1200 |
+
),
|
1201 |
+
2 =>
|
1202 |
+
array (
|
1203 |
+
'name' => 'jose',
|
1204 |
+
'age' => '5',
|
1205 |
+
'skill' => 'dances salsa',
|
1206 |
+
),
|
1207 |
+
)
|
1208 |
+
}}}
|
1209 |
+
|
1210 |
+
|
1211 |
+
now get the second and thirdh row
|
1212 |
+
|
1213 |
+
|
1214 |
+
|
1215 |
+
{{{
|
1216 |
+
var_export($csv->getRows(array(1, 2)));
|
1217 |
+
}}}
|
1218 |
+
|
1219 |
+
|
1220 |
+
output
|
1221 |
+
|
1222 |
+
|
1223 |
+
|
1224 |
+
{{{
|
1225 |
+
array (
|
1226 |
+
0 =>
|
1227 |
+
array (
|
1228 |
+
0 => 'tanaka',
|
1229 |
+
1 => '8',
|
1230 |
+
2 => 'makes sushi',
|
1231 |
+
),
|
1232 |
+
1 =>
|
1233 |
+
array (
|
1234 |
+
0 => 'jose',
|
1235 |
+
1 => '5',
|
1236 |
+
2 => 'dances salsa',
|
1237 |
+
),
|
1238 |
+
)
|
1239 |
+
}}}
|
1240 |
+
|
1241 |
+
|
1242 |
+
now lets try something odd and the goodie third row
|
1243 |
+
|
1244 |
+
|
1245 |
+
|
1246 |
+
{{{
|
1247 |
+
var_export($csv->getRows(array(9, 2)));
|
1248 |
+
}}}
|
1249 |
+
|
1250 |
+
|
1251 |
+
output
|
1252 |
+
|
1253 |
+
|
1254 |
+
|
1255 |
+
{{{
|
1256 |
+
array (
|
1257 |
+
0 =>
|
1258 |
+
array (
|
1259 |
+
0 => 'jose',
|
1260 |
+
1 => '5',
|
1261 |
+
2 => 'dances salsa',
|
1262 |
+
),
|
1263 |
+
)
|
1264 |
+
}}}
|
1265 |
+
|
1266 |
+
|
1267 |
+
# *Argument* _array_ $range a list of rows to retrive
|
1268 |
+
|
1269 |
+
* *Visibility* public
|
1270 |
+
* *Returns* array
|
1271 |
+
|
1272 |
+
|
1273 |
+
----
|
1274 |
+
|
1275 |
+
= Method:hasCell =
|
1276 |
+
|
1277 |
+
_ checks if a coordinate is valid _
|
1278 |
+
|
1279 |
+
sample of a csv file "my_cool.csv"
|
1280 |
+
|
1281 |
+
|
1282 |
+
|
1283 |
+
{{{
|
1284 |
+
name,age,skill
|
1285 |
+
john,13,knows magic
|
1286 |
+
tanaka,8,makes sushi
|
1287 |
+
jose,5,dances salsa
|
1288 |
+
}}}
|
1289 |
+
|
1290 |
+
|
1291 |
+
load the csv file
|
1292 |
+
|
1293 |
+
|
1294 |
+
|
1295 |
+
{{{
|
1296 |
+
$csv = new File_CSV_DataSource;
|
1297 |
+
var_export($csv->load('my_cool.csv')); // true if file is
|
1298 |
+
// loaded
|
1299 |
+
}}}
|
1300 |
+
|
1301 |
+
|
1302 |
+
find out if a coordinate is valid
|
1303 |
+
|
1304 |
+
|
1305 |
+
|
1306 |
+
{{{
|
1307 |
+
var_export($csv->hasCell(99, 3)); // false
|
1308 |
+
}}}
|
1309 |
+
|
1310 |
+
|
1311 |
+
check again for a know valid coordinate and grab that cell
|
1312 |
+
|
1313 |
+
|
1314 |
+
|
1315 |
+
{{{
|
1316 |
+
var_export($csv->hasCell(1, 1)); // true
|
1317 |
+
var_export($csv->getCell(1, 1)); // '8'
|
1318 |
+
}}}
|
1319 |
+
|
1320 |
+
|
1321 |
+
# *Argument* _mixed_ $x the row to fetch
|
1322 |
+
# *Argument* _mixed_ $y the column to fetch
|
1323 |
+
|
1324 |
+
* *Visibility* public
|
1325 |
+
* *Returns* void
|
1326 |
+
|
1327 |
+
|
1328 |
+
----
|
1329 |
+
|
1330 |
+
= Method:hasColumn =
|
1331 |
+
|
1332 |
+
_ column existance checker _
|
1333 |
+
|
1334 |
+
checks if a column exists, columns are identified by their
|
1335 |
+
header name.
|
1336 |
+
|
1337 |
+
sample of a csv file "my_cool.csv"
|
1338 |
+
|
1339 |
+
|
1340 |
+
|
1341 |
+
{{{
|
1342 |
+
name,age,skill
|
1343 |
+
john,13,knows magic
|
1344 |
+
tanaka,8,makes sushi
|
1345 |
+
jose,5,dances salsa
|
1346 |
+
}}}
|
1347 |
+
|
1348 |
+
|
1349 |
+
php implementation
|
1350 |
+
|
1351 |
+
|
1352 |
+
|
1353 |
+
{{{
|
1354 |
+
$csv = new File_CSV_DataSource;
|
1355 |
+
$csv->load('my_cool.csv');
|
1356 |
+
$headers = $csv->getHeaders();
|
1357 |
+
}}}
|
1358 |
+
|
1359 |
+
|
1360 |
+
now lets check if the columns exist
|
1361 |
+
|
1362 |
+
|
1363 |
+
|
1364 |
+
{{{
|
1365 |
+
var_export($csv->hasColumn($headers[0])); // true
|
1366 |
+
var_export($csv->hasColumn('age')); // true
|
1367 |
+
var_export($csv->hasColumn('I dont exist')); // false
|
1368 |
+
}}}
|
1369 |
+
|
1370 |
+
|
1371 |
+
# *Argument* _string_ $string an item returned by getHeaders()
|
1372 |
+
|
1373 |
+
* *Visibility* public
|
1374 |
+
* *Returns* boolean
|
1375 |
+
* *Also see* getHeaders()
|
1376 |
+
|
1377 |
+
|
1378 |
+
----
|
1379 |
+
|
1380 |
+
= Method:hasRow =
|
1381 |
+
|
1382 |
+
_ row existance checker _
|
1383 |
+
|
1384 |
+
Scans currently loaded dataset and
|
1385 |
+
checks if a given row identified by $number exists
|
1386 |
+
|
1387 |
+
sample of a csv file "my_cool.csv"
|
1388 |
+
|
1389 |
+
|
1390 |
+
|
1391 |
+
{{{
|
1392 |
+
name,age,skill
|
1393 |
+
john,13,knows magic
|
1394 |
+
tanaka,8,makes sushi
|
1395 |
+
jose,5,dances salsa
|
1396 |
+
}}}
|
1397 |
+
|
1398 |
+
|
1399 |
+
load library and csv file
|
1400 |
+
|
1401 |
+
|
1402 |
+
|
1403 |
+
{{{
|
1404 |
+
require_once 'File/CSV/DataSource.php';
|
1405 |
+
$csv = new File_CSV_DataSource;
|
1406 |
+
$csv->load('my_cool.csv');
|
1407 |
+
}}}
|
1408 |
+
|
1409 |
+
|
1410 |
+
build a relationship and dump it so we can see the rows we will
|
1411 |
+
be working with
|
1412 |
+
|
1413 |
+
|
1414 |
+
|
1415 |
+
{{{
|
1416 |
+
var_export($csv->connect());
|
1417 |
+
}}}
|
1418 |
+
|
1419 |
+
|
1420 |
+
output
|
1421 |
+
|
1422 |
+
|
1423 |
+
|
1424 |
+
{{{
|
1425 |
+
array (
|
1426 |
+
0 =>
|
1427 |
+
array (
|
1428 |
+
'name' => 'john',
|
1429 |
+
'age' => '13',
|
1430 |
+
'skill' => 'knows magic',
|
1431 |
+
),
|
1432 |
+
1 => // THIS ROW EXISTS!!!
|
1433 |
+
array (
|
1434 |
+
'name' => 'tanaka',
|
1435 |
+
'age' => '8',
|
1436 |
+
'skill' => 'makes sushi',
|
1437 |
+
),
|
1438 |
+
2 =>
|
1439 |
+
array (
|
1440 |
+
'name' => 'jose',
|
1441 |
+
'age' => '5',
|
1442 |
+
'skill' => 'dances salsa',
|
1443 |
+
),
|
1444 |
+
)
|
1445 |
+
}}}
|
1446 |
+
|
1447 |
+
|
1448 |
+
now lets check for row existance
|
1449 |
+
|
1450 |
+
|
1451 |
+
|
1452 |
+
{{{
|
1453 |
+
var_export($csv->hasRow(1));
|
1454 |
+
var_export($csv->hasRow(-1));
|
1455 |
+
var_export($csv->hasRow(9999));
|
1456 |
+
}}}
|
1457 |
+
|
1458 |
+
|
1459 |
+
output
|
1460 |
+
|
1461 |
+
|
1462 |
+
|
1463 |
+
{{{
|
1464 |
+
true
|
1465 |
+
false
|
1466 |
+
false
|
1467 |
+
}}}
|
1468 |
+
|
1469 |
+
|
1470 |
+
# *Argument* _mixed_ $number a numeric value that identifies the row
|
1471 |
+
you are trying to fetch.
|
1472 |
+
|
1473 |
+
* *Visibility* public
|
1474 |
+
* *Returns* boolean
|
1475 |
+
* *Also see* getRow(), getRows(), appendRow(), fillRow()
|
1476 |
+
|
1477 |
+
|
1478 |
+
----
|
1479 |
+
|
1480 |
+
= Method:isSymmetric =
|
1481 |
+
|
1482 |
+
_ data length/symmetry checker _
|
1483 |
+
|
1484 |
+
tells if the headers and all of the contents length match.
|
1485 |
+
Note: there is a lot of methods that won't work if data is not
|
1486 |
+
symmetric this method is very important!
|
1487 |
+
|
1488 |
+
* *Visibility* public
|
1489 |
+
* *Returns* boolean
|
1490 |
+
* *Also see* symmetrize(), getAsymmetricRows(), isSymmetric()
|
1491 |
+
|
1492 |
+
|
1493 |
+
----
|
1494 |
+
|
1495 |
+
= Method:load =
|
1496 |
+
|
1497 |
+
_ csv file loader _
|
1498 |
+
|
1499 |
+
indicates the object which file is to be loaded
|
1500 |
+
|
1501 |
+
|
1502 |
+
|
1503 |
+
{{{
|
1504 |
+
|
1505 |
+
require_once 'File/CSV/DataSource.php';
|
1506 |
+
|
1507 |
+
$csv = new File_CSV_DataSource;
|
1508 |
+
$csv->load('my_cool.csv');
|
1509 |
+
var_export($csv->connect());
|
1510 |
+
|
1511 |
+
array (
|
1512 |
+
0 =>
|
1513 |
+
array (
|
1514 |
+
'name' => 'john',
|
1515 |
+
'age' => '13',
|
1516 |
+
'skill' => 'knows magic',
|
1517 |
+
),
|
1518 |
+
1 =>
|
1519 |
+
array (
|
1520 |
+
'name' => 'tanaka',
|
1521 |
+
'age' => '8',
|
1522 |
+
'skill' => 'makes sushi',
|
1523 |
+
),
|
1524 |
+
2 =>
|
1525 |
+
array (
|
1526 |
+
'name' => 'jose',
|
1527 |
+
'age' => '5',
|
1528 |
+
'skill' => 'dances salsa',
|
1529 |
+
),
|
1530 |
+
)
|
1531 |
+
|
1532 |
+
}}}
|
1533 |
+
|
1534 |
+
|
1535 |
+
# *Argument* _string_ $filename the csv filename to load
|
1536 |
+
|
1537 |
+
* *Visibility* public
|
1538 |
+
* *Returns* boolean true if file was loaded successfully
|
1539 |
+
* *Also see* isSymmetric(), getAsymmetricRows(), symmetrize()
|
1540 |
+
|
1541 |
+
|
1542 |
+
----
|
1543 |
+
|
1544 |
+
= Method:removeColumn =
|
1545 |
+
|
1546 |
+
_ column remover _
|
1547 |
+
|
1548 |
+
Completly removes a whole column identified by $name
|
1549 |
+
Note: that this function will only work if data is symmetric.
|
1550 |
+
|
1551 |
+
sample of a csv file "my_cool.csv"
|
1552 |
+
|
1553 |
+
|
1554 |
+
|
1555 |
+
{{{
|
1556 |
+
name,age,skill
|
1557 |
+
john,13,knows magic
|
1558 |
+
tanaka,8,makes sushi
|
1559 |
+
jose,5,dances salsa
|
1560 |
+
}}}
|
1561 |
+
|
1562 |
+
|
1563 |
+
load the library and csv file
|
1564 |
+
|
1565 |
+
|
1566 |
+
|
1567 |
+
{{{
|
1568 |
+
require_once 'File/CSV/DataSource.php';
|
1569 |
+
$csv = new File_CSV_DataSource;
|
1570 |
+
$csv->load('my_cool.csv');
|
1571 |
+
}}}
|
1572 |
+
|
1573 |
+
|
1574 |
+
lets dump currently loaded data
|
1575 |
+
|
1576 |
+
|
1577 |
+
{{{
|
1578 |
+
var_export($csv->connect());
|
1579 |
+
}}}
|
1580 |
+
|
1581 |
+
|
1582 |
+
output
|
1583 |
+
|
1584 |
+
|
1585 |
+
|
1586 |
+
{{{
|
1587 |
+
array (
|
1588 |
+
0 =>
|
1589 |
+
array (
|
1590 |
+
'name' => 'john',
|
1591 |
+
'age' => '13',
|
1592 |
+
'skill' => 'knows magic',
|
1593 |
+
),
|
1594 |
+
1 =>
|
1595 |
+
array (
|
1596 |
+
'name' => 'tanaka',
|
1597 |
+
'age' => '8',
|
1598 |
+
'skill' => 'makes sushi',
|
1599 |
+
),
|
1600 |
+
2 =>
|
1601 |
+
array (
|
1602 |
+
'name' => 'jose',
|
1603 |
+
'age' => '5',
|
1604 |
+
'skill' => 'dances salsa',
|
1605 |
+
),
|
1606 |
+
)
|
1607 |
+
}}}
|
1608 |
+
|
1609 |
+
|
1610 |
+
and now let's remove the second column
|
1611 |
+
|
1612 |
+
|
1613 |
+
|
1614 |
+
{{{
|
1615 |
+
var_export($csv->removeColumn('age'));
|
1616 |
+
}}}
|
1617 |
+
|
1618 |
+
|
1619 |
+
output
|
1620 |
+
|
1621 |
+
|
1622 |
+
|
1623 |
+
{{{
|
1624 |
+
true
|
1625 |
+
}}}
|
1626 |
+
|
1627 |
+
|
1628 |
+
those changes made let's dump the data again and see what we got
|
1629 |
+
|
1630 |
+
|
1631 |
+
|
1632 |
+
{{{
|
1633 |
+
array (
|
1634 |
+
0 =>
|
1635 |
+
array (
|
1636 |
+
'name' => 'john',
|
1637 |
+
'skill' => 'knows magic',
|
1638 |
+
),
|
1639 |
+
1 =>
|
1640 |
+
array (
|
1641 |
+
'name' => 'tanaka',
|
1642 |
+
'skill' => 'makes sushi',
|
1643 |
+
),
|
1644 |
+
2 =>
|
1645 |
+
array (
|
1646 |
+
'name' => 'jose',
|
1647 |
+
'skill' => 'dances salsa',
|
1648 |
+
),
|
1649 |
+
)
|
1650 |
+
}}}
|
1651 |
+
|
1652 |
+
|
1653 |
+
# *Argument* _string_ $name same as the ones returned by getHeaders();
|
1654 |
+
|
1655 |
+
* *Visibility* public
|
1656 |
+
* *Returns* boolean
|
1657 |
+
* *Also see* hasColumn(), getHeaders(), createHeaders(), setHeaders(),
|
1658 |
+
isSymmetric(), getAsymmetricRows()
|
1659 |
+
|
1660 |
+
|
1661 |
+
----
|
1662 |
+
|
1663 |
+
= Method:removeRow =
|
1664 |
+
|
1665 |
+
_ row remover _
|
1666 |
+
|
1667 |
+
removes one row from the current data set.
|
1668 |
+
|
1669 |
+
sample of a csv file "my_cool.csv"
|
1670 |
+
|
1671 |
+
|
1672 |
+
|
1673 |
+
{{{
|
1674 |
+
name,age,skill
|
1675 |
+
john,13,knows magic
|
1676 |
+
tanaka,8,makes sushi
|
1677 |
+
jose,5,dances salsa
|
1678 |
+
}}}
|
1679 |
+
|
1680 |
+
|
1681 |
+
first let's load the file and output whatever was retrived.
|
1682 |
+
|
1683 |
+
|
1684 |
+
|
1685 |
+
{{{
|
1686 |
+
require_once 'File/CSV/DataSource.php';
|
1687 |
+
$csv = new File_CSV_DataSource;
|
1688 |
+
$csv->load('my_cool.csv');
|
1689 |
+
var_export($csv->connect());
|
1690 |
+
}}}
|
1691 |
+
|
1692 |
+
|
1693 |
+
output
|
1694 |
+
|
1695 |
+
|
1696 |
+
|
1697 |
+
{{{
|
1698 |
+
|
1699 |
+
array (
|
1700 |
+
0 =>
|
1701 |
+
array (
|
1702 |
+
'name' => 'john',
|
1703 |
+
'age' => '13',
|
1704 |
+
'skill' => 'knows magic',
|
1705 |
+
),
|
1706 |
+
1 =>
|
1707 |
+
array (
|
1708 |
+
'name' => 'tanaka',
|
1709 |
+
'age' => '8',
|
1710 |
+
'skill' => 'makes sushi',
|
1711 |
+
),
|
1712 |
+
2 =>
|
1713 |
+
array (
|
1714 |
+
'name' => 'jose',
|
1715 |
+
'age' => '5',
|
1716 |
+
'skill' => 'dances salsa',
|
1717 |
+
),
|
1718 |
+
)
|
1719 |
+
}}}
|
1720 |
+
|
1721 |
+
|
1722 |
+
now lets remove the second row
|
1723 |
+
|
1724 |
+
|
1725 |
+
|
1726 |
+
{{{
|
1727 |
+
var_export($csv->removeRow(1));
|
1728 |
+
}}}
|
1729 |
+
|
1730 |
+
|
1731 |
+
output
|
1732 |
+
|
1733 |
+
|
1734 |
+
|
1735 |
+
{{{
|
1736 |
+
true
|
1737 |
+
}}}
|
1738 |
+
|
1739 |
+
|
1740 |
+
now lets dump again the data and see what changes have been
|
1741 |
+
made
|
1742 |
+
|
1743 |
+
|
1744 |
+
|
1745 |
+
{{{
|
1746 |
+
var_export($csv->connect());
|
1747 |
+
}}}
|
1748 |
+
|
1749 |
+
|
1750 |
+
output
|
1751 |
+
|
1752 |
+
|
1753 |
+
|
1754 |
+
{{{
|
1755 |
+
array (
|
1756 |
+
0 =>
|
1757 |
+
array (
|
1758 |
+
'name' => 'john',
|
1759 |
+
'age' => '13',
|
1760 |
+
'skill' => 'knows magic',
|
1761 |
+
),
|
1762 |
+
1 =>
|
1763 |
+
array (
|
1764 |
+
'name' => 'jose',
|
1765 |
+
'age' => '5',
|
1766 |
+
'skill' => 'dances salsa',
|
1767 |
+
),
|
1768 |
+
)
|
1769 |
+
}}}
|
1770 |
+
|
1771 |
+
|
1772 |
+
# *Argument* _mixed_ $number the key that identifies that row
|
1773 |
+
|
1774 |
+
* *Visibility* public
|
1775 |
+
* *Returns* boolean
|
1776 |
+
* *Also see* hasColumn(), getHeaders(), createHeaders(), setHeaders(),
|
1777 |
+
isSymmetric(), getAsymmetricRows()
|
1778 |
+
|
1779 |
+
|
1780 |
+
----
|
1781 |
+
|
1782 |
+
= Method:setHeaders =
|
1783 |
+
|
1784 |
+
_ header injector _
|
1785 |
+
|
1786 |
+
uses a $list of values which wil be used to replace current
|
1787 |
+
headers.
|
1788 |
+
|
1789 |
+
Note: that given $list must match the length of all rows.
|
1790 |
+
known as symmetric. see isSymmetric() and getAsymmetricRows() methods
|
1791 |
+
|
1792 |
+
Also, that current headers will be used as first row of data
|
1793 |
+
and consecuently all rows order will change with this action.
|
1794 |
+
|
1795 |
+
sample of a csv file "my_cool.csv"
|
1796 |
+
|
1797 |
+
|
1798 |
+
|
1799 |
+
{{{
|
1800 |
+
name,age,skill
|
1801 |
+
john,13,knows magic
|
1802 |
+
tanaka,8,makes sushi
|
1803 |
+
jose,5,dances salsa
|
1804 |
+
}}}
|
1805 |
+
|
1806 |
+
|
1807 |
+
load the library and csv file
|
1808 |
+
|
1809 |
+
|
1810 |
+
|
1811 |
+
{{{
|
1812 |
+
require_once 'File/CSV/DataSource.php';
|
1813 |
+
$csv = new File_CSV_DataSource;
|
1814 |
+
$csv->load('my_cool.csv');
|
1815 |
+
}}}
|
1816 |
+
|
1817 |
+
|
1818 |
+
lets dump currently loaded data
|
1819 |
+
|
1820 |
+
|
1821 |
+
{{{
|
1822 |
+
var_export($csv->connect());
|
1823 |
+
}}}
|
1824 |
+
|
1825 |
+
|
1826 |
+
output
|
1827 |
+
|
1828 |
+
|
1829 |
+
|
1830 |
+
{{{
|
1831 |
+
array (
|
1832 |
+
0 =>
|
1833 |
+
array (
|
1834 |
+
'name' => 'john',
|
1835 |
+
'age' => '13',
|
1836 |
+
'skill' => 'knows magic',
|
1837 |
+
),
|
1838 |
+
1 =>
|
1839 |
+
array (
|
1840 |
+
'name' => 'tanaka',
|
1841 |
+
'age' => '8',
|
1842 |
+
'skill' => 'makes sushi',
|
1843 |
+
),
|
1844 |
+
2 =>
|
1845 |
+
array (
|
1846 |
+
'name' => 'jose',
|
1847 |
+
'age' => '5',
|
1848 |
+
'skill' => 'dances salsa',
|
1849 |
+
),
|
1850 |
+
)
|
1851 |
+
}}}
|
1852 |
+
|
1853 |
+
|
1854 |
+
And now lets create a new set of headers and attempt to inject
|
1855 |
+
them into the current loaded dataset
|
1856 |
+
|
1857 |
+
|
1858 |
+
|
1859 |
+
{{{
|
1860 |
+
$new_headers = array('a', 'b', 'c');
|
1861 |
+
var_export($csv->setHeaders($new_headers));
|
1862 |
+
}}}
|
1863 |
+
|
1864 |
+
|
1865 |
+
output
|
1866 |
+
|
1867 |
+
|
1868 |
+
|
1869 |
+
{{{
|
1870 |
+
true
|
1871 |
+
}}}
|
1872 |
+
|
1873 |
+
|
1874 |
+
Now lets try the same with some headers that do not match the
|
1875 |
+
current headers length. (this should fail)
|
1876 |
+
|
1877 |
+
|
1878 |
+
|
1879 |
+
{{{
|
1880 |
+
$new_headers = array('a', 'b');
|
1881 |
+
var_export($csv->setHeaders($new_headers));
|
1882 |
+
}}}
|
1883 |
+
|
1884 |
+
|
1885 |
+
output
|
1886 |
+
|
1887 |
+
|
1888 |
+
|
1889 |
+
{{{
|
1890 |
+
false
|
1891 |
+
}}}
|
1892 |
+
|
1893 |
+
|
1894 |
+
now let's dump whatever we have changed
|
1895 |
+
|
1896 |
+
|
1897 |
+
|
1898 |
+
{{{
|
1899 |
+
var_export($csv->connect());
|
1900 |
+
}}}
|
1901 |
+
|
1902 |
+
|
1903 |
+
output
|
1904 |
+
|
1905 |
+
|
1906 |
+
|
1907 |
+
{{{
|
1908 |
+
array (
|
1909 |
+
0 =>
|
1910 |
+
array (
|
1911 |
+
'a' => 'name',
|
1912 |
+
'b' => 'age',
|
1913 |
+
'c' => 'skill',
|
1914 |
+
),
|
1915 |
+
1 =>
|
1916 |
+
array (
|
1917 |
+
'a' => 'john',
|
1918 |
+
'b' => '13',
|
1919 |
+
'c' => 'knows magic',
|
1920 |
+
),
|
1921 |
+
2 =>
|
1922 |
+
array (
|
1923 |
+
'a' => 'tanaka',
|
1924 |
+
'b' => '8',
|
1925 |
+
'c' => 'makes sushi',
|
1926 |
+
),
|
1927 |
+
3 =>
|
1928 |
+
array (
|
1929 |
+
'a' => 'jose',
|
1930 |
+
'b' => '5',
|
1931 |
+
'c' => 'dances salsa',
|
1932 |
+
),
|
1933 |
+
)
|
1934 |
+
}}}
|
1935 |
+
|
1936 |
+
|
1937 |
+
# *Argument* _array_ $list a collection of names to use as headers,
|
1938 |
+
|
1939 |
+
* *Visibility* public
|
1940 |
+
* *Returns* boolean fails if data is not symmetric
|
1941 |
+
* *Also see* isSymmetric(), getAsymmetricRows(), getHeaders(), createHeaders()
|
1942 |
+
|
1943 |
+
|
1944 |
+
----
|
1945 |
+
|
1946 |
+
= Method:settings =
|
1947 |
+
|
1948 |
+
_ settings alterator _
|
1949 |
+
|
1950 |
+
lets you define different settings for scanning
|
1951 |
+
|
1952 |
+
Given array will override the internal settings
|
1953 |
+
|
1954 |
+
|
1955 |
+
|
1956 |
+
{{{
|
1957 |
+
$settings = array(
|
1958 |
+
'delimiter' => ',',
|
1959 |
+
'eol' => ";",
|
1960 |
+
'length' => 999999,
|
1961 |
+
'escape' => '"'
|
1962 |
+
);
|
1963 |
+
}}}
|
1964 |
+
|
1965 |
+
|
1966 |
+
# *Argument* _mixed_ $array containing settings to use
|
1967 |
+
|
1968 |
+
* *Visibility* public
|
1969 |
+
* *Returns* boolean true if changes where applyed successfully
|
1970 |
+
* *Also see* $settings
|
1971 |
+
|
1972 |
+
|
1973 |
+
----
|
1974 |
+
|
1975 |
+
= Method:symmetrize =
|
1976 |
+
|
1977 |
+
_ all rows length equalizer _
|
1978 |
+
|
1979 |
+
makes the length of all rows and headers the same. If no $value is given
|
1980 |
+
all unexistent cells will be filled with empty spaces
|
1981 |
+
|
1982 |
+
# *Argument* _mixed_ $value the value to fill the unexistent cells
|
1983 |
+
|
1984 |
+
* *Visibility* public
|
1985 |
+
* *Returns* array
|
1986 |
+
* *Also see* isSymmetric(), getAsymmetricRows(), symmetrize()
|
1987 |
+
|
1988 |
+
|
1989 |
+
----
|
1990 |
+
|
1991 |
+
= Method:walkColumn =
|
1992 |
+
|
1993 |
+
_ column walker _
|
1994 |
+
|
1995 |
+
goes through the whole column and executes a callback for each
|
1996 |
+
one of the cells in it.
|
1997 |
+
|
1998 |
+
Note: callback functions get the value of the cell as an
|
1999 |
+
argument, and whatever that callback returns will be used to
|
2000 |
+
replace the current value of that cell.
|
2001 |
+
|
2002 |
+
# *Argument* _string_ $name the header name used to identify the column
|
2003 |
+
# *Argument* _string_ $callback the callback function to be called per
|
2004 |
+
each cell value
|
2005 |
+
|
2006 |
+
* *Visibility* public
|
2007 |
+
* *Returns* boolean
|
2008 |
+
* *Also see* getHeaders(), fillColumn(), appendColumn()
|
2009 |
+
|
2010 |
+
|
2011 |
+
----
|
2012 |
+
|
2013 |
+
= Method:walkGrid =
|
2014 |
+
|
2015 |
+
_ grid walker _
|
2016 |
+
|
2017 |
+
travels through the whole dataset executing a callback per each
|
2018 |
+
cell
|
2019 |
+
|
2020 |
+
Note: callback functions get the value of the cell as an
|
2021 |
+
argument, and whatever that callback returns will be used to
|
2022 |
+
replace the current value of that cell.
|
2023 |
+
|
2024 |
+
# *Argument* _string_ $callback the callback function to be called per
|
2025 |
+
each cell in the dataset.
|
2026 |
+
|
2027 |
+
* *Visibility* public
|
2028 |
+
* *Returns* void
|
2029 |
+
* *Also see* walkColumn(), walkRow(), fillColumn(), fillRow(), fillCell()
|
2030 |
+
|
2031 |
+
|
2032 |
+
----
|
2033 |
+
|
2034 |
+
= Method:walkRow =
|
2035 |
+
|
2036 |
+
_ row walker _
|
2037 |
+
|
2038 |
+
goes through one full row of data and executes a callback
|
2039 |
+
function per each cell in that row.
|
2040 |
+
|
2041 |
+
Note: callback functions get the value of the cell as an
|
2042 |
+
argument, and whatever that callback returns will be used to
|
2043 |
+
replace the current value of that cell.
|
2044 |
+
|
2045 |
+
# *Argument* _string_ |integer $row anything that is numeric is a valid row
|
2046 |
+
identificator. As long as it is within the range of the currently
|
2047 |
+
loaded dataset
|
2048 |
+
|
2049 |
+
# *Argument* _string_ $callback the callback function to be executed
|
2050 |
+
per each cell in a row
|
2051 |
+
|
2052 |
+
* *Visibility* public
|
2053 |
+
* *Returns* boolean
|
2054 |
+
# false if callback does not exist
|
2055 |
+
# false if row does not exits
|
2056 |
+
|
2057 |
+
|
2058 |
+
----
|
File_CSV_DataSource/tests/File_CSV_DataSourceTest.php
ADDED
@@ -0,0 +1,508 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
require_once 'PHPUnit/Framework.php';
|
3 |
+
|
4 |
+
require_once "File/CSV/DataSource.php";
|
5 |
+
require_once "File/CSV/tests/fixtures/csv.php";
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Test class for File_CSV_DataSource.
|
9 |
+
* Generated by PHPUnit on 2008-10-08 at 20:47:55.
|
10 |
+
*/
|
11 |
+
class File_CSV_DataSourceTest extends PHPUnit_Framework_TestCase
|
12 |
+
{
|
13 |
+
protected $csv;
|
14 |
+
|
15 |
+
protected function setUp()
|
16 |
+
{
|
17 |
+
$this->csv = new File_CSV_DataSource;
|
18 |
+
}
|
19 |
+
|
20 |
+
protected function tearDown()
|
21 |
+
{
|
22 |
+
$this->csv = null;
|
23 |
+
}
|
24 |
+
|
25 |
+
public function test_uses_must_load_valid_files()
|
26 |
+
{
|
27 |
+
// must return true when a file is valid
|
28 |
+
foreach (fix('valid_files') as $file => $msg) {
|
29 |
+
$this->assertTrue($this->csv->load(path($file)), $msg);
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
public function testSettings()
|
34 |
+
{
|
35 |
+
$new_delim = '>>>>';
|
36 |
+
$this->csv->settings(array('delimiter' => $new_delim));
|
37 |
+
|
38 |
+
$expected = array(
|
39 |
+
'delimiter' => $new_delim,
|
40 |
+
'eol' => ";",
|
41 |
+
'length' => 999999,
|
42 |
+
'escape' => '"'
|
43 |
+
);
|
44 |
+
|
45 |
+
$msg = 'settings where not parsed correctly!';
|
46 |
+
$this->assertEquals($expected, $this->csv->settings, $msg);
|
47 |
+
}
|
48 |
+
|
49 |
+
public function testHeaders()
|
50 |
+
{
|
51 |
+
|
52 |
+
$this->csv->load(path('symmetric.csv'));
|
53 |
+
$result = $this->csv->getHeaders();
|
54 |
+
$this->assertEquals(fix('symmetric_headers'), $result);
|
55 |
+
}
|
56 |
+
|
57 |
+
public function testConnect()
|
58 |
+
{
|
59 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
60 |
+
$this->assertEquals(fix('symmetric_connection'), $this->csv->connect());
|
61 |
+
}
|
62 |
+
|
63 |
+
public function test_connect_must_return_emtpy_arr_when_not_aisSymmetric()
|
64 |
+
{
|
65 |
+
$this->assertTrue($this->csv->load(path('escape_ng.csv')));
|
66 |
+
$this->assertEquals(array(), $this->csv->connect());
|
67 |
+
}
|
68 |
+
|
69 |
+
public function testSymmetric_OK()
|
70 |
+
{
|
71 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
72 |
+
$this->assertTrue($this->csv->isSymmetric());
|
73 |
+
}
|
74 |
+
|
75 |
+
public function testSymmetric_NG()
|
76 |
+
{
|
77 |
+
$this->assertTrue($this->csv->load(path('asymmetric.csv')));
|
78 |
+
$this->assertFalse($this->csv->isSymmetric());
|
79 |
+
}
|
80 |
+
|
81 |
+
public function testAsymmetry()
|
82 |
+
{
|
83 |
+
$this->assertTrue($this->csv->load(path('asymmetric.csv')));
|
84 |
+
$result = $this->csv->getAsymmetricRows();
|
85 |
+
$this->assertEquals(fix('asymmetric_rows'), $result);
|
86 |
+
}
|
87 |
+
|
88 |
+
public function testColumn()
|
89 |
+
{
|
90 |
+
$this->assertTrue($this->csv->load(path('asymmetric.csv')));
|
91 |
+
$result = $this->csv->getColumn('header_c');
|
92 |
+
|
93 |
+
$this->assertEquals(fix('expected_column'), $result);
|
94 |
+
|
95 |
+
}
|
96 |
+
|
97 |
+
public function testRaw_array()
|
98 |
+
{
|
99 |
+
$this->assertTrue($this->csv->load(path('raw.csv')));
|
100 |
+
$this->assertEquals(fix('expected_raw'), $this->csv->getRawArray());
|
101 |
+
}
|
102 |
+
|
103 |
+
public function test_if_connect_ignores_valid_escaped_delims()
|
104 |
+
{
|
105 |
+
$this->assertTrue($this->csv->load(path('escape_ok.csv')));
|
106 |
+
$this->assertEquals(fix('expected_escaped'), $this->csv->connect());
|
107 |
+
}
|
108 |
+
|
109 |
+
public function test_create_headers_must_generate_headers_for_symmetric_data()
|
110 |
+
{
|
111 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
112 |
+
$this->assertTrue($this->csv->createHeaders('COL'));
|
113 |
+
$this->assertEquals(fix('expected_headers'), $this->csv->getHeaders());
|
114 |
+
}
|
115 |
+
|
116 |
+
public function tets_create_headers_must_not_create_when_data_is_aisSymmetric()
|
117 |
+
{
|
118 |
+
$this->assertTrue($this->csv->load(path('asymmetric.csv')));
|
119 |
+
$this->assertFalse($this->csv->createHeaders('COL'));
|
120 |
+
$this->assertEquals(fix('original_headers'), $this->csv->getHeaders());
|
121 |
+
}
|
122 |
+
|
123 |
+
public function test_inject_headers_must_inject_headers_for_symmetric_data()
|
124 |
+
{
|
125 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
126 |
+
$this->assertEquals(fix('original_headers'), $this->csv->getHeaders());
|
127 |
+
$this->assertTrue($this->csv->setHeaders(fix('expected_headers')));
|
128 |
+
$this->assertEquals(fix('expected_headers'), $this->csv->getHeaders());
|
129 |
+
$this->assertEquals(fix('symmetric_raw_data'), $this->csv->getRows());
|
130 |
+
}
|
131 |
+
|
132 |
+
public function test_inject_headers_must_not_inject_when_data_is_aisSymmetric()
|
133 |
+
{
|
134 |
+
$this->assertTrue($this->csv->load(path('asymmetric.csv')));
|
135 |
+
$this->assertEquals(fix('original_headers'), $this->csv->getHeaders());
|
136 |
+
$this->assertFalse($this->csv->setHeaders(fix('expected_headers')));
|
137 |
+
$this->assertEquals(fix('original_headers'), $this->csv->getHeaders());
|
138 |
+
}
|
139 |
+
|
140 |
+
public function test_row_count_is_correct()
|
141 |
+
{
|
142 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
143 |
+
$expected_count = count(fix('symmetric_connection'));
|
144 |
+
$this->assertEquals($expected_count, $this->csv->countRows());
|
145 |
+
}
|
146 |
+
|
147 |
+
public function test_row_fetching_returns_correct_result()
|
148 |
+
{
|
149 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
150 |
+
$expected = fix('eighth_row_from_symmetric');
|
151 |
+
$this->assertEquals($expected, $this->csv->getRow(8));
|
152 |
+
}
|
153 |
+
|
154 |
+
public function test_row_must_be_empty_array_when_row_does_not_exist()
|
155 |
+
{
|
156 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
157 |
+
$this->assertEquals(array(), $this->csv->getRow(-1));
|
158 |
+
$this->assertEquals(array(), $this->csv->getRow(10));
|
159 |
+
}
|
160 |
+
|
161 |
+
public function test_connect_must_build_relationship_for_needed_headers_only()
|
162 |
+
{
|
163 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
164 |
+
$result = $this->csv->connect(array('header_a'));
|
165 |
+
$this->assertEquals(fix('header_a_connection'), $result);
|
166 |
+
}
|
167 |
+
|
168 |
+
public function test_connect_must_return_empty_array_if_given_params_are_of_invalid_datatype()
|
169 |
+
{
|
170 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
171 |
+
$this->assertEquals(array(), $this->csv->connect('header_a'));
|
172 |
+
}
|
173 |
+
|
174 |
+
public function test_connect_should_ignore_non_existant_headers_AND_return_empty_array()
|
175 |
+
{
|
176 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
177 |
+
$this->assertEquals(array(), $this->csv->connect(array('non_existent_header')));
|
178 |
+
}
|
179 |
+
|
180 |
+
public function test_connect_should_ignore_non_existant_headers_BUT_get_existent_ones()
|
181 |
+
{
|
182 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
183 |
+
$result = $this->csv->connect(array('non_existent_header', 'header_a'));
|
184 |
+
$this->assertEquals(fix('header_a_connection'), $result);
|
185 |
+
}
|
186 |
+
|
187 |
+
public function test_count_getHeaders()
|
188 |
+
{
|
189 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
190 |
+
$this->assertEquals(5, $this->csv->countHeaders());
|
191 |
+
}
|
192 |
+
|
193 |
+
public function test_raw_array_must_remove_empty_lines()
|
194 |
+
{
|
195 |
+
$this->assertTrue($this->csv->load(path('symmetric_with_empty_lines.csv')));
|
196 |
+
$this->assertEquals(fix('symmetric_connection'), $this->csv->connect());
|
197 |
+
}
|
198 |
+
|
199 |
+
public function test_raw_array_must_remove_empty_records()
|
200 |
+
{
|
201 |
+
$this->assertTrue($this->csv->load(path('symmetric_with_empty_records.csv')));
|
202 |
+
$this->assertEquals(fix('symmetric_connection'), $this->csv->connect());
|
203 |
+
}
|
204 |
+
|
205 |
+
public function test_range_of_rows_should_retrive_specific_rows_only()
|
206 |
+
{
|
207 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
208 |
+
$expected = fix('symmetric_range_of_rows');
|
209 |
+
$this->assertEquals($expected, $this->csv->getRows(range(1, 2)));
|
210 |
+
}
|
211 |
+
|
212 |
+
public function test_non_existent_rows_in_range_should_be_ignored()
|
213 |
+
{
|
214 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
215 |
+
$expected = fix('symmetric_range_of_rows');
|
216 |
+
$this->assertEquals($expected, $this->csv->getRows(array(22, 19, 1, 2)));
|
217 |
+
}
|
218 |
+
|
219 |
+
public function test_fist_row_must_be_zero()
|
220 |
+
{
|
221 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
222 |
+
$this->assertEquals(fix('first_row_from_symmetric'), $this->csv->getRow(0));
|
223 |
+
}
|
224 |
+
|
225 |
+
public function test_uses_must_flush_internal_data_when_new_file_is_given()
|
226 |
+
{
|
227 |
+
$this->assertTrue($this->csv->load(path('another_symmetric.csv')));
|
228 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
229 |
+
$this->assertEquals(fix('symmetric_headers'), $this->csv->getHeaders());
|
230 |
+
$this->assertEquals(fix('symmetric_rows'), $this->csv->getRows());
|
231 |
+
$this->assertEquals(fix('symmetric_raw_data'), $this->csv->getRawArray());
|
232 |
+
}
|
233 |
+
|
234 |
+
public function test_getCell()
|
235 |
+
{
|
236 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
237 |
+
$this->assertEquals(fix('first_symmetric_cell'), $this->csv->getCell(0, 0));
|
238 |
+
}
|
239 |
+
|
240 |
+
public function test_header_exists()
|
241 |
+
{
|
242 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
243 |
+
foreach (fix('symmetric_headers') as $h) {
|
244 |
+
$this->assertTrue($this->csv->hasColumn($h));
|
245 |
+
}
|
246 |
+
}
|
247 |
+
|
248 |
+
public function test_header_exists_must_return_false_when_header_does_not_exist()
|
249 |
+
{
|
250 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
251 |
+
$this->assertFalse($this->csv->hasColumn(md5('x')));
|
252 |
+
}
|
253 |
+
|
254 |
+
public function test_fill_getCell()
|
255 |
+
{
|
256 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
257 |
+
$this->assertTrue($this->csv->fillCell(0, 0, 'hoge hoge'));
|
258 |
+
$this->assertEquals('hoge hoge', $this->csv->getCell(0, 0));
|
259 |
+
}
|
260 |
+
|
261 |
+
public function test_coordinatable_must_return_true_when_coordinates_exist()
|
262 |
+
{
|
263 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
264 |
+
$this->assertTrue($this->csv->hasCell(0, 0));
|
265 |
+
$this->assertFalse($this->csv->hasCell(-1, 0));
|
266 |
+
$this->assertFalse($this->csv->hasCell(0, -1));
|
267 |
+
$this->assertFalse($this->csv->hasCell(-1, -1));
|
268 |
+
$this->assertFalse($this->csv->hasCell(1, 11));
|
269 |
+
}
|
270 |
+
|
271 |
+
public function test_fill_column_must_fill_all_values_of_a_getColumn()
|
272 |
+
{
|
273 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
274 |
+
$fh = fix('first_symmetric_header');
|
275 |
+
$this->assertTrue($this->csv->fillColumn($fh, ''));
|
276 |
+
$this->assertEquals(fix('empty_column'), $this->csv->getColumn($fh));
|
277 |
+
}
|
278 |
+
|
279 |
+
public function test_append_column_must_create_new_header_and_blank_values()
|
280 |
+
{
|
281 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
282 |
+
$this->assertTrue($this->csv->appendColumn('extra'));
|
283 |
+
$se = fix('symmetric_extra_header');
|
284 |
+
$this->assertEquals($se, $this->csv->getHeaders());
|
285 |
+
$this->assertEquals(fix('empty_column'), $this->csv->getColumn('extra'));
|
286 |
+
$this->assertEquals(count($se), $this->csv->countHeaders());
|
287 |
+
}
|
288 |
+
|
289 |
+
public function test_symmetrize_must_convert_asymmetric_file()
|
290 |
+
{
|
291 |
+
$this->assertTrue($this->csv->load(path('asymmetric.csv')));
|
292 |
+
$this->csv->symmetrize();
|
293 |
+
$this->assertTrue($this->csv->isSymmetric());
|
294 |
+
}
|
295 |
+
|
296 |
+
public function test_symetrize_must_not_alter_symmetric_data()
|
297 |
+
{
|
298 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
299 |
+
$this->csv->symmetrize();
|
300 |
+
$this->assertEquals(fix('symmetric_headers'), $this->csv->getHeaders());
|
301 |
+
$this->assertEquals(fix('symmetric_rows'), $this->csv->getRows());
|
302 |
+
$this->assertEquals(fix('symmetric_raw_data'), $this->csv->getRawArray());
|
303 |
+
}
|
304 |
+
|
305 |
+
public function test_remove_column_must_remove_last_column_and_return_true()
|
306 |
+
{
|
307 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
308 |
+
$this->assertTrue($this->csv->removeColumn('header_e'));
|
309 |
+
$this->assertEquals(fix('symmetric_raw_data_with_last_colum_removed'), $this->csv->getRawArray());
|
310 |
+
}
|
311 |
+
|
312 |
+
public function test_remove_column_must_remove_second_column_and_return_true()
|
313 |
+
{
|
314 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
315 |
+
$this->assertTrue($this->csv->removeColumn('header_b'));
|
316 |
+
$this->assertEquals(fix('symmetric_raw_data_with_second_column_removed'), $this->csv->getRawArray());
|
317 |
+
}
|
318 |
+
|
319 |
+
public function test_remove_column_must_return_false_when_column_does_not_exist()
|
320 |
+
{
|
321 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
322 |
+
$this->assertFalse($this->csv->removeColumn(md5('header_b')));
|
323 |
+
}
|
324 |
+
|
325 |
+
public function test_remove_row_must_remove_first_row_successfully_and_return_true()
|
326 |
+
{
|
327 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
328 |
+
$this->assertTrue($this->csv->removeRow(0));
|
329 |
+
$this->assertEquals(fix('symmetric_rows_without_first_row'), $this->csv->getRows());
|
330 |
+
}
|
331 |
+
|
332 |
+
public function test_remove_row_must_remove_only_third_row_and_return_true()
|
333 |
+
{
|
334 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
335 |
+
$this->assertTrue($this->csv->removeRow(2));
|
336 |
+
$this->assertEquals(fix('symmetric_rows_without_third_row'), $this->csv->getRows());
|
337 |
+
}
|
338 |
+
|
339 |
+
public function test_remove_row_must_return_false_and_leave_rows_intact_when_row_does_not_exist()
|
340 |
+
{
|
341 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
342 |
+
$this->assertFalse($this->csv->removeRow(999999));
|
343 |
+
}
|
344 |
+
|
345 |
+
public function test_rows_must_return_all_rows_when_argument_is_not_an_array()
|
346 |
+
{
|
347 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
348 |
+
$this->assertEquals(fix('symmetric_rows'), $this->csv->getRows('lasdjfklsajdf'));
|
349 |
+
$this->assertEquals(fix('symmetric_rows'), $this->csv->getRows(true));
|
350 |
+
$this->assertEquals(fix('symmetric_rows'), $this->csv->getRows(false));
|
351 |
+
$this->assertEquals(fix('symmetric_rows'), $this->csv->getRows(1));
|
352 |
+
$this->assertEquals(fix('symmetric_rows'), $this->csv->getRows(0));
|
353 |
+
}
|
354 |
+
|
355 |
+
public function test_has_row_must_return_true_when_a_row_exists()
|
356 |
+
{
|
357 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
358 |
+
$this->assertTrue($this->csv->hasRow(1));
|
359 |
+
}
|
360 |
+
|
361 |
+
public function test_row_must_return_false_when_a_row_does_not_exist()
|
362 |
+
{
|
363 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
364 |
+
$this->assertFalse($this->csv->hasRow(999999));
|
365 |
+
}
|
366 |
+
|
367 |
+
public function test_fill_row_must_fill_a_row_with_a_string_and_return_true()
|
368 |
+
{
|
369 |
+
$this->assertTrue($this->csv->load(path('one_row_only.csv')));
|
370 |
+
$this->assertTrue($this->csv->fillRow(0, 'hello'));
|
371 |
+
$this->assertEquals(fix('rows_from_one_row_only_plus_one_filled_with_str_hello'), $this->csv->getRows());
|
372 |
+
}
|
373 |
+
|
374 |
+
public function test_fill_row_mus_fill_a_row_with_an_array_and_return_true()
|
375 |
+
{
|
376 |
+
$this->assertTrue($this->csv->load(path('one_row_only.csv')));
|
377 |
+
$this->assertTrue($this->csv->fillRow(0, $this->csv->getHeaders()));
|
378 |
+
$this->assertEquals(fix('rows_from_one_row_only_plus_one_filled_with_arr_abc'), $this->csv->getRows());
|
379 |
+
}
|
380 |
+
|
381 |
+
public function test_fill_row_must_fill_a_row_with_a_number_and_return_true()
|
382 |
+
{
|
383 |
+
$this->assertTrue($this->csv->load(path('one_row_only.csv')));
|
384 |
+
$this->assertTrue($this->csv->fillRow(0, 1));
|
385 |
+
$this->assertEquals(fix('rows_from_one_row_only_plus_one_filled_with_num_1'), $this->csv->getRows());
|
386 |
+
}
|
387 |
+
|
388 |
+
public function test_fill_row_must_not_change_anything_when_given_row_does_not_exist_and_return_false()
|
389 |
+
{
|
390 |
+
$this->assertTrue($this->csv->load(path('one_row_only.csv')));
|
391 |
+
$this->assertFalse($this->csv->fillRow(999, 1));
|
392 |
+
$this->assertEquals(fix('rows_from_one_row_only'), $this->csv->getRows());
|
393 |
+
}
|
394 |
+
|
395 |
+
public function test_fill_row_must_not_change_anything_when_given_value_is_other_than_string_int_or_array_and_return_false()
|
396 |
+
{
|
397 |
+
$this->assertTrue($this->csv->load(path('one_row_only.csv')));
|
398 |
+
$this->assertFalse($this->csv->fillRow(0, new stdClass));
|
399 |
+
$this->assertEquals(fix('rows_from_one_row_only'), $this->csv->getRows());
|
400 |
+
}
|
401 |
+
|
402 |
+
// be strict, no looking back from the end of array
|
403 |
+
public function test_fill_row_must_return_false_when_negative_numbers_are_given()
|
404 |
+
{
|
405 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
406 |
+
$this->assertFalse($this->csv->fillRow(-1, 'xxx'));
|
407 |
+
$this->assertEquals(fix('symmetric_rows'), $this->csv->getRows());
|
408 |
+
}
|
409 |
+
|
410 |
+
public function test_append_row_must_aggregate_a_row_fill_it_with_values_and_return_true()
|
411 |
+
{
|
412 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
413 |
+
$this->assertTrue($this->csv->appendRow(fix('one_row_for_symmetric')));
|
414 |
+
$this->assertEquals(fix('symmetric_rows_plus_one'), $this->csv->getRows());
|
415 |
+
}
|
416 |
+
|
417 |
+
public function test_walk_row_must_replace_values_in_a_row_by_using_a_callback_and_be_true()
|
418 |
+
{
|
419 |
+
$this->assertTrue($this->csv->load(path('one_row_only.csv')));
|
420 |
+
$this->assertTrue($this->csv->walkRow(0, 'callback'));
|
421 |
+
$this->assertEquals(fix('rows_from_one_row_only_plus_one_filled_with_num_1'), $this->csv->getRows());
|
422 |
+
}
|
423 |
+
|
424 |
+
public function test_walk_row_must_return_false_when_callback_does_not_exist()
|
425 |
+
{
|
426 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
427 |
+
$non_existent_callback = md5('');
|
428 |
+
$this->assertFalse($this->csv->walkRow(1, $non_existent_callback));
|
429 |
+
$this->assertEquals(fix('symmetric_rows'), $this->csv->getRows());
|
430 |
+
$this->assertEquals(fix('symmetric_headers'), $this->csv->getHeaders());
|
431 |
+
}
|
432 |
+
|
433 |
+
public function test_walk_column_must_replace_values_in_a_column_and_be_true()
|
434 |
+
{
|
435 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
436 |
+
$fh = fix('first_symmetric_header');
|
437 |
+
$this->assertTrue($this->csv->walkColumn($fh, 'callback2'));
|
438 |
+
$this->assertEquals(fix('empty_column'), $this->csv->getColumn($fh));
|
439 |
+
}
|
440 |
+
|
441 |
+
public function test_walk_column_must_return_false_when_callback_does_not_exist()
|
442 |
+
{
|
443 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
444 |
+
$fh = fix('first_symmetric_header');
|
445 |
+
$non_existent_callback = md5('');
|
446 |
+
$this->assertFalse($this->csv->walkColumn($fh, $non_existent_callback));
|
447 |
+
$this->assertEquals(fix('symmetric_rows'), $this->csv->getRows());
|
448 |
+
$this->assertEquals(fix('symmetric_headers'), $this->csv->getHeaders());
|
449 |
+
}
|
450 |
+
|
451 |
+
public function test_walk_grid_must_replace_the_whole_data_set_and_be_true()
|
452 |
+
{
|
453 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
454 |
+
$this->assertTrue($this->csv->walkGrid('callback2'));
|
455 |
+
$this->assertEquals(fix('symmetric_rows_empty'), $this->csv->getRows());
|
456 |
+
}
|
457 |
+
|
458 |
+
public function test_walk_grid_must_return_false_when_callback_does_not_exist()
|
459 |
+
{
|
460 |
+
$this->assertTrue($this->csv->load(path('symmetric.csv')));
|
461 |
+
$non_existent_callback = md5('');
|
462 |
+
$this->assertFalse($this->csv->walkGrid($non_existent_callback));
|
463 |
+
$this->assertEquals(fix('symmetric_rows'), $this->csv->getRows());
|
464 |
+
$this->assertEquals(fix('symmetric_headers'), $this->csv->getHeaders());
|
465 |
+
}
|
466 |
+
|
467 |
+
public function test_constructor_must_be_equivalent_to_load()
|
468 |
+
{
|
469 |
+
$this->csv = new File_CSV_DataSource(path('symmetric.csv'));
|
470 |
+
$result = $this->csv->getHeaders();
|
471 |
+
$this->assertEquals(fix('symmetric_headers'), $result);
|
472 |
+
$this->assertEquals(fix('symmetric_rows'), $this->csv->getRows());
|
473 |
+
}
|
474 |
+
|
475 |
+
public function test_must_append_row_when_csv_file_only_has_headers_and_array_is_passed_returning_true()
|
476 |
+
{
|
477 |
+
$this->csv = new File_CSV_DataSource(path('only_headers.csv'));
|
478 |
+
$this->assertTrue($this->csv->appendRow(array(1, 2, 3)));
|
479 |
+
$result = array(array('a' => 1, 'b' => 2, 'c' => 3));
|
480 |
+
$this->assertEquals($result, $this->csv->connect());
|
481 |
+
}
|
482 |
+
|
483 |
+
public function test_must_append_row_when_csv_file_only_has_headers_and_string_is_passed_returning_true()
|
484 |
+
{
|
485 |
+
$this->csv = new File_CSV_DataSource(path('only_headers.csv'));
|
486 |
+
$this->assertTrue($this->csv->appendRow('1'));
|
487 |
+
$result = array(array('a' => '1', 'b' => '1', 'c' => '1'));
|
488 |
+
$this->assertEquals($result, $this->csv->connect());
|
489 |
+
}
|
490 |
+
|
491 |
+
public function test_must_append_row_when_csv_file_only_has_headers_and_numeric_value_is_passed_returning_true()
|
492 |
+
{
|
493 |
+
$this->csv = new File_CSV_DataSource(path('only_headers.csv'));
|
494 |
+
$this->assertTrue($this->csv->appendRow(1));
|
495 |
+
$result = array(array('a' => 1, 'b' => 1, 'c' => 1));
|
496 |
+
$this->assertEquals($result, $this->csv->connect());
|
497 |
+
}
|
498 |
+
|
499 |
+
public function test_must_use_headers_as_max_row_padding_when_headers_length_is_longer_than_all_rows_length()
|
500 |
+
{
|
501 |
+
$this->csv = new File_CSV_DataSource(path('longer_headers.csv'));
|
502 |
+
$this->csv->symmetrize();
|
503 |
+
$this->assertEquals(fix('longer_headers'), $this->csv->connect());
|
504 |
+
}
|
505 |
+
|
506 |
+
}
|
507 |
+
|
508 |
+
?>
|
File_CSV_DataSource/tests/data/another_symmetric.csv
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
1 |
+
name,age,skill
|
2 |
+
john,13,knows magic
|
3 |
+
tanaka,8,makes sushi
|
4 |
+
jose,5,dances salsa
|
File_CSV_DataSource/tests/data/asymmetric.csv
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
header_a, header_b, header_c, header_d, header_e
|
2 |
+
1aa, 1bb, 1cc, 1dd, 1ee
|
3 |
+
2aa, 2bb, 2cc, 2dd, 2ee
|
4 |
+
3aa, 3bb, 3cc, 3dd, 3ee
|
5 |
+
4aa, 4bb, 4cc, 4dd, 4ee
|
6 |
+
5aa, 5bb, 5cc, 5dd, 5ee, extra1
|
7 |
+
6aa, 6bb, 6cc, 6dd, 6ee
|
8 |
+
7aa, 7bb, 7cc, 7dd, 7ee
|
9 |
+
8aa, 8bb, 8cc, 8dd, 8ee, extra2
|
10 |
+
9aa, 9bb, 9cc, 9dd, 9ee
|
File_CSV_DataSource/tests/data/empty.csv
ADDED
File without changes
|
File_CSV_DataSource/tests/data/escape_ng.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
1 |
+
one, two, three
|
2 |
+
th,ie, adn, thei
|
3 |
+
thie, adn, thei
|
File_CSV_DataSource/tests/data/escape_ok.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
1 |
+
one, two, three
|
2 |
+
"thie,", adn, thei
|
3 |
+
thie, adn, thei
|
File_CSV_DataSource/tests/data/longer_headers.csv
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
1 |
+
one, two, three, four, five, six
|
2 |
+
1, 2, 3
|
3 |
+
1, 2, 3, 4
|
4 |
+
, 2, 3, 4
|
File_CSV_DataSource/tests/data/multcased.CsV
ADDED
File without changes
|
File_CSV_DataSource/tests/data/non_csv_extension.txt
ADDED
File without changes
|
File_CSV_DataSource/tests/data/one_row_only.csv
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
a,b,c
|
2 |
+
1,2,3
|
File_CSV_DataSource/tests/data/only_headers.csv
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
a,b,c
|
File_CSV_DataSource/tests/data/raw.csv
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
h_one, h_two, h_three
|
2 |
+
v_1one, v_1two, v_1three
|
3 |
+
v_2one, v_2two, v_2three
|
4 |
+
v_3one, v_3two, v_3three
|
5 |
+
|
File_CSV_DataSource/tests/data/symmetric.csv
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
header_a, header_b, header_c, header_d, header_e
|
2 |
+
1aa, 1bb, 1cc, 1dd, 1ee
|
3 |
+
2aa, 2bb, 2cc, 2dd, 2ee
|
4 |
+
3aa, 3bb, 3cc, 3dd, 3ee
|
5 |
+
4aa, 4bb, 4cc, 4dd, 4ee
|
6 |
+
5aa, 5bb, 5cc, 5dd, 5ee
|
7 |
+
6aa, 6bb, 6cc, 6dd, 6ee
|
8 |
+
7aa, 7bb, 7cc, 7dd, 7ee
|
9 |
+
8aa, 8bb, 8cc, 8dd, 8ee
|
10 |
+
9aa, 9bb, 9cc, 9dd, 9ee
|
File_CSV_DataSource/tests/data/symmetric_with_empty_lines.csv
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
header_a, header_b, header_c, header_d, header_e
|
2 |
+
1aa, 1bb, 1cc, 1dd, 1ee
|
3 |
+
2aa, 2bb, 2cc, 2dd, 2ee
|
4 |
+
3aa, 3bb, 3cc, 3dd, 3ee
|
5 |
+
4aa, 4bb, 4cc, 4dd, 4ee
|
6 |
+
|
7 |
+
5aa, 5bb, 5cc, 5dd, 5ee
|
8 |
+
6aa, 6bb, 6cc, 6dd, 6ee
|
9 |
+
|
10 |
+
7aa, 7bb, 7cc, 7dd, 7ee
|
11 |
+
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
8aa, 8bb, 8cc, 8dd, 8ee
|
16 |
+
9aa, 9bb, 9cc, 9dd, 9ee
|
17 |
+
|
18 |
+
|
19 |
+
|
20 |
+
|
File_CSV_DataSource/tests/data/symmetric_with_empty_records.csv
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
header_a, header_b, header_c, header_d, header_e
|
2 |
+
, , , ,
|
3 |
+
, , , ,
|
4 |
+
, , , ,
|
5 |
+
, , , ,
|
6 |
+
1aa, 1bb, 1cc, 1dd, 1ee
|
7 |
+
2aa, 2bb, 2cc, 2dd, 2ee
|
8 |
+
3aa, 3bb, 3cc, 3dd, 3ee
|
9 |
+
, , , ,
|
10 |
+
4aa, 4bb, 4cc, 4dd, 4ee
|
11 |
+
, , , ,
|
12 |
+
5aa, 5bb, 5cc, 5dd, 5ee
|
13 |
+
, , , ,
|
14 |
+
6aa, 6bb, 6cc, 6dd, 6ee
|
15 |
+
, , , ,
|
16 |
+
, , , ,
|
17 |
+
, , , ,
|
18 |
+
, , , ,
|
19 |
+
7aa, 7bb, 7cc, 7dd, 7ee
|
20 |
+
8aa, 8bb, 8cc, 8dd, 8ee
|
21 |
+
9aa, 9bb, 9cc, 9dd, 9ee
|
22 |
+
, , , ,
|
23 |
+
, , , ,
|
24 |
+
, , , ,
|
25 |
+
, , , ,
|
26 |
+
, , , ,
|
27 |
+
, , , ,
|
28 |
+
, , , ,
|
File_CSV_DataSource/tests/data/symmetric_with_trailing_spaces.csv
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
header_a, header_b, header_c, header_d, header_e
|
2 |
+
1aa, 1bb, 1cc, 1dd, 1ee
|
3 |
+
2aa, 2bb, 2cc, 2dd, 2ee
|
4 |
+
3aa , 3bb , 3cc, 3dd, 3ee
|
5 |
+
4aa, 4bb, 4cc, 4dd, 4ee
|
6 |
+
5aa, 5bb, 5cc, 5dd, 5ee
|
7 |
+
6aa, 6bb, 6cc, 6dd, 6ee
|
8 |
+
7aa, 7bb, 7cc, 7dd, 7ee
|
9 |
+
8aa, 8bb, 8cc, 8dd, 8ee
|
10 |
+
9aa, 9bb, 9cc, 9dd, 9ee
|
File_CSV_DataSource/tests/data/uppercased.CSV
ADDED
File without changes
|
File_CSV_DataSource/tests/fixtures/csv.php
ADDED
@@ -0,0 +1,999 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
$fixtures = array (
|
4 |
+
'symmetric_headers' =>
|
5 |
+
array (
|
6 |
+
0 => 'header_a',
|
7 |
+
1 => 'header_b',
|
8 |
+
2 => 'header_c',
|
9 |
+
3 => 'header_d',
|
10 |
+
4 => 'header_e',
|
11 |
+
),
|
12 |
+
'rows_from_one_row_only' => array (
|
13 |
+
array (
|
14 |
+
0 => '1',
|
15 |
+
1 => '2',
|
16 |
+
2 => '3',
|
17 |
+
),
|
18 |
+
),
|
19 |
+
'rows_from_one_row_only_plus_one_filled_with_num_1' => array (
|
20 |
+
array (
|
21 |
+
0 => '1',
|
22 |
+
1 => '1',
|
23 |
+
2 => '1',
|
24 |
+
),
|
25 |
+
),
|
26 |
+
'rows_from_one_row_only_plus_one_filled_with_str_hello' => array (
|
27 |
+
array (
|
28 |
+
0 => 'hello',
|
29 |
+
1 => 'hello',
|
30 |
+
2 => 'hello',
|
31 |
+
),
|
32 |
+
),
|
33 |
+
'rows_from_one_row_only_plus_one_filled_with_arr_abc' => array (
|
34 |
+
array (
|
35 |
+
0 => 'a',
|
36 |
+
1 => 'b',
|
37 |
+
2 => 'c',
|
38 |
+
),
|
39 |
+
),
|
40 |
+
'symmetric_raw_data_with_second_column_removed' =>
|
41 |
+
array (
|
42 |
+
0 =>
|
43 |
+
array (
|
44 |
+
0 => 'header_a',
|
45 |
+
1 => 'header_c',
|
46 |
+
2 => 'header_d',
|
47 |
+
3 => 'header_e',
|
48 |
+
),
|
49 |
+
1 =>
|
50 |
+
array (
|
51 |
+
0 => '1aa',
|
52 |
+
1 => '1cc',
|
53 |
+
2 => '1dd',
|
54 |
+
3 => '1ee',
|
55 |
+
),
|
56 |
+
2 =>
|
57 |
+
array (
|
58 |
+
0 => '2aa',
|
59 |
+
1 => '2cc',
|
60 |
+
2 => '2dd',
|
61 |
+
3 => '2ee',
|
62 |
+
),
|
63 |
+
3 =>
|
64 |
+
array (
|
65 |
+
0 => '3aa',
|
66 |
+
1 => '3cc',
|
67 |
+
2 => '3dd',
|
68 |
+
3 => '3ee',
|
69 |
+
),
|
70 |
+
4 =>
|
71 |
+
array (
|
72 |
+
0 => '4aa',
|
73 |
+
1 => '4cc',
|
74 |
+
2 => '4dd',
|
75 |
+
3 => '4ee',
|
76 |
+
),
|
77 |
+
5 =>
|
78 |
+
array (
|
79 |
+
0 => '5aa',
|
80 |
+
1 => '5cc',
|
81 |
+
2 => '5dd',
|
82 |
+
3 => '5ee',
|
83 |
+
),
|
84 |
+
6 =>
|
85 |
+
array (
|
86 |
+
0 => '6aa',
|
87 |
+
1 => '6cc',
|
88 |
+
2 => '6dd',
|
89 |
+
3 => '6ee',
|
90 |
+
),
|
91 |
+
7 =>
|
92 |
+
array (
|
93 |
+
0 => '7aa',
|
94 |
+
1 => '7cc',
|
95 |
+
2 => '7dd',
|
96 |
+
3 => '7ee',
|
97 |
+
),
|
98 |
+
8 =>
|
99 |
+
array (
|
100 |
+
0 => '8aa',
|
101 |
+
1 => '8cc',
|
102 |
+
2 => '8dd',
|
103 |
+
3 => '8ee',
|
104 |
+
),
|
105 |
+
9 =>
|
106 |
+
array (
|
107 |
+
0 => '9aa',
|
108 |
+
1 => '9cc',
|
109 |
+
2 => '9dd',
|
110 |
+
3 => '9ee',
|
111 |
+
)
|
112 |
+
),
|
113 |
+
'symmetric_raw_data_with_last_colum_removed' =>
|
114 |
+
array (
|
115 |
+
0 =>
|
116 |
+
array (
|
117 |
+
0 => 'header_a',
|
118 |
+
1 => 'header_b',
|
119 |
+
2 => 'header_c',
|
120 |
+
3 => 'header_d',
|
121 |
+
),
|
122 |
+
1 =>
|
123 |
+
array (
|
124 |
+
0 => '1aa',
|
125 |
+
1 => '1bb',
|
126 |
+
2 => '1cc',
|
127 |
+
3 => '1dd',
|
128 |
+
),
|
129 |
+
2 =>
|
130 |
+
array (
|
131 |
+
0 => '2aa',
|
132 |
+
1 => '2bb',
|
133 |
+
2 => '2cc',
|
134 |
+
3 => '2dd',
|
135 |
+
),
|
136 |
+
3 =>
|
137 |
+
array (
|
138 |
+
0 => '3aa',
|
139 |
+
1 => '3bb',
|
140 |
+
2 => '3cc',
|
141 |
+
3 => '3dd',
|
142 |
+
),
|
143 |
+
4 =>
|
144 |
+
array (
|
145 |
+
0 => '4aa',
|
146 |
+
1 => '4bb',
|
147 |
+
2 => '4cc',
|
148 |
+
3 => '4dd',
|
149 |
+
),
|
150 |
+
5 =>
|
151 |
+
array (
|
152 |
+
0 => '5aa',
|
153 |
+
1 => '5bb',
|
154 |
+
2 => '5cc',
|
155 |
+
3 => '5dd',
|
156 |
+
),
|
157 |
+
6 =>
|
158 |
+
array (
|
159 |
+
0 => '6aa',
|
160 |
+
1 => '6bb',
|
161 |
+
2 => '6cc',
|
162 |
+
3 => '6dd',
|
163 |
+
),
|
164 |
+
7 =>
|
165 |
+
array (
|
166 |
+
0 => '7aa',
|
167 |
+
1 => '7bb',
|
168 |
+
2 => '7cc',
|
169 |
+
3 => '7dd',
|
170 |
+
),
|
171 |
+
8 =>
|
172 |
+
array (
|
173 |
+
0 => '8aa',
|
174 |
+
1 => '8bb',
|
175 |
+
2 => '8cc',
|
176 |
+
3 => '8dd',
|
177 |
+
),
|
178 |
+
9 =>
|
179 |
+
array (
|
180 |
+
0 => '9aa',
|
181 |
+
1 => '9bb',
|
182 |
+
2 => '9cc',
|
183 |
+
3 => '9dd',
|
184 |
+
),
|
185 |
+
),
|
186 |
+
|
187 |
+
'first_symmetric_header' => 'header_a',
|
188 |
+
'first_symmetric_cell' => '1aa',
|
189 |
+
|
190 |
+
'symmetric_extra_header' =>
|
191 |
+
array (
|
192 |
+
0 => 'header_a',
|
193 |
+
1 => 'header_b',
|
194 |
+
2 => 'header_c',
|
195 |
+
3 => 'header_d',
|
196 |
+
4 => 'header_e',
|
197 |
+
5 => 'extra',
|
198 |
+
),
|
199 |
+
'first_row_from_symmetric' =>
|
200 |
+
array (
|
201 |
+
0 => '1aa',
|
202 |
+
1 => '1bb',
|
203 |
+
2 => '1cc',
|
204 |
+
3 => '1dd',
|
205 |
+
4 => '1ee',
|
206 |
+
),
|
207 |
+
'eighth_row_from_symmetric' =>
|
208 |
+
array (
|
209 |
+
0 => '9aa',
|
210 |
+
1 => '9bb',
|
211 |
+
2 => '9cc',
|
212 |
+
3 => '9dd',
|
213 |
+
4 => '9ee',
|
214 |
+
),
|
215 |
+
'valid_files' =>
|
216 |
+
array (
|
217 |
+
'empty.csv' => 'emtpy csv file',
|
218 |
+
'uppercased.CSV' => 'upper cased extension',
|
219 |
+
'multcased.CsV' => 'multiple cased extension',
|
220 |
+
'symmetric.csv' => 'symmetric data',
|
221 |
+
'asymmetric.csv' => 'asymmetric data',
|
222 |
+
'escape_ok.csv' => 'valid escape syntax file',
|
223 |
+
'escape_ok.csv' => 'valid escape syntax file',
|
224 |
+
'non_csv_extension.txt' => 'non csv-extension file',
|
225 |
+
),
|
226 |
+
'expected_headers' =>
|
227 |
+
array (
|
228 |
+
0 => 'COL_1',
|
229 |
+
1 => 'COL_2',
|
230 |
+
2 => 'COL_3',
|
231 |
+
3 => 'COL_4',
|
232 |
+
4 => 'COL_5',
|
233 |
+
),
|
234 |
+
'original_headers' =>
|
235 |
+
array (
|
236 |
+
0 => 'header_a',
|
237 |
+
1 => 'header_b',
|
238 |
+
2 => 'header_c',
|
239 |
+
3 => 'header_d',
|
240 |
+
4 => 'header_e',
|
241 |
+
),
|
242 |
+
'symmetric_connection' =>
|
243 |
+
array (
|
244 |
+
0 =>
|
245 |
+
array (
|
246 |
+
'header_a' => '1aa',
|
247 |
+
'header_b' => '1bb',
|
248 |
+
'header_c' => '1cc',
|
249 |
+
'header_d' => '1dd',
|
250 |
+
'header_e' => '1ee',
|
251 |
+
),
|
252 |
+
1 =>
|
253 |
+
array (
|
254 |
+
'header_a' => '2aa',
|
255 |
+
'header_b' => '2bb',
|
256 |
+
'header_c' => '2cc',
|
257 |
+
'header_d' => '2dd',
|
258 |
+
'header_e' => '2ee',
|
259 |
+
),
|
260 |
+
2 =>
|
261 |
+
array (
|
262 |
+
'header_a' => '3aa',
|
263 |
+
'header_b' => '3bb',
|
264 |
+
'header_c' => '3cc',
|
265 |
+
'header_d' => '3dd',
|
266 |
+
'header_e' => '3ee',
|
267 |
+
),
|
268 |
+
3 =>
|
269 |
+
array (
|
270 |
+
'header_a' => '4aa',
|
271 |
+
'header_b' => '4bb',
|
272 |
+
'header_c' => '4cc',
|
273 |
+
'header_d' => '4dd',
|
274 |
+
'header_e' => '4ee',
|
275 |
+
),
|
276 |
+
4 =>
|
277 |
+
array (
|
278 |
+
'header_a' => '5aa',
|
279 |
+
'header_b' => '5bb',
|
280 |
+
'header_c' => '5cc',
|
281 |
+
'header_d' => '5dd',
|
282 |
+
'header_e' => '5ee',
|
283 |
+
),
|
284 |
+
5 =>
|
285 |
+
array (
|
286 |
+
'header_a' => '6aa',
|
287 |
+
'header_b' => '6bb',
|
288 |
+
'header_c' => '6cc',
|
289 |
+
'header_d' => '6dd',
|
290 |
+
'header_e' => '6ee',
|
291 |
+
),
|
292 |
+
6 =>
|
293 |
+
array (
|
294 |
+
'header_a' => '7aa',
|
295 |
+
'header_b' => '7bb',
|
296 |
+
'header_c' => '7cc',
|
297 |
+
'header_d' => '7dd',
|
298 |
+
'header_e' => '7ee',
|
299 |
+
),
|
300 |
+
7 =>
|
301 |
+
array (
|
302 |
+
'header_a' => '8aa',
|
303 |
+
'header_b' => '8bb',
|
304 |
+
'header_c' => '8cc',
|
305 |
+
'header_d' => '8dd',
|
306 |
+
'header_e' => '8ee',
|
307 |
+
),
|
308 |
+
8 =>
|
309 |
+
array (
|
310 |
+
'header_a' => '9aa',
|
311 |
+
'header_b' => '9bb',
|
312 |
+
'header_c' => '9cc',
|
313 |
+
'header_d' => '9dd',
|
314 |
+
'header_e' => '9ee',
|
315 |
+
),
|
316 |
+
),
|
317 |
+
'asymmetric_rows' =>
|
318 |
+
array (
|
319 |
+
0 =>
|
320 |
+
array (
|
321 |
+
0 => '5aa',
|
322 |
+
1 => '5bb',
|
323 |
+
2 => '5cc',
|
324 |
+
3 => '5dd',
|
325 |
+
4 => '5ee',
|
326 |
+
5 => 'extra1',
|
327 |
+
),
|
328 |
+
1 =>
|
329 |
+
array (
|
330 |
+
0 => '8aa',
|
331 |
+
1 => '8bb',
|
332 |
+
2 => '8cc',
|
333 |
+
3 => '8dd',
|
334 |
+
4 => '8ee',
|
335 |
+
5 => 'extra2',
|
336 |
+
),
|
337 |
+
),
|
338 |
+
'empty_column' =>
|
339 |
+
array (
|
340 |
+
0 => '',
|
341 |
+
1 => '',
|
342 |
+
2 => '',
|
343 |
+
3 => '',
|
344 |
+
4 => '',
|
345 |
+
5 => '',
|
346 |
+
6 => '',
|
347 |
+
7 => '',
|
348 |
+
8 => '',
|
349 |
+
),
|
350 |
+
'expected_column' =>
|
351 |
+
array (
|
352 |
+
0 => '1cc',
|
353 |
+
1 => '2cc',
|
354 |
+
2 => '3cc',
|
355 |
+
3 => '4cc',
|
356 |
+
4 => '5cc',
|
357 |
+
5 => '6cc',
|
358 |
+
6 => '7cc',
|
359 |
+
7 => '8cc',
|
360 |
+
8 => '9cc',
|
361 |
+
),
|
362 |
+
'symmetric_rows_without_first_row' =>
|
363 |
+
array (
|
364 |
+
0 =>
|
365 |
+
array (
|
366 |
+
0 => '2aa',
|
367 |
+
1 => '2bb',
|
368 |
+
2 => '2cc',
|
369 |
+
3 => '2dd',
|
370 |
+
4 => '2ee',
|
371 |
+
),
|
372 |
+
1 =>
|
373 |
+
array (
|
374 |
+
0 => '3aa',
|
375 |
+
1 => '3bb',
|
376 |
+
2 => '3cc',
|
377 |
+
3 => '3dd',
|
378 |
+
4 => '3ee',
|
379 |
+
),
|
380 |
+
2 =>
|
381 |
+
array (
|
382 |
+
0 => '4aa',
|
383 |
+
1 => '4bb',
|
384 |
+
2 => '4cc',
|
385 |
+
3 => '4dd',
|
386 |
+
4 => '4ee',
|
387 |
+
),
|
388 |
+
3 =>
|
389 |
+
array (
|
390 |
+
0 => '5aa',
|
391 |
+
1 => '5bb',
|
392 |
+
2 => '5cc',
|
393 |
+
3 => '5dd',
|
394 |
+
4 => '5ee',
|
395 |
+
),
|
396 |
+
4 =>
|
397 |
+
array (
|
398 |
+
0 => '6aa',
|
399 |
+
1 => '6bb',
|
400 |
+
2 => '6cc',
|
401 |
+
3 => '6dd',
|
402 |
+
4 => '6ee',
|
403 |
+
),
|
404 |
+
5 =>
|
405 |
+
array (
|
406 |
+
0 => '7aa',
|
407 |
+
1 => '7bb',
|
408 |
+
2 => '7cc',
|
409 |
+
3 => '7dd',
|
410 |
+
4 => '7ee',
|
411 |
+
),
|
412 |
+
6 =>
|
413 |
+
array (
|
414 |
+
0 => '8aa',
|
415 |
+
1 => '8bb',
|
416 |
+
2 => '8cc',
|
417 |
+
3 => '8dd',
|
418 |
+
4 => '8ee',
|
419 |
+
),
|
420 |
+
7 =>
|
421 |
+
array (
|
422 |
+
0 => '9aa',
|
423 |
+
1 => '9bb',
|
424 |
+
2 => '9cc',
|
425 |
+
3 => '9dd',
|
426 |
+
4 => '9ee',
|
427 |
+
),
|
428 |
+
),
|
429 |
+
'symmetric_rows_without_third_row' =>
|
430 |
+
array (
|
431 |
+
0 =>
|
432 |
+
array (
|
433 |
+
0 => '1aa',
|
434 |
+
1 => '1bb',
|
435 |
+
2 => '1cc',
|
436 |
+
3 => '1dd',
|
437 |
+
4 => '1ee',
|
438 |
+
),
|
439 |
+
1 =>
|
440 |
+
array (
|
441 |
+
0 => '2aa',
|
442 |
+
1 => '2bb',
|
443 |
+
2 => '2cc',
|
444 |
+
3 => '2dd',
|
445 |
+
4 => '2ee',
|
446 |
+
),
|
447 |
+
2 =>
|
448 |
+
array (
|
449 |
+
0 => '4aa',
|
450 |
+
1 => '4bb',
|
451 |
+
2 => '4cc',
|
452 |
+
3 => '4dd',
|
453 |
+
4 => '4ee',
|
454 |
+
),
|
455 |
+
3 =>
|
456 |
+
array (
|
457 |
+
0 => '5aa',
|
458 |
+
1 => '5bb',
|
459 |
+
2 => '5cc',
|
460 |
+
3 => '5dd',
|
461 |
+
4 => '5ee',
|
462 |
+
),
|
463 |
+
4 =>
|
464 |
+
array (
|
465 |
+
0 => '6aa',
|
466 |
+
1 => '6bb',
|
467 |
+
2 => '6cc',
|
468 |
+
3 => '6dd',
|
469 |
+
4 => '6ee',
|
470 |
+
),
|
471 |
+
5 =>
|
472 |
+
array (
|
473 |
+
0 => '7aa',
|
474 |
+
1 => '7bb',
|
475 |
+
2 => '7cc',
|
476 |
+
3 => '7dd',
|
477 |
+
4 => '7ee',
|
478 |
+
),
|
479 |
+
6 =>
|
480 |
+
array (
|
481 |
+
0 => '8aa',
|
482 |
+
1 => '8bb',
|
483 |
+
2 => '8cc',
|
484 |
+
3 => '8dd',
|
485 |
+
4 => '8ee',
|
486 |
+
),
|
487 |
+
7 =>
|
488 |
+
array (
|
489 |
+
0 => '9aa',
|
490 |
+
1 => '9bb',
|
491 |
+
2 => '9cc',
|
492 |
+
3 => '9dd',
|
493 |
+
4 => '9ee',
|
494 |
+
),
|
495 |
+
),
|
496 |
+
'one_row_for_symmetric' => array (
|
497 |
+
0 => '10aa',
|
498 |
+
1 => '10bb',
|
499 |
+
2 => '10cc',
|
500 |
+
3 => '10dd',
|
501 |
+
4 => '10ee',
|
502 |
+
),
|
503 |
+
'symmetric_rows_plus_one' => // contains 'one_row_for_symmetric'
|
504 |
+
array (
|
505 |
+
0 =>
|
506 |
+
array (
|
507 |
+
0 => '1aa',
|
508 |
+
1 => '1bb',
|
509 |
+
2 => '1cc',
|
510 |
+
3 => '1dd',
|
511 |
+
4 => '1ee',
|
512 |
+
),
|
513 |
+
1 =>
|
514 |
+
array (
|
515 |
+
0 => '2aa',
|
516 |
+
1 => '2bb',
|
517 |
+
2 => '2cc',
|
518 |
+
3 => '2dd',
|
519 |
+
4 => '2ee',
|
520 |
+
),
|
521 |
+
2 =>
|
522 |
+
array (
|
523 |
+
0 => '3aa',
|
524 |
+
1 => '3bb',
|
525 |
+
2 => '3cc',
|
526 |
+
3 => '3dd',
|
527 |
+
4 => '3ee',
|
528 |
+
),
|
529 |
+
3 =>
|
530 |
+
array (
|
531 |
+
0 => '4aa',
|
532 |
+
1 => '4bb',
|
533 |
+
2 => '4cc',
|
534 |
+
3 => '4dd',
|
535 |
+
4 => '4ee',
|
536 |
+
),
|
537 |
+
4 =>
|
538 |
+
array (
|
539 |
+
0 => '5aa',
|
540 |
+
1 => '5bb',
|
541 |
+
2 => '5cc',
|
542 |
+
3 => '5dd',
|
543 |
+
4 => '5ee',
|
544 |
+
),
|
545 |
+
5 =>
|
546 |
+
array (
|
547 |
+
0 => '6aa',
|
548 |
+
1 => '6bb',
|
549 |
+
2 => '6cc',
|
550 |
+
3 => '6dd',
|
551 |
+
4 => '6ee',
|
552 |
+
),
|
553 |
+
6 =>
|
554 |
+
array (
|
555 |
+
0 => '7aa',
|
556 |
+
1 => '7bb',
|
557 |
+
2 => '7cc',
|
558 |
+
3 => '7dd',
|
559 |
+
4 => '7ee',
|
560 |
+
),
|
561 |
+
7 =>
|
562 |
+
array (
|
563 |
+
0 => '8aa',
|
564 |
+
1 => '8bb',
|
565 |
+
2 => '8cc',
|
566 |
+
3 => '8dd',
|
567 |
+
4 => '8ee',
|
568 |
+
),
|
569 |
+
8 =>
|
570 |
+
array (
|
571 |
+
0 => '9aa',
|
572 |
+
1 => '9bb',
|
573 |
+
2 => '9cc',
|
574 |
+
3 => '9dd',
|
575 |
+
4 => '9ee',
|
576 |
+
),
|
577 |
+
9 =>
|
578 |
+
array (
|
579 |
+
0 => '10aa',
|
580 |
+
1 => '10bb',
|
581 |
+
2 => '10cc',
|
582 |
+
3 => '10dd',
|
583 |
+
4 => '10ee',
|
584 |
+
),
|
585 |
+
),
|
586 |
+
'symmetric_rows_empty' =>
|
587 |
+
array (
|
588 |
+
0 =>
|
589 |
+
array (
|
590 |
+
0 => '',
|
591 |
+
1 => '',
|
592 |
+
2 => '',
|
593 |
+
3 => '',
|
594 |
+
4 => '',
|
595 |
+
),
|
596 |
+
1 =>
|
597 |
+
array (
|
598 |
+
0 => '',
|
599 |
+
1 => '',
|
600 |
+
2 => '',
|
601 |
+
3 => '',
|
602 |
+
4 => '',
|
603 |
+
),
|
604 |
+
2 =>
|
605 |
+
array (
|
606 |
+
0 => '',
|
607 |
+
1 => '',
|
608 |
+
2 => '',
|
609 |
+
3 => '',
|
610 |
+
4 => '',
|
611 |
+
),
|
612 |
+
3 =>
|
613 |
+
array (
|
614 |
+
0 => '',
|
615 |
+
1 => '',
|
616 |
+
2 => '',
|
617 |
+
3 => '',
|
618 |
+
4 => '',
|
619 |
+
),
|
620 |
+
4 =>
|
621 |
+
array (
|
622 |
+
0 => '',
|
623 |
+
1 => '',
|
624 |
+
2 => '',
|
625 |
+
3 => '',
|
626 |
+
4 => '',
|
627 |
+
),
|
628 |
+
5 =>
|
629 |
+
array (
|
630 |
+
0 => '',
|
631 |
+
1 => '',
|
632 |
+
2 => '',
|
633 |
+
3 => '',
|
634 |
+
4 => '',
|
635 |
+
),
|
636 |
+
6 =>
|
637 |
+
array (
|
638 |
+
0 => '',
|
639 |
+
1 => '',
|
640 |
+
2 => '',
|
641 |
+
3 => '',
|
642 |
+
4 => '',
|
643 |
+
),
|
644 |
+
7 =>
|
645 |
+
array (
|
646 |
+
0 => '',
|
647 |
+
1 => '',
|
648 |
+
2 => '',
|
649 |
+
3 => '',
|
650 |
+
4 => '',
|
651 |
+
),
|
652 |
+
8 =>
|
653 |
+
array (
|
654 |
+
0 => '',
|
655 |
+
1 => '',
|
656 |
+
2 => '',
|
657 |
+
3 => '',
|
658 |
+
4 => '',
|
659 |
+
),
|
660 |
+
),
|
661 |
+
'symmetric_rows' =>
|
662 |
+
array (
|
663 |
+
0 =>
|
664 |
+
array (
|
665 |
+
0 => '1aa',
|
666 |
+
1 => '1bb',
|
667 |
+
2 => '1cc',
|
668 |
+
3 => '1dd',
|
669 |
+
4 => '1ee',
|
670 |
+
),
|
671 |
+
1 =>
|
672 |
+
array (
|
673 |
+
0 => '2aa',
|
674 |
+
1 => '2bb',
|
675 |
+
2 => '2cc',
|
676 |
+
3 => '2dd',
|
677 |
+
4 => '2ee',
|
678 |
+
),
|
679 |
+
2 =>
|
680 |
+
array (
|
681 |
+
0 => '3aa',
|
682 |
+
1 => '3bb',
|
683 |
+
2 => '3cc',
|
684 |
+
3 => '3dd',
|
685 |
+
4 => '3ee',
|
686 |
+
),
|
687 |
+
3 =>
|
688 |
+
array (
|
689 |
+
0 => '4aa',
|
690 |
+
1 => '4bb',
|
691 |
+
2 => '4cc',
|
692 |
+
3 => '4dd',
|
693 |
+
4 => '4ee',
|
694 |
+
),
|
695 |
+
4 =>
|
696 |
+
array (
|
697 |
+
0 => '5aa',
|
698 |
+
1 => '5bb',
|
699 |
+
2 => '5cc',
|
700 |
+
3 => '5dd',
|
701 |
+
4 => '5ee',
|
702 |
+
),
|
703 |
+
5 =>
|
704 |
+
array (
|
705 |
+
0 => '6aa',
|
706 |
+
1 => '6bb',
|
707 |
+
2 => '6cc',
|
708 |
+
3 => '6dd',
|
709 |
+
4 => '6ee',
|
710 |
+
),
|
711 |
+
6 =>
|
712 |
+
array (
|
713 |
+
0 => '7aa',
|
714 |
+
1 => '7bb',
|
715 |
+
2 => '7cc',
|
716 |
+
3 => '7dd',
|
717 |
+
4 => '7ee',
|
718 |
+
),
|
719 |
+
7 =>
|
720 |
+
array (
|
721 |
+
0 => '8aa',
|
722 |
+
1 => '8bb',
|
723 |
+
2 => '8cc',
|
724 |
+
3 => '8dd',
|
725 |
+
4 => '8ee',
|
726 |
+
),
|
727 |
+
8 =>
|
728 |
+
array (
|
729 |
+
0 => '9aa',
|
730 |
+
1 => '9bb',
|
731 |
+
2 => '9cc',
|
732 |
+
3 => '9dd',
|
733 |
+
4 => '9ee',
|
734 |
+
),
|
735 |
+
),
|
736 |
+
'symmetric_raw_data' =>
|
737 |
+
array (
|
738 |
+
0 =>
|
739 |
+
array (
|
740 |
+
0 => 'header_a',
|
741 |
+
1 => 'header_b',
|
742 |
+
2 => 'header_c',
|
743 |
+
3 => 'header_d',
|
744 |
+
4 => 'header_e',
|
745 |
+
),
|
746 |
+
1 =>
|
747 |
+
array (
|
748 |
+
0 => '1aa',
|
749 |
+
1 => '1bb',
|
750 |
+
2 => '1cc',
|
751 |
+
3 => '1dd',
|
752 |
+
4 => '1ee',
|
753 |
+
),
|
754 |
+
2 =>
|
755 |
+
array (
|
756 |
+
0 => '2aa',
|
757 |
+
1 => '2bb',
|
758 |
+
2 => '2cc',
|
759 |
+
3 => '2dd',
|
760 |
+
4 => '2ee',
|
761 |
+
),
|
762 |
+
3 =>
|
763 |
+
array (
|
764 |
+
0 => '3aa',
|
765 |
+
1 => '3bb',
|
766 |
+
2 => '3cc',
|
767 |
+
3 => '3dd',
|
768 |
+
4 => '3ee',
|
769 |
+
),
|
770 |
+
4 =>
|
771 |
+
array (
|
772 |
+
0 => '4aa',
|
773 |
+
1 => '4bb',
|
774 |
+
2 => '4cc',
|
775 |
+
3 => '4dd',
|
776 |
+
4 => '4ee',
|
777 |
+
),
|
778 |
+
5 =>
|
779 |
+
array (
|
780 |
+
0 => '5aa',
|
781 |
+
1 => '5bb',
|
782 |
+
2 => '5cc',
|
783 |
+
3 => '5dd',
|
784 |
+
4 => '5ee',
|
785 |
+
),
|
786 |
+
6 =>
|
787 |
+
array (
|
788 |
+
0 => '6aa',
|
789 |
+
1 => '6bb',
|
790 |
+
2 => '6cc',
|
791 |
+
3 => '6dd',
|
792 |
+
4 => '6ee',
|
793 |
+
),
|
794 |
+
7 =>
|
795 |
+
array (
|
796 |
+
0 => '7aa',
|
797 |
+
1 => '7bb',
|
798 |
+
2 => '7cc',
|
799 |
+
3 => '7dd',
|
800 |
+
4 => '7ee',
|
801 |
+
),
|
802 |
+
8 =>
|
803 |
+
array (
|
804 |
+
0 => '8aa',
|
805 |
+
1 => '8bb',
|
806 |
+
2 => '8cc',
|
807 |
+
3 => '8dd',
|
808 |
+
4 => '8ee',
|
809 |
+
),
|
810 |
+
9 =>
|
811 |
+
array (
|
812 |
+
0 => '9aa',
|
813 |
+
1 => '9bb',
|
814 |
+
2 => '9cc',
|
815 |
+
3 => '9dd',
|
816 |
+
4 => '9ee',
|
817 |
+
),
|
818 |
+
),
|
819 |
+
'expected_raw' =>
|
820 |
+
array (
|
821 |
+
0 =>
|
822 |
+
array (
|
823 |
+
0 => 'h_one',
|
824 |
+
1 => 'h_two',
|
825 |
+
2 => 'h_three',
|
826 |
+
),
|
827 |
+
1 =>
|
828 |
+
array (
|
829 |
+
0 => 'v_1one',
|
830 |
+
1 => 'v_1two',
|
831 |
+
2 => 'v_1three',
|
832 |
+
),
|
833 |
+
2 =>
|
834 |
+
array (
|
835 |
+
0 => 'v_2one',
|
836 |
+
1 => 'v_2two',
|
837 |
+
2 => 'v_2three',
|
838 |
+
),
|
839 |
+
3 =>
|
840 |
+
array (
|
841 |
+
0 => 'v_3one',
|
842 |
+
1 => 'v_3two',
|
843 |
+
2 => 'v_3three',
|
844 |
+
),
|
845 |
+
),
|
846 |
+
'expected_escaped' =>
|
847 |
+
array (
|
848 |
+
0 =>
|
849 |
+
array (
|
850 |
+
'one' => 'thie,',
|
851 |
+
'two' => 'adn',
|
852 |
+
'three' => 'thei',
|
853 |
+
),
|
854 |
+
1 =>
|
855 |
+
array (
|
856 |
+
'one' => 'thie',
|
857 |
+
'two' => 'adn',
|
858 |
+
'three' => 'thei',
|
859 |
+
),
|
860 |
+
),
|
861 |
+
'header_a_connection' =>
|
862 |
+
array (
|
863 |
+
0 =>
|
864 |
+
array (
|
865 |
+
'header_a' => '1aa',
|
866 |
+
),
|
867 |
+
1 =>
|
868 |
+
array (
|
869 |
+
'header_a' => '2aa',
|
870 |
+
),
|
871 |
+
2 =>
|
872 |
+
array (
|
873 |
+
'header_a' => '3aa',
|
874 |
+
),
|
875 |
+
3 =>
|
876 |
+
array (
|
877 |
+
'header_a' => '4aa',
|
878 |
+
),
|
879 |
+
4 =>
|
880 |
+
array (
|
881 |
+
'header_a' => '5aa',
|
882 |
+
),
|
883 |
+
5 =>
|
884 |
+
array (
|
885 |
+
'header_a' => '6aa',
|
886 |
+
),
|
887 |
+
6 =>
|
888 |
+
array (
|
889 |
+
'header_a' => '7aa',
|
890 |
+
),
|
891 |
+
7 =>
|
892 |
+
array (
|
893 |
+
'header_a' => '8aa',
|
894 |
+
),
|
895 |
+
8 =>
|
896 |
+
array (
|
897 |
+
'header_a' => '9aa',
|
898 |
+
),
|
899 |
+
),
|
900 |
+
'symmetric_queries' =>
|
901 |
+
array (
|
902 |
+
0 => 'INSERT INTO test_table (header_a, header_b, header_c, header_d, header_e) VALUES (\'1aa\', \'1bb\', \'1cc\', \'1dd\', \'1ee\')',
|
903 |
+
1 => 'INSERT INTO test_table (header_a, header_b, header_c, header_d, header_e) VALUES (\'2aa\', \'2bb\', \'2cc\', \'2dd\', \'2ee\')',
|
904 |
+
2 => 'INSERT INTO test_table (header_a, header_b, header_c, header_d, header_e) VALUES (\'3aa\', \'3bb\', \'3cc\', \'3dd\', \'3ee\')',
|
905 |
+
3 => 'INSERT INTO test_table (header_a, header_b, header_c, header_d, header_e) VALUES (\'4aa\', \'4bb\', \'4cc\', \'4dd\', \'4ee\')',
|
906 |
+
4 => 'INSERT INTO test_table (header_a, header_b, header_c, header_d, header_e) VALUES (\'5aa\', \'5bb\', \'5cc\', \'5dd\', \'5ee\')',
|
907 |
+
5 => 'INSERT INTO test_table (header_a, header_b, header_c, header_d, header_e) VALUES (\'6aa\', \'6bb\', \'6cc\', \'6dd\', \'6ee\')',
|
908 |
+
6 => 'INSERT INTO test_table (header_a, header_b, header_c, header_d, header_e) VALUES (\'7aa\', \'7bb\', \'7cc\', \'7dd\', \'7ee\')',
|
909 |
+
7 => 'INSERT INTO test_table (header_a, header_b, header_c, header_d, header_e) VALUES (\'8aa\', \'8bb\', \'8cc\', \'8dd\', \'8ee\')',
|
910 |
+
8 => 'INSERT INTO test_table (header_a, header_b, header_c, header_d, header_e) VALUES (\'9aa\', \'9bb\', \'9cc\', \'9dd\', \'9ee\')',
|
911 |
+
),
|
912 |
+
'alternated_header_queries' =>
|
913 |
+
array (
|
914 |
+
0 => 'INSERT INTO test_table (header_a, header_c) VALUES (\'1aa\', \'1cc\')',
|
915 |
+
1 => 'INSERT INTO test_table (header_a, header_c) VALUES (\'2aa\', \'2cc\')',
|
916 |
+
2 => 'INSERT INTO test_table (header_a, header_c) VALUES (\'3aa\', \'3cc\')',
|
917 |
+
3 => 'INSERT INTO test_table (header_a, header_c) VALUES (\'4aa\', \'4cc\')',
|
918 |
+
4 => 'INSERT INTO test_table (header_a, header_c) VALUES (\'5aa\', \'5cc\')',
|
919 |
+
5 => 'INSERT INTO test_table (header_a, header_c) VALUES (\'6aa\', \'6cc\')',
|
920 |
+
6 => 'INSERT INTO test_table (header_a, header_c) VALUES (\'7aa\', \'7cc\')',
|
921 |
+
7 => 'INSERT INTO test_table (header_a, header_c) VALUES (\'8aa\', \'8cc\')',
|
922 |
+
8 => 'INSERT INTO test_table (header_a, header_c) VALUES (\'9aa\', \'9cc\')',
|
923 |
+
),
|
924 |
+
'symmetric_range_of_rows' =>
|
925 |
+
array (
|
926 |
+
0 =>
|
927 |
+
array (
|
928 |
+
0 => '2aa',
|
929 |
+
1 => '2bb',
|
930 |
+
2 => '2cc',
|
931 |
+
3 => '2dd',
|
932 |
+
4 => '2ee',
|
933 |
+
),
|
934 |
+
1 =>
|
935 |
+
array (
|
936 |
+
0 => '3aa',
|
937 |
+
1 => '3bb',
|
938 |
+
2 => '3cc',
|
939 |
+
3 => '3dd',
|
940 |
+
4 => '3ee',
|
941 |
+
),
|
942 |
+
),
|
943 |
+
'longer_headers' =>
|
944 |
+
array (
|
945 |
+
0 =>
|
946 |
+
array (
|
947 |
+
'one' => '1',
|
948 |
+
'two' => '2',
|
949 |
+
'three' => '3',
|
950 |
+
'four' => '',
|
951 |
+
'five' => '',
|
952 |
+
'six' => '',
|
953 |
+
),
|
954 |
+
1 =>
|
955 |
+
array (
|
956 |
+
'one' => '1',
|
957 |
+
'two' => '2',
|
958 |
+
'three' => '3',
|
959 |
+
'four' => '4',
|
960 |
+
'five' => '',
|
961 |
+
'six' => '',
|
962 |
+
),
|
963 |
+
2 =>
|
964 |
+
array (
|
965 |
+
'one' => '',
|
966 |
+
'two' => '2',
|
967 |
+
'three' => '3',
|
968 |
+
'four' => '4',
|
969 |
+
'five' => '',
|
970 |
+
'six' => '',
|
971 |
+
),
|
972 |
+
),
|
973 |
+
|
974 |
+
);
|
975 |
+
|
976 |
+
function fix($key) {
|
977 |
+
global $fixtures;
|
978 |
+
if (!array_key_exists($key, $fixtures)) {
|
979 |
+
throw new Exception("Fixture not found: '$key' ");
|
980 |
+
}
|
981 |
+
return $fixtures[$key];
|
982 |
+
}
|
983 |
+
|
984 |
+
function path($file)
|
985 |
+
{
|
986 |
+
return 'File/CSV/tests/data/' . $file;
|
987 |
+
}
|
988 |
+
|
989 |
+
function callback($value)
|
990 |
+
{
|
991 |
+
return 1;
|
992 |
+
}
|
993 |
+
|
994 |
+
function callback2($value)
|
995 |
+
{
|
996 |
+
return '';
|
997 |
+
}
|
998 |
+
|
999 |
+
?>
|
LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
The MIT License
|
2 |
+
|
3 |
+
Copyright (c) <2009> <Denis Kobozev>
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in
|
13 |
+
all copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21 |
+
THE SOFTWARE.
|
TODO
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
* Add a column for page templates
|
2 |
+
* Add column for importing post thumbnails
|
3 |
+
* Add an option to the GUI for specifying a delimiter other than a comma
|
4 |
+
* Create users if they don't exist (as an option)
|
5 |
+
* Add support for unix timestamp dates
|
6 |
+
* Add support for category descriptions
|
csv_importer.php
ADDED
@@ -0,0 +1,540 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Plugin Name: CSV Importer
|
4 |
+
Description: Import data as posts from a CSV file. <em>You can reach the author at <a href="mailto:d.v.kobozev@gmail.com">d.v.kobozev@gmail.com</a></em>.
|
5 |
+
Version: 0.3.6
|
6 |
+
Author: Denis Kobozev
|
7 |
+
*/
|
8 |
+
|
9 |
+
/**
|
10 |
+
* LICENSE: The MIT License {{{
|
11 |
+
*
|
12 |
+
* Copyright (c) <2009> <Denis Kobozev>
|
13 |
+
*
|
14 |
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
15 |
+
* of this software and associated documentation files (the "Software"), to deal
|
16 |
+
* in the Software without restriction, including without limitation the rights
|
17 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
18 |
+
* copies of the Software, and to permit persons to whom the Software is
|
19 |
+
* furnished to do so, subject to the following conditions:
|
20 |
+
*
|
21 |
+
* The above copyright notice and this permission notice shall be included in
|
22 |
+
* all copies or substantial portions of the Software.
|
23 |
+
*
|
24 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
25 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
26 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
27 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
28 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
29 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
30 |
+
* THE SOFTWARE.
|
31 |
+
*
|
32 |
+
* @author Denis Kobozev <d.v.kobozev@gmail.com>
|
33 |
+
* @copyright 2009 Denis Kobozev
|
34 |
+
* @license The MIT License
|
35 |
+
* }}}
|
36 |
+
*/
|
37 |
+
|
38 |
+
class CSVImporterPlugin {
|
39 |
+
var $defaults = array(
|
40 |
+
'csv_post_title' => null,
|
41 |
+
'csv_post_post' => null,
|
42 |
+
'csv_post_type' => null,
|
43 |
+
'csv_post_excerpt' => null,
|
44 |
+
'csv_post_date' => null,
|
45 |
+
'csv_post_tags' => null,
|
46 |
+
'csv_post_categories' => null,
|
47 |
+
'csv_post_author' => null,
|
48 |
+
'csv_post_slug' => null,
|
49 |
+
'csv_post_parent' => 0,
|
50 |
+
);
|
51 |
+
|
52 |
+
var $log = array();
|
53 |
+
|
54 |
+
// determine value of option $name from database, $default value or $params,
|
55 |
+
// save it to the db if needed and return it
|
56 |
+
function process_option($name, $default, $params) {
|
57 |
+
if (array_key_exists($name, $params)) {
|
58 |
+
$value = stripslashes($params[$name]);
|
59 |
+
} elseif (array_key_exists('_'.$name, $params)) {
|
60 |
+
// unchecked checkbox value
|
61 |
+
$value = stripslashes($params['_'.$name]);
|
62 |
+
} else {
|
63 |
+
$value = null;
|
64 |
+
}
|
65 |
+
$stored_value = get_option($name);
|
66 |
+
if ($value == null) {
|
67 |
+
if ($stored_value === false) {
|
68 |
+
if (is_callable($default) &&
|
69 |
+
method_exists($default[0], $default[1])) {
|
70 |
+
$value = call_user_func($default);
|
71 |
+
} else {
|
72 |
+
$value = $default;
|
73 |
+
}
|
74 |
+
add_option($name, $value);
|
75 |
+
} else {
|
76 |
+
$value = $stored_value;
|
77 |
+
}
|
78 |
+
} else {
|
79 |
+
if ($stored_value === false) {
|
80 |
+
add_option($name, $value);
|
81 |
+
} elseif ($stored_value != $value) {
|
82 |
+
update_option($name, $value);
|
83 |
+
}
|
84 |
+
}
|
85 |
+
return $value;
|
86 |
+
}
|
87 |
+
|
88 |
+
// Plugin's interface
|
89 |
+
function form() {
|
90 |
+
$opt_draft = $this->process_option('csv_importer_import_as_draft',
|
91 |
+
'publish', $_POST);
|
92 |
+
$opt_cat = $this->process_option('csv_importer_cat', 0, $_POST);
|
93 |
+
|
94 |
+
if ('POST' == $_SERVER['REQUEST_METHOD']) {
|
95 |
+
$this->post(compact('opt_draft', 'opt_cat'));
|
96 |
+
}
|
97 |
+
|
98 |
+
// form HTML {{{
|
99 |
+
?>
|
100 |
+
|
101 |
+
<div class="wrap">
|
102 |
+
<h2>Import CSV</h2>
|
103 |
+
<form class="add:the-list: validate" method="post" enctype="multipart/form-data">
|
104 |
+
<!-- Import as draft -->
|
105 |
+
<p>
|
106 |
+
<input name="_csv_importer_import_as_draft" type="hidden" value="publish" />
|
107 |
+
<label><input name="csv_importer_import_as_draft" type="checkbox" <?php if ('draft' == $opt_draft) { echo 'checked="checked"'; } ?> value="draft" /> Import posts as drafts</label>
|
108 |
+
</p>
|
109 |
+
|
110 |
+
<!-- Parent category -->
|
111 |
+
<p>Organize into category <?php wp_dropdown_categories(array('show_option_all' => 'Select one ...', 'hide_empty' => 0, 'hierarchical' => 1, 'show_count' => 0, 'name' => 'csv_importer_cat', 'orderby' => 'name', 'selected' => $opt_cat));?><br/>
|
112 |
+
<small>This will create new categories inside the category parent you choose.</small></p>
|
113 |
+
|
114 |
+
<!-- File input -->
|
115 |
+
<p><label for="csv_import">Upload file:</label><br/>
|
116 |
+
<input name="csv_import" id="csv_import" type="file" value="" aria-required="true" /></p>
|
117 |
+
<p class="submit"><input type="submit" class="button" name="submit" value="Import" /></p>
|
118 |
+
</form>
|
119 |
+
</div><!-- end wrap -->
|
120 |
+
|
121 |
+
<?php
|
122 |
+
// end form HTML }}}
|
123 |
+
|
124 |
+
}
|
125 |
+
|
126 |
+
function print_messages() {
|
127 |
+
if (!empty($this->log)) {
|
128 |
+
|
129 |
+
// messages HTML {{{
|
130 |
+
?>
|
131 |
+
|
132 |
+
<div class="wrap">
|
133 |
+
<?php if (!empty($this->log['error'])): ?>
|
134 |
+
|
135 |
+
<div class="error">
|
136 |
+
|
137 |
+
<?php foreach ($this->log['error'] as $error): ?>
|
138 |
+
<p><?php echo $error; ?></p>
|
139 |
+
<?php endforeach; ?>
|
140 |
+
|
141 |
+
</div>
|
142 |
+
|
143 |
+
<?php endif; ?>
|
144 |
+
|
145 |
+
<?php if (!empty($this->log['notice'])): ?>
|
146 |
+
|
147 |
+
<div class="updated fade">
|
148 |
+
|
149 |
+
<?php foreach ($this->log['notice'] as $notice): ?>
|
150 |
+
<p><?php echo $notice; ?></p>
|
151 |
+
<?php endforeach; ?>
|
152 |
+
|
153 |
+
</div>
|
154 |
+
|
155 |
+
<?php endif; ?>
|
156 |
+
</div><!-- end wrap -->
|
157 |
+
|
158 |
+
<?php
|
159 |
+
// end messages HTML }}}
|
160 |
+
|
161 |
+
$this->log = array();
|
162 |
+
}
|
163 |
+
}
|
164 |
+
|
165 |
+
// Handle POST submission
|
166 |
+
function post($options) {
|
167 |
+
if (empty($_FILES['csv_import']['tmp_name'])) {
|
168 |
+
$this->log['error'][] = 'No file uploaded, aborting.';
|
169 |
+
$this->print_messages();
|
170 |
+
return;
|
171 |
+
}
|
172 |
+
|
173 |
+
require_once 'File_CSV_DataSource/DataSource.php';
|
174 |
+
|
175 |
+
$time_start = microtime(true);
|
176 |
+
$csv = new File_CSV_DataSource;
|
177 |
+
$file = $_FILES['csv_import']['tmp_name'];
|
178 |
+
$this->stripBOM($file);
|
179 |
+
|
180 |
+
if (!$csv->load($file)) {
|
181 |
+
$this->log['error'][] = 'Failed to load file, aborting.';
|
182 |
+
$this->print_messages();
|
183 |
+
return;
|
184 |
+
}
|
185 |
+
|
186 |
+
// pad shorter rows with empty values
|
187 |
+
$csv->symmetrize();
|
188 |
+
|
189 |
+
// WordPress sets the correct timezone for date functions somewhere
|
190 |
+
// in the bowels of wp_insert_post(). We need strtotime() to return
|
191 |
+
// correct time before the call to wp_insert_post().
|
192 |
+
$tz = get_option('timezone_string');
|
193 |
+
if ($tz && function_exists('date_default_timezone_set')) {
|
194 |
+
date_default_timezone_set($tz);
|
195 |
+
}
|
196 |
+
|
197 |
+
$skipped = 0;
|
198 |
+
$imported = 0;
|
199 |
+
$comments = 0;
|
200 |
+
foreach ($csv->connect() as $csv_data) {
|
201 |
+
if ($post_id = $this->create_post($csv_data, $options)) {
|
202 |
+
$imported++;
|
203 |
+
$comments += $this->add_comments($post_id, $csv_data);
|
204 |
+
$this->create_custom_fields($post_id, $csv_data);
|
205 |
+
} else {
|
206 |
+
$skipped++;
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
if (file_exists($file)) {
|
211 |
+
@unlink($file);
|
212 |
+
}
|
213 |
+
|
214 |
+
$exec_time = microtime(true) - $time_start;
|
215 |
+
|
216 |
+
if ($skipped) {
|
217 |
+
$this->log['notice'][] = "<b>Skipped {$skipped} posts (most likely due to empty title, body and excerpt).</b>";
|
218 |
+
}
|
219 |
+
$this->log['notice'][] = sprintf("<b>Imported {$imported} posts and {$comments} comments in %.2f seconds.</b>", $exec_time);
|
220 |
+
$this->print_messages();
|
221 |
+
}
|
222 |
+
|
223 |
+
function create_post($data, $options) {
|
224 |
+
extract($options);
|
225 |
+
|
226 |
+
$data = array_merge($this->defaults, $data);
|
227 |
+
$type = $data['csv_post_type'] ? $data['csv_post_type'] : 'post';
|
228 |
+
$valid_type = (function_exists('post_type_exists') &&
|
229 |
+
post_type_exists($type)) || in_array($type, array('post', 'page'));
|
230 |
+
|
231 |
+
if (!$valid_type) {
|
232 |
+
$this->log['error']["type-{$type}"] = sprintf(
|
233 |
+
'Unknown post type "%s".', $type);
|
234 |
+
}
|
235 |
+
|
236 |
+
$new_post = array(
|
237 |
+
'post_title' => convert_chars($data['csv_post_title']),
|
238 |
+
'post_content' => wpautop(convert_chars($data['csv_post_post'])),
|
239 |
+
'post_status' => $opt_draft,
|
240 |
+
'post_type' => $type,
|
241 |
+
'post_date' => $this->parse_date($data['csv_post_date']),
|
242 |
+
'post_excerpt' => convert_chars($data['csv_post_excerpt']),
|
243 |
+
'post_name' => $data['csv_post_slug'],
|
244 |
+
'post_author' => $this->get_auth_id($data['csv_post_author']),
|
245 |
+
'tax_input' => $this->get_taxonomies($data),
|
246 |
+
'post_parent' => $data['csv_post_parent'],
|
247 |
+
);
|
248 |
+
|
249 |
+
// pages don't have tags or categories
|
250 |
+
if ('page' !== $type) {
|
251 |
+
$new_post['tags_input'] = $data['csv_post_tags'];
|
252 |
+
|
253 |
+
// Setup categories before inserting - this should make insertion
|
254 |
+
// faster, but I don't exactly remember why :) Most likely because
|
255 |
+
// we don't assign default cat to post when csv_post_categories
|
256 |
+
// is not empty.
|
257 |
+
$cats = $this->create_or_get_categories($data, $opt_cat);
|
258 |
+
$new_post['post_category'] = $cats['post'];
|
259 |
+
}
|
260 |
+
|
261 |
+
// create!
|
262 |
+
$id = wp_insert_post($new_post);
|
263 |
+
|
264 |
+
if ('page' !== $type && !$id) {
|
265 |
+
// cleanup new categories on failure
|
266 |
+
foreach ($cats['cleanup'] as $c) {
|
267 |
+
wp_delete_term($c, 'category');
|
268 |
+
}
|
269 |
+
}
|
270 |
+
return $id;
|
271 |
+
}
|
272 |
+
|
273 |
+
/**
|
274 |
+
* Return an array of category ids for a post.
|
275 |
+
*
|
276 |
+
* @param string $data csv_post_categories cell contents
|
277 |
+
* @param integer $common_parent_id common parent id for all categories
|
278 |
+
*
|
279 |
+
* @return array() category ids
|
280 |
+
*/
|
281 |
+
function create_or_get_categories($data, $common_parent_id) {
|
282 |
+
$ids = array(
|
283 |
+
'post' => array(),
|
284 |
+
'cleanup' => array(),
|
285 |
+
);
|
286 |
+
$items = array_map('trim', explode(',', $data['csv_post_categories']));
|
287 |
+
foreach ($items as $item) {
|
288 |
+
if (is_numeric($item)) {
|
289 |
+
if (get_category($item) !== null) {
|
290 |
+
$ids['post'][] = $item;
|
291 |
+
} else {
|
292 |
+
$this->log['error'][] = "Category ID {$item} does not exist, skipping.";
|
293 |
+
}
|
294 |
+
} else {
|
295 |
+
$parent_id = $common_parent_id;
|
296 |
+
// item can be a single category name or a string such as
|
297 |
+
// Parent > Child > Grandchild
|
298 |
+
$categories = array_map('trim', explode('>', $item));
|
299 |
+
if (count($categories) > 1 && is_numeric($categories[0])) {
|
300 |
+
$parent_id = $categories[0];
|
301 |
+
if (get_category($parent_id) !== null) {
|
302 |
+
// valid id, everything's ok
|
303 |
+
$categories = array_slice($categories, 1);
|
304 |
+
} else {
|
305 |
+
$this->log['error'][] = "Category ID {$parent_id} does not exist, skipping.";
|
306 |
+
continue;
|
307 |
+
}
|
308 |
+
}
|
309 |
+
foreach ($categories as $category) {
|
310 |
+
if ($category) {
|
311 |
+
$term = is_term($category, 'category', $parent_id);
|
312 |
+
if ($term) {
|
313 |
+
$term_id = $term['term_id'];
|
314 |
+
} else {
|
315 |
+
$term_id = wp_insert_category(array(
|
316 |
+
'cat_name' => $category,
|
317 |
+
'category_parent' => $parent_id,
|
318 |
+
));
|
319 |
+
$ids['cleanup'][] = $term_id;
|
320 |
+
}
|
321 |
+
$parent_id = $term_id;
|
322 |
+
}
|
323 |
+
}
|
324 |
+
$ids['post'][] = $term_id;
|
325 |
+
}
|
326 |
+
}
|
327 |
+
return $ids;
|
328 |
+
}
|
329 |
+
|
330 |
+
// Parse taxonomy data from the file
|
331 |
+
//
|
332 |
+
// array(
|
333 |
+
// // hierarchical taxonomy name => ID array
|
334 |
+
// 'my taxonomy 1' => array(1, 2, 3, ...),
|
335 |
+
// // non-hierarchical taxonomy name => term names string
|
336 |
+
// 'my taxonomy 2' => array('term1', 'term2', ...),
|
337 |
+
// )
|
338 |
+
function get_taxonomies($data) {
|
339 |
+
$taxonomies = array();
|
340 |
+
foreach ($data as $k => $v) {
|
341 |
+
if (preg_match('/^csv_ctax_(.*)$/', $k, $matches)) {
|
342 |
+
$t_name = $matches[1];
|
343 |
+
if (is_taxonomy($t_name)) {
|
344 |
+
$taxonomies[$t_name] = $this->create_terms($t_name,
|
345 |
+
$data[$k]);
|
346 |
+
} else {
|
347 |
+
$this->log['error'][] = "Unknown taxonomy $t_name";
|
348 |
+
}
|
349 |
+
}
|
350 |
+
}
|
351 |
+
return $taxonomies;
|
352 |
+
}
|
353 |
+
|
354 |
+
// Return an array of term IDs for hierarchical taxonomies or the original
|
355 |
+
// string from CSV for non-hierarchical taxonomies. The original string
|
356 |
+
// should have the same format as csv_post_tags.
|
357 |
+
function create_terms($taxonomy, $field) {
|
358 |
+
if (is_taxonomy_hierarchical($taxonomy)) {
|
359 |
+
$term_ids = array();
|
360 |
+
foreach ($this->_parse_tax($field) as $row) {
|
361 |
+
list($parent, $child) = $row;
|
362 |
+
$parent_ok = true;
|
363 |
+
if ($parent) {
|
364 |
+
$parent_info = is_term($parent, $taxonomy);
|
365 |
+
if (!$parent_info) {
|
366 |
+
// create parent
|
367 |
+
$parent_info = wp_insert_term($parent, $taxonomy);
|
368 |
+
}
|
369 |
+
if (!is_wp_error($parent_info)) {
|
370 |
+
$parent_id = $parent_info['term_id'];
|
371 |
+
} else {
|
372 |
+
// could not find or create parent
|
373 |
+
$parent_ok = false;
|
374 |
+
}
|
375 |
+
} else {
|
376 |
+
$parent_id = 0;
|
377 |
+
}
|
378 |
+
|
379 |
+
if ($parent_ok) {
|
380 |
+
$child_info = is_term($child, $taxonomy, $parent_id);
|
381 |
+
if (!$child_info) {
|
382 |
+
// create child
|
383 |
+
$child_info = wp_insert_term($child, $taxonomy,
|
384 |
+
array('parent' => $parent_id));
|
385 |
+
}
|
386 |
+
if (!is_wp_error($child_info)) {
|
387 |
+
$term_ids[] = $child_info['term_id'];
|
388 |
+
}
|
389 |
+
}
|
390 |
+
}
|
391 |
+
return $term_ids;
|
392 |
+
} else {
|
393 |
+
return $field;
|
394 |
+
}
|
395 |
+
}
|
396 |
+
|
397 |
+
// hierarchical taxonomy fields are tiny CSV files in their own right
|
398 |
+
function _parse_tax($field) {
|
399 |
+
$data = array();
|
400 |
+
if (function_exists('str_getcsv')) { // PHP 5 >= 5.3.0
|
401 |
+
$lines = explode("\n", $field);
|
402 |
+
|
403 |
+
foreach ($lines as $line) {
|
404 |
+
$data[] = str_getcsv($line, ',', '"');
|
405 |
+
}
|
406 |
+
} else {
|
407 |
+
// Use temp files for older PHP versions. Reusing the tmp file for
|
408 |
+
// the duration of the script might be faster, but not necessarily
|
409 |
+
// significant.
|
410 |
+
$handle = tmpfile();
|
411 |
+
fwrite($handle, $field);
|
412 |
+
fseek($handle, 0);
|
413 |
+
|
414 |
+
while (($r = fgetcsv($handle, 999999, ',', '"')) !== false) {
|
415 |
+
$data[] = $r;
|
416 |
+
}
|
417 |
+
fclose($handle);
|
418 |
+
}
|
419 |
+
return $data;
|
420 |
+
}
|
421 |
+
|
422 |
+
function add_comments($post_id, $data) {
|
423 |
+
// First get a list of the comments for this post
|
424 |
+
$comments = array();
|
425 |
+
foreach ($data as $k => $v) {
|
426 |
+
// comments start with cvs_comment_
|
427 |
+
if ( preg_match('/^csv_comment_([^_]+)_(.*)/', $k, $matches) &&
|
428 |
+
$v != '') {
|
429 |
+
$comments[$matches[1]] = 1;
|
430 |
+
}
|
431 |
+
}
|
432 |
+
// Sort this list which specifies the order they are inserted, in case
|
433 |
+
// that matters somewhere
|
434 |
+
ksort($comments);
|
435 |
+
|
436 |
+
// Now go through each comment and insert it. More fields are possible
|
437 |
+
// in principle (see docu of wp_insert_comment), but I didn't have data
|
438 |
+
// for them so I didn't test them, so I didn't include them.
|
439 |
+
$count = 0;
|
440 |
+
foreach ($comments as $cid => $v) {
|
441 |
+
$new_comment = array(
|
442 |
+
'comment_post_ID' => $post_id,
|
443 |
+
'comment_approved' => 1,
|
444 |
+
);
|
445 |
+
|
446 |
+
if (isset($data["csv_comment_{$cid}_author"])) {
|
447 |
+
$new_comment['comment_author'] = convert_chars(
|
448 |
+
$data["csv_comment_{$cid}_author"]);
|
449 |
+
}
|
450 |
+
if (isset($data["csv_comment_{$cid}_author_email"])) {
|
451 |
+
$new_comment['comment_author_email'] = convert_chars(
|
452 |
+
$data["csv_comment_{$cid}_author_email"]);
|
453 |
+
}
|
454 |
+
if (isset($data["csv_comment_{$cid}_url"])) {
|
455 |
+
$new_comment['comment_author_url'] = convert_chars(
|
456 |
+
$data["csv_comment_{$cid}_url"]);
|
457 |
+
}
|
458 |
+
if (isset($data["csv_comment_{$cid}_content"])) {
|
459 |
+
$new_comment['comment_content'] = convert_chars(
|
460 |
+
$data["csv_comment_{$cid}_content"]);
|
461 |
+
}
|
462 |
+
if (isset($data["csv_comment_{$cid}_date"])) {
|
463 |
+
$new_comment['comment_date'] = $this->parse_date(
|
464 |
+
$data["csv_comment_{$cid}_date"]);
|
465 |
+
}
|
466 |
+
|
467 |
+
$id = wp_insert_comment($new_comment);
|
468 |
+
if ($id) {
|
469 |
+
$count++;
|
470 |
+
} else {
|
471 |
+
$this->log['error'][] = "Could not add comment $cid";
|
472 |
+
}
|
473 |
+
}
|
474 |
+
return $count;
|
475 |
+
}
|
476 |
+
|
477 |
+
function create_custom_fields($post_id, $data) {
|
478 |
+
foreach ($data as $k => $v) {
|
479 |
+
// anything that doesn't start with csv_ is a custom field
|
480 |
+
if (!preg_match('/^csv_/', $k) && $v != '') {
|
481 |
+
add_post_meta($post_id, $k, $v);
|
482 |
+
}
|
483 |
+
}
|
484 |
+
}
|
485 |
+
|
486 |
+
function get_auth_id($author) {
|
487 |
+
if (is_numeric($author)) {
|
488 |
+
return $author;
|
489 |
+
}
|
490 |
+
$author_data = get_userdatabylogin($author);
|
491 |
+
return ($author_data) ? $author_data->ID : 0;
|
492 |
+
}
|
493 |
+
|
494 |
+
// Convert date in CSV file to 1999-12-31 23:52:00 format
|
495 |
+
function parse_date($data) {
|
496 |
+
$timestamp = strtotime($data);
|
497 |
+
if (false === $timestamp) {
|
498 |
+
return '';
|
499 |
+
} else {
|
500 |
+
return date('Y-m-d H:i:s', $timestamp);
|
501 |
+
}
|
502 |
+
}
|
503 |
+
|
504 |
+
// delete BOM from UTF-8 file
|
505 |
+
function stripBOM($fname) {
|
506 |
+
$res = fopen($fname, 'rb');
|
507 |
+
if (false !== $res) {
|
508 |
+
$bytes = fread($res, 3);
|
509 |
+
if ($bytes == pack('CCC', 0xef, 0xbb, 0xbf)) {
|
510 |
+
$this->log['notice'][] = 'Getting rid of byte order mark...';
|
511 |
+
fclose($res);
|
512 |
+
|
513 |
+
$contents = file_get_contents($fname);
|
514 |
+
if (false === $contents) {
|
515 |
+
trigger_error('Failed to get file contents.', E_USER_WARNING);
|
516 |
+
}
|
517 |
+
$contents = substr($contents, 3);
|
518 |
+
$success = file_put_contents($fname, $contents);
|
519 |
+
if (false === $success) {
|
520 |
+
trigger_error('Failed to put file contents.', E_USER_WARNING);
|
521 |
+
}
|
522 |
+
} else {
|
523 |
+
fclose($res);
|
524 |
+
}
|
525 |
+
} else {
|
526 |
+
$this->log['error'][] = 'Failed to open file, aborting.';
|
527 |
+
}
|
528 |
+
}
|
529 |
+
}
|
530 |
+
|
531 |
+
|
532 |
+
function csv_admin_menu() {
|
533 |
+
require_once ABSPATH . '/wp-admin/admin.php';
|
534 |
+
$plugin = new CSVImporterPlugin;
|
535 |
+
add_management_page('edit.php', 'CSV Importer', 9, __FILE__, array($plugin, 'form'));
|
536 |
+
}
|
537 |
+
|
538 |
+
add_action('admin_menu', 'csv_admin_menu');
|
539 |
+
|
540 |
+
?>
|
examples/comments.csv
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
"csv_post_title","csv_post_post","csv_post_categories","csv_post_tags","csv_comment_1_author","csv_comment_1_content","csv_comment_2_author","csv_comment_2_author_email","csv_comment_2_url","csv_comment_2_content","csv_comment_2_date"
|
2 |
+
"Minitel","The Minitel is a Videotex online service accessible through the telephone lines, and is considered one of the world's most successful pre-World Wide Web online services.","Testing CSV Importer","test,import,csv","gordon","Wow, I have never heard about such service.","eli","eli@example.com","http://example.com","From its early days, users could make online purchases, make train reservations, check stock prices, search the telephone directory, and chat in a similar way to that now made possible by the Internet.","yesterday"
|
examples/custom-taxonomies.csv
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"csv_post_title","csv_post_post","csv_post_excerpt","csv_post_categories","csv_post_tags","csv_post_date","csv_post_author","csv_post_slug","csv_ctax_art","csv_ctax_country","my_custom1"
|
2 |
+
"Vincent Van Gogh","Vincent Willem van Gogh[a 1] (30 March 1853 – 29 July 1890) was a Dutch post-Impressionist painter whose work had a far-reaching influence on 20th century art for its vivid colors and emotional impact. He suffered from anxiety and increasingly frequent bouts of mental illness throughout his life, and died largely unknown, at the age of 37, from a self-inflicted gunshot wound.","Vincent Willem van Gogh[a 1] (30 March 1853 – 29 July 1890) was a Dutch post-Impressionist painter","Art, CSV Importer","van gogh, dutch, painter","June 1, 2010","alice","Van-gogh-one","Painting, post-impressionism","Netherlands,France",53
|
3 |
+
"Claude Monet","Claude Monet (French pronunciation: [klod mɔnɛ]), born Oscar Claude Monet (14 November 1840 – 5 December 1926)[1] was a founder of French impressionist painting, and the most consistent and prolific practitioner of the movement's philosophy of expressing one's perceptions before nature, especially as applied to plein-air landscape painting. ","Claude Monet (French pronunciation: [klod mɔnɛ]), born Oscar Claude Monet (14 November 1840 – 5 December 1926)[1] was a founder of French impressionist painting","Art, CSV Importer","monet, french, painter","May 30, 2010","alice","Claude-monet-one","Painting, impressionism","France",40
|
4 |
+
"Pablo Picasso","Pablo Diego José Francisco de Paula Juan Nepomuceno María de los Remedios Cipriano de la Santísima Trinidad Clito Ruiz y Picasso Ruiz Picasso known as Pablo Ruiz Picasso (25 October 1881 – 8 April 1973) was a Spanish painter, draughtsman, and sculptor. He is best known for co-founding the Cubist movement and for the wide variety of styles embodied in his work.","Pablo Ruiz Picasso (25 October 1881 – 8 April 1973) was a Spanish painter, draughtsman, and sculptor.","Art, CSV Importer","picasso, spanish, painter, sculptor","August 25 2009","alice","Pablo-picasso-one","Painting, cubism
|
5 |
+
Sculpture, cubism","France, Spain",81
|
6 |
+
"Oscar Wilde","Oscar Fingal O'Flahertie Wills Wilde (16 October 1854 – 30 November 1900) was an Irish writer, poet, and prominent aesthete. His parents were successful Dublin intellectuals, and from an early age he was tutored at home, where he showed his intelligence, becoming fluent in French and German. ","Oscar Fingal O'Flahertie Wills Wilde (16 October 1854 – 30 November 1900) was an Irish writer, poet, and prominent aesthete.","Art, CSV Importer","wilde, irish, poet","August 25 2009","bob","Oscar-wilde-one","Poetry, aestheticism
|
7 |
+
Prose, ""fiction, gothic""","Ireland, UK, France",54
|
examples/functions.inc.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// Set up custom taxonomies for CSV Importer custom-taxonomies.csv example. You
|
4 |
+
// can copy-and-paste the code below to your theme's functions.php file.
|
5 |
+
|
6 |
+
add_action('init', 'csv_importer_taxonomies', 0);
|
7 |
+
|
8 |
+
function csv_importer_taxonomies() {
|
9 |
+
register_taxonomy('art', 'post', array(
|
10 |
+
'hierarchical' => true,
|
11 |
+
'label' => 'Art',
|
12 |
+
));
|
13 |
+
register_taxonomy('country', 'post', array(
|
14 |
+
'hierarchical' => false,
|
15 |
+
'label' => 'Country',
|
16 |
+
));
|
17 |
+
}
|
18 |
+
|
19 |
+
?>
|
examples/sample-advanced.csv
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"csv_post_title","csv_post_post","csv_post_categories","csv_post_date","csv_post_author","csv_post_slug","csv_post_type","csv_post_parent"
|
2 |
+
"[CSV Importer] Assign an author","You can manually assign an author to a post, provided that user exists.","Testing CSV Importer",,"alice",,,
|
3 |
+
"[CSV Importer] Set a slug","Slugs are supported, too.","Testing CSV Importer",,,"slug-ability",,
|
4 |
+
"[CSV Importer] Yesterday's post","Dates can be specified in a variety of formats, including plain English (with limitations, of course).","Testing CSV Importer","yesterday",,,,
|
5 |
+
"[CSV Importer] A year ago","Set date to the same day, a year ago.","Testing CSV Importer","-1 year",,,,
|
6 |
+
"[CSV Importer] Exact date 1","More precise date formats are supported, too.","Testing CSV Importer","2011, feb 2",,,,
|
7 |
+
"[CSV Importer] Exact date 2","More precise date formats are supported, too.","Testing CSV Importer","01/01/11",,,,
|
8 |
+
"[CSV Importer] Parent","You can specify a parent page using its id. The page has to already exist for this to work.","Testing CSV Importer",,,,"page",83
|
9 |
+
"[CSV Importer] Subcategories","To specify a category structure, use the greater than sign > in the csv_post_categories column.","Testing CSV Importer > Guitars > Electric",,,,,
|
examples/sample.csv
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"csv_post_title","csv_post_post","csv_post_type","csv_post_excerpt","csv_post_categories","csv_post_tags","csv_post_date","custom_field_1","custom_field_2"
|
2 |
+
"[CSV Importer] Test","Don't panic, this is only a test.
|
3 |
+
|
4 |
+
The <a href=""http://wordpress.org/extend/plugins/csv-importer/other_notes/"">manual</a> has a lot of useful information.
|
5 |
+
|
6 |
+
Unsurprisingly, one of the most frequently asked questions is ""What should I do if my data has commas and double quotes?"".
|
7 |
+
|
8 |
+
<em>CSV Importer</em> can be used with any language (just make sure to save the file with UTF-8 encoding):
|
9 |
+
|
10 |
+
<blockquote>
|
11 |
+
A comma-separated values or character-separated values (CSV) file is a simple text format for a database table.
|
12 |
+
|
13 |
+
Comma-separated values (CSV) est un format informatique ouvert représentant des données tabulaires sous forme de « valeurs séparées par des virgules ».
|
14 |
+
|
15 |
+
CSV (от англ. Comma Separated Values — значения, разделённые запятыми) — текстовый формат, предназначенный для представления табличных данных.
|
16 |
+
|
17 |
+
Comma-Separated Values(略称:CSV)は、いくつかのフィールド(項目)をカンマ「,」で区切ったテキストデータおよびテキストファイル。
|
18 |
+
</blockquote>",,"This is an excerpt for a CSV Importer test post.","Testing CSV Importer, Testing CSV Importer 2","test,csv","2000-12-31 20:00:12","custom value","custom value 2"
|
19 |
+
"[CSV Importer] A future post","This is a post that's scheduled to be published in the future (provided that it's not imported as a draft).","post","An excerpt of a future post.","Testing CSV Importer","test,csv,future","2014-01-01 14:00:00",42,43
|
20 |
+
"[CSV Importer] How to import a page?","To import a page, set csv_post_type column value to ""page"".","page",,,,,,
|
readme.txt
ADDED
@@ -0,0 +1,339 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== CSV Importer ===
|
2 |
+
Contributors: dvkob
|
3 |
+
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=4YJEU5U2Y4LTS&lc=US&item_name=Support%20CSV%20Importer%20development¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted
|
4 |
+
Tags: csv, import, batch, spreadsheet, excel
|
5 |
+
Requires at least: 2.0.2
|
6 |
+
Tested up to: 3.0.4
|
7 |
+
Stable tag: trunk
|
8 |
+
|
9 |
+
Import posts from CSV files into WordPress.
|
10 |
+
|
11 |
+
|
12 |
+
== Description ==
|
13 |
+
|
14 |
+
This plugin imports posts from CSV (Comma Separated Value) files into your
|
15 |
+
WordPress blog. It can prove extremely useful when you want to import a bunch
|
16 |
+
of posts from an Excel document or the like - simply export your document into
|
17 |
+
a CSV file and the plugin will take care of the rest.
|
18 |
+
|
19 |
+
= Features =
|
20 |
+
|
21 |
+
* Imports post title, body, excerpt, tags, date, categories etc.
|
22 |
+
* Supports custom fields, custom taxonomies and comments
|
23 |
+
* Deals with Word-style quotes and other non-standard characters using
|
24 |
+
WordPress' built-in mechanism (same one that normalizes your input when you
|
25 |
+
write your posts)
|
26 |
+
* Columns in the CSV file can be in any order, provided that they have correct
|
27 |
+
headings
|
28 |
+
* Multilanguage support
|
29 |
+
|
30 |
+
|
31 |
+
== Screenshots ==
|
32 |
+
|
33 |
+
1. Plugin's interface
|
34 |
+
|
35 |
+
|
36 |
+
== Installation ==
|
37 |
+
|
38 |
+
Installing the plugin:
|
39 |
+
|
40 |
+
1. Unzip the plugin's directory into `wp-content/plugins`.
|
41 |
+
1. Activate the plugin through the 'Plugins' menu in WordPress.
|
42 |
+
1. The plugin will be available under Tools -> CSV Importer on
|
43 |
+
WordPress administration page.
|
44 |
+
|
45 |
+
|
46 |
+
== Usage ==
|
47 |
+
|
48 |
+
Click on the CSV Importer link on your WordPress admin page, choose the
|
49 |
+
file you would like to import and click Import. The `examples` directory
|
50 |
+
inside the plugin's directory contains several files that demonstrate
|
51 |
+
how to use the plugin. The best way to get started is to import one of
|
52 |
+
these files and look at the results.
|
53 |
+
|
54 |
+
CSV is a tabular format that consists of rows and columns. Each row in
|
55 |
+
a CSV file represents a post; each column identifies a piece of information
|
56 |
+
that comprises a post.
|
57 |
+
|
58 |
+
= Basic post information =
|
59 |
+
|
60 |
+
* `csv_post_title` - title of the post
|
61 |
+
* `csv_post_post` - body of the post
|
62 |
+
* `csv_post_type` - `post`, `page` or a custom post type.
|
63 |
+
__New in version 0.3.2__
|
64 |
+
In prior versions, importing rows as pages could be specified on a
|
65 |
+
per-file basis using the plugins UI. In 0.3.2, `csv_post_type` column
|
66 |
+
was added to support custom post types as well.
|
67 |
+
Refer to the WordPress
|
68 |
+
[documentation on custom post types][custom_post_types] for more info
|
69 |
+
on how to set up custom post types.
|
70 |
+
* `csv_post_excerpt` - post excerpt
|
71 |
+
* `csv_post_categories` - a comma separated list of category names or ids.
|
72 |
+
__New in version 0.3.5__
|
73 |
+
It's also possible to assign posts to non-existing subcategories, using
|
74 |
+
> to denote category relationships, e.g. `Animalia > Chordata > Mammalia`.
|
75 |
+
If any of the categories in the chain does not exist, the plugin will
|
76 |
+
automatically create it. It's also possible to specify the parent category
|
77 |
+
using an id, as in `42 > Primates > Callitrichidae`, where `42` is an
|
78 |
+
existing category id.
|
79 |
+
* `csv_post_tags` - a comma separated list of tags.
|
80 |
+
* `csv_post_date` - about any English textual description of a date and time.
|
81 |
+
For example, `now`, `11/16/2009 0:00`, `1999-12-31 23:55:00`, `+1 week`,
|
82 |
+
`next Thursday`, `last year` are all valid descriptions. For technical
|
83 |
+
details, consult PHP's `strtotime()` function [documentation][strtotime].
|
84 |
+
|
85 |
+
[custom_post_types]: http://codex.wordpress.org/Custom_Post_Types
|
86 |
+
[strtotime]: http://php.net/manual/en/function.strtotime.php
|
87 |
+
|
88 |
+
= Custom fields =
|
89 |
+
|
90 |
+
Any column that doesn't start with `csv_` is considered to be a custom field
|
91 |
+
name. The data in that column will be imported as the custom fields value.
|
92 |
+
|
93 |
+
= General remarks =
|
94 |
+
|
95 |
+
* WordPress pages [don't have categories or tags][pages].
|
96 |
+
* Most columns are optional. Either `csv_post_title`, `csv_post_post` or
|
97 |
+
`csv_post_excerpt` are sufficient to create a post. If all of these
|
98 |
+
columns are empty in a row, the plugin will skip that row.
|
99 |
+
* The plugin will attempt to reuse existing categories or tags; if an
|
100 |
+
existing category or tag cannot be found, the plugin will create it.
|
101 |
+
* To specify a category that has a greater than sign (>) in the name, use
|
102 |
+
the HTML entity `>`
|
103 |
+
|
104 |
+
[pages]: http://codex.wordpress.org/Pages
|
105 |
+
|
106 |
+
= Advanced usage =
|
107 |
+
|
108 |
+
* `csv_post_author` - numeric user id or login name. If not specified or
|
109 |
+
user does not exist, the plugin will assign the posts to the user
|
110 |
+
performing the import.
|
111 |
+
* `csv_post_slug` - post slug used in permalinks.
|
112 |
+
* `csv_post_parent` - post parent id.
|
113 |
+
|
114 |
+
== Custom taxonomies ==
|
115 |
+
|
116 |
+
__New in version 0.3.0__
|
117 |
+
|
118 |
+
Once custom taxonomies are set up in your theme's functions.php file or
|
119 |
+
by using a 3rd party plugin, `csv_ctax_(taxonomy name)` columns can be
|
120 |
+
used to assign imported data to the taxonomies.
|
121 |
+
|
122 |
+
__Non-hierarchical taxonomies__
|
123 |
+
|
124 |
+
The syntax for non-hierarchical taxonomies is straightforward and is essentially
|
125 |
+
the same as the `csv_post_tags` syntax.
|
126 |
+
|
127 |
+
__Hierarchical taxonomies__
|
128 |
+
|
129 |
+
The syntax for hierarchical taxonomies is more complicated. Each hierarchical
|
130 |
+
taxonomy field is a tiny two-column CSV file, where _the order of columns
|
131 |
+
matters_. The first column contains the name of the parent term and the second
|
132 |
+
column contains the name of the child term. Top level terms have to be preceded
|
133 |
+
either by an empty string or a 0 (zero).
|
134 |
+
|
135 |
+
Sample `examples/custom-taxonomies.csv` file included with the plugin
|
136 |
+
illustrates custom taxonomy support. To see how it works, make sure to set up
|
137 |
+
custom taxonomies from `functions.inc.php`.
|
138 |
+
|
139 |
+
Make sure that the quotation marks used as text delimiters in `csv_ctax_`
|
140 |
+
columns are regular ASCII double quotes, not typographical quotes like “
|
141 |
+
(U+201C) and ” (U+201D).
|
142 |
+
|
143 |
+
== Comments ==
|
144 |
+
|
145 |
+
__New in version 0.3.1__
|
146 |
+
|
147 |
+
An example file with comments is included in the `examples` directory.
|
148 |
+
In short, comments can be imported along with posts by specifying columns
|
149 |
+
such as `csv_comment_*_author`, `csv_comment_*_content` etc, where * is
|
150 |
+
a comment ID number. This ID doesn't go into WordPress. It is only there
|
151 |
+
to have the connection information in the CSV file.
|
152 |
+
|
153 |
+
|
154 |
+
== Frequently Asked Questions ==
|
155 |
+
|
156 |
+
> I have quotation marks and commas as values in my CSV file. How do I tell CSV
|
157 |
+
Importer to use a different separator?
|
158 |
+
|
159 |
+
It doesn't really matter what kind of separator you use if your file is
|
160 |
+
properly escaped. To see what I mean by proper escaping, take a look at
|
161 |
+
`examples/sample.csv` file which has cells with quotation marks and commas.
|
162 |
+
|
163 |
+
If the software you use for exporting to CSV is unable to escape quotation
|
164 |
+
marks and commas, you might want to give [OpenOffice Calc][calc] a try.
|
165 |
+
|
166 |
+
[calc]: http://www.openoffice.org/
|
167 |
+
|
168 |
+
> How can I import characters with diacritics, Cyrillic or Han characters?
|
169 |
+
|
170 |
+
Make sure to save your CSV file with utf-8 encoding.
|
171 |
+
|
172 |
+
Prior to version 6.0.4, MySQL [did not support][5] some rare Han characters. As
|
173 |
+
a workaround, you can insert characters such as 𠊎 (U+2028E) by
|
174 |
+
converting them to HTML entities - &\#x2028e;
|
175 |
+
|
176 |
+
[5]: http://dev.mysql.com/doc/refman/5.1/en/faqs-cjk.html#qandaitem-24-11-1-13
|
177 |
+
|
178 |
+
> I cannot import anything - the plugin displays "Imported 0 posts in 0.01
|
179 |
+
seconds."
|
180 |
+
|
181 |
+
Update to version 0.3.1 or greater. Previous versions required write access to
|
182 |
+
the /tmp directory and the plugin failed if access was denied by PHP's safe
|
183 |
+
mode or other settings.
|
184 |
+
|
185 |
+
> I'm importing a file, but not all rows in it are imported and I don't see
|
186 |
+
a confirmation message. Why?
|
187 |
+
|
188 |
+
WordPress can be many things, but one thing it's not is blazing fast. The
|
189 |
+
reason why not all rows are imported and there's no confirmation message is
|
190 |
+
that the plugin times out during execution - PHP decides that it has been
|
191 |
+
running too long and terminates it.
|
192 |
+
|
193 |
+
There are a number of solutions you can try. First, make sure that you're not
|
194 |
+
using any plugins that may slow down post insertion. For example, a Twitter
|
195 |
+
plugin might attempt to tweet every post you import - not a very good idea
|
196 |
+
if you have 200 posts. Second, you can break up a file into smaller chunks that
|
197 |
+
take less time to import and therefore will not cause the plugin to time out.
|
198 |
+
Third, you can try adjusting PHP's `max_execution_time` option that sets how
|
199 |
+
long scripts are allowed to run. Description of how to do it is beyond the
|
200 |
+
scope of this FAQ - you should search the web and/or use your web host's help
|
201 |
+
to find out how. However, putting the following line in `.htaccess` file inside
|
202 |
+
public_html directory works for some people:
|
203 |
+
|
204 |
+
# Sets max execution time to 2 minutes. Adjust as necessary.
|
205 |
+
php_value max_execution_time 120
|
206 |
+
|
207 |
+
The problem can be approached from another angle, namely instead of giving
|
208 |
+
scripts more time to run making them run faster. There's not much I can do to
|
209 |
+
speed up the plugin (you can contact me at dvkobozev at gmail.com if you like
|
210 |
+
to prove me wrong), so you can try to speed up WordPress. It is a pretty broad
|
211 |
+
topic, ranging from database optimizations to PHP accelerators such as APC,
|
212 |
+
eAccelerator or XCache, so I'm afraid you're on your own here.
|
213 |
+
|
214 |
+
> I receive the following error when I try to import my CSV file: "Invalid CSV
|
215 |
+
file: header length and/or row lengths do not match". What's wrong with your
|
216 |
+
plugin/my file?
|
217 |
+
|
218 |
+
Short answer: update to version 0.2.0 or later. Longer answer: the number of
|
219 |
+
fields (values) in rows in your file does not match the number of columns.
|
220 |
+
Version 0.2.0 pads such rows with empty values (if there are more columns than
|
221 |
+
cells in a row) or discards extra fields (if there are less columns than cells
|
222 |
+
in a row).
|
223 |
+
|
224 |
+
> I'm getting the following error: `Parse error: syntax error, unexpected
|
225 |
+
T_STRING, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or '}' in .../public_html/wp-content/plugins/csv-importer/File_CSV_DataSource/DataSource.php
|
226 |
+
on line 61`. What gives?
|
227 |
+
|
228 |
+
This plugin requires PHP5, while you probably have PHP4 or older. Update your
|
229 |
+
PHP installation or ask your hosting provider to do it for you.
|
230 |
+
|
231 |
+
|
232 |
+
== Credits ==
|
233 |
+
|
234 |
+
This plugin uses [php-csv-parser][3] by Kazuyoshi Tlacaelel.
|
235 |
+
It was inspired by JayBlogger's [CSV Import][4] plugin.
|
236 |
+
|
237 |
+
Contributors:
|
238 |
+
|
239 |
+
* Kevin Hagerty (post_author support)
|
240 |
+
* Edir Pedro (root category option and tableless HTML markup)
|
241 |
+
* Frank Loeffler (comments support)
|
242 |
+
* Micah Gates (subcategory syntax)
|
243 |
+
|
244 |
+
[3]: http://code.google.com/p/php-csv-parser/
|
245 |
+
[4]: http://www.jayblogger.com/the-birth-of-my-first-plugin-import-csv/
|
246 |
+
|
247 |
+
|
248 |
+
== Changelog ==
|
249 |
+
|
250 |
+
= 0.3.6 =
|
251 |
+
* Fix category cleanup bug
|
252 |
+
|
253 |
+
= 0.3.5 =
|
254 |
+
* Added 'greater-than' category syntax
|
255 |
+
* Updated the docs
|
256 |
+
|
257 |
+
= 0.3.4 =
|
258 |
+
* Added csv_post_parent column
|
259 |
+
* Updated the docs
|
260 |
+
* Got rid of a deprecation warning
|
261 |
+
|
262 |
+
= 0.3.3 =
|
263 |
+
* Fixes incompatibility with versions of WordPress prior to 3.0 introduced
|
264 |
+
in previous release.
|
265 |
+
|
266 |
+
= 0.3.2 =
|
267 |
+
* Added ability to specify custom post type.
|
268 |
+
|
269 |
+
= 0.3.1 =
|
270 |
+
* Import comments.
|
271 |
+
* Updated php-csv-parser - the plugin should no longer create files in /tmp.
|
272 |
+
|
273 |
+
= 0.3.0 =
|
274 |
+
* Custom taxonomies.
|
275 |
+
|
276 |
+
= 0.2.4 =
|
277 |
+
* Root category selection, cleaner HTML.
|
278 |
+
|
279 |
+
= 0.2.3 =
|
280 |
+
* Slight speed increase, support for post_author and post_name.
|
281 |
+
|
282 |
+
= 0.2.2 =
|
283 |
+
* Bugfix release to deal with BOM that may occur in UTF-8 encoded files.
|
284 |
+
|
285 |
+
= 0.2.1 =
|
286 |
+
* Ability to import rows as pages, not posts.
|
287 |
+
* Starting with this version, you can also specify category ids instead of
|
288 |
+
names.
|
289 |
+
|
290 |
+
= 0.2.0 =
|
291 |
+
* Ability to handle CSV files where the number of cells in rows does not
|
292 |
+
match the number of columns
|
293 |
+
* Smart date parsing
|
294 |
+
* Code cleanup.
|
295 |
+
|
296 |
+
= 0.1.3 =
|
297 |
+
* New option to import posts with published status.
|
298 |
+
|
299 |
+
= 0.1.2 =
|
300 |
+
* Added support for post excerpts.
|
301 |
+
|
302 |
+
= 0.1.1 =
|
303 |
+
* Code cleanup
|
304 |
+
* Changed column names for CSV input. Sorry if it breaks anything for you,
|
305 |
+
folks, but it had to be done in order to allow for custom fields such as
|
306 |
+
`title` ([All in One SEO Pack][1] uses those, for example).
|
307 |
+
|
308 |
+
= v0.1.0 =
|
309 |
+
* Initial version of the plugin
|
310 |
+
|
311 |
+
[1]: http://wordpress.org/extend/plugins/all-in-one-seo-pack/
|
312 |
+
|
313 |
+
|
314 |
+
== Upgrade Notice ==
|
315 |
+
|
316 |
+
= 0.3.6 =
|
317 |
+
Fix for 'Invalid argument supplied for foreach() on line 268' error message
|
318 |
+
|
319 |
+
= 0.3.5 =
|
320 |
+
Subcategory creation support. Documentation update.
|
321 |
+
|
322 |
+
= 0.3.4 =
|
323 |
+
Post parent support. Documentation update.
|
324 |
+
|
325 |
+
= 0.3.3 =
|
326 |
+
Fixes "Call to undefined function post_type_exists()" error for versions of
|
327 |
+
Wordpress prior to 3.0
|
328 |
+
|
329 |
+
= 0.3.2 =
|
330 |
+
Adds support for custom post types. Option to import pages has been removed from
|
331 |
+
the interface. To import a page, add csv_post_type column to your csv file and
|
332 |
+
set it to "page".
|
333 |
+
|
334 |
+
= 0.3.1 =
|
335 |
+
Adds support for comments
|
336 |
+
|
337 |
+
= 0.3.0 =
|
338 |
+
Adds support for custom taxonomies
|
339 |
+
|
screenshot-1.png
ADDED
Binary file
|