* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Sonata\Exporter\Writer; /** * Generate a Xml Excel file. * * @author Vincent Touzet */ final class XmlExcelWriter implements WriterInterface { /** * @var string */ private $filename; /** * @var resource|null */ private $file; /** * @var bool */ private $showHeaders; /** * @var mixed|null */ private $columnsType; /** * @var int */ private $position = 0; /** * @var string */ private $header = ''; private $footer = '
'; /** * @param mixed $columnsType Define cells type to use * If string: force all cells to the given type. e.g: 'Number' * If array: force only given cells. e.g: array('ean'=>'String', 'price'=>'Number') * If null: will guess the type. 'Number' if value is numeric, 'String' otherwise * * @throws \RuntimeException */ public function __construct(string $filename, bool $showHeaders = true, $columnsType = null) { $this->filename = $filename; $this->showHeaders = $showHeaders; $this->columnsType = $columnsType; if (is_file($filename)) { throw new \RuntimeException(sprintf('The file %s already exist', $filename)); } } public function open(): void { $this->file = fopen($this->filename, 'w'); fwrite($this->file, $this->header); } public function write(array $data): void { if (0 === $this->position && $this->showHeaders) { $header = array_keys($data); fwrite($this->file, $this->getXmlString($header)); ++$this->position; } fwrite($this->file, $this->getXmlString($data)); ++$this->position; } public function close(): void { fwrite($this->file, $this->footer); fclose($this->file); } /** * Prepare and return XML string for MS Excel XML from array. */ private function getXmlString(array $fields = []): string { $xmlData = []; $xmlData[] = ''; foreach ($fields as $key => $value) { $value = htmlspecialchars($value); $value = str_replace(["\r\n", "\r", "\n"], ' ', $value); $dataType = 'String'; if (0 !== $this->position || !$this->showHeaders) { $dataType = $this->getDataType((string) $key, $value); } $xmlData[] = ''.$value.''; } $xmlData[] = ''; return implode('', $xmlData); } private function getDataType(string $key, string $value): string { $dataType = null; if (null !== $this->columnsType) { if (\is_string($this->columnsType)) { $dataType = $this->columnsType; } elseif (\is_array($this->columnsType)) { if (\array_key_exists($key, $this->columnsType)) { $dataType = $this->columnsType[$key]; } } } if (null === $dataType) { // guess the type if (is_numeric($value)) { $dataType = 'Number'; } else { $dataType = 'String'; } } return $dataType; } }