diff --git a/core/lib/Thelia/Core/FileFormat/Formatting/Formatter/CSVFormatter.php b/core/lib/Thelia/Core/FileFormat/Formatting/Formatter/CSVFormatter.php new file mode 100644 index 000000000..004cab8a0 --- /dev/null +++ b/core/lib/Thelia/Core/FileFormat/Formatting/Formatter/CSVFormatter.php @@ -0,0 +1,172 @@ + + */ +class CSVFormatter extends AbstractFormatter +{ + public $delimiter = ";"; + public $lineReturn = "\r\n"; + public $stringDelimiter = "\""; + + /** + * @return string + * + * This method must return a string, the name of the format. + * + * example: + * return "XML"; + */ + public function getName() + { + return "CSV"; + } + + /** + * @return string + * + * This method must return a string, the extension of the file format, without the ".". + * The string should be lowercase. + * + * example: + * return "xml"; + */ + public function getExtension() + { + return "csv"; + } + + /** + * @return string + * + * This method must return a string, the mime type of the file format. + * + * example: + * return "application/json"; + */ + public function getMimeType() + { + return "text/csv"; + } + + /** + * @param FormatterData $data + * @return mixed + * + * This method must use a FormatterData object and output + * a formatted value. + */ + public function encode(FormatterData $data) + { + $string = ""; + $firstRow = $data->getRow(); + $delimiterLength = strlen($this->delimiter); + $lineReturnLength = strlen($this->lineReturn); + + + if (false !== $firstRow) { + $rawKeys = array_keys($firstRow); + $keys = []; + + foreach ($rawKeys as $key) { + $keys[$key] = $key; + } + + $values = $data->getData(); + array_unshift($values, $keys); + + while (null !== $row = array_shift($values)) { + foreach ($keys as $key) { + if (!is_scalar($row[$key])) { + $row[$key] = serialize($row[$key]); + } + + $string .= $this->stringDelimiter . addslashes($row[$key]) . $this->stringDelimiter . $this->delimiter; + } + + $string = substr($string,0, -$delimiterLength) . $this->lineReturn; + } + + } + + return substr($string,0, -$lineReturnLength); + } + + /** + * @param $rawData + * @return FormatterData + * + * This must takes raw data as argument and outputs + * a FormatterData object. + */ + public function decode($rawData) + { + $raw = explode($this->lineReturn, $rawData); + $decoded = []; + + if (count($raw) > 0) { + $keys = explode($this->delimiter, array_shift($raw)); + + foreach ($keys as &$key) { + $key = trim($key, $this->stringDelimiter); + } + + $columns = count ($keys); + + while (null !== $row = array_shift($raw)) { + $newRow = []; + $row = explode($this->delimiter, $row); + + for ($i = 0; $i < $columns; ++$i) { + $value = trim($row[$i], $this->stringDelimiter); + + if (false !== $unserialized = @unserialize($row[$i])) { + $value = $unserialized; + } + + $newRow[$keys[$i]] = $value; + } + + $decoded[] = $newRow; + + } + } + + return (new FormatterData())->setData($decoded); + } + + /** + * @return string + * + * return a string that defines the handled format type. + * + * Thelia types are defined in \Thelia\Core\FileFormat\FormatType + * + * examples: + * return FormatType::TABLE; + * return FormatType::UNBOUNDED; + */ + public function getHandledType() + { + return FormatType::TABLE; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Tests/FileFormat/Formatting/Formatter/CSVFormatterTest.php b/core/lib/Thelia/Tests/FileFormat/Formatting/Formatter/CSVFormatterTest.php new file mode 100644 index 000000000..fd95c2f25 --- /dev/null +++ b/core/lib/Thelia/Tests/FileFormat/Formatting/Formatter/CSVFormatterTest.php @@ -0,0 +1,134 @@ + + */ +class CSVFormatterTest extends \PHPUnit_Framework_TestCase +{ + /** @var CSVFormatter */ + protected $formatter; + + public function setUp() + { + new Translator(new Container()); + + $this->formatter = new CSVFormatter(); + } + + public function testSimpleEncode() + { + $expected = "\"ref\";\"stock\"\r\n\"foo\";\"bar\""; + + $data = [ + [ + "ref" => "foo", + "stock" => "bar", + ], + ]; + + $data = (new FormatterData())->setData($data); + + $this->assertEquals( + $expected, + $this->formatter->encode($data) + ); + } + + public function testComplexEncode() + { + $this->formatter->lineReturn = "\n"; + $this->formatter->delimiter = ","; + $expected = "\"foo\",\"bar\",\"baz\"\n\"1\",\"2\",\"3\"\n\"4\",\"5\",\"6\"\n\"1\",\"2\",\"3\""; + + $data = [ + [ + "foo" => "1", + "bar" => "2", + "baz" => "3", + ], + [ + "foo" => "4", + "bar" => "5", + "baz" => "6", + ], + [ + "foo" => "1", + "bar" => "2", + "baz" => "3", + ], + ]; + + $data = (new FormatterData())->setData($data); + + $this->assertEquals( + $expected, + $this->formatter->encode($data) + ); + } + + public function testSimpleDecode() + { + $data = "\"ref\";\"stock\"\r\n\"foo\";\"bar\""; + + $expected = [ + [ + "ref" => "foo", + "stock" => "bar", + ], + ]; + + $this->assertEquals( + $expected, + $this->formatter->decode($data)->getData() + ); + } + + public function testComplexDecode() + { + $this->formatter->lineReturn = "\n"; + $this->formatter->delimiter = ","; + $data = "\"foo\",\"bar\",\"baz\"\n\"1\",\"2\",\"3\"\n\"4\",\"5\",\"6\"\n\"1\",\"2\",\"3\""; + + $expected = [ + [ + "foo" => "1", + "bar" => "2", + "baz" => "3", + ], + [ + "foo" => "4", + "bar" => "5", + "baz" => "6", + ], + [ + "foo" => "1", + "bar" => "2", + "baz" => "3", + ], + ]; + + $this->assertEquals( + $expected, + $this->formatter->decode($data)->getData() + ); + } + +} \ No newline at end of file