CSV Importer - Version 0.3.6

Version Description

  • Fix category cleanup bug
Download this release

Release Info

Developer dvkob
Plugin Icon wp plugin CSV Importer
Version 0.3.6
Comparing to
See all releases

Version 0.3.6

Files changed (33) hide show
  1. File_CSV_DataSource/DataSource.php +2265 -0
  2. File_CSV_DataSource/docs/LICENSE +23 -0
  3. File_CSV_DataSource/docs/README +19 -0
  4. File_CSV_DataSource/docs/examples/EXAMPLES +72 -0
  5. File_CSV_DataSource/docs/examples/documentation.wiki +2058 -0
  6. File_CSV_DataSource/tests/File_CSV_DataSourceTest.php +508 -0
  7. File_CSV_DataSource/tests/data/another_symmetric.csv +4 -0
  8. File_CSV_DataSource/tests/data/asymmetric.csv +10 -0
  9. File_CSV_DataSource/tests/data/empty.csv +0 -0
  10. File_CSV_DataSource/tests/data/escape_ng.csv +3 -0
  11. File_CSV_DataSource/tests/data/escape_ok.csv +3 -0
  12. File_CSV_DataSource/tests/data/longer_headers.csv +4 -0
  13. File_CSV_DataSource/tests/data/multcased.CsV +0 -0
  14. File_CSV_DataSource/tests/data/non_csv_extension.txt +0 -0
  15. File_CSV_DataSource/tests/data/one_row_only.csv +2 -0
  16. File_CSV_DataSource/tests/data/only_headers.csv +1 -0
  17. File_CSV_DataSource/tests/data/raw.csv +5 -0
  18. File_CSV_DataSource/tests/data/symmetric.csv +10 -0
  19. File_CSV_DataSource/tests/data/symmetric_with_empty_lines.csv +20 -0
  20. File_CSV_DataSource/tests/data/symmetric_with_empty_records.csv +28 -0
  21. File_CSV_DataSource/tests/data/symmetric_with_trailing_spaces.csv +10 -0
  22. File_CSV_DataSource/tests/data/uppercased.CSV +0 -0
  23. File_CSV_DataSource/tests/fixtures/csv.php +999 -0
  24. LICENSE +21 -0
  25. TODO +6 -0
  26. csv_importer.php +540 -0
  27. examples/comments.csv +2 -0
  28. examples/custom-taxonomies.csv +7 -0
  29. examples/functions.inc.php +19 -0
  30. examples/sample-advanced.csv +9 -0
  31. examples/sample.csv +20 -0
  32. readme.txt +339 -0
  33. 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&currency_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
+ &gt; 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 `&gt;`
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 &#x2028e; (U+2028E) by
174
+ converting them to HTML entities - &amp;\#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