ajout SsReader et CsvReader
This commit is contained in:
parent
291b478d93
commit
6bffe89904
|
@ -1,10 +1,31 @@
|
|||
<?php
|
||||
namespace nur\sery\ext\spreadsheet;
|
||||
|
||||
use nur\sery\ValueException;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
|
||||
class wsutils {
|
||||
static function get_ws(?string $wsname, Spreadsheet $ss, bool $create=false): ?Worksheet {
|
||||
if ($wsname == null) {
|
||||
$ws = $ss->getActiveSheet();
|
||||
} elseif (is_numeric($wsname)) {
|
||||
$sheetCount = $ss->getSheetCount();
|
||||
if ($wsname < 1 || $wsname > $sheetCount) {
|
||||
throw ValueException::invalid_value($wsname, "sheet index");
|
||||
}
|
||||
$ws = $ss->getSheet($wsname - 1);
|
||||
} else {
|
||||
$ws = $ss->getSheetByName($wsname);
|
||||
if ($ws === null) {
|
||||
if ($create) $ws = $ss->createSheet()->setTitle($wsname);
|
||||
else throw ValueException::invalid_value($wsname, "sheet name");
|
||||
}
|
||||
}
|
||||
return $ws;
|
||||
}
|
||||
|
||||
static function get_highest_coords(Worksheet $ws): array {
|
||||
$highestColumnA = $ws->getHighestColumn();
|
||||
$highestCol = Coordinate::columnIndexFromString($highestColumnA);
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
namespace nur\sery\file\csv;
|
||||
|
||||
use IteratorAggregate;
|
||||
|
||||
abstract class AbstractReader implements IReader {
|
||||
const SCHEMA = null;
|
||||
|
||||
const HEADERS = null;
|
||||
|
||||
/** @var ?string nom du fichier depuis lequel lire */
|
||||
const INPUT = null;
|
||||
|
||||
function __construct($input, ?array $params=null) {
|
||||
if ($input !== null) $params["input"] = $input;
|
||||
#
|
||||
$this->schema = $params["schema"] ?? static::SCHEMA;
|
||||
$this->headers = $params["headers"] ?? static::HEADERS;
|
||||
$this->input = $params["input"] ?? static::INPUT;
|
||||
}
|
||||
|
||||
protected ?array $schema;
|
||||
|
||||
protected ?array $headers;
|
||||
|
||||
protected $input;
|
||||
|
||||
protected int $isrc = 0, $idest = 0;
|
||||
|
||||
protected function cook(array &$row): bool {
|
||||
if ($this->isrc == 0) {
|
||||
# ligne d'en-tête
|
||||
$headers = $this->headers;
|
||||
if ($headers === null) {
|
||||
if ($this->schema === null) $headers = null;
|
||||
else $headers = array_keys($this->schema);
|
||||
if ($headers === null) $headers = $row;
|
||||
$this->headers = $headers;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$row = array_combine($this->headers, $row);
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
namespace nur\sery\file\csv;
|
||||
|
||||
use nur\sery\file\FileReader;
|
||||
use nur\sery\php\time\Date;
|
||||
use nur\sery\php\time\DateTime;
|
||||
|
||||
class CsvReader extends AbstractReader {
|
||||
function getIterator() {
|
||||
$reader = new FileReader($this->input);
|
||||
while (($row = $reader->fgetcsv()) !== null) {
|
||||
foreach ($row as &$col) {
|
||||
# conversion Date et DateTime
|
||||
if (DateTime::isa_datetime($col, true)) {
|
||||
$col = new DateTime($col);
|
||||
} elseif (DateTime::isa_date($col, true)) {
|
||||
$col = new Date($col);
|
||||
}
|
||||
}; unset($col);
|
||||
|
||||
if ($this->cook($row)) {
|
||||
yield $row;
|
||||
$this->idest++;
|
||||
}
|
||||
$this->isrc++;
|
||||
}
|
||||
$reader->close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
namespace nur\sery\file\csv;
|
||||
|
||||
use IteratorAggregate;
|
||||
|
||||
interface IReader extends IteratorAggregate {
|
||||
}
|
|
@ -3,6 +3,7 @@ namespace nur\sery\file\csv;
|
|||
|
||||
use nur\sery\ext\spreadsheet\wsutils;
|
||||
use nur\sery\os\path;
|
||||
use nur\sery\ValueException;
|
||||
use nur\sery\web\http;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\IValueBinder;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\StringValueBinder;
|
||||
|
@ -19,11 +20,14 @@ use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
|||
class SsBuilder extends AbstractBuilder {
|
||||
use TAbstractBuilder;
|
||||
|
||||
/** @var ?string nom de la feuille dans laquelle écrire */
|
||||
const WSNAME = null;
|
||||
|
||||
function __construct(?string $output, ?array $params=null) {
|
||||
parent::__construct($output, $params);
|
||||
$this->ss = new Spreadsheet();
|
||||
$this->valueBinder = new StringValueBinder();
|
||||
$this->setWsname($params["wsname"] ?? null);
|
||||
$this->setWsname($params["wsname"] ?? static::WSNAME);
|
||||
}
|
||||
|
||||
protected Spreadsheet $ss;
|
||||
|
@ -45,6 +49,12 @@ class SsBuilder extends AbstractBuilder {
|
|||
$this->rowStyle = self::STYLE_ROW;
|
||||
if ($wsname === null) {
|
||||
$ws = $ss->getActiveSheet();
|
||||
} elseif (is_numeric($wsname)) {
|
||||
$sheetCount = $ss->getSheetCount();
|
||||
if ($wsname < 1 || $wsname > $sheetCount) {
|
||||
throw ValueException::invalid_value($wsname, "sheet index");
|
||||
}
|
||||
$ws = $ss->getSheet($wsname - 1);
|
||||
} else {
|
||||
$ws = $ss->getSheetByName($wsname);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
namespace nur\sery\file\csv;
|
||||
|
||||
use nur\sery\cl;
|
||||
use nur\sery\ext\spreadsheet\wsutils;
|
||||
use nur\sery\file\web\Upload;
|
||||
use nur\sery\php\time\Date;
|
||||
use nur\sery\php\time\DateTime;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\DataType;
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
use PhpOffice\PhpSpreadsheet\RichText\RichText;
|
||||
|
||||
class SsReader extends AbstractReader {
|
||||
static function with(Upload $upload): IReader {
|
||||
if ($upload->isExt(".csv")) {
|
||||
return new CsvReader($upload->tmpName);
|
||||
} else {
|
||||
return new static($upload->tmpName);
|
||||
}
|
||||
}
|
||||
|
||||
const DATETIME_FORMAT = 'dd/mm/yyyy hh:mm:ss';
|
||||
const DATE_FORMAT = 'dd/mm/yyyy';
|
||||
const TIME_FORMAT = 'hh:mm:ss';
|
||||
const FORMAT_MAPPINGS = [
|
||||
'mm/dd hh' => self::DATETIME_FORMAT,
|
||||
'dd/mm hh' => self::DATETIME_FORMAT,
|
||||
'mm/dd hh:mm' => self::DATETIME_FORMAT,
|
||||
'dd/mm hh:mm' => self::DATETIME_FORMAT,
|
||||
'mm/dd hh:mm:ss' => self::DATETIME_FORMAT,
|
||||
'dd/mm hh:mm:ss' => self::DATETIME_FORMAT,
|
||||
'mm/dd/yyyy hh' => self::DATETIME_FORMAT,
|
||||
'dd/mm/yyyy hh' => self::DATETIME_FORMAT,
|
||||
'mm/dd/yyyy hh:mm' => self::DATETIME_FORMAT,
|
||||
'dd/mm/yyyy hh:mm' => self::DATETIME_FORMAT,
|
||||
'mm/dd/yyyy hh:mm:ss' => self::DATETIME_FORMAT,
|
||||
'dd/mm/yyyy hh:mm:ss' => self::DATETIME_FORMAT,
|
||||
'yyyy/mm/dd hh' => self::DATETIME_FORMAT,
|
||||
'yyyy/mm/dd hh:mm' => self::DATETIME_FORMAT,
|
||||
'yyyy/mm/dd hh:mm:ss' => self::DATETIME_FORMAT,
|
||||
|
||||
'mm/dd' => self::DATE_FORMAT,
|
||||
'dd/mm' => self::DATE_FORMAT,
|
||||
'mm/dd/yyyy' => self::DATE_FORMAT,
|
||||
'dd/mm/yyyy' => self::DATE_FORMAT,
|
||||
'yyyy/mm/dd' => self::DATE_FORMAT,
|
||||
'mm/yyyy' => self::DATE_FORMAT,
|
||||
|
||||
'hh AM/PM' => self::TIME_FORMAT,
|
||||
'hh:mm AM/PM' => self::TIME_FORMAT,
|
||||
'hh:mm:ss AM/PM' => self::TIME_FORMAT,
|
||||
'hh' => self::TIME_FORMAT,
|
||||
'hh:mm' => self::TIME_FORMAT,
|
||||
'hh:mm:ss' => self::TIME_FORMAT,
|
||||
'[hh]:mm:ss' => self::TIME_FORMAT,
|
||||
'mm:ss' => self::TIME_FORMAT,
|
||||
];
|
||||
|
||||
/** @var ?string nom de la feuille depuis laquelle lire */
|
||||
const WSNAME = null;
|
||||
|
||||
function __construct($input, ?array $params=null) {
|
||||
parent::__construct($input, $params);
|
||||
$this->wsname = $params["wsname"] ?? static::WSNAME;
|
||||
}
|
||||
|
||||
protected ?string $wsname;
|
||||
|
||||
function getIterator() {
|
||||
$ss = IOFactory::load($this->input);
|
||||
$ws = wsutils::get_ws($this->wsname, $ss);
|
||||
|
||||
[$nbCols, $nbRows] = wsutils::compute_max_coords($ws);
|
||||
$this->isrc = $this->idest = 0;
|
||||
for ($nrow = 1; $nrow <= $nbRows; $nrow++) {
|
||||
$row = [];
|
||||
for ($ncol = 1; $ncol <= $nbCols; $ncol++) {
|
||||
if ($ws->cellExistsByColumnAndRow($ncol, $nrow)) {
|
||||
$cell = $ws->getCellByColumnAndRow($ncol, $nrow);
|
||||
$value = $cell->getValue();
|
||||
if ($value instanceof RichText) {
|
||||
$value = $value->getPlainText();
|
||||
} else {
|
||||
$dataType = $cell->getDataType();
|
||||
if ($dataType == DataType::TYPE_NUMERIC || $dataType == DataType::TYPE_FORMULA) {
|
||||
# si c'est un format date, le forcer à une valeur standard
|
||||
$origFormatCode = $cell->getStyle()->getNumberFormat()->getFormatCode();
|
||||
if (strpbrk($origFormatCode, "ymdhs") !== false) {
|
||||
$formatCode = $origFormatCode;
|
||||
$formatCode = preg_replace('/y+/', "yyyy", $formatCode);
|
||||
$formatCode = preg_replace('/m+/', "mm", $formatCode);
|
||||
$formatCode = preg_replace('/d+/', "dd", $formatCode);
|
||||
$formatCode = preg_replace('/h+/', "hh", $formatCode);
|
||||
$formatCode = preg_replace('/s+/', "ss", $formatCode);
|
||||
$formatCode = preg_replace('/-+/', "/", $formatCode);
|
||||
$formatCode = preg_replace('/\\\\ /', " ", $formatCode);
|
||||
$formatCode = preg_replace('/;@$/', "", $formatCode);
|
||||
$formatCode = cl::get(self::FORMAT_MAPPINGS, $formatCode, $formatCode);
|
||||
if ($formatCode !== $origFormatCode) {
|
||||
$cell->getStyle()->getNumberFormat()->setFormatCode($formatCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
$value = $cell->getFormattedValue();
|
||||
# conversion Date et DateTime
|
||||
if (DateTime::isa_datetime($value, true)) {
|
||||
$value = new DateTime($value);
|
||||
} elseif (DateTime::isa_date($value, true)) {
|
||||
$value = new Date($value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$value = null;
|
||||
}
|
||||
$row[] = $value;
|
||||
}
|
||||
if ($this->cook($row)) {
|
||||
yield $row;
|
||||
$this->idest++;
|
||||
}
|
||||
$this->isrc++;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue