|
17 | 17 | use CallbackFilterIterator; |
18 | 18 | use Iterator; |
19 | 19 | use LimitIterator; |
| 20 | +use TypeError; |
20 | 21 | use function array_reduce; |
21 | | -use function iterator_to_array; |
22 | 22 |
|
23 | 23 | /** |
24 | 24 | * Criteria to filter a {@link Reader} object. |
@@ -135,20 +135,63 @@ public function limit(int $limit): self |
135 | 135 | /** |
136 | 136 | * Execute the prepared Statement on the {@link Reader} object. |
137 | 137 | * |
138 | | - * @param string[] $header an optional header to use instead of the CSV document header |
| 138 | + * @param Reader|ResultSet $records |
| 139 | + * @param string[] $header an optional header to use instead of the CSV document header |
139 | 140 | */ |
140 | | - public function process(Reader $csv, array $header = []): ResultSet |
| 141 | + public function process($records, array $header = []): ResultSet |
141 | 142 | { |
| 143 | + if (!($records instanceof Reader) && !($records instanceof ResultSet)) { |
| 144 | + throw new TypeError(sprintf( |
| 145 | + '%s::parse expects parameter 1 to be a %s or a %s object, %s given', |
| 146 | + Statement::class, |
| 147 | + ResultSet::class, |
| 148 | + Reader::class, |
| 149 | + get_class($records) |
| 150 | + )); |
| 151 | + } |
| 152 | + |
142 | 153 | if ([] === $header) { |
143 | | - $header = $csv->getHeader(); |
| 154 | + $header = $records->getHeader(); |
144 | 155 | } |
145 | 156 |
|
146 | | - $iterator = array_reduce($this->where, [$this, 'filter'], $csv->getRecords($header)); |
| 157 | + $iterator = $this->combineHeader($records, $header); |
| 158 | + $iterator = array_reduce($this->where, [$this, 'filter'], $iterator); |
147 | 159 | $iterator = $this->buildOrderBy($iterator); |
148 | 160 |
|
149 | 161 | return new ResultSet(new LimitIterator($iterator, $this->offset, $this->limit), $header); |
150 | 162 | } |
151 | 163 |
|
| 164 | + /** |
| 165 | + * Combine the CSV header to each record if present. |
| 166 | + * |
| 167 | + * @param Reader|ResultSet $iterator |
| 168 | + * @param string[] $header |
| 169 | + */ |
| 170 | + protected function combineHeader($iterator, array $header): Iterator |
| 171 | + { |
| 172 | + if ($iterator instanceof Reader) { |
| 173 | + return $iterator->getRecords($header); |
| 174 | + } |
| 175 | + |
| 176 | + if ($header === $iterator->getHeader()) { |
| 177 | + return $iterator->getRecords(); |
| 178 | + } |
| 179 | + |
| 180 | + $field_count = count($header); |
| 181 | + $mapper = static function (array $record) use ($header, $field_count): array { |
| 182 | + if (count($record) != $field_count) { |
| 183 | + $record = array_slice(array_pad($record, $field_count, null), 0, $field_count); |
| 184 | + } |
| 185 | + |
| 186 | + /** @var array<string|null> $assocRecord */ |
| 187 | + $assocRecord = array_combine($header, $record); |
| 188 | + |
| 189 | + return $assocRecord; |
| 190 | + }; |
| 191 | + |
| 192 | + return new MapIterator($iterator, $mapper); |
| 193 | + } |
| 194 | + |
152 | 195 | /** |
153 | 196 | * Filters elements of an Iterator using a callback function. |
154 | 197 | */ |
@@ -176,9 +219,12 @@ protected function buildOrderBy(Iterator $iterator): Iterator |
176 | 219 | return $cmp ?? 0; |
177 | 220 | }; |
178 | 221 |
|
179 | | - $iterator = new ArrayIterator(iterator_to_array($iterator)); |
180 | | - $iterator->uasort($compare); |
| 222 | + $it = new ArrayIterator(); |
| 223 | + foreach ($iterator as $offset => $value) { |
| 224 | + $it[$offset] = $value; |
| 225 | + } |
| 226 | + $it->uasort($compare); |
181 | 227 |
|
182 | | - return $iterator; |
| 228 | + return $it; |
183 | 229 | } |
184 | 230 | } |
0 commit comments