Compare commits
35 Commits
upstream-3
...
php74
Author | SHA1 | Date | |
---|---|---|---|
6e58b99069 | |||
664a713c0a | |||
c8db7095c9 | |||
702ef1cb4f | |||
967319ff0b | |||
1d2d8686c4 | |||
51ebba1ab7 | |||
11724eef98 | |||
099cdcfc3e | |||
65a9876d3d | |||
7d699ee61e | |||
747f61a03d | |||
2b4dff08e2 | |||
a9df7e7c30 | |||
b6f35877ae | |||
fd68d0ecd5 | |||
60dfb1e177 | |||
19a3cb9b76 | |||
71ca020b1e | |||
4468c648da | |||
2fb49a110e | |||
0c87ff1a7b | |||
8b79df5a75 | |||
d2c6d51bdb | |||
4865e6a1fc | |||
23ded28680 | |||
f9fd6b838e | |||
ed34b1e093 | |||
8258dd53b5 | |||
bda119cbed | |||
d416e6799b | |||
9f2bc810e4 | |||
958a9c9090 | |||
075374015c | |||
80850f0540 |
6
.composer.yaml
Normal file
6
.composer.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
# -*- coding: utf-8 mode: yaml -*- vim:sw=2:sts=2:et:ai:si:sta:fenc=utf-8
|
||||
require:
|
||||
nulib/php: ^7.4-dev
|
||||
branch:
|
||||
develop:
|
||||
master:
|
0
.dockerignore
Normal file
0
.dockerignore
Normal file
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
.~lock*#
|
||||
.*.swp
|
||||
/vendor/
|
||||
|
||||
/.idea/shelf/
|
||||
/.idea/workspace.xml
|
||||
/.idea/httpRequests/
|
||||
/.idea/dataSources/
|
||||
/.idea/dataSources.local.xml
|
||||
/.phpunit.result.cache
|
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
12
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
12
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,12 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="GrazieInspection" enabled="false" level="GRAMMAR_ERROR" enabled_by_default="false" />
|
||||
<inspection_tool class="LanguageDetectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
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-spout.iml" filepath="$PROJECT_DIR$/.idea/nulib-spout.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
13
.idea/nulib-spout.iml
generated
Normal file
13
.idea/nulib-spout.iml
generated
Normal file
@ -0,0 +1,13 @@
|
||||
<?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\" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="nulib\ext\" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/upstream-3.x/src" isTestSource="false" packagePrefix="OpenSpout\" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
23
.idea/php-docker-settings.xml
generated
Normal file
23
.idea/php-docker-settings.xml
generated
Normal file
@ -0,0 +1,23 @@
|
||||
<?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" />
|
||||
</DockerVolumeBindingImpl>
|
||||
</list>
|
||||
</option>
|
||||
</DockerContainerSettings>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</list>
|
||||
</component>
|
||||
</project>
|
14
.idea/php-test-framework.xml
generated
Normal file
14
.idea/php-test-framework.xml
generated
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PhpTestFrameworkVersionCache">
|
||||
<tools_cache>
|
||||
<tool tool_name="PHPUnit">
|
||||
<cache>
|
||||
<versions>
|
||||
<info id="Local/vendor/autoload.php" version="9.6.21" />
|
||||
</versions>
|
||||
</cache>
|
||||
</tool>
|
||||
</tools_cache>
|
||||
</component>
|
||||
</project>
|
107
.idea/php.xml
generated
Normal file
107
.idea/php.xml
generated
Normal file
@ -0,0 +1,107 @@
|
||||
<?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="PhpCSFixer">
|
||||
<phpcsfixer_settings>
|
||||
<PhpCSFixerConfiguration tool_path="$PROJECT_DIR$/vendor/bin/php-cs-fixer" />
|
||||
</phpcsfixer_settings>
|
||||
</component>
|
||||
<component name="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/string" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/process" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/resource-operations" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||
<path value="$PROJECT_DIR$/vendor/friendsofphp/php-cs-fixer" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpstan/phpstan-phpunit" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpstan/phpstan" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||
<path value="$PROJECT_DIR$/vendor/clue/ndjson-react" />
|
||||
<path value="$PROJECT_DIR$/vendor/evenement/evenement" />
|
||||
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/promise" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/fidry/cpu-core-counter" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/dns" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/child-process" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/event-loop" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/socket" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/stream" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php81" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php73" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php80" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-ctype" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/stopwatch" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<path value="$PROJECT_DIR$/vendor/nulib/tests" />
|
||||
<path value="$PROJECT_DIR$/vendor/nulib/php" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/yaml" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.4">
|
||||
<option name="suggestChangeDefaultLanguageLevel" value="false" />
|
||||
</component>
|
||||
<component name="PhpStan">
|
||||
<PhpStan_settings>
|
||||
<PhpStanConfiguration tool_path="$PROJECT_DIR$/vendor/bin/phpstan" />
|
||||
</PhpStan_settings>
|
||||
</component>
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpUnit">
|
||||
<phpunit_settings>
|
||||
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" phpunit_phar_path="" />
|
||||
</phpunit_settings>
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
</project>
|
10
.idea/phpunit.xml
generated
Normal file
10
.idea/phpunit.xml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PHPUnit">
|
||||
<option name="directories">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/tests" />
|
||||
</list>
|
||||
</option>
|
||||
</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>
|
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
|
25
_merge2php82
Executable file
25
_merge2php82
Executable file
@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||||
mydir="$(cd "$(dirname -- "$0")"; pwd)"
|
||||
myself="$mydir/$(basename -- "$0")"
|
||||
cwd="$(pwd)"
|
||||
if [ "$1" != --stage2 -o -z "$2" ]; then
|
||||
cp "$myself" /tmp/merge2php82.sh
|
||||
exec /tmp/merge2php82.sh --stage2 "$mydir"
|
||||
fi
|
||||
|
||||
cd "$2" || die
|
||||
if [ -f vendor/nulib/php/load.sh ]; then
|
||||
source ./vendor/nulib/php/load.sh || exit 1
|
||||
else
|
||||
source /etc/nulib.sh || exit 1
|
||||
fi
|
||||
|
||||
git checkout php82
|
||||
git rebase php74 ||
|
||||
die "Le rebase automatique a échoué. Après avoir résolu les conflits, faire
|
||||
git checkout php74
|
||||
pp -af
|
||||
"
|
||||
git checkout php74
|
||||
pp -af
|
62
composer.json
Normal file
62
composer.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"name": "nulib/spout",
|
||||
"type": "library",
|
||||
"description": "wrapper pour openspout/openspout",
|
||||
"repositories": [
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../nulib"
|
||||
},
|
||||
{
|
||||
"type": "composer",
|
||||
"url": "https://repos.univ-reunion.fr/composer"
|
||||
}
|
||||
],
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-php74": "7.4.x-dev",
|
||||
"dev-php82": "8.2.x-dev"
|
||||
}
|
||||
},
|
||||
"replace": {
|
||||
"openspout/openspout": "v3.7.4"
|
||||
},
|
||||
"require": {
|
||||
"nulib/php": "^7.4-dev",
|
||||
"ext-dom": "*",
|
||||
"ext-filter": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-xmlreader": "*",
|
||||
"ext-zip": "*",
|
||||
"php": "^7.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"nulib/tests": "^7.4",
|
||||
"friendsofphp/php-cs-fixer": "^3.4",
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"ext-zlib": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"nulib\\": "src",
|
||||
"OpenSpout\\": "upstream-3.x/src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"nulib\\ext\\": "tests"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jephte Clain",
|
||||
"email": "Jephte.Clain@univ-reunion.fr"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"infection/extension-installer": false
|
||||
}
|
||||
}
|
||||
}
|
4583
composer.lock
generated
Normal file
4583
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
77
patches/v3.7.4.patch
Normal file
77
patches/v3.7.4.patch
Normal file
@ -0,0 +1,77 @@
|
||||
diff --git a/src/Writer/WriterAbstract.php b/src/Writer/WriterAbstract.php
|
||||
index fd7c472..a2a5e37 100644
|
||||
--- a/src/Writer/WriterAbstract.php
|
||||
+++ b/src/Writer/WriterAbstract.php
|
||||
@@ -22,6 +22,9 @@ abstract class WriterAbstract implements WriterInterface
|
||||
/** @var resource Pointer to the file/stream we will write to */
|
||||
protected $filePointer;
|
||||
|
||||
+ /** @var bool faut-il garder ouvert le flux quand close() est appelé? */
|
||||
+ protected $dontCloseFilePointer = false;
|
||||
+
|
||||
/** @var bool Indicates whether the writer has been opened or not */
|
||||
protected $isWriterOpened = false;
|
||||
|
||||
@@ -57,6 +60,20 @@ abstract class WriterAbstract implements WriterInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
+ public function writeToStream($filePointer)
|
||||
+ {
|
||||
+ $this->outputFilePath = null;
|
||||
+
|
||||
+ $this->filePointer = $filePointer;
|
||||
+ $this->dontCloseFilePointer = true;
|
||||
+ $this->throwIfFilePointerIsNotAvailable();
|
||||
+
|
||||
+ $this->openWriter();
|
||||
+ $this->isWriterOpened = true;
|
||||
+
|
||||
+ return $this;
|
||||
+ }
|
||||
+
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -177,7 +194,7 @@ abstract class WriterAbstract implements WriterInterface
|
||||
|
||||
$this->closeWriter();
|
||||
|
||||
- if (\is_resource($this->filePointer)) {
|
||||
+ if (!$this->dontCloseFilePointer && \is_resource($this->filePointer)) {
|
||||
$this->globalFunctionsHelper->fclose($this->filePointer);
|
||||
}
|
||||
|
||||
diff --git a/src/Reader/XLSX/Helper/CellValueFormatter.php b/src/Reader/XLSX/Helper/CellValueFormatter.php
|
||||
index 1734fb5..08e5282 100644
|
||||
--- a/src/Reader/XLSX/Helper/CellValueFormatter.php
|
||||
+++ b/src/Reader/XLSX/Helper/CellValueFormatter.php
|
||||
@@ -268,9 +268,13 @@ class CellValueFormatter
|
||||
$dateObj->modify('+'.$secondsRemainder.'seconds');
|
||||
|
||||
if ($this->shouldFormatDates) {
|
||||
- $styleNumberFormatCode = $this->styleManager->getNumberFormatCode($cellStyleId);
|
||||
- $phpDateFormat = DateFormatHelper::toPHPDateFormat($styleNumberFormatCode);
|
||||
+ //$styleNumberFormatCode = $this->styleManager->getNumberFormatCode($cellStyleId);
|
||||
+ //$phpDateFormat = DateFormatHelper::toPHPDateFormat($styleNumberFormatCode);
|
||||
+ // Toujours utiliser le format français complet
|
||||
+ $phpDateFormat = "d/m/Y H:i:s";
|
||||
$cellValue = $dateObj->format($phpDateFormat);
|
||||
+ // Enlever la composante heure si elle n'existe pas
|
||||
+ $cellValue = preg_replace('/ 00:00:00$/', "", $cellValue);
|
||||
} else {
|
||||
$cellValue = $dateObj;
|
||||
}
|
||||
diff --git a/src/Reader/XLSX/Manager/OptionsManager.php b/src/Reader/XLSX/Manager/OptionsManager.php
|
||||
index b04b92c..5749f65 100644
|
||||
--- a/src/Reader/XLSX/Manager/OptionsManager.php
|
||||
+++ b/src/Reader/XLSX/Manager/OptionsManager.php
|
||||
@@ -29,7 +29,7 @@ class OptionsManager extends OptionsManagerAbstract
|
||||
protected function setDefaultOptions()
|
||||
{
|
||||
$this->setOption(Options::TEMP_FOLDER, sys_get_temp_dir());
|
||||
- $this->setOption(Options::SHOULD_FORMAT_DATES, false);
|
||||
+ $this->setOption(Options::SHOULD_FORMAT_DATES, true);
|
||||
$this->setOption(Options::SHOULD_PRESERVE_EMPTY_ROWS, false);
|
||||
$this->setOption(Options::SHOULD_USE_1904_DATES, false);
|
||||
}
|
0
src/.gitignore
vendored
Normal file
0
src/.gitignore
vendored
Normal file
465
src/ext/spout/SpoutBuilder.php
Normal file
465
src/ext/spout/SpoutBuilder.php
Normal file
@ -0,0 +1,465 @@
|
||||
<?php
|
||||
namespace nulib\ext\spout;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\file\tab\AbstractBuilder;
|
||||
use nulib\file\tab\TAbstractBuilder;
|
||||
use nulib\os\path;
|
||||
use nulib\php\func;
|
||||
use nulib\php\nur_func;
|
||||
use nulib\php\time\Date;
|
||||
use nulib\php\time\DateTime;
|
||||
use nulib\ref\ext\spout\ref_builder;
|
||||
use nulib\ref\ext\spout\ref_builder_ods;
|
||||
use nulib\ref\ext\spout\ref_builder_xlsx;
|
||||
use nulib\str;
|
||||
use nulib\web\http;
|
||||
use OpenSpout\Common\Entity\Cell;
|
||||
use OpenSpout\Common\Entity\Style\Border;
|
||||
use OpenSpout\Common\Entity\Style\BorderPart;
|
||||
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;
|
||||
|
||||
protected static function apply_params($object, ?array $params, array $refParams) {
|
||||
foreach (array_keys($refParams) as $method) {
|
||||
if (!str::starts_with("->", $method)) continue;
|
||||
$func = func::with([$object, $method]);
|
||||
if (($args = $params[$method] ?? null) !== null) {
|
||||
$func->invoke(cl::with($args));
|
||||
}
|
||||
if (($argss = $params["$method*"] ?? null) !== null) {
|
||||
foreach ($argss as $args) {
|
||||
$func->invoke(cl::with($args));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
protected static function add_border_part(?Border &$border, string $name, ?array $params): void {
|
||||
if ($params === null) return;
|
||||
if ($border === null) $border = new Border();
|
||||
$part = new BorderPart($name);
|
||||
if (($color = $params["color"] ?? null) !== null) {
|
||||
$part->setColor(cl::get(ref_builder::COLORS, $color, $color));
|
||||
}
|
||||
if (($width = $params["width"] ?? null) !== null) $part->setWidth($width);
|
||||
if (($style = $params["style"] ?? null) !== null) $part->setStyle($style);
|
||||
$border->addPart($part);
|
||||
}
|
||||
|
||||
protected static function set_defaults(?array &$params, string $key, array $defaults): void {
|
||||
if ($params !== null && array_key_exists($key, $params)) {
|
||||
if ($params[$key] === false) $params[$key] = null;
|
||||
else $params[$key] ??= $defaults;
|
||||
} else {
|
||||
$params[$key] ??= $defaults;
|
||||
}
|
||||
}
|
||||
|
||||
protected static function ensure_style(&$style): ?Style {
|
||||
if ($style === null) return null;
|
||||
if ($style instanceof Style) return $style;
|
||||
$cell = $style;
|
||||
$style = new Style();
|
||||
$font = $cell["font"] ?? null;
|
||||
if ($font["bold"] ?? null) $style->setFontBold();
|
||||
if ($font["italic"] ?? null) $style->setFontItalic();
|
||||
if ($font["underline"] ?? null) $style->setFontUnderline();
|
||||
if ($font["strikethrough"] ?? null) $style->setFontStrikethrough();
|
||||
if (($name = $font["name"] ?? null) !== null) $style->setFontName($name);
|
||||
if (($size = $font["size"] ?? null) !== null) $style->setFontSize($size);
|
||||
if (($color = $font["color"] ?? null) !== null) {
|
||||
$style->setFontColor(cl::get(ref_builder::COLORS, $color, $color));
|
||||
}
|
||||
if (($color = $cell["bg_color"] ?? null) !== null) {
|
||||
$style->setBackgroundColor(cl::get(ref_builder::COLORS, $color, $color));
|
||||
}
|
||||
if (($align = $cell["align"] ?? null) !== null) $style->setCellAlignment($align);
|
||||
//if (($align = $cell["valign"] ?? null) !== null) $style->setCellVerticalAlignment($align);
|
||||
if (($wrap = $cell["wrap"] ?? null) !== null) $style->setShouldWrapText($wrap);
|
||||
if (($format = $cell["format"] ?? null) !== null) $style->setFormat($format);
|
||||
if (($border = $cell["border"] ?? null) !== null) {
|
||||
if (is_string($border)) {
|
||||
$parts = explode(" ", $border);
|
||||
$border = [];
|
||||
$styleAll = null;
|
||||
$widthAll = null;
|
||||
$colorAll = null;
|
||||
foreach ($parts as $part) {
|
||||
if ($part === "all") {
|
||||
$border["left"] = [];
|
||||
$border["top"] = [];
|
||||
$border["right"] = [];
|
||||
$border["bottom"] = [];
|
||||
} elseif (preg_match('/^(left|top|right|bottom)$/', $part)) {
|
||||
$border[$part] = [];
|
||||
} elseif (preg_match('/^(none|solid|dashed|dotted|double)$/', $part)) {
|
||||
$styleAll = $part;
|
||||
} elseif (preg_match('/^(thin|medium|thick)$/', $part)) {
|
||||
$widthAll = $part;
|
||||
} else {
|
||||
$colorAll = $part;
|
||||
}
|
||||
}
|
||||
foreach ($border as &$part) {
|
||||
if ($styleAll !== null) $part["style"] = $styleAll;
|
||||
if ($widthAll !== null) $part["width"] = $widthAll;
|
||||
if ($colorAll !== null) $part["color"] = $colorAll;
|
||||
}; unset($part);
|
||||
}
|
||||
|
||||
$top = $border["top"] ?? null;
|
||||
$right = $border["right"] ?? null;
|
||||
$bottom = $border["bottom"] ?? null;
|
||||
$left = $border["left"] ?? null;
|
||||
$border = null;
|
||||
self::add_border_part($border, "top", $top);
|
||||
self::add_border_part($border, "right", $right);
|
||||
self::add_border_part($border, "bottom", $bottom);
|
||||
self::add_border_part($border, "left", $left);
|
||||
if ($border !== null) $style->setBorder($border);
|
||||
}
|
||||
return $style;
|
||||
}
|
||||
|
||||
const DATE_FORMAT = "dd/mm/yyyy";
|
||||
|
||||
const DATETIME_FORMAT = "dd/mm/yyyy hh:mm:ss";
|
||||
|
||||
/** @var bool faut-il choisir le type numérique pour une chaine numérique? */
|
||||
const TYPE_NUMERIC = true;
|
||||
|
||||
/** @var bool faut-il choisir le type date pour une chaine au bon format? */
|
||||
const TYPE_DATE = true;
|
||||
|
||||
/** @var array configuration du writer */
|
||||
const SPOUT_PARAMS = null;
|
||||
|
||||
/** @var array configuration de la première feuille */
|
||||
const SHEET_PARAMS = null;
|
||||
|
||||
/** @var string nom de la première feuille */
|
||||
const SHEET_NAME = null;
|
||||
|
||||
/** @var array configuration de la vue de la première feuille */
|
||||
const SHEET_VIEW_PARAMS = 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 = self::SS_TYPE_ODS;
|
||||
break;
|
||||
case ".xlsx":
|
||||
default:
|
||||
$ssType = self::SS_TYPE_XLSX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$spoutParams = $params["spout"] ?? static::SPOUT_PARAMS;
|
||||
$spoutParams["default_column_width"] ??= 10.5;
|
||||
self::ensure_style($spoutParams["default_row_style"]);
|
||||
switch ($ssType) {
|
||||
case "ods":
|
||||
case self::SS_TYPE_ODS:
|
||||
$ssType = self::SS_TYPE_ODS;
|
||||
$ssWriter = WriterEntityFactory::createODSWriter();
|
||||
self::apply_params($ssWriter, $spoutParams, ref_builder_ods::PARAMS_SPOUT);
|
||||
break;
|
||||
case "xlsx":
|
||||
case self::SS_TYPE_XLSX:
|
||||
default:
|
||||
$ssType = self::SS_TYPE_XLSX;
|
||||
$ssWriter = WriterEntityFactory::createXLSXWriter();
|
||||
self::apply_params($ssWriter, $spoutParams, ref_builder_xlsx::PARAMS_SPOUT);
|
||||
break;
|
||||
}
|
||||
$defaultColumnWidth = $spoutParams["default_column_width"] ?? null;
|
||||
if ($defaultColumnWidth !== null) $ssWriter->setDefaultColumnWidth($defaultColumnWidth);
|
||||
$defaultRowHeight = $spoutParams["default_row_height"] ?? null;
|
||||
if ($defaultRowHeight !== null) $ssWriter->setDefaultRowHeight($defaultRowHeight);
|
||||
$defaultRowStyle = $spoutParams["default_row_style"] ?? null;
|
||||
if ($defaultRowStyle !== null) $ssWriter->setDefaultRowStyle($defaultRowStyle);
|
||||
$ssWriter->writeToStream($this->getResource());
|
||||
|
||||
$this->ssType = $ssType;
|
||||
$this->ssWriter = $ssWriter;
|
||||
$this->spoutParams = $spoutParams;
|
||||
$this->typeNumeric = boolval($params["type_numeric"] ?? static::TYPE_NUMERIC);
|
||||
$this->typeDate = boolval($params["type_date"] ?? static::TYPE_DATE);
|
||||
|
||||
$sheetParams = $params["sheet"] ?? static::SHEET_PARAMS;
|
||||
$sheetName = $params["sheet_name"] ?? static::SHEET_NAME;
|
||||
if ($sheetName !== null) $sheetParams["->setName"] = $sheetName;
|
||||
$sheetViewParams = $params["sheet_view"] ?? static::SHEET_VIEW_PARAMS;
|
||||
if ($sheetViewParams !== null) $sheetParams["view"] = $sheetViewParams;
|
||||
$this->firstSheet = true;
|
||||
$this->sheetParams = null;
|
||||
$this->setSheet(null, $sheetParams);
|
||||
}
|
||||
|
||||
const SS_TYPE_ODS = 1, SS_TYPE_XLSX = 2;
|
||||
|
||||
/** @var int type de fichier généré */
|
||||
protected int $ssType;
|
||||
|
||||
protected WriterMultiSheetsAbstract $ssWriter;
|
||||
|
||||
protected ?array $spoutParams;
|
||||
|
||||
protected bool $typeNumeric;
|
||||
|
||||
protected bool $typeDate;
|
||||
|
||||
function setParams(?array $params): self {
|
||||
if ($params !== null) {
|
||||
if (array_key_exists("type_numeric", $params)) {
|
||||
$this->typeNumeric = boolval($params["type_numeric"] ?? static::TYPE_NUMERIC);
|
||||
}
|
||||
if (array_key_exists("type_date", $params)) {
|
||||
$this->typeDate = boolval($params["type_date"] ?? static::TYPE_DATE);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected bool $firstSheet;
|
||||
|
||||
protected ?array $sheetParams;
|
||||
|
||||
const STYLE_ROW = 0, STYLE_HEADER = 1;
|
||||
|
||||
protected int $rowStyle;
|
||||
|
||||
protected int $currentRow;
|
||||
|
||||
protected ?bool $differentOddEven = null;
|
||||
|
||||
protected int $oddEvenIndex = 0;
|
||||
|
||||
function setDifferentOddEven(bool $differentOddEven, ?bool $startWithOdd=null): self {
|
||||
$this->differentOddEven = $differentOddEven;
|
||||
if ($differentOddEven && $startWithOdd !== null) $this->oddEvenIndex = $startWithOdd? 1: 0;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int|null $sheetName
|
||||
*/
|
||||
function setSheet($sheetName, ?array $sheetParams=null): self {
|
||||
$sheet = $params["sheet"] ?? null;
|
||||
$sheetName = $sheetName ?? $sheetParams["sheet_name"] ?? null;
|
||||
$sheetViewParams = $sheetParams["sheet_view"] ?? null;
|
||||
|
||||
if ($sheet !== null) $sheetParams = $sheet;
|
||||
if ($sheetName !== null) $sheetParams["->setName"] = $sheetName;
|
||||
if ($sheetViewParams !== null) $sheetParams["view"] = $sheetViewParams;
|
||||
|
||||
$writer = $this->ssWriter;
|
||||
if ($this->firstSheet) {
|
||||
$this->firstSheet = false;
|
||||
$sheet = $writer->getCurrentSheet();
|
||||
} else {
|
||||
$sheet = $writer->addNewSheetAndMakeItCurrent();
|
||||
$this->wroteHeaders = false;
|
||||
$this->built = false;
|
||||
}
|
||||
$this->rowStyle = self::STYLE_ROW;
|
||||
$this->currentRow = 1;
|
||||
|
||||
switch ($this->ssType) {
|
||||
case self::SS_TYPE_ODS:
|
||||
# appliquer les paramètres de la feuille
|
||||
$this->apply_params($sheet, $sheetParams, ref_builder_ods::PARAMS_SHEET);
|
||||
break;
|
||||
case self::SS_TYPE_XLSX:
|
||||
# appliquer les paramètres de la feuille
|
||||
$this->apply_params($sheet, $sheetParams, ref_builder_xlsx::PARAMS_SHEET);
|
||||
# appliquer les paramètres de la vue de la feuille
|
||||
$sheetViewParams =& $sheetParams["view"];
|
||||
$sheetViewParams["->setFreezeRow"] ??= 2;
|
||||
$sheet->setSheetView(self::apply_params(new SheetView(), $sheetViewParams, ref_builder_xlsx::PARAMS_SHEET_VIEW));
|
||||
break;
|
||||
}
|
||||
self::set_defaults($sheetParams, "header_style", [
|
||||
"font" => ["bold" => true],
|
||||
"bg_color" => "gray",
|
||||
]);
|
||||
self::set_defaults($sheetParams, "odd_style", [
|
||||
"wrap" => false,
|
||||
]);
|
||||
self::set_defaults($sheetParams, "even_style", [
|
||||
"bg_color" => "light_gray",
|
||||
"wrap" => false,
|
||||
]);
|
||||
$this->ensure_style($sheetParams["header_style"]);
|
||||
$this->ensure_style($sheetParams["odd_style"]);
|
||||
$this->ensure_style($sheetParams["even_style"]);
|
||||
$this->sheetParams = $sheetParams;
|
||||
|
||||
if ($sheetParams !== null) {
|
||||
if (array_key_exists("schema", $sheetParams)) {
|
||||
$this->schema = $sheetParams["schema"] ?? null;
|
||||
}
|
||||
if (array_key_exists("headers", $sheetParams)) {
|
||||
$this->headers = $sheetParams["headers"] ?? null;
|
||||
}
|
||||
if (array_key_exists("rows", $sheetParams)) {
|
||||
$rows = $sheetParams["rows"] ?? null;
|
||||
if (is_callable($rows)) $rows = $rows();
|
||||
$this->rows = $rows;
|
||||
}
|
||||
if (array_key_exists("cook_func", $sheetParams)) {
|
||||
$cookFunc = $sheetParams["cook_func"] ?? null;
|
||||
$cookCtx = $cookArgs = null;
|
||||
if ($cookFunc !== null) {
|
||||
nur_func::ensure_func($cookFunc, $this, $cookArgs);
|
||||
$cookCtx = nur_func::_prepare($cookFunc);
|
||||
}
|
||||
$this->cookCtx = $cookCtx;
|
||||
$this->cookArgs = $cookArgs;
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* les colonnes sont indexées sur 0 (e.g A = 0, B = 1, etc.)
|
||||
* Les lignes sont indexées sur 1
|
||||
*/
|
||||
function mergeCells(int $topLeftCol, int $topLeftRow, int $bottomRightCol, int $bottomRightRow): void {
|
||||
$this->ssWriter->mergeCells([$topLeftCol, $topLeftRow], [$bottomRightCol, $bottomRightRow]);
|
||||
}
|
||||
|
||||
protected function isNumeric($value): bool {
|
||||
if ($this->typeNumeric && is_numeric($value)) return true;
|
||||
if (!is_string($value) && is_numeric($value)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isDate(&$value, &$style): bool {
|
||||
if ($value instanceof Date) {
|
||||
$style ??= new Style();
|
||||
$style->setFormat(self::DATE_FORMAT);
|
||||
return true;
|
||||
} elseif ($value instanceof DateTime) {
|
||||
$style ??= new Style();
|
||||
$style->setFormat(self::DATETIME_FORMAT);
|
||||
return true;
|
||||
} elseif (CellTypeHelper::isDateTimeOrDateInterval($value)) {
|
||||
$style ??= new Style();
|
||||
$style->setFormat(self::DATE_FORMAT);
|
||||
return true;
|
||||
}
|
||||
if (!is_string($value) || !$this->typeDate) return false;
|
||||
if (DateTime::isa_datetime($value, true)) {
|
||||
$value = new DateTime($value);
|
||||
$style ??= new Style();
|
||||
$style->setFormat(self::DATETIME_FORMAT);
|
||||
return true;
|
||||
}
|
||||
if (DateTime::isa_date($value, true)) {
|
||||
$value = new Date($value);
|
||||
$style ??= new Style();
|
||||
$style->setFormat(self::DATE_FORMAT);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function _write(array $row, ?array $colStyles=null, ?array $rowStyle=null): void {
|
||||
$rowParams = null;
|
||||
if ($rowStyle !== null) {
|
||||
# séparer rowParams (pour configurer l'instance de $row) et $rowStyle
|
||||
# (pour appliquer un style sur la ligne)
|
||||
foreach (array_keys(ref_builder::ROW_PARAMS) as $method) {
|
||||
$value = $rowStyle[$method] ?? null;
|
||||
unset($rowStyle[$method]);
|
||||
if ($value !== null) $rowParams[$method] = $value;
|
||||
}
|
||||
if ($rowStyle === []) $rowStyle = null;
|
||||
}
|
||||
$sheetParams = $this->sheetParams;
|
||||
$headerStyle = $sheetParams["header_style"] ?? null;
|
||||
$oddStyle = $sheetParams["odd_style"] ?? null;
|
||||
$evenStyle = $sheetParams["even_style"] ?? null;
|
||||
$differentOddEven = $this->differentOddEven;
|
||||
$differentOddEven ??= $sheetParams["different_odd_even"] ?? true;
|
||||
|
||||
$cells = [];
|
||||
foreach ($row as $key => $col) {
|
||||
$style = $colStyles[$key] ?? null;
|
||||
self::ensure_style($style);
|
||||
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 ??= $headerStyle;
|
||||
} elseif ($differentOddEven && $this->oddEvenIndex % 2 == 0) {
|
||||
$rowStyle ??= $evenStyle;
|
||||
}
|
||||
$rowStyle ??= $oddStyle;
|
||||
self::ensure_style($rowStyle);
|
||||
$row = WriterEntityFactory::createRow($cells, $rowStyle);
|
||||
self::apply_params($row, $rowParams, ref_builder::ROW_PARAMS);
|
||||
|
||||
$mergeCells = $rowParams["merge_cells"] ?? null;
|
||||
$mergeOffset = $rowParams["merge_offset"] ?? 0;
|
||||
if ($mergeCells !== null) {
|
||||
$currentRow = $this->currentRow;
|
||||
foreach ($mergeCells as [$leftCol, $rightCol]) {
|
||||
$this->mergeCells($leftCol + $mergeOffset, $currentRow, $rightCol + $mergeOffset, $currentRow);
|
||||
}
|
||||
}
|
||||
|
||||
$this->ssWriter->addRow($row);
|
||||
$this->currentRow++;
|
||||
if ($differentOddEven) $this->oddEvenIndex++;
|
||||
}
|
||||
|
||||
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 {
|
||||
$this->ssWriter->close();
|
||||
$this->rewind();
|
||||
return true;
|
||||
}
|
||||
}
|
121
src/ext/spout/SpoutReader.php
Normal file
121
src/ext/spout/SpoutReader.php
Normal file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
namespace nulib\ext\spout;
|
||||
|
||||
use nulib\cl;
|
||||
use nulib\file\tab\AbstractReader;
|
||||
use OpenSpout\Reader\Common\Creator\ReaderEntityFactory;
|
||||
|
||||
class SpoutReader extends AbstractReader {
|
||||
/** @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->ssType = $params["ss_type"] ?? null;
|
||||
$this->allSheets = $params["all_sheets"] ?? true;
|
||||
$wsname = static::WSNAME;
|
||||
if ($params !== null && array_key_exists("wsname", $params)) {
|
||||
# spécifié par l'utilisateur: $allSheets = false
|
||||
$this->setWsname($params["wsname"]);
|
||||
} elseif ($wsname !== null) {
|
||||
# valeur non nulle de la classe: $allSheets = false
|
||||
$this->setWsname($wsname);
|
||||
} else {
|
||||
# pas de valeur définie dans la classe, laisser $allSheets à sa valeur
|
||||
# actuelle
|
||||
$this->wsname = null;
|
||||
}
|
||||
$this->includeWsnames = cl::withn($params["include_wsnames"] ?? null);
|
||||
$this->excludeWsnames = cl::withn($params["exclude_wsnames"] ?? null);
|
||||
}
|
||||
|
||||
protected ?string $ssType;
|
||||
|
||||
/** @var bool faut-il retourner les lignes de toutes les feuilles? */
|
||||
protected bool $allSheets;
|
||||
|
||||
function setAllSheets(bool $allSheets=true): self {
|
||||
$this->allSheets = $allSheets;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array|null si non null, liste de feuilles à inclure. n'est pris en
|
||||
* compte que si $allSheets===true
|
||||
*/
|
||||
protected ?array $includeWsnames;
|
||||
|
||||
/**
|
||||
* @var array|null si non null, liste de feuilles à exclure. n'est pris en
|
||||
* compte que si $allSheets===true
|
||||
*/
|
||||
protected ?array $excludeWsnames;
|
||||
|
||||
protected $wsname;
|
||||
|
||||
/**
|
||||
* @param string|int|null $wsname l'unique feuille à sélectionner
|
||||
*
|
||||
* NB: appeler cette méthode réinitialise $allSheets à false
|
||||
*/
|
||||
function setWsname($wsname): self {
|
||||
$this->wsname = $wsname;
|
||||
$this->allSheets = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
function getIterator() {
|
||||
switch ($this->ssType) {
|
||||
case "ods":
|
||||
$ss = ReaderEntityFactory::createODSReader();
|
||||
break;
|
||||
case "xlsx":
|
||||
$ss = ReaderEntityFactory::createXLSXReader();
|
||||
break;
|
||||
default:
|
||||
$ss = ReaderEntityFactory::createReaderFromFile($this->input);
|
||||
break;
|
||||
}
|
||||
$ss->open($this->input);
|
||||
try {
|
||||
$allSheets = $this->allSheets;
|
||||
$includeWsnames = $this->includeWsnames;
|
||||
$excludeWsnames = $this->excludeWsnames;
|
||||
$wsname = $this->wsname;
|
||||
$first = true;
|
||||
foreach ($ss->getSheetIterator() as $ws) {
|
||||
if ($allSheets) {
|
||||
$wsname = $ws->getName();
|
||||
$found = ($includeWsnames === null || in_array($wsname, $includeWsnames))
|
||||
&& ($excludeWsnames === null || !in_array($wsname, $excludeWsnames));
|
||||
} else {
|
||||
$found = $wsname === null || $wsname === $ws->getName();
|
||||
}
|
||||
if ($found) {
|
||||
if ($first) {
|
||||
$first = false;
|
||||
} else {
|
||||
yield null;
|
||||
# on garde le même schéma le cas échéant, mais supprimer headers
|
||||
# pour permettre son recalcul
|
||||
$this->headers = null;
|
||||
}
|
||||
$this->isrc = $this->idest = 0;
|
||||
foreach ($ws->getRowIterator() as $row) {
|
||||
$row = $row->toArray();
|
||||
foreach ($row as &$col) {
|
||||
$this->verifixCol($col);
|
||||
}; unset($col);
|
||||
if ($this->cookRow($row)) {
|
||||
yield $row;
|
||||
$this->idest++;
|
||||
}
|
||||
$this->isrc++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
$ss->close();
|
||||
}
|
||||
}
|
||||
}
|
11
src/ext/tab/SsBuilder.php
Normal file
11
src/ext/tab/SsBuilder.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace nulib\ext\tab;
|
||||
|
||||
use nulib\ext\spout\SpoutBuilder;
|
||||
|
||||
/**
|
||||
* Class SsBuilder: construction d'une feuille de calcul, pour envoi à
|
||||
* l'utilisateur
|
||||
*/
|
||||
class SsBuilder extends SpoutBuilder {
|
||||
}
|
9
src/ext/tab/SsReader.php
Normal file
9
src/ext/tab/SsReader.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace nulib\ext\tab;
|
||||
|
||||
use nulib\ext\spout\SpoutReader;
|
||||
use nulib\file\tab\TAbstractReader;
|
||||
|
||||
class SsReader extends SpoutReader {
|
||||
use TAbstractReader;
|
||||
}
|
93
src/ref/ext/spout/ref_builder.php
Normal file
93
src/ref/ext/spout/ref_builder.php
Normal file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
namespace nulib\ref\ext\spout;
|
||||
|
||||
use OpenSpout\Common\Entity\Style\Color;
|
||||
|
||||
class ref_builder {
|
||||
const PARAMS = [
|
||||
# Builder
|
||||
"output" => "?string",
|
||||
"schema" => "?array",
|
||||
"headers" => "?array",
|
||||
"use_headers" => "bool",
|
||||
"rows" => "?array",
|
||||
"cook_func" => "?callable",
|
||||
"ss_type" => "?string",
|
||||
# SpoutBuilder
|
||||
"type_numeric" => "bool",
|
||||
"type_date" => "bool",
|
||||
"spout" => self::PARAMS_SPOUT,
|
||||
"sheet" => self::PARAMS_SHEET,
|
||||
"sheet_name" => "?string",
|
||||
"sheet_view" => self::PARAMS_SHEET_VIEW,
|
||||
# TempStream
|
||||
"max_memory" => "?int",
|
||||
"throw_on_error" => "?bool",
|
||||
];
|
||||
|
||||
const PARAMS_SPOUT = [
|
||||
"->setColumnWidth" => ["float", ["int", null]],
|
||||
"->setColumnWidthForRange" => ["int", "int", "int"],
|
||||
"default_column_width" => "float",
|
||||
"default_row_height" => "float",
|
||||
"default_row_style" => self::STYLE,
|
||||
];
|
||||
|
||||
const PARAMS_SHEET = [
|
||||
"view" => self::PARAMS_SHEET_VIEW,
|
||||
"->setName" => ["string"],
|
||||
"->setIsVisible" => ["bool"],
|
||||
"header_style" => self::STYLE,
|
||||
"odd_style" => self::STYLE,
|
||||
"even_style" => self::STYLE,
|
||||
"different_odd_even" => "bool",
|
||||
];
|
||||
|
||||
const PARAMS_SHEET_VIEW = [];
|
||||
|
||||
const ROW_PARAMS = [
|
||||
"->setHeight" => ["float"],
|
||||
"merge_cells" => "array",
|
||||
"merge_offset" => "int",
|
||||
];
|
||||
|
||||
const COLORS = [
|
||||
"black" => Color::BLACK,
|
||||
"white" => Color::WHITE,
|
||||
"red" => Color::RED,
|
||||
"dark_red" => Color::DARK_RED,
|
||||
"orange" => Color::ORANGE,
|
||||
"yellow" => Color::YELLOW,
|
||||
"light_green" => Color::LIGHT_GREEN,
|
||||
"green" => Color::GREEN,
|
||||
"light_blue" => Color::LIGHT_BLUE,
|
||||
"blue" => Color::BLUE,
|
||||
"dark_blue" => Color::DARK_BLUE,
|
||||
"purple" => Color::PURPLE,
|
||||
"light_gray" => "EEEEEE",
|
||||
"gray" => "B2B2B2",
|
||||
];
|
||||
|
||||
const STYLE = [
|
||||
"font" => [
|
||||
"bold" => "bool",
|
||||
"italic" => "bool",
|
||||
"underline" => "bool",
|
||||
"strikethrough" => "bool",
|
||||
"name" => "string",
|
||||
"size" => "int",
|
||||
"color" => "string",
|
||||
],
|
||||
"bg_color" => "string",
|
||||
"align" => "string",
|
||||
"valign" => "string",
|
||||
"wrap" => "bool",
|
||||
"format" => "string",
|
||||
"border" => [
|
||||
"top" => ["color" => "string", "width" => "string", "style" => "string"],
|
||||
"right" => ["color" => "string", "width" => "string", "style" => "string"],
|
||||
"bottom" => ["color" => "string", "width" => "string", "style" => "string"],
|
||||
"left" => ["color" => "string", "width" => "string", "style" => "string"],
|
||||
],
|
||||
];
|
||||
}
|
5
src/ref/ext/spout/ref_builder_ods.php
Normal file
5
src/ref/ext/spout/ref_builder_ods.php
Normal file
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
namespace nulib\ref\ext\spout;
|
||||
|
||||
class ref_builder_ods extends ref_builder {
|
||||
}
|
36
src/ref/ext/spout/ref_builder_xlsx.php
Normal file
36
src/ref/ext/spout/ref_builder_xlsx.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace nulib\ref\ext\spout;
|
||||
|
||||
class ref_builder_xlsx extends ref_builder {
|
||||
const PARAMS_SHEET = [
|
||||
"view" => self::PARAMS_SHEET_VIEW,
|
||||
# copie de parent::SHEET
|
||||
"->setName" => ["string"],
|
||||
"->setIsVisible" => ["bool"],
|
||||
"header_style" => self::STYLE,
|
||||
"odd_style" => self::STYLE,
|
||||
"even_style" => self::STYLE,
|
||||
"different_odd_even" => "bool",
|
||||
];
|
||||
|
||||
const PARAMS_SHEET_VIEW = [
|
||||
"->setFreezeRow" => ["int"],
|
||||
"->setFreezeColumn" => ["string"],
|
||||
"->setZoomScale" => ["int"],
|
||||
"->setShowFormulas" => ["bool"],
|
||||
"->setShowGridLines" => ["bool"],
|
||||
"->setShowRowColHeaders" => ["bool"],
|
||||
"->setShowZeroes" => ["bool"],
|
||||
"->setRightToLeft" => ["bool"],
|
||||
"->setTabSelected" => ["bool"],
|
||||
"->setShowOutlineSymbols" => ["bool"],
|
||||
"->setDefaultGridColor" => ["bool"],
|
||||
"->setView" => ["string"],
|
||||
"->setTopLeftCell" => ["string"],
|
||||
"->setColorId" => ["int"],
|
||||
"->setZoomScaleNormal" => ["int"],
|
||||
"->setZoomScalePageLayoutView" => ["int"],
|
||||
"->setWorkbookViewId" => ["int"],
|
||||
# copie de parent::PARAMS_SHEET_VIEW
|
||||
];
|
||||
}
|
0
tests/.gitignore
vendored
Normal file
0
tests/.gitignore
vendored
Normal file
@ -268,9 +268,13 @@ class CellValueFormatter
|
||||
$dateObj->modify('+'.$secondsRemainder.'seconds');
|
||||
|
||||
if ($this->shouldFormatDates) {
|
||||
$styleNumberFormatCode = $this->styleManager->getNumberFormatCode($cellStyleId);
|
||||
$phpDateFormat = DateFormatHelper::toPHPDateFormat($styleNumberFormatCode);
|
||||
//$styleNumberFormatCode = $this->styleManager->getNumberFormatCode($cellStyleId);
|
||||
//$phpDateFormat = DateFormatHelper::toPHPDateFormat($styleNumberFormatCode);
|
||||
// Toujours utiliser le format français complet
|
||||
$phpDateFormat = "d/m/Y H:i:s";
|
||||
$cellValue = $dateObj->format($phpDateFormat);
|
||||
// Enlever la composante heure si elle n'existe pas
|
||||
$cellValue = preg_replace('/ 00:00:00$/', "", $cellValue);
|
||||
} else {
|
||||
$cellValue = $dateObj;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class OptionsManager extends OptionsManagerAbstract
|
||||
protected function setDefaultOptions()
|
||||
{
|
||||
$this->setOption(Options::TEMP_FOLDER, sys_get_temp_dir());
|
||||
$this->setOption(Options::SHOULD_FORMAT_DATES, false);
|
||||
$this->setOption(Options::SHOULD_FORMAT_DATES, true);
|
||||
$this->setOption(Options::SHOULD_PRESERVE_EMPTY_ROWS, false);
|
||||
$this->setOption(Options::SHOULD_USE_1904_DATES, false);
|
||||
}
|
||||
|
@ -22,6 +22,9 @@ abstract class WriterAbstract implements WriterInterface
|
||||
/** @var resource Pointer to the file/stream we will write to */
|
||||
protected $filePointer;
|
||||
|
||||
/** @var bool faut-il garder ouvert le flux quand close() est appelé? */
|
||||
protected $dontCloseFilePointer = false;
|
||||
|
||||
/** @var bool Indicates whether the writer has been opened or not */
|
||||
protected $isWriterOpened = false;
|
||||
|
||||
@ -57,6 +60,20 @@ abstract class WriterAbstract implements WriterInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function writeToStream($filePointer)
|
||||
{
|
||||
$this->outputFilePath = null;
|
||||
|
||||
$this->filePointer = $filePointer;
|
||||
$this->dontCloseFilePointer = true;
|
||||
$this->throwIfFilePointerIsNotAvailable();
|
||||
|
||||
$this->openWriter();
|
||||
$this->isWriterOpened = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -177,7 +194,7 @@ abstract class WriterAbstract implements WriterInterface
|
||||
|
||||
$this->closeWriter();
|
||||
|
||||
if (\is_resource($this->filePointer)) {
|
||||
if (!$this->dontCloseFilePointer && \is_resource($this->filePointer)) {
|
||||
$this->globalFunctionsHelper->fclose($this->filePointer);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user