annotate vendor/symfony/serializer/Encoder/CsvEncoder.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 1fec387a4317
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\Serializer\Encoder;
Chris@0 13
Chris@0 14 use Symfony\Component\Serializer\Exception\InvalidArgumentException;
Chris@0 15
Chris@0 16 /**
Chris@0 17 * Encodes CSV data.
Chris@0 18 *
Chris@0 19 * @author Kévin Dunglas <dunglas@gmail.com>
Chris@0 20 */
Chris@0 21 class CsvEncoder implements EncoderInterface, DecoderInterface
Chris@0 22 {
Chris@0 23 const FORMAT = 'csv';
Chris@0 24
Chris@0 25 private $delimiter;
Chris@0 26 private $enclosure;
Chris@0 27 private $escapeChar;
Chris@0 28 private $keySeparator;
Chris@0 29
Chris@0 30 /**
Chris@0 31 * @param string $delimiter
Chris@0 32 * @param string $enclosure
Chris@0 33 * @param string $escapeChar
Chris@0 34 * @param string $keySeparator
Chris@0 35 */
Chris@0 36 public function __construct($delimiter = ',', $enclosure = '"', $escapeChar = '\\', $keySeparator = '.')
Chris@0 37 {
Chris@0 38 $this->delimiter = $delimiter;
Chris@0 39 $this->enclosure = $enclosure;
Chris@0 40 $this->escapeChar = $escapeChar;
Chris@0 41 $this->keySeparator = $keySeparator;
Chris@0 42 }
Chris@0 43
Chris@0 44 /**
Chris@0 45 * {@inheritdoc}
Chris@0 46 */
Chris@0 47 public function encode($data, $format, array $context = array())
Chris@0 48 {
Chris@0 49 $handle = fopen('php://temp,', 'w+');
Chris@0 50
Chris@0 51 if (!is_array($data)) {
Chris@0 52 $data = array(array($data));
Chris@0 53 } elseif (empty($data)) {
Chris@0 54 $data = array(array());
Chris@0 55 } else {
Chris@0 56 // Sequential arrays of arrays are considered as collections
Chris@0 57 $i = 0;
Chris@0 58 foreach ($data as $key => $value) {
Chris@0 59 if ($i !== $key || !is_array($value)) {
Chris@0 60 $data = array($data);
Chris@0 61 break;
Chris@0 62 }
Chris@0 63
Chris@0 64 ++$i;
Chris@0 65 }
Chris@0 66 }
Chris@0 67
Chris@0 68 $headers = null;
Chris@0 69 foreach ($data as $value) {
Chris@0 70 $result = array();
Chris@0 71 $this->flatten($value, $result);
Chris@0 72
Chris@0 73 if (null === $headers) {
Chris@0 74 $headers = array_keys($result);
Chris@0 75 fputcsv($handle, $headers, $this->delimiter, $this->enclosure, $this->escapeChar);
Chris@0 76 } elseif (array_keys($result) !== $headers) {
Chris@0 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.');
Chris@0 78 }
Chris@0 79
Chris@0 80 fputcsv($handle, $result, $this->delimiter, $this->enclosure, $this->escapeChar);
Chris@0 81 }
Chris@0 82
Chris@0 83 rewind($handle);
Chris@0 84 $value = stream_get_contents($handle);
Chris@0 85 fclose($handle);
Chris@0 86
Chris@0 87 return $value;
Chris@0 88 }
Chris@0 89
Chris@0 90 /**
Chris@0 91 * {@inheritdoc}
Chris@0 92 */
Chris@0 93 public function supportsEncoding($format)
Chris@0 94 {
Chris@0 95 return self::FORMAT === $format;
Chris@0 96 }
Chris@0 97
Chris@0 98 /**
Chris@0 99 * {@inheritdoc}
Chris@0 100 */
Chris@0 101 public function decode($data, $format, array $context = array())
Chris@0 102 {
Chris@0 103 $handle = fopen('php://temp', 'r+');
Chris@0 104 fwrite($handle, $data);
Chris@0 105 rewind($handle);
Chris@0 106
Chris@0 107 $headers = null;
Chris@0 108 $nbHeaders = 0;
Chris@0 109 $result = array();
Chris@0 110
Chris@0 111 while (false !== ($cols = fgetcsv($handle, 0, $this->delimiter, $this->enclosure, $this->escapeChar))) {
Chris@0 112 $nbCols = count($cols);
Chris@0 113
Chris@0 114 if (null === $headers) {
Chris@0 115 $nbHeaders = $nbCols;
Chris@0 116
Chris@0 117 foreach ($cols as $col) {
Chris@0 118 $headers[] = explode($this->keySeparator, $col);
Chris@0 119 }
Chris@0 120
Chris@0 121 continue;
Chris@0 122 }
Chris@0 123
Chris@0 124 $item = array();
Chris@0 125 for ($i = 0; ($i < $nbCols) && ($i < $nbHeaders); ++$i) {
Chris@0 126 $depth = count($headers[$i]);
Chris@0 127 $arr = &$item;
Chris@0 128 for ($j = 0; $j < $depth; ++$j) {
Chris@0 129 // Handle nested arrays
Chris@0 130 if ($j === ($depth - 1)) {
Chris@0 131 $arr[$headers[$i][$j]] = $cols[$i];
Chris@0 132
Chris@0 133 continue;
Chris@0 134 }
Chris@0 135
Chris@0 136 if (!isset($arr[$headers[$i][$j]])) {
Chris@0 137 $arr[$headers[$i][$j]] = array();
Chris@0 138 }
Chris@0 139
Chris@0 140 $arr = &$arr[$headers[$i][$j]];
Chris@0 141 }
Chris@0 142 }
Chris@0 143
Chris@0 144 $result[] = $item;
Chris@0 145 }
Chris@0 146 fclose($handle);
Chris@0 147
Chris@0 148 if (empty($result) || isset($result[1])) {
Chris@0 149 return $result;
Chris@0 150 }
Chris@0 151
Chris@0 152 // If there is only one data line in the document, return it (the line), the result is not considered as a collection
Chris@0 153 return $result[0];
Chris@0 154 }
Chris@0 155
Chris@0 156 /**
Chris@0 157 * {@inheritdoc}
Chris@0 158 */
Chris@0 159 public function supportsDecoding($format)
Chris@0 160 {
Chris@0 161 return self::FORMAT === $format;
Chris@0 162 }
Chris@0 163
Chris@0 164 /**
Chris@0 165 * Flattens an array and generates keys including the path.
Chris@0 166 *
Chris@0 167 * @param array $array
Chris@0 168 * @param array $result
Chris@0 169 * @param string $parentKey
Chris@0 170 */
Chris@0 171 private function flatten(array $array, array &$result, $parentKey = '')
Chris@0 172 {
Chris@0 173 foreach ($array as $key => $value) {
Chris@0 174 if (is_array($value)) {
Chris@0 175 $this->flatten($value, $result, $parentKey.$key.$this->keySeparator);
Chris@0 176 } else {
Chris@0 177 $result[$parentKey.$key] = $value;
Chris@0 178 }
Chris@0 179 }
Chris@0 180 }
Chris@0 181 }