importation nulib/phpss:php74
This commit is contained in:
parent
bd9b0027f3
commit
ea95c9a5e6
0
.dockerignore
Normal file
0
.dockerignore
Normal file
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,2 +1,10 @@
|
||||
.~lock*#
|
||||
.*.swp
|
||||
/vendor/
|
||||
|
||||
/.idea/shelf/
|
||||
/.idea/workspace.xml
|
||||
/.idea/httpRequests/
|
||||
/.idea/dataSources/
|
||||
/.idea/dataSources.local.xml
|
||||
/.phpunit.result.cache
|
||||
|
17
.idea/misc.xml
generated
Normal file
17
.idea/misc.xml
generated
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectInspectionProfilesVisibleTreeState">
|
||||
<entry key="Project Default">
|
||||
<profile-state>
|
||||
<expanded-state>
|
||||
<State />
|
||||
</expanded-state>
|
||||
<selected-state>
|
||||
<State>
|
||||
<id>Angular</id>
|
||||
</State>
|
||||
</selected-state>
|
||||
</profile-state>
|
||||
</entry>
|
||||
</component>
|
||||
</project>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/nulib-phpss.iml" filepath="$PROJECT_DIR$/.idea/nulib-phpss.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
12
.idea/nulib-phpss.iml
generated
Normal file
12
.idea/nulib-phpss.iml
generated
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="nulib\ext\" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="nulib\ext\" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
38
.idea/php-docker-settings.xml
generated
Normal file
38
.idea/php-docker-settings.xml
generated
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PhpDockerContainerSettings">
|
||||
<list>
|
||||
<map>
|
||||
<entry key="125ffb9d-fd5f-4e71-8182-94191665795a">
|
||||
<value>
|
||||
<DockerContainerSettings>
|
||||
<option name="version" value="1" />
|
||||
<option name="volumeBindings">
|
||||
<list>
|
||||
<DockerVolumeBindingImpl>
|
||||
<option name="containerPath" value="/opt/project" />
|
||||
<option name="hostPath" value="$PROJECT_DIR$" />
|
||||
</DockerVolumeBindingImpl>
|
||||
</list>
|
||||
</option>
|
||||
</DockerContainerSettings>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="c4cf2564-ed91-488c-a93d-fe2daeae80db">
|
||||
<value>
|
||||
<DockerContainerSettings>
|
||||
<option name="version" value="1" />
|
||||
<option name="volumeBindings">
|
||||
<list>
|
||||
<DockerVolumeBindingImpl>
|
||||
<option name="containerPath" value="/opt/project" />
|
||||
</DockerVolumeBindingImpl>
|
||||
</list>
|
||||
</option>
|
||||
</DockerContainerSettings>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</list>
|
||||
</component>
|
||||
</project>
|
66
.idea/php.xml
generated
Normal file
66
.idea/php.xml
generated
Normal file
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MessDetectorOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCSFixerOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/markbaker/complex" />
|
||||
<path value="$PROJECT_DIR$/vendor/markbaker/matrix" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpoffice/phpspreadsheet" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
||||
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
||||
<path value="$PROJECT_DIR$/vendor/maennchen/zipstream-php" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/http-factory" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/simple-cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/http-client" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/http-message" />
|
||||
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit" />
|
||||
<path value="$PROJECT_DIR$/vendor/nulib/php" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/nulib/tests" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||
<path value="$PROJECT_DIR$/vendor/ezyang/htmlpurifier" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/resource-operations" />
|
||||
<path value="$PROJECT_DIR$/vendor/myclabs/php-enum" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.4" />
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -9,4 +9,4 @@ TAG_PREFIX=
|
||||
TAG_SUFFIX=p74
|
||||
HOTFIX=hotf74-
|
||||
DIST=
|
||||
NOAUTO=
|
||||
NOAUTO=1
|
||||
|
8
.runphp.conf
Normal file
8
.runphp.conf
Normal file
@ -0,0 +1,8 @@
|
||||
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||
|
||||
# Chemin vers runphp, e.g sbin/runphp
|
||||
RUNPHP=
|
||||
|
||||
# Si RUNPHP n'est pas défini, les variables suivantes peuvent être définies
|
||||
DIST=d11
|
||||
#REGISTRY=pubdocker.univ-reunion.fr/dist
|
5
TODO.md
Normal file
5
TODO.md
Normal file
@ -0,0 +1,5 @@
|
||||
# TODO
|
||||
|
||||
* [ ] mettre en cohérence avec l'API de nulib/spout (notamment wsname et spout)
|
||||
|
||||
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary
|
45
composer.json
Normal file
45
composer.json
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "nulib/phpss",
|
||||
"type": "library",
|
||||
"description": "wrapper pour phpoffice/phpspreadsheet",
|
||||
"repositories": [
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../nulib"
|
||||
},
|
||||
{
|
||||
"type": "composer",
|
||||
"url": "https://repos.univ-reunion.fr/composer"
|
||||
}
|
||||
],
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-dev74": "7.4.x-dev",
|
||||
"dev-dev82": "8.2.x-dev"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"nulib/php": "^7.4-dev",
|
||||
"phpoffice/phpspreadsheet": "^1.0",
|
||||
"php": "^7.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"nulib/tests": "^7.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"nulib\\ext\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"nulib\\ext\\": "tests"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jephte Clain",
|
||||
"email": "Jephte.Clain@univ-reunion.fr"
|
||||
}
|
||||
]
|
||||
}
|
2857
composer.lock
generated
Normal file
2857
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
0
src/.gitignore
vendored
Normal file
0
src/.gitignore
vendored
Normal file
112
src/phpss/PhpSpreadsheetBuilder.php
Normal file
112
src/phpss/PhpSpreadsheetBuilder.php
Normal file
@ -0,0 +1,112 @@
|
||||
<?php
|
||||
namespace nulib\ext\phpss;
|
||||
|
||||
use nulib\file\tab\AbstractBuilder;
|
||||
use nulib\file\tab\TAbstractBuilder;
|
||||
use nulib\os\path;
|
||||
use nulib\web\http;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\IValueBinder;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\StringValueBinder;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Ods;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||
|
||||
class PhpSpreadsheetBuilder extends AbstractBuilder {
|
||||
use TAbstractBuilder;
|
||||
|
||||
/** @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);
|
||||
$this->ss = new Spreadsheet();
|
||||
$this->valueBinder = new StringValueBinder();
|
||||
$this->setWsname($params["wsname"] ?? static::WSNAME);
|
||||
}
|
||||
|
||||
protected Spreadsheet $ss;
|
||||
|
||||
protected IValueBinder $valueBinder;
|
||||
|
||||
protected ?Worksheet $ws;
|
||||
|
||||
protected int $nrow;
|
||||
|
||||
const STYLE_ROW = 0, STYLE_HEADER = 1;
|
||||
|
||||
protected int $rowStyle;
|
||||
|
||||
/**
|
||||
* @param string|int|null $wsname
|
||||
*/
|
||||
function setWsname($wsname): self {
|
||||
$ss = $this->ss;
|
||||
$this->ws = null;
|
||||
$this->nrow = 0;
|
||||
$this->rowStyle = self::STYLE_ROW;
|
||||
|
||||
$ws = wsutils::get_ws($wsname, $ss);
|
||||
if ($ws === null) {
|
||||
$ws = $ss->createSheet()->setTitle($wsname);
|
||||
$this->wroteHeaders = false;
|
||||
} else {
|
||||
$maxRow = wsutils::compute_max_coords($ws)[1];
|
||||
$this->nrow = $maxRow - 1;
|
||||
$this->wroteHeaders = $maxRow > 1;
|
||||
}
|
||||
$this->ws = $ws;
|
||||
return $this;
|
||||
}
|
||||
|
||||
function _write(array $row): void {
|
||||
$ws = $this->ws;
|
||||
$styleHeader = $this->rowStyle === self::STYLE_HEADER;
|
||||
$nrow = ++$this->nrow;
|
||||
$ncol = 1;
|
||||
foreach ($row as $col) {
|
||||
$ws->getCellByColumnAndRow($ncol++, $nrow)->setValue($col, $this->valueBinder);
|
||||
}
|
||||
if ($styleHeader) {
|
||||
$ws->getStyle("$nrow:$nrow")->getFont()->setBold(true);
|
||||
$maxcol = count($row);
|
||||
for ($ncol = 1; $ncol <= $maxcol; $ncol++) {
|
||||
$ws->getColumnDimensionByColumn($ncol)->setAutoSize(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
protected function _checkOk(): bool {
|
||||
switch (path::ext($this->output)) {
|
||||
case ".ods":
|
||||
$writer = new Ods($this->ss);
|
||||
break;
|
||||
case ".xlsx":
|
||||
default:
|
||||
$writer = new Xlsx($this->ss);
|
||||
break;
|
||||
}
|
||||
$writer->save($this->getResource());
|
||||
$this->rewind();
|
||||
return true;
|
||||
}
|
||||
}
|
116
src/phpss/PhpSpreadsheetReader.php
Normal file
116
src/phpss/PhpSpreadsheetReader.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
namespace nulib\ext\phpss;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\file\tab\AbstractReader;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\DataType;
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
use PhpOffice\PhpSpreadsheet\RichText\RichText;
|
||||
|
||||
class PhpSpreadsheetReader extends AbstractReader {
|
||||
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|int|null 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 $wsname;
|
||||
|
||||
/**
|
||||
* @param string|int|null $wsname
|
||||
*/
|
||||
function setWsname($wsname): self {
|
||||
$this->wsname = $wsname;
|
||||
return $this;
|
||||
}
|
||||
|
||||
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);
|
||||
$col = $cell->getValue();
|
||||
if ($col instanceof RichText) {
|
||||
$col = $col->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
$col = $cell->getFormattedValue();
|
||||
$this->verifixCol($col);
|
||||
}
|
||||
} else {
|
||||
$col = null;
|
||||
}
|
||||
$row[] = $col;
|
||||
}
|
||||
if ($this->cookRow($row)) {
|
||||
yield $row;
|
||||
$this->idest++;
|
||||
}
|
||||
$this->isrc++;
|
||||
}
|
||||
}
|
||||
}
|
14
src/phpss/ssutils.php
Normal file
14
src/phpss/ssutils.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
namespace nulib\ext\phpss;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
|
||||
class ssutils {
|
||||
static function each_compute_max_coords(Spreadsheet $ss): array {
|
||||
$max_coords = [];
|
||||
foreach ($ss->getAllSheets() as $ws) {
|
||||
$max_coords[$ws->getTitle()] = wsutils::compute_max_coords($ws);
|
||||
}
|
||||
return $max_coords;
|
||||
}
|
||||
}
|
80
src/phpss/wsutils.php
Normal file
80
src/phpss/wsutils.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
namespace nulib\ext\phpss;
|
||||
|
||||
use nulib\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);
|
||||
$highestRow = $ws->getHighestRow();
|
||||
return [$highestCol, $highestRow];
|
||||
}
|
||||
|
||||
/**
|
||||
* @var int nombre de colonnes/lignes au bout desquels on arrête de chercher
|
||||
* si on n'a trouvé que des cellules vides.
|
||||
*
|
||||
* c'est nécessaire à cause de certains fichiers provenant d'Excel que j'ai
|
||||
* reçus qui ont jusqu'à 10000 colonne vides et/ou 1048576 lignes vides. un
|
||||
* algorithme "bête" perd énormément de temps à chercher dans le vide, donnant
|
||||
* l'impression que le processus a planté.
|
||||
*/
|
||||
const MAX_EMPTY_THRESHOLD = 150;
|
||||
|
||||
static function compute_max_coords(Worksheet $ws): array {
|
||||
[$highestCol, $highestRow] = self::get_highest_coords($ws);
|
||||
|
||||
$maxCol = 1;
|
||||
$maxRow = 1;
|
||||
$maxEmptyRows = self::MAX_EMPTY_THRESHOLD;
|
||||
for ($row = 1; $row <= $highestRow; $row++) {
|
||||
$emptyRow = true;
|
||||
$maxEmptyCols = self::MAX_EMPTY_THRESHOLD;
|
||||
for ($col = 1; $col <= $highestCol; $col++) {
|
||||
$value = null;
|
||||
if ($ws->cellExistsByColumnAndRow($col, $row)) {
|
||||
$value = $ws->getCellByColumnAndRow($col, $row)->getValue();
|
||||
}
|
||||
if ($value === null) {
|
||||
$maxEmptyCols--;
|
||||
if ($maxEmptyCols == 0) break;
|
||||
} else {
|
||||
$maxEmptyCols = self::MAX_EMPTY_THRESHOLD;
|
||||
if ($row > $maxRow) $maxRow = $row;
|
||||
if ($col > $maxCol) $maxCol = $col;
|
||||
$emptyRow = false;
|
||||
}
|
||||
}
|
||||
if ($emptyRow) {
|
||||
$maxEmptyRows--;
|
||||
if ($maxEmptyRows == 0) break;
|
||||
} else {
|
||||
$maxEmptyRows = self::MAX_EMPTY_THRESHOLD;
|
||||
}
|
||||
}
|
||||
return [$maxCol, $maxRow];
|
||||
}
|
||||
}
|
0
tests/.gitignore
vendored
Normal file
0
tests/.gitignore
vendored
Normal file
Loading…
Reference in New Issue
Block a user