Mercurial > hg > isophonics-drupal-site
comparison vendor/symfony/serializer/Encoder/CsvEncoder.php @ 14:1fec387a4317
Update Drupal core to 8.5.2 via Composer
author | Chris Cannam |
---|---|
date | Mon, 23 Apr 2018 09:46:53 +0100 |
parents | 4c8ae668cc8c |
children | 129ea1e6d783 |
comparison
equal
deleted
inserted
replaced
13:5fb285c0d0e3 | 14:1fec387a4317 |
---|---|
15 | 15 |
16 /** | 16 /** |
17 * Encodes CSV data. | 17 * Encodes CSV data. |
18 * | 18 * |
19 * @author Kévin Dunglas <dunglas@gmail.com> | 19 * @author Kévin Dunglas <dunglas@gmail.com> |
20 * @author Oliver Hoff <oliver@hofff.com> | |
20 */ | 21 */ |
21 class CsvEncoder implements EncoderInterface, DecoderInterface | 22 class CsvEncoder implements EncoderInterface, DecoderInterface |
22 { | 23 { |
23 const FORMAT = 'csv'; | 24 const FORMAT = 'csv'; |
25 const DELIMITER_KEY = 'csv_delimiter'; | |
26 const ENCLOSURE_KEY = 'csv_enclosure'; | |
27 const ESCAPE_CHAR_KEY = 'csv_escape_char'; | |
28 const KEY_SEPARATOR_KEY = 'csv_key_separator'; | |
29 const HEADERS_KEY = 'csv_headers'; | |
24 | 30 |
25 private $delimiter; | 31 private $delimiter; |
26 private $enclosure; | 32 private $enclosure; |
27 private $escapeChar; | 33 private $escapeChar; |
28 private $keySeparator; | 34 private $keySeparator; |
63 | 69 |
64 ++$i; | 70 ++$i; |
65 } | 71 } |
66 } | 72 } |
67 | 73 |
68 $headers = null; | 74 list($delimiter, $enclosure, $escapeChar, $keySeparator, $headers) = $this->getCsvOptions($context); |
69 foreach ($data as $value) { | 75 |
70 $result = array(); | 76 foreach ($data as &$value) { |
71 $this->flatten($value, $result); | 77 $flattened = array(); |
72 | 78 $this->flatten($value, $flattened, $keySeparator); |
73 if (null === $headers) { | 79 $value = $flattened; |
74 $headers = array_keys($result); | 80 } |
75 fputcsv($handle, $headers, $this->delimiter, $this->enclosure, $this->escapeChar); | 81 unset($value); |
76 } elseif (array_keys($result) !== $headers) { | 82 |
77 throw new InvalidArgumentException('To use the CSV encoder, each line in the data array must have the same structure. You may want to use a custom normalizer class to normalize the data format before passing it to the CSV encoder.'); | 83 $headers = array_merge(array_values($headers), array_diff($this->extractHeaders($data), $headers)); |
78 } | 84 |
79 | 85 fputcsv($handle, $headers, $delimiter, $enclosure, $escapeChar); |
80 fputcsv($handle, $result, $this->delimiter, $this->enclosure, $this->escapeChar); | 86 |
87 $headers = array_fill_keys($headers, ''); | |
88 foreach ($data as $row) { | |
89 fputcsv($handle, array_replace($headers, $row), $delimiter, $enclosure, $escapeChar); | |
81 } | 90 } |
82 | 91 |
83 rewind($handle); | 92 rewind($handle); |
84 $value = stream_get_contents($handle); | 93 $value = stream_get_contents($handle); |
85 fclose($handle); | 94 fclose($handle); |
104 fwrite($handle, $data); | 113 fwrite($handle, $data); |
105 rewind($handle); | 114 rewind($handle); |
106 | 115 |
107 $headers = null; | 116 $headers = null; |
108 $nbHeaders = 0; | 117 $nbHeaders = 0; |
118 $headerCount = array(); | |
109 $result = array(); | 119 $result = array(); |
110 | 120 |
111 while (false !== ($cols = fgetcsv($handle, 0, $this->delimiter, $this->enclosure, $this->escapeChar))) { | 121 list($delimiter, $enclosure, $escapeChar, $keySeparator) = $this->getCsvOptions($context); |
122 | |
123 while (false !== ($cols = fgetcsv($handle, 0, $delimiter, $enclosure, $escapeChar))) { | |
112 $nbCols = count($cols); | 124 $nbCols = count($cols); |
113 | 125 |
114 if (null === $headers) { | 126 if (null === $headers) { |
115 $nbHeaders = $nbCols; | 127 $nbHeaders = $nbCols; |
116 | 128 |
117 foreach ($cols as $col) { | 129 foreach ($cols as $col) { |
118 $headers[] = explode($this->keySeparator, $col); | 130 $header = explode($keySeparator, $col); |
131 $headers[] = $header; | |
132 $headerCount[] = count($header); | |
119 } | 133 } |
120 | 134 |
121 continue; | 135 continue; |
122 } | 136 } |
123 | 137 |
124 $item = array(); | 138 $item = array(); |
125 for ($i = 0; ($i < $nbCols) && ($i < $nbHeaders); ++$i) { | 139 for ($i = 0; ($i < $nbCols) && ($i < $nbHeaders); ++$i) { |
126 $depth = count($headers[$i]); | 140 $depth = $headerCount[$i]; |
127 $arr = &$item; | 141 $arr = &$item; |
128 for ($j = 0; $j < $depth; ++$j) { | 142 for ($j = 0; $j < $depth; ++$j) { |
129 // Handle nested arrays | 143 // Handle nested arrays |
130 if ($j === ($depth - 1)) { | 144 if ($j === ($depth - 1)) { |
131 $arr[$headers[$i][$j]] = $cols[$i]; | 145 $arr[$headers[$i][$j]] = $cols[$i]; |
164 /** | 178 /** |
165 * Flattens an array and generates keys including the path. | 179 * Flattens an array and generates keys including the path. |
166 * | 180 * |
167 * @param array $array | 181 * @param array $array |
168 * @param array $result | 182 * @param array $result |
183 * @param string $keySeparator | |
169 * @param string $parentKey | 184 * @param string $parentKey |
170 */ | 185 */ |
171 private function flatten(array $array, array &$result, $parentKey = '') | 186 private function flatten(array $array, array &$result, $keySeparator, $parentKey = '') |
172 { | 187 { |
173 foreach ($array as $key => $value) { | 188 foreach ($array as $key => $value) { |
174 if (is_array($value)) { | 189 if (is_array($value)) { |
175 $this->flatten($value, $result, $parentKey.$key.$this->keySeparator); | 190 $this->flatten($value, $result, $keySeparator, $parentKey.$key.$keySeparator); |
176 } else { | 191 } else { |
177 $result[$parentKey.$key] = $value; | 192 $result[$parentKey.$key] = $value; |
178 } | 193 } |
179 } | 194 } |
180 } | 195 } |
196 | |
197 private function getCsvOptions(array $context) | |
198 { | |
199 $delimiter = isset($context[self::DELIMITER_KEY]) ? $context[self::DELIMITER_KEY] : $this->delimiter; | |
200 $enclosure = isset($context[self::ENCLOSURE_KEY]) ? $context[self::ENCLOSURE_KEY] : $this->enclosure; | |
201 $escapeChar = isset($context[self::ESCAPE_CHAR_KEY]) ? $context[self::ESCAPE_CHAR_KEY] : $this->escapeChar; | |
202 $keySeparator = isset($context[self::KEY_SEPARATOR_KEY]) ? $context[self::KEY_SEPARATOR_KEY] : $this->keySeparator; | |
203 $headers = isset($context[self::HEADERS_KEY]) ? $context[self::HEADERS_KEY] : array(); | |
204 | |
205 if (!is_array($headers)) { | |
206 throw new InvalidArgumentException(sprintf('The "%s" context variable must be an array or null, given "%s".', self::HEADERS_KEY, gettype($headers))); | |
207 } | |
208 | |
209 return array($delimiter, $enclosure, $escapeChar, $keySeparator, $headers); | |
210 } | |
211 | |
212 /** | |
213 * @return string[] | |
214 */ | |
215 private function extractHeaders(array $data) | |
216 { | |
217 $headers = array(); | |
218 $flippedHeaders = array(); | |
219 | |
220 foreach ($data as $row) { | |
221 $previousHeader = null; | |
222 | |
223 foreach ($row as $header => $_) { | |
224 if (isset($flippedHeaders[$header])) { | |
225 $previousHeader = $header; | |
226 continue; | |
227 } | |
228 | |
229 if (null === $previousHeader) { | |
230 $n = count($headers); | |
231 } else { | |
232 $n = $flippedHeaders[$previousHeader] + 1; | |
233 | |
234 for ($j = count($headers); $j > $n; --$j) { | |
235 ++$flippedHeaders[$headers[$j] = $headers[$j - 1]]; | |
236 } | |
237 } | |
238 | |
239 $headers[$n] = $header; | |
240 $flippedHeaders[$header] = $n; | |
241 $previousHeader = $header; | |
242 } | |
243 } | |
244 | |
245 return $headers; | |
246 } | |
181 } | 247 } |