165 lines
4.4 KiB
PHP
165 lines
4.4 KiB
PHP
<?php
|
|
namespace nur\sery\ext\spreadsheet;
|
|
|
|
use nur\sery\file\csv\AbstractBuilder;
|
|
use nur\sery\file\csv\TAbstractBuilder;
|
|
use nur\sery\os\path;
|
|
use nur\sery\php\time\Date;
|
|
use nur\sery\php\time\DateTime;
|
|
use nur\sery\web\http;
|
|
use OpenSpout\Common\Entity\Cell;
|
|
use OpenSpout\Common\Entity\Style\Style;
|
|
use OpenSpout\Common\Helper\CellTypeHelper;
|
|
use OpenSpout\Writer\Common\Creator\WriterEntityFactory;
|
|
use OpenSpout\Writer\WriterMultiSheetsAbstract;
|
|
use OpenSpout\Writer\XLSX\Entity\SheetView;
|
|
|
|
class SpoutBuilder extends AbstractBuilder {
|
|
use TAbstractBuilder;
|
|
|
|
const DATE_FORMAT = "mm/dd/yyyy";
|
|
|
|
const DATETIME_FORMAT = "mm/dd/yyyy hh:mm:ss";
|
|
|
|
/** @var string|int|null nom de la feuille dans laquelle écrire */
|
|
const WSNAME = null;
|
|
|
|
function __construct(?string $output, ?array $params=null) {
|
|
parent::__construct($output, $params);
|
|
$ssType = $params["ss_type"] ?? null;
|
|
if ($ssType === null) {
|
|
switch (path::ext($this->output)) {
|
|
case ".ods":
|
|
$ssType = "ods";
|
|
break;
|
|
case ".xlsx":
|
|
default:
|
|
$ssType = "xlsx";
|
|
break;
|
|
}
|
|
}
|
|
switch ($ssType) {
|
|
case "ods":
|
|
$ss = WriterEntityFactory::createODSWriter();
|
|
break;
|
|
case "xlsx":
|
|
default:
|
|
$ss = WriterEntityFactory::createXLSXWriter();
|
|
break;
|
|
}
|
|
$ss->setDefaultColumnWidth(10.5);
|
|
$ss->writeToStream($this->getResource());
|
|
$this->ss = $ss;
|
|
$this->parseNumeric = boolval($params["parse_numeric"] ?? false);
|
|
$this->parseDate = boolval($params["parse_date"] ?? true);
|
|
$this->firstSheet = true;
|
|
$this->setWsname($params["wsname"] ?? static::WSNAME);
|
|
}
|
|
|
|
protected WriterMultiSheetsAbstract $ss;
|
|
|
|
protected bool $parseNumeric;
|
|
|
|
protected bool $parseDate;
|
|
|
|
const STYLE_ROW = 0, STYLE_HEADER = 1;
|
|
|
|
protected int $rowStyle;
|
|
|
|
protected bool $firstSheet;
|
|
|
|
/**
|
|
* @param string|int|null $wsname
|
|
*/
|
|
function setWsname($wsname): self {
|
|
$ss = $this->ss;
|
|
$this->rowStyle = self::STYLE_ROW;
|
|
if ($this->firstSheet) {
|
|
$this->firstSheet = false;
|
|
$ws = $ss->getCurrentSheet();
|
|
} else {
|
|
$ws = $ss->addNewSheetAndMakeItCurrent();
|
|
}
|
|
if ($wsname !== null) $ws->setName($wsname);
|
|
$ws->setSheetView((new SheetView())
|
|
->setFreezeRow(2)
|
|
);
|
|
return $this;
|
|
}
|
|
|
|
protected function isNumeric($value): bool {
|
|
if ($this->parseNumeric && is_numeric($value)) return true;
|
|
if (!is_string($value) && is_numeric($value)) return true;
|
|
return false;
|
|
}
|
|
|
|
protected function isDate(&$value, &$style): bool {
|
|
if (CellTypeHelper::isDateTimeOrDateInterval($value)) {
|
|
$style = (new Style())->setFormat(self::DATE_FORMAT);
|
|
return true;
|
|
}
|
|
if (!is_string($value)) return false;
|
|
if (DateTime::isa_datetime($value, true)) {
|
|
$value = new DateTime($value);
|
|
$style = (new Style())->setFormat(self::DATETIME_FORMAT);
|
|
return true;
|
|
}
|
|
if (DateTime::isa_date($value, true)) {
|
|
$value = new Date($value);
|
|
$style = (new Style())->setFormat(self::DATE_FORMAT);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function _write(array $row): void {
|
|
$cells = [];
|
|
$rowStyle = null;
|
|
foreach ($row as $col) {
|
|
$style = null;
|
|
if ($col === null || $col === "") {
|
|
$type = Cell::TYPE_EMPTY;
|
|
} elseif ($this->isNumeric($col)) {
|
|
$type = Cell::TYPE_NUMERIC;
|
|
} elseif ($this->isDate($col, $style)) {
|
|
$type = Cell::TYPE_DATE;
|
|
} else {
|
|
$type = Cell::TYPE_STRING;
|
|
}
|
|
$cell = WriterEntityFactory::createCell($col, $style);
|
|
$cell->setType($type);
|
|
$cells[] = $cell;
|
|
}
|
|
if ($this->rowStyle === self::STYLE_HEADER) {
|
|
$rowStyle = (new Style())->setFontBold();
|
|
}
|
|
$this->ss->addRow(WriterEntityFactory::createRow($cells, $rowStyle));
|
|
}
|
|
|
|
function writeHeaders(?array $headers=null): void {
|
|
$this->rowStyle = self::STYLE_HEADER;
|
|
parent::writeHeaders($headers);
|
|
$this->rowStyle = self::STYLE_ROW;
|
|
}
|
|
|
|
function _sendContentType(): void {
|
|
switch (path::ext($this->output)) {
|
|
case ".ods":
|
|
$contentType = "application/vnd.oasis.opendocument.spreadsheet";
|
|
break;
|
|
case ".xlsx":
|
|
default:
|
|
$contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
break;
|
|
}
|
|
http::content_type($contentType);
|
|
}
|
|
|
|
function _sendFile(): int {
|
|
$this->ss->close();
|
|
$this->rewind();
|
|
$this->sendHeaders();
|
|
return $this->fpassthru();
|
|
}
|
|
}
|