Merge branch 'master' into docprops

This commit is contained in:
Mark Baker 2021-05-30 13:37:07 +02:00 committed by GitHub
commit bff2317a03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 1626 additions and 1397 deletions

View File

@ -27,9 +27,11 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Removed ### Removed
- Nothing. - Use of `nb` rather than `no` as the locale language code for Norsk Bokmål.
### Fixed ### Fixed
- Fixed error in COUPNCD() calculation for end of month [Issue #2116](https://github.com/PHPOffice/PhpSpreadsheet/issues/2116) - [PR #2119](https://github.com/PHPOffice/PhpSpreadsheet/pull/2119)
- Resolve default values when a null argument is passed for HLOOKUP(), VLOOKUP() and ADDRESS() functions [Issue #2120](https://github.com/PHPOffice/PhpSpreadsheet/issues/2120) - [PR #2121](https://github.com/PHPOffice/PhpSpreadsheet/pull/2121)
- Fixed incorrect R1C1 to A1 subtraction formula conversion (`R[-2]C-R[2]C`) [Issue #2076](https://github.com/PHPOffice/PhpSpreadsheet/pull/2076) [PR #2086](https://github.com/PHPOffice/PhpSpreadsheet/pull/2086) - Fixed incorrect R1C1 to A1 subtraction formula conversion (`R[-2]C-R[2]C`) [Issue #2076](https://github.com/PHPOffice/PhpSpreadsheet/pull/2076) [PR #2086](https://github.com/PHPOffice/PhpSpreadsheet/pull/2086)
- Correctly handle absolute A1 references when converting to R1C1 format [PR #2060](https://github.com/PHPOffice/PhpSpreadsheet/pull/2060) - Correctly handle absolute A1 references when converting to R1C1 format [PR #2060](https://github.com/PHPOffice/PhpSpreadsheet/pull/2060)
- Correct default fill style for conditional without a pattern defined [Issue #2035](https://github.com/PHPOffice/PhpSpreadsheet/issues/2035) [PR #2050](https://github.com/PHPOffice/PhpSpreadsheet/pull/2050) - Correct default fill style for conditional without a pattern defined [Issue #2035](https://github.com/PHPOffice/PhpSpreadsheet/issues/2035) [PR #2050](https://github.com/PHPOffice/PhpSpreadsheet/pull/2050)
@ -41,6 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
- Fixed issue with Xlsx@listWorksheetInfo not returning any data - Fixed issue with Xlsx@listWorksheetInfo not returning any data
- Fixed invalid arguments triggering mb_substr() error in LEFT(), MID() and RIGHT() text functions. [Issue #640](https://github.com/PHPOffice/PhpSpreadsheet/issues/640) - Fixed invalid arguments triggering mb_substr() error in LEFT(), MID() and RIGHT() text functions. [Issue #640](https://github.com/PHPOffice/PhpSpreadsheet/issues/640)
- Fix for [Issue #1916](https://github.com/PHPOffice/PhpSpreadsheet/issues/1916) - Invalid signature check for XML files - Fix for [Issue #1916](https://github.com/PHPOffice/PhpSpreadsheet/issues/1916) - Invalid signature check for XML files
- Fix change in `Font::setSize()` behavior for PHP8. [PR #2100](https://github.com/PHPOffice/PhpSpreadsheet/pull/2100)
## 1.17.1 - 2021-03-01 ## 1.17.1 - 2021-03-01
@ -109,7 +112,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Deprecated ### Deprecated
- Nothing. - All Excel Function implementations in `Calculation\Database`, `Calculation\DateTime`, `Calculation\Engineering`, `Calculation\Financial`, `Calculation\Logical`, `Calculation\LookupRef`, `Calculation\MathTrig`, `Calculation\Statistical`, `Calculation\TextData` and `Calculation\Web` have been moved to dedicated classes for individual functions or groups of related functions. See the docblocks against all the deprecated methods for details of the new methods to call instead. At some point, these old classes will be deleted.
### Removed ### Removed

View File

@ -2,12 +2,13 @@
<?php <?php
use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\DocumentGenerator; use PhpOffice\PhpSpreadsheetInfra\DocumentGenerator;
require_once 'vendor/autoload.php'; require_once 'vendor/autoload.php';
try { try {
$phpSpreadsheetFunctionsProperty = (new ReflectionClass(Calculation::class))->getProperty('phpSpreadsheetFunctions'); $phpSpreadsheetFunctionsProperty = (new ReflectionClass(Calculation::class))
->getProperty('phpSpreadsheetFunctions');
$phpSpreadsheetFunctionsProperty->setAccessible(true); $phpSpreadsheetFunctionsProperty->setAccessible(true);
$phpSpreadsheetFunctions = $phpSpreadsheetFunctionsProperty->getValue(); $phpSpreadsheetFunctions = $phpSpreadsheetFunctionsProperty->getValue();
ksort($phpSpreadsheetFunctions); ksort($phpSpreadsheetFunctions);

View File

@ -7,14 +7,16 @@ use PhpOffice\PhpSpreadsheetInfra\LocaleGenerator;
require_once 'vendor/autoload.php'; require_once 'vendor/autoload.php';
try { try {
$phpSpreadsheetFunctionsProperty = (new ReflectionClass(Calculation::class))->getProperty('phpSpreadsheetFunctions'); $phpSpreadsheetFunctionsProperty = (new ReflectionClass(Calculation::class))
->getProperty('phpSpreadsheetFunctions');
$phpSpreadsheetFunctionsProperty->setAccessible(true); $phpSpreadsheetFunctionsProperty->setAccessible(true);
$phpSpreadsheetFunctions = $phpSpreadsheetFunctionsProperty->getValue(); $phpSpreadsheetFunctions = $phpSpreadsheetFunctionsProperty->getValue();
$localeGenerator = new LocaleGenerator( $localeGenerator = new LocaleGenerator(
__DIR__ . '/../src/PhpSpreadsheet/Calculation/locale/', realpath(__DIR__ . '/../src/PhpSpreadsheet/Calculation/locale/'),
'Translations.xlsx', 'Translations.xlsx',
$phpSpreadsheetFunctions $phpSpreadsheetFunctions,
true
); );
$localeGenerator->generateLocales(); $localeGenerator->generateLocales();
} catch (\Exception $e) { } catch (\Exception $e) {

View File

@ -1,195 +0,0 @@
<?php
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
error_reporting(E_ALL);
set_time_limit(0);
date_default_timezone_set('UTC');
// Adjust the path as required to reference the PHPSpreadsheet Bootstrap file
require_once __DIR__ . '/../samples/Bootstrap.php';
class ExcelFunction
{
public $category;
public $functionName;
public $excelVersion;
public $implementation;
public function __construct(string $category, string $functionName, string $excelVersion, string $implementation)
{
$this->category = $category;
$this->functionName = $functionName;
$this->excelVersion = $excelVersion;
$this->implementation = $implementation;
}
}
class ColumnSettings
{
public $length;
public $title;
public $underline;
public function __construct(string $title, int $length)
{
$this->length = $length;
$this->title = str_pad($title, $length, ' ');
$this->underline = str_repeat('-', $length);
}
}
class ListBuilder
{
private $inputFileName;
public $list = [];
public function __construct(string $inputFileName)
{
$this->inputFileName = $inputFileName;
$this->buildList();
uasort(
$this->list,
function ($a, $b) {
$aSortName = str_replace('.', '', $a->functionName, $aCount) . str_repeat('.', $aCount);
$bSortName = str_replace('.', '', $b->functionName, $bCount) . str_repeat('.', $bCount);
return $aSortName <=> $bSortName;
}
);
}
private function buildList(): void
{
$inputFile = new \SplFileObject($this->inputFileName);
$category = null;
while (!$inputFile->eof()) {
$line = $inputFile->fgets();
if (strpos($line, '#') === 0) {
if (strpos($line, '##') === 0) {
$category = trim(substr($line, 3));
}
continue;
}
$lineData = explode('|', $line);
if (count($lineData) <= 1 || strpos($line, '--') === 0) {
continue;
}
$functionData = array_map('trim', $lineData);
if ($functionData[0] === 'Excel Function') {
continue;
}
$function = new ExcelFunction($category, ...$functionData);
if (array_key_exists($function->functionName, $this->list)) {
echo " ERROR: Duplicate entry for function {$function->functionName} in master file", PHP_EOL;
continue;
}
$this->list[$function->functionName] = $function;
}
}
}
class AlphabeticFileWriter
{
private $outputFileName;
private $outputFile;
public function __construct(string $outputFileName)
{
$this->outputFileName = $outputFileName;
}
public function generate(ExcelFunction ...$functionList): void
{
$this->outputFile = new \SplFileObject($this->outputFileName, 'w');
$this->excelFunctionColumnSettings = new ColumnSettings('Excel Function', max(array_map('strlen', array_column($functionList, 'functionName'))));
$this->categoryColumnSettings = new ColumnSettings('Category', max(array_map('strlen', array_column($functionList, 'category'))));
$this->excelVersionColumnSettings = new ColumnSettings('Excel Version', 13);
$this->phpSpreadsheetFunctionColumnSettings = new ColumnSettings('PhpSpreadsheet Function', 24);
$this->header();
$this->body(...$functionList);
}
private function header(): void
{
$this->outputFile->fwrite('# Function list by name' . PHP_EOL);
}
private function body(ExcelFunction ...$functionList): void
{
$initialCharacter = null;
foreach ($functionList as $excelFunction) {
if (substr($excelFunction->functionName, 0, 1) !== $initialCharacter) {
$initialCharacter = $this->subHeader($excelFunction);
}
$functionName = str_pad($excelFunction->functionName, $this->excelFunctionColumnSettings->length, ' ');
$category = str_pad($excelFunction->category, $this->categoryColumnSettings->length, ' ');
$excelVersion = str_pad($excelFunction->excelVersion, $this->excelVersionColumnSettings->length, ' ');
$this->outputFile->fwrite("{$functionName} | {$category} | {$excelVersion} | {$excelFunction->implementation}" . PHP_EOL);
}
}
private function subHeader(ExcelFunction $excelFunction)
{
$initialCharacter = substr($excelFunction->functionName, 0, 1);
$this->outputFile->fwrite(PHP_EOL . "## {$initialCharacter}" . PHP_EOL . PHP_EOL);
$this->outputFile->fwrite("{$this->excelFunctionColumnSettings->title} | {$this->categoryColumnSettings->title} | {$this->excelVersionColumnSettings->title} | {$this->phpSpreadsheetFunctionColumnSettings->title}" . PHP_EOL);
$this->outputFile->fwrite("{$this->excelFunctionColumnSettings->underline}-|-{$this->categoryColumnSettings->underline}-|-{$this->excelVersionColumnSettings->underline}-|-{$this->phpSpreadsheetFunctionColumnSettings->underline}" . PHP_EOL);
return $initialCharacter;
}
}
$folder = __DIR__ . '/../docs/references/';
$inputFileName = 'function-list-by-category.md';
$outputFileName = 'function-list-by-name.md';
echo "Building list of functions from master file {$inputFileName}", PHP_EOL;
$listBuilder = new ListBuilder($folder . $inputFileName);
echo "Building new documentation list of alphabetic functions in {$outputFileName}", PHP_EOL;
$alphabeticFileWriter = new AlphabeticFileWriter($folder . $outputFileName);
$alphabeticFileWriter->generate(...array_values($listBuilder->list));
echo 'Identifying discrepancies between the master file and the Calculation Engine codebase', PHP_EOL;
$definedFunctions = (new Calculation())->getFunctions();
foreach ($listBuilder->list as $excelFunction) {
if (!array_key_exists($excelFunction->functionName, $definedFunctions)) {
echo " ERROR: Function {$excelFunction->functionName}() of category {$excelFunction->category} is not defined in the Calculation Engine", PHP_EOL;
} elseif (array_key_exists($excelFunction->functionName, $definedFunctions) && $excelFunction->implementation === '**Not yet Implemented**') {
if ($definedFunctions[$excelFunction->functionName]['functionCall'] !== [Functions::class, 'DUMMY']) {
echo " ERROR: Function {$excelFunction->functionName}() of category {$excelFunction->category} is flagged as not yet implemented in the documentation", PHP_EOL;
echo ' but does have an implementation in the code', PHP_EOL;
}
}
}
foreach ($definedFunctions as $definedFunction => $definedFunctionDetail) {
if (!array_key_exists($definedFunction, $listBuilder->list)) {
echo " ERROR: Function {$definedFunction}() of category {$definedFunctionDetail['category']} is defined in the Calculation Engine, but not in the master file", PHP_EOL;
}
}

352
composer.lock generated
View File

@ -133,16 +133,16 @@
}, },
{ {
"name": "markbaker/complex", "name": "markbaker/complex",
"version": "2.0.0", "version": "2.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/MarkBaker/PHPComplex.git", "url": "https://github.com/MarkBaker/PHPComplex.git",
"reference": "9999f1432fae467bc93c53f357105b4c31bb994c" "reference": "d18272926d58065140314c01e18ec3dd7ae854ea"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/9999f1432fae467bc93c53f357105b4c31bb994c", "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/d18272926d58065140314c01e18ec3dd7ae854ea",
"reference": "9999f1432fae467bc93c53f357105b4c31bb994c", "reference": "d18272926d58065140314c01e18ec3dd7ae854ea",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -151,11 +151,7 @@
"require-dev": { "require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"phpcompatibility/php-compatibility": "^9.0", "phpcompatibility/php-compatibility": "^9.0",
"phpdocumentor/phpdocumentor": "2.*",
"phploc/phploc": "^4.0",
"phpmd/phpmd": "2.*",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.3", "phpunit/phpunit": "^7.0 || ^8.0 || ^9.3",
"sebastian/phpcpd": "^4.0",
"squizlabs/php_codesniffer": "^3.4" "squizlabs/php_codesniffer": "^3.4"
}, },
"type": "library", "type": "library",
@ -226,22 +222,22 @@
], ],
"support": { "support": {
"issues": "https://github.com/MarkBaker/PHPComplex/issues", "issues": "https://github.com/MarkBaker/PHPComplex/issues",
"source": "https://github.com/MarkBaker/PHPComplex/tree/PHP8" "source": "https://github.com/MarkBaker/PHPComplex/tree/2.0.2"
}, },
"time": "2020-08-26T10:42:07+00:00" "time": "2021-05-24T10:53:30+00:00"
}, },
{ {
"name": "markbaker/matrix", "name": "markbaker/matrix",
"version": "2.1.2", "version": "2.1.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/MarkBaker/PHPMatrix.git", "url": "https://github.com/MarkBaker/PHPMatrix.git",
"reference": "361c0f545c3172ee26c3d596a0aa03f0cef65e6a" "reference": "174395a901b5ba0925f1d790fa91bab531074b61"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/361c0f545c3172ee26c3d596a0aa03f0cef65e6a", "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/174395a901b5ba0925f1d790fa91bab531074b61",
"reference": "361c0f545c3172ee26c3d596a0aa03f0cef65e6a", "reference": "174395a901b5ba0925f1d790fa91bab531074b61",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -300,32 +296,32 @@
], ],
"support": { "support": {
"issues": "https://github.com/MarkBaker/PHPMatrix/issues", "issues": "https://github.com/MarkBaker/PHPMatrix/issues",
"source": "https://github.com/MarkBaker/PHPMatrix/tree/2.1.2" "source": "https://github.com/MarkBaker/PHPMatrix/tree/2.1.3"
}, },
"time": "2021-01-23T16:37:31+00:00" "time": "2021-05-25T15:42:17+00:00"
}, },
{ {
"name": "myclabs/php-enum", "name": "myclabs/php-enum",
"version": "1.7.7", "version": "1.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/myclabs/php-enum.git", "url": "https://github.com/myclabs/php-enum.git",
"reference": "d178027d1e679832db9f38248fcc7200647dc2b7" "reference": "46cf3d8498b095bd33727b13fd5707263af99421"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/myclabs/php-enum/zipball/d178027d1e679832db9f38248fcc7200647dc2b7", "url": "https://api.github.com/repos/myclabs/php-enum/zipball/46cf3d8498b095bd33727b13fd5707263af99421",
"reference": "d178027d1e679832db9f38248fcc7200647dc2b7", "reference": "46cf3d8498b095bd33727b13fd5707263af99421",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-json": "*", "ext-json": "*",
"php": ">=7.1" "php": "^7.3 || ^8.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^7", "phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "1.*", "squizlabs/php_codesniffer": "1.*",
"vimeo/psalm": "^3.8" "vimeo/psalm": "^4.5.1"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -350,7 +346,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/myclabs/php-enum/issues", "issues": "https://github.com/myclabs/php-enum/issues",
"source": "https://github.com/myclabs/php-enum/tree/1.7.7" "source": "https://github.com/myclabs/php-enum/tree/1.8.0"
}, },
"funding": [ "funding": [
{ {
@ -362,7 +358,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2020-11-14T18:14:52+00:00" "time": "2021-02-15T16:11:48+00:00"
}, },
{ {
"name": "psr/http-client", "name": "psr/http-client",
@ -659,16 +655,16 @@
"packages-dev": [ "packages-dev": [
{ {
"name": "composer/semver", "name": "composer/semver",
"version": "3.2.4", "version": "3.2.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/semver.git", "url": "https://github.com/composer/semver.git",
"reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464" "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", "url": "https://api.github.com/repos/composer/semver/zipball/31f3ea725711245195f62e54ffa402d8ef2fdba9",
"reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", "reference": "31f3ea725711245195f62e54ffa402d8ef2fdba9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -720,7 +716,7 @@
"support": { "support": {
"irc": "irc://irc.freenode.org/composer", "irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/semver/issues", "issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.2.4" "source": "https://github.com/composer/semver/tree/3.2.5"
}, },
"funding": [ "funding": [
{ {
@ -736,20 +732,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2020-11-13T08:59:24+00:00" "time": "2021-05-24T12:41:47+00:00"
}, },
{ {
"name": "composer/xdebug-handler", "name": "composer/xdebug-handler",
"version": "1.4.6", "version": "2.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/xdebug-handler.git", "url": "https://github.com/composer/xdebug-handler.git",
"reference": "f27e06cd9675801df441b3656569b328e04aa37c" "reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f27e06cd9675801df441b3656569b328e04aa37c", "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/964adcdd3a28bf9ed5d9ac6450064e0d71ed7496",
"reference": "f27e06cd9675801df441b3656569b328e04aa37c", "reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -784,7 +780,7 @@
"support": { "support": {
"irc": "irc://irc.freenode.org/composer", "irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/xdebug-handler/issues", "issues": "https://github.com/composer/xdebug-handler/issues",
"source": "https://github.com/composer/xdebug-handler/tree/1.4.6" "source": "https://github.com/composer/xdebug-handler/tree/2.0.1"
}, },
"funding": [ "funding": [
{ {
@ -800,7 +796,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-03-25T17:01:18+00:00" "time": "2021-05-05T19:37:51+00:00"
}, },
{ {
"name": "dealerdirect/phpcodesniffer-composer-installer", "name": "dealerdirect/phpcodesniffer-composer-installer",
@ -875,28 +871,30 @@
}, },
{ {
"name": "doctrine/annotations", "name": "doctrine/annotations",
"version": "1.12.1", "version": "1.13.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/annotations.git", "url": "https://github.com/doctrine/annotations.git",
"reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b" "reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/b17c5014ef81d212ac539f07a1001832df1b6d3b", "url": "https://api.github.com/repos/doctrine/annotations/zipball/e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f",
"reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b", "reference": "e6e7b7d5b45a2f2abc5460cc6396480b2b1d321f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/lexer": "1.*", "doctrine/lexer": "1.*",
"ext-tokenizer": "*", "ext-tokenizer": "*",
"php": "^7.1 || ^8.0" "php": "^7.1 || ^8.0",
"psr/cache": "^1 || ^2 || ^3"
}, },
"require-dev": { "require-dev": {
"doctrine/cache": "1.*", "doctrine/cache": "^1.11 || ^2.0",
"doctrine/coding-standard": "^6.0 || ^8.1", "doctrine/coding-standard": "^6.0 || ^8.1",
"phpstan/phpstan": "^0.12.20", "phpstan/phpstan": "^0.12.20",
"phpunit/phpunit": "^7.5 || ^9.1.5" "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5",
"symfony/cache": "^4.4 || ^5.2"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -939,9 +937,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/annotations/issues", "issues": "https://github.com/doctrine/annotations/issues",
"source": "https://github.com/doctrine/annotations/tree/1.12.1" "source": "https://github.com/doctrine/annotations/tree/1.13.1"
}, },
"time": "2021-02-21T21:00:45+00:00" "time": "2021-05-16T18:07:53+00:00"
}, },
{ {
"name": "doctrine/instantiator", "name": "doctrine/instantiator",
@ -1166,21 +1164,21 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v2.18.4", "version": "v2.19.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
"reference": "06f764e3cb6d60822d8f5135205f9d32b5508a31" "reference": "d5b8a9d852b292c2f8a035200fa6844b1f82300b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/06f764e3cb6d60822d8f5135205f9d32b5508a31", "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/d5b8a9d852b292c2f8a035200fa6844b1f82300b",
"reference": "06f764e3cb6d60822d8f5135205f9d32b5508a31", "reference": "d5b8a9d852b292c2f8a035200fa6844b1f82300b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"composer/semver": "^1.4 || ^2.0 || ^3.0", "composer/semver": "^1.4 || ^2.0 || ^3.0",
"composer/xdebug-handler": "^1.2", "composer/xdebug-handler": "^1.2 || ^2.0",
"doctrine/annotations": "^1.2", "doctrine/annotations": "^1.2",
"ext-json": "*", "ext-json": "*",
"ext-tokenizer": "*", "ext-tokenizer": "*",
@ -1223,6 +1221,11 @@
"php-cs-fixer" "php-cs-fixer"
], ],
"type": "application", "type": "application",
"extra": {
"branch-alias": {
"dev-master": "2.19-dev"
}
},
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"PhpCsFixer\\": "src/" "PhpCsFixer\\": "src/"
@ -1258,7 +1261,7 @@
"description": "A tool to automatically fix PHP code style", "description": "A tool to automatically fix PHP code style",
"support": { "support": {
"issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues",
"source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.18.4" "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.19.0"
}, },
"funding": [ "funding": [
{ {
@ -1266,7 +1269,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2021-03-20T14:52:33+00:00" "time": "2021-05-03T21:43:24+00:00"
}, },
{ {
"name": "jpgraph/jpgraph", "name": "jpgraph/jpgraph",
@ -1315,16 +1318,16 @@
}, },
{ {
"name": "mpdf/mpdf", "name": "mpdf/mpdf",
"version": "v8.0.10", "version": "v8.0.11",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/mpdf/mpdf.git", "url": "https://github.com/mpdf/mpdf.git",
"reference": "1333a962cd2f7ae1a127b7534b7734b58179186f" "reference": "af17afbbfa0b6ce76defc8da5d02a73d54f94c64"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/mpdf/mpdf/zipball/1333a962cd2f7ae1a127b7534b7734b58179186f", "url": "https://api.github.com/repos/mpdf/mpdf/zipball/af17afbbfa0b6ce76defc8da5d02a73d54f94c64",
"reference": "1333a962cd2f7ae1a127b7534b7734b58179186f", "reference": "af17afbbfa0b6ce76defc8da5d02a73d54f94c64",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1386,7 +1389,7 @@
"type": "custom" "type": "custom"
} }
], ],
"time": "2021-01-08T14:59:28+00:00" "time": "2021-05-12T14:18:06+00:00"
}, },
{ {
"name": "myclabs/deep-copy", "name": "myclabs/deep-copy",
@ -2036,16 +2039,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "0.12.82", "version": "0.12.88",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "3920f0fb0aff39263d3a4cb0bca120a67a1a6a11" "reference": "464d1a81af49409c41074aa6640ed0c4cbd9bb68"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/3920f0fb0aff39263d3a4cb0bca120a67a1a6a11", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/464d1a81af49409c41074aa6640ed0c4cbd9bb68",
"reference": "3920f0fb0aff39263d3a4cb0bca120a67a1a6a11", "reference": "464d1a81af49409c41074aa6640ed0c4cbd9bb68",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2076,7 +2079,7 @@
"description": "PHPStan - PHP Static Analysis Tool", "description": "PHPStan - PHP Static Analysis Tool",
"support": { "support": {
"issues": "https://github.com/phpstan/phpstan/issues", "issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/0.12.82" "source": "https://github.com/phpstan/phpstan/tree/0.12.88"
}, },
"funding": [ "funding": [
{ {
@ -2092,25 +2095,25 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-03-19T06:08:17+00:00" "time": "2021-05-17T12:24:49+00:00"
}, },
{ {
"name": "phpstan/phpstan-phpunit", "name": "phpstan/phpstan-phpunit",
"version": "0.12.18", "version": "0.12.19",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git", "url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72" "reference": "52f7072ddc5f81492f9d2de65a24813a48c90b18"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72", "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/52f7072ddc5f81492f9d2de65a24813a48c90b18",
"reference": "ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72", "reference": "52f7072ddc5f81492f9d2de65a24813a48c90b18",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.1 || ^8.0", "php": "^7.1 || ^8.0",
"phpstan/phpstan": "^0.12.60" "phpstan/phpstan": "^0.12.86"
}, },
"conflict": { "conflict": {
"phpunit/phpunit": "<7.0" "phpunit/phpunit": "<7.0"
@ -2145,9 +2148,9 @@
"description": "PHPUnit extensions and rules for PHPStan", "description": "PHPUnit extensions and rules for PHPStan",
"support": { "support": {
"issues": "https://github.com/phpstan/phpstan-phpunit/issues", "issues": "https://github.com/phpstan/phpstan-phpunit/issues",
"source": "https://github.com/phpstan/phpstan-phpunit/tree/0.12.18" "source": "https://github.com/phpstan/phpstan-phpunit/tree/0.12.19"
}, },
"time": "2021-03-06T11:51:27+00:00" "time": "2021-04-30T11:10:37+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
@ -2388,29 +2391,29 @@
}, },
{ {
"name": "phpunit/php-token-stream", "name": "phpunit/php-token-stream",
"version": "3.1.2", "version": "4.0.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git", "url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "472b687829041c24b25f475e14c2f38a09edf1c2" "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/472b687829041c24b25f475e14c2f38a09edf1c2", "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3",
"reference": "472b687829041c24b25f475e14c2f38a09edf1c2", "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-tokenizer": "*", "ext-tokenizer": "*",
"php": ">=7.1" "php": "^7.3 || ^8.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^7.0" "phpunit/phpunit": "^9.0"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "3.1-dev" "dev-master": "4.0-dev"
} }
}, },
"autoload": { "autoload": {
@ -2435,7 +2438,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/php-token-stream/issues", "issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
"source": "https://github.com/sebastianbergmann/php-token-stream/tree/3.1.2" "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master"
}, },
"funding": [ "funding": [
{ {
@ -2444,7 +2447,7 @@
} }
], ],
"abandoned": true, "abandoned": true,
"time": "2020-11-30T08:38:46+00:00" "time": "2020-08-04T08:28:15+00:00"
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
@ -2543,6 +2546,55 @@
], ],
"time": "2021-03-17T07:27:54+00:00" "time": "2021-03-17T07:27:54+00:00"
}, },
{
"name": "psr/cache",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/cache.git",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
"reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Cache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for caching libraries",
"keywords": [
"cache",
"psr",
"psr-6"
],
"support": {
"source": "https://github.com/php-fig/cache/tree/master"
},
"time": "2016-08-06T20:24:11+00:00"
},
{ {
"name": "psr/container", "name": "psr/container",
"version": "1.1.1", "version": "1.1.1",
@ -2643,16 +2695,16 @@
}, },
{ {
"name": "psr/log", "name": "psr/log",
"version": "1.1.3", "version": "1.1.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-fig/log.git", "url": "https://github.com/php-fig/log.git",
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" "reference": "d49695b909c3b7628b6289db5479a1c204601f11"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", "reference": "d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2676,7 +2728,7 @@
"authors": [ "authors": [
{ {
"name": "PHP-FIG", "name": "PHP-FIG",
"homepage": "http://www.php-fig.org/" "homepage": "https://www.php-fig.org/"
} }
], ],
"description": "Common interface for logging libraries", "description": "Common interface for logging libraries",
@ -2687,9 +2739,9 @@
"psr-3" "psr-3"
], ],
"support": { "support": {
"source": "https://github.com/php-fig/log/tree/1.1.3" "source": "https://github.com/php-fig/log/tree/1.1.4"
}, },
"time": "2020-03-23T09:12:05+00:00" "time": "2021-05-03T11:20:27+00:00"
}, },
{ {
"name": "sabberworm/php-css-parser", "name": "sabberworm/php-css-parser",
@ -3543,16 +3595,16 @@
}, },
{ {
"name": "squizlabs/php_codesniffer", "name": "squizlabs/php_codesniffer",
"version": "3.5.8", "version": "3.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "9d583721a7157ee997f235f327de038e7ea6dac4" "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4", "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ffced0d2c8fa8e6cdc4d695a743271fab6c38625",
"reference": "9d583721a7157ee997f235f327de038e7ea6dac4", "reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3595,20 +3647,20 @@
"source": "https://github.com/squizlabs/PHP_CodeSniffer", "source": "https://github.com/squizlabs/PHP_CodeSniffer",
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
}, },
"time": "2020-10-23T02:01:07+00:00" "time": "2021-04-09T00:54:41+00:00"
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v5.2.5", "version": "v5.2.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "938ebbadae1b0a9c9d1ec313f87f9708609f1b79" "reference": "864568fdc0208b3eba3638b6000b69d2386e6768"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/938ebbadae1b0a9c9d1ec313f87f9708609f1b79", "url": "https://api.github.com/repos/symfony/console/zipball/864568fdc0208b3eba3638b6000b69d2386e6768",
"reference": "938ebbadae1b0a9c9d1ec313f87f9708609f1b79", "reference": "864568fdc0208b3eba3638b6000b69d2386e6768",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3676,7 +3728,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v5.2.5" "source": "https://github.com/symfony/console/tree/v5.2.8"
}, },
"funding": [ "funding": [
{ {
@ -3692,20 +3744,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-03-06T13:42:15+00:00" "time": "2021-05-11T15:45:21+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
"version": "v2.2.0", "version": "v2.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git", "url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665" "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665", "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627",
"reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665", "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3714,7 +3766,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.2-dev" "dev-main": "2.4-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/contracts", "name": "symfony/contracts",
@ -3743,7 +3795,7 @@
"description": "A generic function and convention to trigger deprecation notices", "description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/master" "source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0"
}, },
"funding": [ "funding": [
{ {
@ -3759,7 +3811,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2020-09-07T11:33:47+00:00" "time": "2021-03-23T23:28:01+00:00"
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
@ -3848,16 +3900,16 @@
}, },
{ {
"name": "symfony/event-dispatcher-contracts", "name": "symfony/event-dispatcher-contracts",
"version": "v2.2.0", "version": "v2.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git", "url": "https://github.com/symfony/event-dispatcher-contracts.git",
"reference": "0ba7d54483095a198fa51781bc608d17e84dffa2" "reference": "69fee1ad2332a7cbab3aca13591953da9cdb7a11"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/0ba7d54483095a198fa51781bc608d17e84dffa2", "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/69fee1ad2332a7cbab3aca13591953da9cdb7a11",
"reference": "0ba7d54483095a198fa51781bc608d17e84dffa2", "reference": "69fee1ad2332a7cbab3aca13591953da9cdb7a11",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3870,7 +3922,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.2-dev" "dev-main": "2.4-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/contracts", "name": "symfony/contracts",
@ -3907,7 +3959,7 @@
"standards" "standards"
], ],
"support": { "support": {
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.2.0" "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.4.0"
}, },
"funding": [ "funding": [
{ {
@ -3923,20 +3975,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2020-09-07T11:33:47+00:00" "time": "2021-03-23T23:28:01+00:00"
}, },
{ {
"name": "symfony/filesystem", "name": "symfony/filesystem",
"version": "v5.2.4", "version": "v5.2.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/filesystem.git", "url": "https://github.com/symfony/filesystem.git",
"reference": "710d364200997a5afde34d9fe57bd52f3cc1e108" "reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/710d364200997a5afde34d9fe57bd52f3cc1e108", "url": "https://api.github.com/repos/symfony/filesystem/zipball/056e92acc21d977c37e6ea8e97374b2a6c8551b0",
"reference": "710d364200997a5afde34d9fe57bd52f3cc1e108", "reference": "056e92acc21d977c37e6ea8e97374b2a6c8551b0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3969,7 +4021,7 @@
"description": "Provides basic utilities for the filesystem", "description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/filesystem/tree/v5.2.4" "source": "https://github.com/symfony/filesystem/tree/v5.2.7"
}, },
"funding": [ "funding": [
{ {
@ -3985,20 +4037,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-02-12T10:38:38+00:00" "time": "2021-04-01T10:42:13+00:00"
}, },
{ {
"name": "symfony/finder", "name": "symfony/finder",
"version": "v5.2.4", "version": "v5.2.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/finder.git", "url": "https://github.com/symfony/finder.git",
"reference": "0d639a0943822626290d169965804f79400e6a04" "reference": "ccccb9d48ca42757dd12f2ca4bf857a4e217d90d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04", "url": "https://api.github.com/repos/symfony/finder/zipball/ccccb9d48ca42757dd12f2ca4bf857a4e217d90d",
"reference": "0d639a0943822626290d169965804f79400e6a04", "reference": "ccccb9d48ca42757dd12f2ca4bf857a4e217d90d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4030,7 +4082,7 @@
"description": "Finds files and directories via an intuitive fluent interface", "description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/finder/tree/v5.2.4" "source": "https://github.com/symfony/finder/tree/v5.2.9"
}, },
"funding": [ "funding": [
{ {
@ -4046,7 +4098,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-02-15T18:55:04+00:00" "time": "2021-05-16T13:07:46+00:00"
}, },
{ {
"name": "symfony/options-resolver", "name": "symfony/options-resolver",
@ -4669,16 +4721,16 @@
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v5.2.4", "version": "v5.2.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/process.git", "url": "https://github.com/symfony/process.git",
"reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f" "reference": "98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/313a38f09c77fbcdc1d223e57d368cea76a2fd2f", "url": "https://api.github.com/repos/symfony/process/zipball/98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e",
"reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f", "reference": "98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4711,7 +4763,7 @@
"description": "Executes commands in sub-processes", "description": "Executes commands in sub-processes",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/process/tree/v5.2.4" "source": "https://github.com/symfony/process/tree/v5.3.0-BETA1"
}, },
"funding": [ "funding": [
{ {
@ -4727,25 +4779,25 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-01-27T10:15:41+00:00" "time": "2021-04-08T10:27:02+00:00"
}, },
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",
"version": "v2.2.0", "version": "v2.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/service-contracts.git", "url": "https://github.com/symfony/service-contracts.git",
"reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1" "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1", "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb",
"reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1", "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.2.5",
"psr/container": "^1.0" "psr/container": "^1.1"
}, },
"suggest": { "suggest": {
"symfony/service-implementation": "" "symfony/service-implementation": ""
@ -4753,7 +4805,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.2-dev" "dev-main": "2.4-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/contracts", "name": "symfony/contracts",
@ -4790,7 +4842,7 @@
"standards" "standards"
], ],
"support": { "support": {
"source": "https://github.com/symfony/service-contracts/tree/master" "source": "https://github.com/symfony/service-contracts/tree/v2.4.0"
}, },
"funding": [ "funding": [
{ {
@ -4806,20 +4858,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2020-09-07T11:33:47+00:00" "time": "2021-04-01T10:43:52+00:00"
}, },
{ {
"name": "symfony/stopwatch", "name": "symfony/stopwatch",
"version": "v5.2.4", "version": "v5.2.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/stopwatch.git", "url": "https://github.com/symfony/stopwatch.git",
"reference": "b12274acfab9d9850c52583d136a24398cdf1a0c" "reference": "d99310c33e833def36419c284f60e8027d359678"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/b12274acfab9d9850c52583d136a24398cdf1a0c", "url": "https://api.github.com/repos/symfony/stopwatch/zipball/d99310c33e833def36419c284f60e8027d359678",
"reference": "b12274acfab9d9850c52583d136a24398cdf1a0c", "reference": "d99310c33e833def36419c284f60e8027d359678",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4852,7 +4904,7 @@
"description": "Provides a way to profile code", "description": "Provides a way to profile code",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/stopwatch/tree/v5.2.4" "source": "https://github.com/symfony/stopwatch/tree/v5.3.0-BETA1"
}, },
"funding": [ "funding": [
{ {
@ -4868,20 +4920,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-01-27T10:15:41+00:00" "time": "2021-03-29T15:28:41+00:00"
}, },
{ {
"name": "symfony/string", "name": "symfony/string",
"version": "v5.2.4", "version": "v5.2.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/string.git", "url": "https://github.com/symfony/string.git",
"reference": "4e78d7d47061fa183639927ec40d607973699609" "reference": "01b35eb64cac8467c3f94cd0ce2d0d376bb7d1db"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/4e78d7d47061fa183639927ec40d607973699609", "url": "https://api.github.com/repos/symfony/string/zipball/01b35eb64cac8467c3f94cd0ce2d0d376bb7d1db",
"reference": "4e78d7d47061fa183639927ec40d607973699609", "reference": "01b35eb64cac8467c3f94cd0ce2d0d376bb7d1db",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4935,7 +4987,7 @@
"utf8" "utf8"
], ],
"support": { "support": {
"source": "https://github.com/symfony/string/tree/v5.2.4" "source": "https://github.com/symfony/string/tree/v5.2.8"
}, },
"funding": [ "funding": [
{ {
@ -4951,7 +5003,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-02-16T10:20:28+00:00" "time": "2021-05-10T14:56:10+00:00"
}, },
{ {
"name": "tecnickcom/tcpdf", "name": "tecnickcom/tcpdf",

View File

@ -71,7 +71,7 @@ library.
### Csv ### Csv
Comma Separated Value (CSV) file format is a common structuring strategy Comma Separated Value (CSV) file format is a common structuring strategy
for text format files. In CSV flies, each line in the file represents a for text format files. In CSV files, each line in the file represents a
row of data and (within each line of the file) the different data fields row of data and (within each line of the file) the different data fields
(or columns) are separated from one another using a comma (`,`). If a (or columns) are separated from one another using a comma (`,`). If a
data field contains a comma, then it should be enclosed (typically in data field contains a comma, then it should be enclosed (typically in

View File

@ -1,6 +1,6 @@
# Memory saving # Memory saving
PhpSpreadsheet uses an average of about 1k per cell in your worksheets, so PhpSpreadsheet uses an average of about 1k per cell (1.6k on 64-bit PHP) in your worksheets, so
large workbooks can quickly use up available memory. Cell caching large workbooks can quickly use up available memory. Cell caching
provides a mechanism that allows PhpSpreadsheet to maintain the cell provides a mechanism that allows PhpSpreadsheet to maintain the cell
objects in a smaller size of memory, or off-memory (eg: on disk, in APCu, objects in a smaller size of memory, or off-memory (eg: on disk, in APCu,

View File

@ -139,6 +139,11 @@ $reader->setReadFilter( new MyReadFilter() );
$spreadsheet = $reader->load("06largescale.xlsx"); $spreadsheet = $reader->load("06largescale.xlsx");
``` ```
Read Filtering does not renumber cell rows and columns. If you filter to read only rows 100-200, cells that you read will still be numbered A100-A200, not A1-A101. Cells A1-A99 will not be loaded, but if you then try to call `getCell()` for a cell outside your loaded range, then PHPSpreadsheet will create a new cell with a null value.
Methods such as `toArray()` assume that all cells in a spreadsheet has been loaded from A1, so will return null values for rows and columns that fall outside your filter range: it is recommended that you keep track of the range that your filter has requested, and use `rangeToArray()` instead.
### \PhpOffice\PhpSpreadsheet\Writer\Xlsx ### \PhpOffice\PhpSpreadsheet\Writer\Xlsx
#### Writing a spreadsheet #### Writing a spreadsheet
@ -162,6 +167,9 @@ $writer->setPreCalculateFormulas(false);
$writer->save("05featuredemo.xlsx"); $writer->save("05featuredemo.xlsx");
``` ```
**Note** Formulas will still be calculated in any column set to be autosized
even if pre-calculated is set to false
#### Office 2003 compatibility pack #### Office 2003 compatibility pack
Because of a bug in the Office2003 compatibility pack, there can be some Because of a bug in the Office2003 compatibility pack, there can be some
@ -477,6 +485,41 @@ $reader->setSheetIndex(0);
$spreadsheet = $reader->load('sample.csv'); $spreadsheet = $reader->load('sample.csv');
``` ```
You can also set the reader to guess the encoding
rather than calling guessEncoding directly. In this case,
the user-settable fallback encoding is used if nothing else works.
```php
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
$reader->setInputEncoding(\PhpOffice\PhpSpreadsheet\Reader\Csv::GUESS_ENCODING);
$reader->setFallbackEncoding('ISO-8859-2'); // default CP1252 without this statement
$reader->setDelimiter(';');
$reader->setEnclosure('');
$reader->setSheetIndex(0);
$spreadsheet = $reader->load('sample.csv');
```
Finally, you can set a callback to be invoked when the constructor is executed,
either through `new Csv()` or `IOFactory::load`,
and have that callback set the customizable attributes to whatever
defaults are appropriate for your environment.
```php
function constructorCallback(\PhpOffice\PhpSpreadsheet\Reader\Csv $reader): void
{
$reader->setInputEncoding(\PhpOffice\PhpSpreadsheet\Reader\Csv::GUESS_ENCODING);
$reader->setFallbackEncoding('ISO-8859-2');
$reader->setDelimiter(',');
$reader->setEnclosure('"');
// Following represents how Excel behaves better than the default escape character
$reader->setEscapeCharacter((version_compare(PHP_VERSION, '7.4') < 0) ? "\x0" : '');
}
\PhpOffice\PhpSpreadsheet\Reader\Csv::setConstructorCallback('constructorCallback');
$spreadsheet = \PhpSpreadsheet\IOFactory::load('sample.csv');
```
#### Read a specific worksheet #### Read a specific worksheet
CSV files can only contain one worksheet. Therefore, you can specify CSV files can only contain one worksheet. Therefore, you can specify

View File

@ -324,6 +324,10 @@ to read and process a large workbook in "chunks": an example of this
usage might be when transferring data from an Excel worksheet to a usage might be when transferring data from an Excel worksheet to a
database. database.
Read Filtering does not renumber cell rows and columns. If you filter to read only rows 100-200, cells that you read will still be numbered A100-A200, not A1-A101. Cells A1-A99 will not be loaded, but if you then try to call `getCell()` for a cell outside your loaded range, then PHPSpreadsheet will create a new cell with a null value.
Methods such as `toArray()` assume that all cells in a spreadsheet has been loaded from A1, so will return null values for rows and columns that fall outside your filter range: it is recommended that you keep track of the range that your filter has requested, and use `rangeToArray()` instead.
```php ```php
$inputFileType = 'Xls'; $inputFileType = 'Xls';
$inputFileName = './sampleData/example2.xls'; $inputFileName = './sampleData/example2.xls';

View File

@ -988,6 +988,9 @@ $security->setLockStructure(true);
$security->setWorkbookPassword("PhpSpreadsheet"); $security->setWorkbookPassword("PhpSpreadsheet");
``` ```
Note that there are additional methods setLockRevision and setRevisionsPassword
which apply only to change tracking and history for shared workbooks.
### Worksheet ### Worksheet
An example on setting worksheet security: An example on setting worksheet security:

View File

@ -1,6 +1,6 @@
<?php <?php
namespace PhpOffice\PhpSpreadsheet; namespace PhpOffice\PhpSpreadsheetInfra;
use PhpOffice\PhpSpreadsheet\Calculation\Category; use PhpOffice\PhpSpreadsheet\Calculation\Category;
use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\Functions;
@ -78,6 +78,7 @@ class DocumentGenerator
$result = "# Function list by name\n"; $result = "# Function list by name\n";
$lastAlphabet = null; $lastAlphabet = null;
foreach ($phpSpreadsheetFunctions as $excelFunction => $functionInfo) { foreach ($phpSpreadsheetFunctions as $excelFunction => $functionInfo) {
/** @var string $excelFunction */
$lengths = [25, 31, 37]; $lengths = [25, 31, 37];
if ($lastAlphabet !== $excelFunction[0]) { if ($lastAlphabet !== $excelFunction[0]) {
$lastAlphabet = $excelFunction[0]; $lastAlphabet = $excelFunction[0];

View File

@ -43,6 +43,8 @@ class LocaleGenerator
*/ */
protected $translationSpreadsheet; protected $translationSpreadsheet;
protected $verbose;
/** /**
* @var Worksheet * @var Worksheet
*/ */
@ -64,11 +66,13 @@ class LocaleGenerator
public function __construct( public function __construct(
string $translationBaseFolder, string $translationBaseFolder,
string $translationSpreadsheetName, string $translationSpreadsheetName,
array $phpSpreadsheetFunctions array $phpSpreadsheetFunctions,
bool $verbose = false
) { ) {
$this->translationBaseFolder = $translationBaseFolder; $this->translationBaseFolder = $translationBaseFolder;
$this->translationSpreadsheetName = $translationSpreadsheetName; $this->translationSpreadsheetName = $translationSpreadsheetName;
$this->phpSpreadsheetFunctions = $phpSpreadsheetFunctions; $this->phpSpreadsheetFunctions = $phpSpreadsheetFunctions;
$this->verbose = $verbose;
} }
public function generateLocales(): void public function generateLocales(): void
@ -110,7 +114,7 @@ class LocaleGenerator
} else { } else {
$errorCodeTranslation = "{$errorCode}" . PHP_EOL; $errorCodeTranslation = "{$errorCode}" . PHP_EOL;
fwrite($configFile, $errorCodeTranslation); fwrite($configFile, $errorCodeTranslation);
echo "No {$language} translation available for error code {$errorCode}", PHP_EOL; $this->log("No {$language} translation available for error code {$errorCode}");
} }
} }
@ -125,7 +129,7 @@ class LocaleGenerator
$functionTranslation = "ArgumentSeparator = {$localeValue}" . PHP_EOL; $functionTranslation = "ArgumentSeparator = {$localeValue}" . PHP_EOL;
fwrite($configFile, $functionTranslation); fwrite($configFile, $functionTranslation);
} else { } else {
echo 'No Argument Separator defined', PHP_EOL; $this->log('No Argument Separator defined');
} }
} }
@ -142,12 +146,12 @@ class LocaleGenerator
if ($this->isFunctionCategoryEntry($translationCell)) { if ($this->isFunctionCategoryEntry($translationCell)) {
$this->writeFileSectionHeader($functionFile, "{$translationValue} ({$functionName})"); $this->writeFileSectionHeader($functionFile, "{$translationValue} ({$functionName})");
} elseif (!array_key_exists($functionName, $this->phpSpreadsheetFunctions)) { } elseif (!array_key_exists($functionName, $this->phpSpreadsheetFunctions)) {
echo "Function {$functionName} is not defined in PhpSpreadsheet", PHP_EOL; $this->log("Function {$functionName} is not defined in PhpSpreadsheet");
} elseif (!empty($translationValue)) { } elseif (!empty($translationValue)) {
$functionTranslation = "{$functionName} = {$translationValue}" . PHP_EOL; $functionTranslation = "{$functionName} = {$translationValue}" . PHP_EOL;
fwrite($functionFile, $functionTranslation); fwrite($functionFile, $functionTranslation);
} else { } else {
echo "No {$language} translation available for function {$functionName}", PHP_EOL; $this->log("No {$language} translation available for function {$functionName}");
} }
} }
@ -156,11 +160,11 @@ class LocaleGenerator
protected function openConfigFile(string $locale, string $language, string $localeLanguage) protected function openConfigFile(string $locale, string $language, string $localeLanguage)
{ {
echo "Building locale {$locale} ($language) configuration", PHP_EOL; $this->log("Building locale {$locale} ($language) configuration");
$localeFolder = $this->getLocaleFolder($locale); $localeFolder = $this->getLocaleFolder($locale);
$configFileName = realpath($localeFolder . DIRECTORY_SEPARATOR . 'config'); $configFileName = realpath($localeFolder . DIRECTORY_SEPARATOR . 'config');
echo "Writing locale configuration to {$configFileName}", PHP_EOL; $this->log("Writing locale configuration to {$configFileName}");
$configFile = fopen($configFileName, 'wb'); $configFile = fopen($configFileName, 'wb');
$this->writeFileHeader($configFile, $localeLanguage, $language, 'locale settings'); $this->writeFileHeader($configFile, $localeLanguage, $language, 'locale settings');
@ -170,11 +174,11 @@ class LocaleGenerator
protected function openFunctionNameFile(string $locale, string $language, string $localeLanguage) protected function openFunctionNameFile(string $locale, string $language, string $localeLanguage)
{ {
echo "Building locale {$locale} ($language) function names", PHP_EOL; $this->log("Building locale {$locale} ($language) function names");
$localeFolder = $this->getLocaleFolder($locale); $localeFolder = $this->getLocaleFolder($locale);
$functionFileName = realpath($localeFolder . DIRECTORY_SEPARATOR . 'functions'); $functionFileName = realpath($localeFolder . DIRECTORY_SEPARATOR . 'functions');
echo "Writing local function names to {$functionFileName}", PHP_EOL; $this->log("Writing local function names to {$functionFileName}");
$functionFile = fopen($functionFileName, 'wb'); $functionFile = fopen($functionFileName, 'wb');
$this->writeFileHeader($functionFile, $localeLanguage, $language, 'function name translations'); $this->writeFileHeader($functionFile, $localeLanguage, $language, 'function name translations');
@ -231,7 +235,7 @@ class LocaleGenerator
protected function mapLanguageColumns(Worksheet $translationWorksheet): array protected function mapLanguageColumns(Worksheet $translationWorksheet): array
{ {
$sheetName = $translationWorksheet->getTitle(); $sheetName = $translationWorksheet->getTitle();
echo "Mapping Languages for {$sheetName}:", PHP_EOL; $this->log("Mapping Languages for {$sheetName}:");
$baseColumn = self::ENGLISH_REFERENCE_COLUMN; $baseColumn = self::ENGLISH_REFERENCE_COLUMN;
$languagesList = $translationWorksheet->getColumnIterator(++$baseColumn); $languagesList = $translationWorksheet->getColumnIterator(++$baseColumn);
@ -245,7 +249,7 @@ class LocaleGenerator
/** @var Cell $cell */ /** @var Cell $cell */
if ($this->localeCanBeSupported($translationWorksheet, $cell)) { if ($this->localeCanBeSupported($translationWorksheet, $cell)) {
$languageNameMap[$cell->getColumn()] = $cell->getValue(); $languageNameMap[$cell->getColumn()] = $cell->getValue();
echo $cell->getColumn(), ' -> ', $cell->getValue(), PHP_EOL; $this->log($cell->getColumn() . ' -> ' . $cell->getValue());
} }
} }
} }
@ -270,7 +274,7 @@ class LocaleGenerator
protected function mapErrorCodeRows(): void protected function mapErrorCodeRows(): void
{ {
echo 'Mapping Error Codes:', PHP_EOL; $this->log('Mapping Error Codes:');
$errorList = $this->localeTranslations->getRowIterator(self::ERROR_CODES_FIRST_ROW); $errorList = $this->localeTranslations->getRowIterator(self::ERROR_CODES_FIRST_ROW);
foreach ($errorList as $errorRow) { foreach ($errorList as $errorRow) {
@ -280,7 +284,7 @@ class LocaleGenerator
foreach ($cells as $cell) { foreach ($cells as $cell) {
/** @var Cell $cell */ /** @var Cell $cell */
if ($cell->getValue() != '') { if ($cell->getValue() != '') {
echo $cell->getRow(), ' -> ', $cell->getValue(), PHP_EOL; $this->log($cell->getRow() . ' -> ' . $cell->getValue());
$this->errorCodeMap[$cell->getValue()] = $cell->getRow(); $this->errorCodeMap[$cell->getValue()] = $cell->getRow();
} }
} }
@ -289,7 +293,7 @@ class LocaleGenerator
protected function mapFunctionNameRows(): void protected function mapFunctionNameRows(): void
{ {
echo 'Mapping Functions:', PHP_EOL; $this->log('Mapping Functions:');
$functionList = $this->functionNameTranslations->getRowIterator(self::FUNCTION_NAME_LIST_FIRST_ROW); $functionList = $this->functionNameTranslations->getRowIterator(self::FUNCTION_NAME_LIST_FIRST_ROW);
foreach ($functionList as $functionRow) { foreach ($functionList as $functionRow) {
@ -300,7 +304,7 @@ class LocaleGenerator
/** @var Cell $cell */ /** @var Cell $cell */
if ($this->isFunctionCategoryEntry($cell)) { if ($this->isFunctionCategoryEntry($cell)) {
if (!empty($cell->getValue())) { if (!empty($cell->getValue())) {
echo 'CATEGORY: ', $cell->getValue(), PHP_EOL; $this->log('CATEGORY: ' . $cell->getValue());
$this->functionNameMap[$cell->getValue()] = $cell->getRow(); $this->functionNameMap[$cell->getValue()] = $cell->getRow();
} }
@ -308,10 +312,10 @@ class LocaleGenerator
} }
if ($cell->getValue() != '') { if ($cell->getValue() != '') {
if (is_bool($cell->getValue())) { if (is_bool($cell->getValue())) {
echo $cell->getRow(), ' -> ', ($cell->getValue() ? 'TRUE' : 'FALSE'), PHP_EOL; $this->log($cell->getRow() . ' -> ' . ($cell->getValue() ? 'TRUE' : 'FALSE'));
$this->functionNameMap[($cell->getValue() ? 'TRUE' : 'FALSE')] = $cell->getRow(); $this->functionNameMap[($cell->getValue() ? 'TRUE' : 'FALSE')] = $cell->getRow();
} else { } else {
echo $cell->getRow(), ' -> ', $cell->getValue(), PHP_EOL; $this->log($cell->getRow() . ' -> ' . $cell->getValue());
$this->functionNameMap[$cell->getValue()] = $cell->getRow(); $this->functionNameMap[$cell->getValue()] = $cell->getRow();
} }
} }
@ -328,4 +332,13 @@ class LocaleGenerator
return false; return false;
} }
private function log(string $message): void
{
if ($this->verbose === false) {
return;
}
echo $message, PHP_EOL;
}
} }

View File

@ -635,46 +635,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/Periodic.php path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/Periodic.php
-
message: "#^Binary operation \"\\*\" between float\\|string and int results in an error\\.$#"
count: 2
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Binary operation \"\\*\" between float\\|string and int\\|string results in an error\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has no return typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$next with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateCouponPeriod\\(\\) has parameter \\$maturity with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateCouponPeriod\\(\\) has parameter \\$settlement with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
- -
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateCost\\(\\) has parameter \\$cost with no typehint specified\\.$#" message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateCost\\(\\) has parameter \\$cost with no typehint specified\\.$#"
count: 1 count: 1
@ -2205,16 +2165,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/DefinedName.php path: src/PhpSpreadsheet/DefinedName.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\DocumentGenerator\\:\\:getPhpSpreadsheetFunctionText\\(\\) has parameter \\$functionCall with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/DocumentGenerator.php
-
message: "#^Cannot access offset 0 on \\(int\\|string\\)\\.$#"
count: 2
path: src/PhpSpreadsheet/DocumentGenerator.php
- -
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\HashTable\\:\\:getIndexForHashCode\\(\\) should return int but returns int\\|string\\|false\\.$#" message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\HashTable\\:\\:getIndexForHashCode\\(\\) should return int but returns int\\|string\\|false\\.$#"
count: 1 count: 1
@ -2415,101 +2365,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Reader/BaseReader.php path: src/PhpSpreadsheet/Reader/BaseReader.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\:\\:\\$delimiter \\(string\\) does not accept string\\|null\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Parameter \\#1 \\$var of function count expects array\\|Countable, array\\|null given\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\:\\:openFileOrMemory\\(\\) has parameter \\$pFilename with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Parameter \\#1 \\$value of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:convertEncoding\\(\\) expects string, string\\|false given\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Parameter \\#1 \\$fp of function fwrite expects resource, resource\\|false given\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Argument of an invalid type array\\|null supplied for foreach, only iterables are supported\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Parameter \\#2 \\$newvalue of function ini_set expects string, string\\|false given\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Call to function is_array\\(\\) with string will always evaluate to false\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$fileHandle has no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$escapeCharacter has no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$enclosure has no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$counts has no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$numberLines has no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$delimiter has no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:__construct\\(\\) has parameter \\$enclosure with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:__construct\\(\\) has parameter \\$escapeCharacter with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:__construct\\(\\) has parameter \\$fileHandle with no typehint specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|null given\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:getNextLine\\(\\) should return string\\|false but returns string\\|null\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php
- -
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$rowspan has no typehint specified\\.$#" message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$rowspan has no typehint specified\\.$#"
count: 1 count: 1
@ -7455,41 +7310,6 @@ parameters:
count: 5 count: 5
path: tests/PhpSpreadsheetTests/NamedRangeTest.php path: tests/PhpSpreadsheetTests/NamedRangeTest.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:setFilterType\\(\\) has parameter \\$type with no typehint specified\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:filter1\\(\\) has no return typehint specified\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:filter1\\(\\) has parameter \\$row with no typehint specified\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:filter0\\(\\) has no return typehint specified\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:filter0\\(\\) has parameter \\$row with no typehint specified\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php
-
message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#"
count: 3
path: tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php
-
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertNull\\(\\) with string will always evaluate to false\\.$#"
count: 1
path: tests/PhpSpreadsheetTests/Reader/CsvTest.php
- -
message: "#^Unreachable statement \\- code above always terminates\\.$#" message: "#^Unreachable statement \\- code above always terminates\\.$#"
count: 1 count: 1

View File

@ -0,0 +1,35 @@
<?php
use PhpOffice\PhpSpreadsheet\Spreadsheet;
require __DIR__ . '/../../Header.php';
$helper->log('Searches for a value in the top row of a table or an array of values,
and then returns a value in the same column from a row you specify
in the table or array.');
// Create new PhpSpreadsheet object
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$data = [
['ID', 'First Name', 'Last Name', 'Salary'],
[72, 'Emily', 'Smith', 64901, null, 'ID', 53, 66, 56],
[66, 'James', 'Anderson', 70855, null, 'Salary'],
[14, 'Mia', 'Clark', 188657],
[30, 'John', 'Lewis', 97566],
[53, 'Jessica', 'Walker', 58339],
[56, 'Mark', 'Reed', 125180],
[79, 'Richard', 'Lopez', 91632],
];
$worksheet->fromArray($data, null, 'B2');
$worksheet->getCell('H4')->setValue('=VLOOKUP(H3, B3:E9, 4, FALSE)');
$worksheet->getCell('I4')->setValue('=VLOOKUP(I3, B3:E9, 4, FALSE)');
$worksheet->getCell('J4')->setValue('=VLOOKUP(J3, B3:E9, 4, FALSE)');
for ($column = 'H'; $column !== 'K'; ++$column) {
$cell = $worksheet->getCell("{$column}4");
$helper->log("{$column}4: {$cell->getValue()} => {$cell->getCalculatedValue()}");
}

View File

@ -299,6 +299,11 @@ class Calculation
'functionCall' => [Functions::class, 'DUMMY'], 'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '1', 'argumentCount' => '1',
], ],
'ARRAYTOTEXT' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'ASC' => [ 'ASC' => [
'category' => Category::CATEGORY_TEXT_AND_DATA, 'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'], 'functionCall' => [Functions::class, 'DUMMY'],
@ -766,6 +771,11 @@ class Calculation
'functionCall' => [DateTimeExcel\Difference::class, 'interval'], 'functionCall' => [DateTimeExcel\Difference::class, 'interval'],
'argumentCount' => '2,3', 'argumentCount' => '2,3',
], ],
'DATESTRING' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'DATEVALUE' => [ 'DATEVALUE' => [
'category' => Category::CATEGORY_DATE_AND_TIME, 'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTimeExcel\DateValue::class, 'fromString'], 'functionCall' => [DateTimeExcel\DateValue::class, 'fromString'],
@ -1527,6 +1537,11 @@ class Calculation
'functionCall' => [Functions::class, 'isText'], 'functionCall' => [Functions::class, 'isText'],
'argumentCount' => '1', 'argumentCount' => '1',
], ],
'ISTHAIDIGIT' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'JIS' => [ 'JIS' => [
'category' => Category::CATEGORY_TEXT_AND_DATA, 'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'], 'functionCall' => [Functions::class, 'DUMMY'],
@ -1842,6 +1857,11 @@ class Calculation
'functionCall' => [Financial\CashFlow\Variable\Periodic::class, 'presentValue'], 'functionCall' => [Financial\CashFlow\Variable\Periodic::class, 'presentValue'],
'argumentCount' => '2+', 'argumentCount' => '2+',
], ],
'NUMBERSTRING' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'NUMBERVALUE' => [ 'NUMBERVALUE' => [
'category' => Category::CATEGORY_TEXT_AND_DATA, 'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [TextData\Format::class, 'NUMBERVALUE'], 'functionCall' => [TextData\Format::class, 'NUMBERVALUE'],
@ -2124,6 +2144,16 @@ class Calculation
'functionCall' => [MathTrig\Round::class, 'round'], 'functionCall' => [MathTrig\Round::class, 'round'],
'argumentCount' => '2', 'argumentCount' => '2',
], ],
'ROUNDBAHTDOWN' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'ROUNDBAHTUP' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'ROUNDDOWN' => [ 'ROUNDDOWN' => [
'category' => Category::CATEGORY_MATH_AND_TRIG, 'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig\Round::class, 'down'], 'functionCall' => [MathTrig\Round::class, 'down'],
@ -2427,6 +2457,41 @@ class Calculation
'functionCall' => [TextData\Concatenate::class, 'TEXTJOIN'], 'functionCall' => [TextData\Concatenate::class, 'TEXTJOIN'],
'argumentCount' => '3+', 'argumentCount' => '3+',
], ],
'THAIDAYOFWEEK' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'THAIDIGIT' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'THAIMONTHOFYEAR' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'THAINUMSOUND' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'THAINUMSTRING' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'THAISTRINGLENGTH' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'THAIYEAR' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'TIME' => [ 'TIME' => [
'category' => Category::CATEGORY_DATE_AND_TIME, 'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTimeExcel\Time::class, 'fromHMS'], 'functionCall' => [DateTimeExcel\Time::class, 'fromHMS'],
@ -2532,6 +2597,11 @@ class Calculation
'functionCall' => [TextData\Format::class, 'VALUE'], 'functionCall' => [TextData\Format::class, 'VALUE'],
'argumentCount' => '1', 'argumentCount' => '1',
], ],
'VALUETOTEXT' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'argumentCount' => '?',
],
'VAR' => [ 'VAR' => [
'category' => Category::CATEGORY_STATISTICAL, 'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Statistical\Variances::class, 'VAR'], 'functionCall' => [Statistical\Variances::class, 'VAR'],

View File

@ -2,6 +2,7 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial; namespace PhpOffice\PhpSpreadsheet\Calculation\Financial;
use DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants; use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants;
@ -73,7 +74,7 @@ class Coupons
return abs((float) DateTimeExcel\Days::between($prev, $settlement)); return abs((float) DateTimeExcel\Days::between($prev, $settlement));
} }
return DateTimeExcel\YearFrac::fraction($prev, $settlement, $basis) * $daysPerYear; return (float) DateTimeExcel\YearFrac::fraction($prev, $settlement, $basis) * $daysPerYear;
} }
/** /**
@ -208,7 +209,7 @@ class Coupons
} }
} }
return DateTimeExcel\YearFrac::fraction($settlement, $next, $basis) * $daysPerYear; return (float) DateTimeExcel\YearFrac::fraction($settlement, $next, $basis) * $daysPerYear;
} }
/** /**
@ -322,7 +323,7 @@ class Coupons
FinancialConstants::BASIS_DAYS_PER_YEAR_NASD FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
); );
return (int) ceil($yearsBetweenSettlementAndMaturity * $frequency); return (int) ceil((float) $yearsBetweenSettlementAndMaturity * $frequency);
} }
/** /**
@ -379,28 +380,33 @@ class Coupons
return self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS); return self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS);
} }
private static function couponFirstPeriodDate($settlement, $maturity, int $frequency, $next) private static function monthsDiff(DateTime $result, int $months, string $plusOrMinus, int $day, bool $lastDayFlag): void
{
$result->setDate((int) $result->format('Y'), (int) $result->format('m'), 1);
$result->modify("$plusOrMinus $months months");
$daysInMonth = (int) $result->format('t');
$result->setDate((int) $result->format('Y'), (int) $result->format('m'), $lastDayFlag ? $daysInMonth : min($day, $daysInMonth));
}
private static function couponFirstPeriodDate(float $settlement, float $maturity, int $frequency, bool $next): float
{ {
$months = 12 / $frequency; $months = 12 / $frequency;
$result = Date::excelToDateTimeObject($maturity); $result = Date::excelToDateTimeObject($maturity);
$maturityEoM = Helpers::isLastDayOfMonth($result); $day = (int) $result->format('d');
$lastDayFlag = Helpers::isLastDayOfMonth($result);
while ($settlement < Date::PHPToExcel($result)) { while ($settlement < Date::PHPToExcel($result)) {
$result->modify('-' . $months . ' months'); self::monthsDiff($result, $months, '-', $day, $lastDayFlag);
} }
if ($next === true) { if ($next === true) {
$result->modify('+' . $months . ' months'); self::monthsDiff($result, $months, '+', $day, $lastDayFlag);
} }
if ($maturityEoM === true) { return (float) Date::PHPToExcel($result);
$result->modify('-1 day');
} }
return Date::PHPToExcel($result); private static function validateCouponPeriod(float $settlement, float $maturity): void
}
private static function validateCouponPeriod($settlement, $maturity): void
{ {
if ($settlement >= $maturity) { if ($settlement >= $maturity) {
throw new Exception(Functions::NAN()); throw new Exception(Functions::NAN());

View File

@ -41,7 +41,8 @@ class Address
{ {
$row = Functions::flattenSingleValue($row); $row = Functions::flattenSingleValue($row);
$column = Functions::flattenSingleValue($column); $column = Functions::flattenSingleValue($column);
$relativity = Functions::flattenSingleValue($relativity); $relativity = ($relativity === null) ? 1 : Functions::flattenSingleValue($relativity);
$referenceStyle = ($referenceStyle === null) ? true : Functions::flattenSingleValue($referenceStyle);
$sheetName = Functions::flattenSingleValue($sheetName); $sheetName = Functions::flattenSingleValue($sheetName);
if (($row < 1) || ($column < 1)) { if (($row < 1) || ($column < 1)) {

View File

@ -25,7 +25,7 @@ class HLookup extends LookupBase
{ {
$lookupValue = Functions::flattenSingleValue($lookupValue); $lookupValue = Functions::flattenSingleValue($lookupValue);
$indexNumber = Functions::flattenSingleValue($indexNumber); $indexNumber = Functions::flattenSingleValue($indexNumber);
$notExactMatch = Functions::flattenSingleValue($notExactMatch); $notExactMatch = ($notExactMatch === null) ? true : Functions::flattenSingleValue($notExactMatch);
try { try {
$indexNumber = self::validateIndexLookup($lookupArray, $indexNumber); $indexNumber = self::validateIndexLookup($lookupArray, $indexNumber);

View File

@ -13,7 +13,8 @@ class Indirect
/** /**
* Determine whether cell address is in A1 (true) or R1C1 (false) format. * Determine whether cell address is in A1 (true) or R1C1 (false) format.
* *
* @param mixed $a1fmt Expect bool Helpers::CELLADDRESS_USE_A1 or CELLADDRESS_USE_R1C1, but can be provided as numeric which is cast to bool * @param mixed $a1fmt Expect bool Helpers::CELLADDRESS_USE_A1 or CELLADDRESS_USE_R1C1,
* but can be provided as numeric which is cast to bool
*/ */
private static function a1Format($a1fmt): bool private static function a1Format($a1fmt): bool
{ {
@ -53,7 +54,8 @@ class Indirect
* =INDIRECT(cellAddress, bool) where the bool argument is optional * =INDIRECT(cellAddress, bool) where the bool argument is optional
* *
* @param array|string $cellAddress $cellAddress The cell address of the current cell (containing this formula) * @param array|string $cellAddress $cellAddress The cell address of the current cell (containing this formula)
* @param mixed $a1fmt Expect bool Helpers::CELLADDRESS_USE_A1 or CELLADDRESS_USE_R1C1, but can be provided as numeric which is cast to bool * @param mixed $a1fmt Expect bool Helpers::CELLADDRESS_USE_A1 or CELLADDRESS_USE_R1C1,
* but can be provided as numeric which is cast to bool
* @param Cell $pCell The current cell (containing this formula) * @param Cell $pCell The current cell (containing this formula)
* *
* @return array|string An array containing a cell or range of cells, or a string on error * @return array|string An array containing a cell or range of cells, or a string on error
@ -84,7 +86,8 @@ class Indirect
/** /**
* Extract range values. * Extract range values.
* *
* @return mixed Array of values in range if range contains more than one element. Otherwise, a single value is returned. * @return mixed Array of values in range if range contains more than one element.
* Otherwise, a single value is returned.
*/ */
private static function extractRequiredCells(?Worksheet $pSheet, string $cellAddress) private static function extractRequiredCells(?Worksheet $pSheet, string $cellAddress)
{ {

View File

@ -25,7 +25,7 @@ class VLookup extends LookupBase
{ {
$lookupValue = Functions::flattenSingleValue($lookupValue); $lookupValue = Functions::flattenSingleValue($lookupValue);
$indexNumber = Functions::flattenSingleValue($indexNumber); $indexNumber = Functions::flattenSingleValue($indexNumber);
$notExactMatch = Functions::flattenSingleValue($notExactMatch); $notExactMatch = ($notExactMatch === null) ? true : Functions::flattenSingleValue($notExactMatch);
try { try {
$indexNumber = self::validateIndexLookup($lookupArray, $indexNumber); $indexNumber = self::validateIndexLookup($lookupArray, $indexNumber);

View File

@ -39,6 +39,7 @@ DVARP = DVARIANSP
## ##
DATE = DATO DATE = DATO
DATEDIF = DATO.FORSKEL DATEDIF = DATO.FORSKEL
DATESTRING = DATOSTRENG
DATEVALUE = DATOVÆRDI DATEVALUE = DATOVÆRDI
DAY = DAG DAY = DAG
DAYS = DAGE DAYS = DAGE
@ -53,6 +54,9 @@ NETWORKDAYS = ANTAL.ARBEJDSDAGE
NETWORKDAYS.INTL = ANTAL.ARBEJDSDAGE.INTL NETWORKDAYS.INTL = ANTAL.ARBEJDSDAGE.INTL
NOW = NU NOW = NU
SECOND = SEKUND SECOND = SEKUND
THAIDAYOFWEEK = THAILANDSKUGEDAG
THAIMONTHOFYEAR = THAILANDSKMÅNED
THAIYEAR = THAILANDSKÅR
TIME = TID TIME = TID
TIMEVALUE = TIDSVÆRDI TIMEVALUE = TIDSVÆRDI
TODAY = IDAG TODAY = IDAG
@ -301,6 +305,8 @@ RAND = SLUMP
RANDBETWEEN = SLUMPMELLEM RANDBETWEEN = SLUMPMELLEM
ROMAN = ROMERTAL ROMAN = ROMERTAL
ROUND = AFRUND ROUND = AFRUND
ROUNDBAHTDOWN = RUNDBAHTNED
ROUNDBAHTUP = RUNDBAHTOP
ROUNDDOWN = RUND.NED ROUNDDOWN = RUND.NED
ROUNDUP = RUND.OP ROUNDUP = RUND.OP
SEC = SEC SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = KR
EXACT = EKSAKT EXACT = EKSAKT
FIND = FIND FIND = FIND
FIXED = FAST FIXED = FAST
ISTHAIDIGIT = ERTHAILANDSKCIFFER
LEFT = VENSTRE LEFT = VENSTRE
LEN = LÆNGDE LEN = LÆNGDE
LOWER = SMÅ.BOGSTAVER LOWER = SMÅ.BOGSTAVER
MID = MIDT MID = MIDT
NUMBERSTRING = TALSTRENG
NUMBERVALUE = TALVÆRDI NUMBERVALUE = TALVÆRDI
PHONETIC = FONETISK PHONETIC = FONETISK
PROPER = STORT.FORBOGSTAV PROPER = STORT.FORBOGSTAV
@ -465,6 +473,10 @@ SUBSTITUTE = UDSKIFT
T = T T = T
TEXT = TEKST TEXT = TEKST
TEXTJOIN = TEKST.KOMBINER TEXTJOIN = TEKST.KOMBINER
THAIDIGIT = THAILANDSKCIFFER
THAINUMSOUND = THAILANDSKNUMLYD
THAINUMSTRING = THAILANDSKNUMSTRENG
THAISTRINGLENGTH = THAILANDSKSTRENGLÆNGDE
TRIM = FJERN.OVERFLØDIGE.BLANKE TRIM = FJERN.OVERFLØDIGE.BLANKE
UNICHAR = UNICHAR UNICHAR = UNICHAR
UNICODE = UNICODE UNICODE = UNICODE

View File

@ -52,6 +52,9 @@ NETWORKDAYS = NETTOARBEITSTAGE
NETWORKDAYS.INTL = NETTOARBEITSTAGE.INTL NETWORKDAYS.INTL = NETTOARBEITSTAGE.INTL
NOW = JETZT NOW = JETZT
SECOND = SEKUNDE SECOND = SEKUNDE
THAIDAYOFWEEK = THAIWOCHENTAG
THAIMONTHOFYEAR = THAIMONATDESJAHRES
THAIYEAR = THAIJAHR
TIME = ZEIT TIME = ZEIT
TIMEVALUE = ZEITWERT TIMEVALUE = ZEITWERT
TODAY = HEUTE TODAY = HEUTE
@ -300,6 +303,8 @@ RAND = ZUFALLSZAHL
RANDBETWEEN = ZUFALLSBEREICH RANDBETWEEN = ZUFALLSBEREICH
ROMAN = RÖMISCH ROMAN = RÖMISCH
ROUND = RUNDEN ROUND = RUNDEN
ROUNDBAHTDOWN = RUNDBAHTNED
ROUNDBAHTUP = BAHTAUFRUNDEN
ROUNDDOWN = ABRUNDEN ROUNDDOWN = ABRUNDEN
ROUNDUP = AUFRUNDEN ROUNDUP = AUFRUNDEN
SEC = SEC SEC = SEC
@ -449,6 +454,7 @@ DOLLAR = DM
EXACT = IDENTISCH EXACT = IDENTISCH
FIND = FINDEN FIND = FINDEN
FIXED = FEST FIXED = FEST
ISTHAIDIGIT = ISTTHAIZAHLENWORT
LEFT = LINKS LEFT = LINKS
LEN = LÄNGE LEN = LÄNGE
LOWER = KLEIN LOWER = KLEIN
@ -463,6 +469,10 @@ SUBSTITUTE = WECHSELN
T = T T = T
TEXT = TEXT TEXT = TEXT
TEXTJOIN = TEXTVERKETTEN TEXTJOIN = TEXTVERKETTEN
THAIDIGIT = THAIZAHLENWORT
THAINUMSOUND = THAIZAHLSOUND
THAINUMSTRING = THAILANDSKNUMSTRENG
THAISTRINGLENGTH = THAIZEICHENFOLGENLÄNGE
TRIM = GLÄTTEN TRIM = GLÄTTEN
UNICHAR = UNIZEICHEN UNICHAR = UNIZEICHEN
UNICODE = UNICODE UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = BDVARP
## ##
DATE = FECHA DATE = FECHA
DATEDIF = SIFECHA DATEDIF = SIFECHA
DATESTRING = CADENA.FECHA
DATEVALUE = FECHANUMERO DATEVALUE = FECHANUMERO
DAY = DIA DAY = DIA
DAYS = DIAS DAYS = DIAS
@ -53,6 +54,9 @@ NETWORKDAYS = DIAS.LAB
NETWORKDAYS.INTL = DIAS.LAB.INTL NETWORKDAYS.INTL = DIAS.LAB.INTL
NOW = AHORA NOW = AHORA
SECOND = SEGUNDO SECOND = SEGUNDO
THAIDAYOFWEEK = DIASEMTAI
THAIMONTHOFYEAR = MESAÑOTAI
THAIYEAR = AÑOTAI
TIME = NSHORA TIME = NSHORA
TIMEVALUE = HORANUMERO TIMEVALUE = HORANUMERO
TODAY = HOY TODAY = HOY
@ -301,6 +305,8 @@ RAND = ALEATORIO
RANDBETWEEN = ALEATORIO.ENTRE RANDBETWEEN = ALEATORIO.ENTRE
ROMAN = NUMERO.ROMANO ROMAN = NUMERO.ROMANO
ROUND = REDONDEAR ROUND = REDONDEAR
ROUNDBAHTDOWN = REDONDEAR.BAHT.MAS
ROUNDBAHTUP = REDONDEAR.BAHT.MENOS
ROUNDDOWN = REDONDEAR.MENOS ROUNDDOWN = REDONDEAR.MENOS
ROUNDUP = REDONDEAR.MAS ROUNDUP = REDONDEAR.MAS
SEC = SEC SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = MONEDA
EXACT = IGUAL EXACT = IGUAL
FIND = ENCONTRAR FIND = ENCONTRAR
FIXED = DECIMAL FIXED = DECIMAL
ISTHAIDIGIT = ESDIGITOTAI
LEFT = IZQUIERDA LEFT = IZQUIERDA
LEN = LARGO LEN = LARGO
LOWER = MINUSC LOWER = MINUSC
MID = EXTRAE MID = EXTRAE
NUMBERSTRING = CADENA.NUMERO
NUMBERVALUE = VALOR.NUMERO NUMBERVALUE = VALOR.NUMERO
PHONETIC = FONETICO PHONETIC = FONETICO
PROPER = NOMPROPIO PROPER = NOMPROPIO
@ -465,6 +473,10 @@ SUBSTITUTE = SUSTITUIR
T = T T = T
TEXT = TEXTO TEXT = TEXTO
TEXTJOIN = UNIRCADENAS TEXTJOIN = UNIRCADENAS
THAIDIGIT = DIGITOTAI
THAINUMSOUND = SONNUMTAI
THAINUMSTRING = CADENANUMTAI
THAISTRINGLENGTH = LONGCADENATAI
TRIM = ESPACIOS TRIM = ESPACIOS
UNICHAR = UNICAR UNICHAR = UNICAR
UNICODE = UNICODE UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = TVARIANSSIP
## ##
DATE = PÄIVÄYS DATE = PÄIVÄYS
DATEDIF = PVMERO DATEDIF = PVMERO
DATESTRING = PVMMERKKIJONO
DATEVALUE = PÄIVÄYSARVO DATEVALUE = PÄIVÄYSARVO
DAY = PÄIVÄ DAY = PÄIVÄ
DAYS = PÄIVÄT DAYS = PÄIVÄT
@ -53,6 +54,9 @@ NETWORKDAYS = TYÖPÄIVÄT
NETWORKDAYS.INTL = TYÖPÄIVÄT.KANSVÄL NETWORKDAYS.INTL = TYÖPÄIVÄT.KANSVÄL
NOW = NYT NOW = NYT
SECOND = SEKUNNIT SECOND = SEKUNNIT
THAIDAYOFWEEK = THAI.VIIKONPÄIVÄ
THAIMONTHOFYEAR = THAI.KUUKAUSI
THAIYEAR = THAI.VUOSI
TIME = AIKA TIME = AIKA
TIMEVALUE = AIKA_ARVO TIMEVALUE = AIKA_ARVO
TODAY = TÄMÄ.PÄIVÄ TODAY = TÄMÄ.PÄIVÄ
@ -301,6 +305,8 @@ RAND = SATUNNAISLUKU
RANDBETWEEN = SATUNNAISLUKU.VÄLILTÄ RANDBETWEEN = SATUNNAISLUKU.VÄLILTÄ
ROMAN = ROMAN ROMAN = ROMAN
ROUND = PYÖRISTÄ ROUND = PYÖRISTÄ
ROUNDBAHTDOWN = PYÖRISTÄ.BAHT.ALAS
ROUNDBAHTUP = PYÖRISTÄ.BAHT.YLÖS
ROUNDDOWN = PYÖRISTÄ.DES.ALAS ROUNDDOWN = PYÖRISTÄ.DES.ALAS
ROUNDUP = PYÖRISTÄ.DES.YLÖS ROUNDUP = PYÖRISTÄ.DES.YLÖS
SEC = SEK SEC = SEK
@ -450,10 +456,12 @@ DOLLAR = VALUUTTA
EXACT = VERTAA EXACT = VERTAA
FIND = ETSI FIND = ETSI
FIXED = KIINTEÄ FIXED = KIINTEÄ
ISTHAIDIGIT = ON.THAI.NUMERO
LEFT = VASEN LEFT = VASEN
LEN = PITUUS LEN = PITUUS
LOWER = PIENET LOWER = PIENET
MID = POIMI.TEKSTI MID = POIMI.TEKSTI
NUMBERSTRING = NROMERKKIJONO
NUMBERVALUE = NROARVO NUMBERVALUE = NROARVO
PHONETIC = FONEETTINEN PHONETIC = FONEETTINEN
PROPER = ERISNIMI PROPER = ERISNIMI
@ -465,6 +473,10 @@ SUBSTITUTE = VAIHDA
T = T T = T
TEXT = TEKSTI TEXT = TEKSTI
TEXTJOIN = TEKSTI.YHDISTÄ TEXTJOIN = TEKSTI.YHDISTÄ
THAIDIGIT = THAI.NUMERO
THAINUMSOUND = THAI.LUKU.ÄÄNI
THAINUMSTRING = THAI.LUKU.MERKKIJONO
THAISTRINGLENGTH = THAI.MERKKIJONON.PITUUS
TRIM = POISTA.VÄLIT TRIM = POISTA.VÄLIT
UNICHAR = UNICODEMERKKI UNICHAR = UNICODEMERKKI
UNICODE = UNICODE UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = AB.VAR2
## ##
DATE = DÁTUM DATE = DÁTUM
DATEDIF = DÁTUMTÓLIG DATEDIF = DÁTUMTÓLIG
DATESTRING = DÁTUMSZÖVEG
DATEVALUE = DÁTUMÉRTÉK DATEVALUE = DÁTUMÉRTÉK
DAY = NAP DAY = NAP
DAYS = NAPOK DAYS = NAPOK
@ -53,6 +54,9 @@ NETWORKDAYS = ÖSSZ.MUNKANAP
NETWORKDAYS.INTL = ÖSSZ.MUNKANAP.INTL NETWORKDAYS.INTL = ÖSSZ.MUNKANAP.INTL
NOW = MOST NOW = MOST
SECOND = MPERC SECOND = MPERC
THAIDAYOFWEEK = THAIHÉTNAPJA
THAIMONTHOFYEAR = THAIHÓNAP
THAIYEAR = THAIÉV
TIME = IDŐ TIME = IDŐ
TIMEVALUE = IDŐÉRTÉK TIMEVALUE = IDŐÉRTÉK
TODAY = MA TODAY = MA
@ -301,6 +305,8 @@ RAND = VÉL
RANDBETWEEN = VÉLETLEN.KÖZÖTT RANDBETWEEN = VÉLETLEN.KÖZÖTT
ROMAN = RÓMAI ROMAN = RÓMAI
ROUND = KEREKÍTÉS ROUND = KEREKÍTÉS
ROUNDBAHTDOWN = BAHTKEREK.LE
ROUNDBAHTUP = BAHTKEREK.FEL
ROUNDDOWN = KEREK.LE ROUNDDOWN = KEREK.LE
ROUNDUP = KEREK.FEL ROUNDUP = KEREK.FEL
SEC = SEC SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = FORINT
EXACT = AZONOS EXACT = AZONOS
FIND = SZÖVEG.TALÁL FIND = SZÖVEG.TALÁL
FIXED = FIX FIXED = FIX
ISTHAIDIGIT = ON.THAI.NUMERO
LEFT = BAL LEFT = BAL
LEN = HOSSZ LEN = HOSSZ
LOWER = KISBETŰ LOWER = KISBETŰ
MID = KÖZÉP MID = KÖZÉP
NUMBERSTRING = SZÁM.BETŰVEL
NUMBERVALUE = SZÁMÉRTÉK NUMBERVALUE = SZÁMÉRTÉK
PHONETIC = FONETIKUS PHONETIC = FONETIKUS
PROPER = TNÉV PROPER = TNÉV
@ -465,6 +473,10 @@ SUBSTITUTE = HELYETTE
T = T T = T
TEXT = SZÖVEG TEXT = SZÖVEG
TEXTJOIN = SZÖVEGÖSSZEFŰZÉS TEXTJOIN = SZÖVEGÖSSZEFŰZÉS
THAIDIGIT = THAISZÁM
THAINUMSOUND = THAISZÁMHANG
THAINUMSTRING = THAISZÁMKAR
THAISTRINGLENGTH = THAIKARHOSSZ
TRIM = KIMETSZ TRIM = KIMETSZ
UNICHAR = UNIKARAKTER UNICHAR = UNIKARAKTER
UNICODE = UNICODE UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = DB.VAR.POP
## ##
DATE = DATA DATE = DATA
DATEDIF = DATA.DIFF DATEDIF = DATA.DIFF
DATESTRING = DATA.STRINGA
DATEVALUE = DATA.VALORE DATEVALUE = DATA.VALORE
DAY = GIORNO DAY = GIORNO
DAYS = GIORNI DAYS = GIORNI
@ -53,6 +54,9 @@ NETWORKDAYS = GIORNI.LAVORATIVI.TOT
NETWORKDAYS.INTL = GIORNI.LAVORATIVI.TOT.INTL NETWORKDAYS.INTL = GIORNI.LAVORATIVI.TOT.INTL
NOW = ADESSO NOW = ADESSO
SECOND = SECONDO SECOND = SECONDO
THAIDAYOFWEEK = THAIGIORNODELLASETTIMANA
THAIMONTHOFYEAR = THAIMESEDELLANNO
THAIYEAR = THAIANNO
TIME = ORARIO TIME = ORARIO
TIMEVALUE = ORARIO.VALORE TIMEVALUE = ORARIO.VALORE
TODAY = OGGI TODAY = OGGI
@ -301,6 +305,8 @@ RAND = CASUALE
RANDBETWEEN = CASUALE.TRA RANDBETWEEN = CASUALE.TRA
ROMAN = ROMANO ROMAN = ROMANO
ROUND = ARROTONDA ROUND = ARROTONDA
ROUNDBAHTDOWN = ARROTBAHTGIU
ROUNDBAHTUP = ARROTBAHTSU
ROUNDDOWN = ARROTONDA.PER.DIF ROUNDDOWN = ARROTONDA.PER.DIF
ROUNDUP = ARROTONDA.PER.ECC ROUNDUP = ARROTONDA.PER.ECC
SEC = SEC SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = VALUTA
EXACT = IDENTICO EXACT = IDENTICO
FIND = TROVA FIND = TROVA
FIXED = FISSO FIXED = FISSO
ISTHAIDIGIT = ÈTHAICIFRA
LEFT = SINISTRA LEFT = SINISTRA
LEN = LUNGHEZZA LEN = LUNGHEZZA
LOWER = MINUSC LOWER = MINUSC
MID = STRINGA.ESTRAI MID = STRINGA.ESTRAI
NUMBERSTRING = NUMERO.STRINGA
NUMBERVALUE = NUMERO.VALORE NUMBERVALUE = NUMERO.VALORE
PHONETIC = FURIGANA PHONETIC = FURIGANA
PROPER = MAIUSC.INIZ PROPER = MAIUSC.INIZ
@ -465,6 +473,10 @@ SUBSTITUTE = SOSTITUISCI
T = T T = T
TEXT = TESTO TEXT = TESTO
TEXTJOIN = TESTO.UNISCI TEXTJOIN = TESTO.UNISCI
THAIDIGIT = THAICIFRA
THAINUMSOUND = THAINUMSUONO
THAINUMSTRING = THAISZÁMKAR
THAISTRINGLENGTH = THAILUNGSTRINGA
TRIM = ANNULLA.SPAZI TRIM = ANNULLA.SPAZI
UNICHAR = CARATT.UNI UNICHAR = CARATT.UNI
UNICODE = UNICODE UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = DVARIANSP
## ##
DATE = DATO DATE = DATO
DATEDIF = DATODIFF DATEDIF = DATODIFF
DATESTRING = DATOSTRENG
DATEVALUE = DATOVERDI DATEVALUE = DATOVERDI
DAY = DAG DAY = DAG
DAYS = DAGER DAYS = DAGER
@ -53,6 +54,9 @@ NETWORKDAYS = NETT.ARBEIDSDAGER
NETWORKDAYS.INTL = NETT.ARBEIDSDAGER.INTL NETWORKDAYS.INTL = NETT.ARBEIDSDAGER.INTL
NOW = NÅ NOW = NÅ
SECOND = SEKUND SECOND = SEKUND
THAIDAYOFWEEK = THAIUKEDAG
THAIMONTHOFYEAR = THAIMÅNED
THAIYEAR = THAIÅR
TIME = TID TIME = TID
TIMEVALUE = TIDSVERDI TIMEVALUE = TIDSVERDI
TODAY = IDAG TODAY = IDAG
@ -301,6 +305,8 @@ RAND = TILFELDIG
RANDBETWEEN = TILFELDIGMELLOM RANDBETWEEN = TILFELDIGMELLOM
ROMAN = ROMERTALL ROMAN = ROMERTALL
ROUND = AVRUND ROUND = AVRUND
ROUNDBAHTDOWN = RUNDAVBAHTNEDOVER
ROUNDBAHTUP = RUNDAVBAHTOPPOVER
ROUNDDOWN = AVRUND.NED ROUNDDOWN = AVRUND.NED
ROUNDUP = AVRUND.OPP ROUNDUP = AVRUND.OPP
SEC = SEC SEC = SEC
@ -451,10 +457,12 @@ DOLLAR = VALUTA
EXACT = EKSAKT EXACT = EKSAKT
FIND = FINN FIND = FINN
FIXED = FASTSATT FIXED = FASTSATT
ISTHAIDIGIT = ERTHAISIFFER
LEFT = VENSTRE LEFT = VENSTRE
LEN = LENGDE LEN = LENGDE
LOWER = SMÅ LOWER = SMÅ
MID = DELTEKST MID = DELTEKST
NUMBERSTRING = TALLSTRENG
NUMBERVALUE = TALLVERDI NUMBERVALUE = TALLVERDI
PHONETIC = FURIGANA PHONETIC = FURIGANA
PROPER = STOR.FORBOKSTAV PROPER = STOR.FORBOKSTAV
@ -466,6 +474,10 @@ SUBSTITUTE = BYTT.UT
T = T T = T
TEXT = TEKST TEXT = TEKST
TEXTJOIN = TEKST.KOMBINER TEXTJOIN = TEKST.KOMBINER
THAIDIGIT = THAISIFFER
THAINUMSOUND = THAINUMLYD
THAINUMSTRING = THAINUMSTRENG
THAISTRINGLENGTH = THAISTRENGLENGDE
TRIM = TRIMME TRIM = TRIMME
UNICHAR = UNICODETEGN UNICHAR = UNICODETEGN
UNICODE = UNICODE UNICODE = UNICODE

View File

@ -38,6 +38,7 @@ DVARP = DBVARP
## Datum- en tijdfuncties (Date & Time Functions) ## Datum- en tijdfuncties (Date & Time Functions)
## ##
DATE = DATUM DATE = DATUM
DATESTRING = DATUMNOTATIE
DATEVALUE = DATUMWAARDE DATEVALUE = DATUMWAARDE
DAY = DAG DAY = DAG
DAYS = DAGEN DAYS = DAGEN
@ -52,6 +53,9 @@ NETWORKDAYS = NETTO.WERKDAGEN
NETWORKDAYS.INTL = NETWERKDAGEN.INTL NETWORKDAYS.INTL = NETWERKDAGEN.INTL
NOW = NU NOW = NU
SECOND = SECONDE SECOND = SECONDE
THAIDAYOFWEEK = THAIS.WEEKDAG
THAIMONTHOFYEAR = THAIS.MAAND.VAN.JAAR
THAIYEAR = THAIS.JAAR
TIME = TIJD TIME = TIJD
TIMEVALUE = TIJDWAARDE TIMEVALUE = TIJDWAARDE
TODAY = VANDAAG TODAY = VANDAAG
@ -300,6 +304,8 @@ RAND = ASELECT
RANDBETWEEN = ASELECTTUSSEN RANDBETWEEN = ASELECTTUSSEN
ROMAN = ROMEINS ROMAN = ROMEINS
ROUND = AFRONDEN ROUND = AFRONDEN
ROUNDBAHTDOWN = BAHT.AFR.NAAR.BENEDEN
ROUNDBAHTUP = BAHT.AFR.NAAR.BOVEN
ROUNDDOWN = AFRONDEN.NAAR.BENEDEN ROUNDDOWN = AFRONDEN.NAAR.BENEDEN
ROUNDUP = AFRONDEN.NAAR.BOVEN ROUNDUP = AFRONDEN.NAAR.BOVEN
SEC = SEC SEC = SEC
@ -449,10 +455,12 @@ DOLLAR = EURO
EXACT = GELIJK EXACT = GELIJK
FIND = VIND.ALLES FIND = VIND.ALLES
FIXED = VAST FIXED = VAST
ISTHAIDIGIT = IS.THAIS.CIJFER
LEFT = LINKS LEFT = LINKS
LEN = LENGTE LEN = LENGTE
LOWER = KLEINE.LETTERS LOWER = KLEINE.LETTERS
MID = DEEL MID = DEEL
NUMBERSTRING = GETALNOTATIE
NUMBERVALUE = NUMERIEKE.WAARDE NUMBERVALUE = NUMERIEKE.WAARDE
PHONETIC = FONETISCH PHONETIC = FONETISCH
PROPER = BEGINLETTERS PROPER = BEGINLETTERS
@ -464,6 +472,10 @@ SUBSTITUTE = SUBSTITUEREN
T = T T = T
TEXT = TEKST TEXT = TEKST
TEXTJOIN = TEKST.COMBINEREN TEXTJOIN = TEKST.COMBINEREN
THAIDIGIT = THAIS.CIJFER
THAINUMSOUND = THAIS.GETAL.GELUID
THAINUMSTRING = THAIS.GETAL.REEKS
THAISTRINGLENGTH = THAIS.REEKS.LENGTE
TRIM = SPATIES.WISSEN TRIM = SPATIES.WISSEN
UNICHAR = UNITEKEN UNICHAR = UNITEKEN
UNICODE = UNICODE UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = BD.WARIANCJA.POPUL
## ##
DATE = DATA DATE = DATA
DATEDIF = DATA.RÓŻNICA DATEDIF = DATA.RÓŻNICA
DATESTRING = DATA.CIĄG.ZNAK
DATEVALUE = DATA.WARTOŚĆ DATEVALUE = DATA.WARTOŚĆ
DAY = DZIEŃ DAY = DZIEŃ
DAYS = DNI DAYS = DNI
@ -53,6 +54,9 @@ NETWORKDAYS = DNI.ROBOCZE
NETWORKDAYS.INTL = DNI.ROBOCZE.NIESTAND NETWORKDAYS.INTL = DNI.ROBOCZE.NIESTAND
NOW = TERAZ NOW = TERAZ
SECOND = SEKUNDA SECOND = SEKUNDA
THAIDAYOFWEEK = TAJ.DZIEŃ.TYGODNIA
THAIMONTHOFYEAR = TAJ.MIESIĄC.ROKU
THAIYEAR = TAJ.ROK
TIME = CZAS TIME = CZAS
TIMEVALUE = CZAS.WARTOŚĆ TIMEVALUE = CZAS.WARTOŚĆ
TODAY = DZIŚ TODAY = DZIŚ
@ -301,6 +305,8 @@ RAND = LOS
RANDBETWEEN = LOS.ZAKR RANDBETWEEN = LOS.ZAKR
ROMAN = RZYMSKIE ROMAN = RZYMSKIE
ROUND = ZAOKR ROUND = ZAOKR
ROUNDBAHTDOWN = ZAOKR.DÓŁ.BAT
ROUNDBAHTUP = ZAOKR.GÓRA.BAT
ROUNDDOWN = ZAOKR.DÓŁ ROUNDDOWN = ZAOKR.DÓŁ
ROUNDUP = ZAOKR.GÓRA ROUNDUP = ZAOKR.GÓRA
SEC = SEC SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = KWOTA
EXACT = PORÓWNAJ EXACT = PORÓWNAJ
FIND = ZNAJDŹ FIND = ZNAJDŹ
FIXED = ZAOKR.DO.TEKST FIXED = ZAOKR.DO.TEKST
ISTHAIDIGIT = CZY.CYFRA.TAJ
LEFT = LEWY LEFT = LEWY
LEN = DŁ LEN = DŁ
LOWER = LITERY.MAŁE LOWER = LITERY.MAŁE
MID = FRAGMENT.TEKSTU MID = FRAGMENT.TEKSTU
NUMBERSTRING = LICZBA.CIĄG.ZNAK
NUMBERVALUE = WARTOŚĆ.LICZBOWA NUMBERVALUE = WARTOŚĆ.LICZBOWA
PROPER = Z.WIELKIEJ.LITERY PROPER = Z.WIELKIEJ.LITERY
REPLACE = ZASTĄP REPLACE = ZASTĄP
@ -464,6 +472,10 @@ SUBSTITUTE = PODSTAW
T = T T = T
TEXT = TEKST TEXT = TEKST
TEXTJOIN = POŁĄCZ.TEKSTY TEXTJOIN = POŁĄCZ.TEKSTY
THAIDIGIT = TAJ.CYFRA
THAINUMSOUND = TAJ.DŹWIĘK.NUM
THAINUMSTRING = TAJ.CIĄG.NUM
THAISTRINGLENGTH = TAJ.DŁUGOŚĆ.CIĄGU
TRIM = USUŃ.ZBĘDNE.ODSTĘPY TRIM = USUŃ.ZBĘDNE.ODSTĘPY
UNICHAR = ZNAK.UNICODE UNICHAR = ZNAK.UNICODE
UNICODE = UNICODE UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = BDVARP
## ##
DATE = DATA DATE = DATA
DATEDIF = DATADIF DATEDIF = DATADIF
DATESTRING = DATA.SÉRIE
DATEVALUE = DATA.VALOR DATEVALUE = DATA.VALOR
DAY = DIA DAY = DIA
DAYS = DIAS DAYS = DIAS
@ -454,6 +455,7 @@ LEFT = ESQUERDA
LEN = NÚM.CARACT LEN = NÚM.CARACT
LOWER = MINÚSCULA LOWER = MINÚSCULA
MID = EXT.TEXTO MID = EXT.TEXTO
NUMBERSTRING = SEQÜÊNCIA.NÚMERO
NUMBERVALUE = VALORNUMÉRICO NUMBERVALUE = VALORNUMÉRICO
PHONETIC = FONÉTICA PHONETIC = FONÉTICA
PROPER = PRI.MAIÚSCULA PROPER = PRI.MAIÚSCULA

View File

@ -39,6 +39,7 @@ DVARP = BDVARP
## ##
DATE = DATA DATE = DATA
DATEDIF = DATADIF DATEDIF = DATADIF
DATESTRING = DATA.CADEIA
DATEVALUE = DATA.VALOR DATEVALUE = DATA.VALOR
DAY = DIA DAY = DIA
DAYS = DIAS DAYS = DIAS
@ -53,6 +54,9 @@ NETWORKDAYS = DIATRABALHOTOTAL
NETWORKDAYS.INTL = DIATRABALHOTOTAL.INTL NETWORKDAYS.INTL = DIATRABALHOTOTAL.INTL
NOW = AGORA NOW = AGORA
SECOND = SEGUNDO SECOND = SEGUNDO
THAIDAYOFWEEK = DIA.DA.SEMANA.TAILANDÊS
THAIMONTHOFYEAR = MÊS.DO.ANO.TAILANDÊS
THAIYEAR = ANO.TAILANDÊS
TIME = TEMPO TIME = TEMPO
TIMEVALUE = VALOR.TEMPO TIMEVALUE = VALOR.TEMPO
TODAY = HOJE TODAY = HOJE
@ -301,6 +305,8 @@ RAND = ALEATÓRIO
RANDBETWEEN = ALEATÓRIOENTRE RANDBETWEEN = ALEATÓRIOENTRE
ROMAN = ROMANO ROMAN = ROMANO
ROUND = ARRED ROUND = ARRED
ROUNDBAHTDOWN = ARREDOND.BAHT.BAIXO
ROUNDBAHTUP = ARREDOND.BAHT.CIMA
ROUNDDOWN = ARRED.PARA.BAIXO ROUNDDOWN = ARRED.PARA.BAIXO
ROUNDUP = ARRED.PARA.CIMA ROUNDUP = ARRED.PARA.CIMA
SEC = SEC SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = MOEDA
EXACT = EXATO EXACT = EXATO
FIND = LOCALIZAR FIND = LOCALIZAR
FIXED = FIXA FIXED = FIXA
ISTHAIDIGIT = É.DÍGITO.TAILANDÊS
LEFT = ESQUERDA LEFT = ESQUERDA
LEN = NÚM.CARAT LEN = NÚM.CARAT
LOWER = MINÚSCULAS LOWER = MINÚSCULAS
MID = SEG.TEXTO MID = SEG.TEXTO
NUMBERSTRING = NÚMERO.CADEIA
NUMBERVALUE = VALOR.NÚMERO NUMBERVALUE = VALOR.NÚMERO
PHONETIC = FONÉTICA PHONETIC = FONÉTICA
PROPER = INICIAL.MAIÚSCULA PROPER = INICIAL.MAIÚSCULA
@ -465,6 +473,10 @@ SUBSTITUTE = SUBST
T = T T = T
TEXT = TEXTO TEXT = TEXTO
TEXTJOIN = UNIRTEXTO TEXTJOIN = UNIRTEXTO
THAIDIGIT = DÍGITO.TAILANDÊS
THAINUMSOUND = SOM.NÚM.TAILANDÊS
THAINUMSTRING = CADEIA.NÚM.TAILANDÊS
THAISTRINGLENGTH = COMP.CADEIA.TAILANDÊS
TRIM = COMPACTAR TRIM = COMPACTAR
UNICHAR = UNICARÁT UNICHAR = UNICARÁT
UNICODE = UNICODE UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = БДДИСПП
## ##
DATE = ДАТА DATE = ДАТА
DATEDIF = РАЗНДАТ DATEDIF = РАЗНДАТ
DATESTRING = СТРОКАДАННЫХ
DATEVALUE = ДАТАЗНАЧ DATEVALUE = ДАТАЗНАЧ
DAY = ДЕНЬ DAY = ДЕНЬ
DAYS = ДНИ DAYS = ДНИ
@ -53,6 +54,9 @@ NETWORKDAYS = ЧИСТРАБДНИ
NETWORKDAYS.INTL = ЧИСТРАБДНИ.МЕЖД NETWORKDAYS.INTL = ЧИСТРАБДНИ.МЕЖД
NOW = ТДАТА NOW = ТДАТА
SECOND = СЕКУНДЫ SECOND = СЕКУНДЫ
THAIDAYOFWEEK = ТАЙДЕНЬНЕД
THAIMONTHOFYEAR = ТАЙМЕСЯЦ
THAIYEAR = ТАЙГОД
TIME = ВРЕМЯ TIME = ВРЕМЯ
TIMEVALUE = ВРЕМЗНАЧ TIMEVALUE = ВРЕМЗНАЧ
TODAY = СЕГОДНЯ TODAY = СЕГОДНЯ
@ -301,6 +305,8 @@ RAND = СЛЧИС
RANDBETWEEN = СЛУЧМЕЖДУ RANDBETWEEN = СЛУЧМЕЖДУ
ROMAN = РИМСКОЕ ROMAN = РИМСКОЕ
ROUND = ОКРУГЛ ROUND = ОКРУГЛ
ROUNDBAHTDOWN = ОКРУГЛБАТВНИЗ
ROUNDBAHTUP = ОКРУГЛБАТВВЕРХ
ROUNDDOWN = ОКРУГЛВНИЗ ROUNDDOWN = ОКРУГЛВНИЗ
ROUNDUP = ОКРУГЛВВЕРХ ROUNDUP = ОКРУГЛВВЕРХ
SEC = SEC SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = РУБЛЬ
EXACT = СОВПАД EXACT = СОВПАД
FIND = НАЙТИ FIND = НАЙТИ
FIXED = ФИКСИРОВАННЫЙ FIXED = ФИКСИРОВАННЫЙ
ISTHAIDIGIT = TAYRAKAMIYSA
LEFT = ЛЕВСИМВ LEFT = ЛЕВСИМВ
LEN = ДЛСТР LEN = ДЛСТР
LOWER = СТРОЧН LOWER = СТРОЧН
MID = ПСТР MID = ПСТР
NUMBERSTRING = СТРОКАЧИСЕЛ
NUMBERVALUE = ЧЗНАЧ NUMBERVALUE = ЧЗНАЧ
PROPER = ПРОПНАЧ PROPER = ПРОПНАЧ
REPLACE = ЗАМЕНИТЬ REPLACE = ЗАМЕНИТЬ
@ -464,6 +472,10 @@ SUBSTITUTE = ПОДСТАВИТЬ
T = Т T = Т
TEXT = ТЕКСТ TEXT = ТЕКСТ
TEXTJOIN = ОБЪЕДИНИТЬ TEXTJOIN = ОБЪЕДИНИТЬ
THAIDIGIT = ТАЙЦИФРА
THAINUMSOUND = ТАЙЧИСЛОВЗВУК
THAINUMSTRING = ТАЙЧИСЛОВСТРОКУ
THAISTRINGLENGTH = ТАЙДЛИНАСТРОКИ
TRIM = СЖПРОБЕЛЫ TRIM = СЖПРОБЕЛЫ
UNICHAR = ЮНИСИМВ UNICHAR = ЮНИСИМВ
UNICODE = UNICODE UNICODE = UNICODE

View File

@ -52,6 +52,9 @@ NETWORKDAYS = NETTOARBETSDAGAR
NETWORKDAYS.INTL = NETTOARBETSDAGAR.INT NETWORKDAYS.INTL = NETTOARBETSDAGAR.INT
NOW = NU NOW = NU
SECOND = SEKUND SECOND = SEKUND
THAIDAYOFWEEK = THAIVECKODAG
THAIMONTHOFYEAR = THAIMÅNAD
THAIYEAR = THAIÅR
TIME = KLOCKSLAG TIME = KLOCKSLAG
TIMEVALUE = TIDVÄRDE TIMEVALUE = TIDVÄRDE
TODAY = IDAG TODAY = IDAG
@ -300,6 +303,8 @@ RAND = SLUMP
RANDBETWEEN = SLUMP.MELLAN RANDBETWEEN = SLUMP.MELLAN
ROMAN = ROMERSK ROMAN = ROMERSK
ROUND = AVRUNDA ROUND = AVRUNDA
ROUNDBAHTDOWN = AVRUNDABAHTNEDÅT
ROUNDBAHTUP = AVRUNDABAHTUPPÅT
ROUNDDOWN = AVRUNDA.NEDÅT ROUNDDOWN = AVRUNDA.NEDÅT
ROUNDUP = AVRUNDA.UPPÅT ROUNDUP = AVRUNDA.UPPÅT
SEC = SEK SEC = SEK
@ -463,6 +468,10 @@ SUBSTITUTE = BYT.UT
T = T T = T
TEXT = TEXT TEXT = TEXT
TEXTJOIN = TEXTJOIN TEXTJOIN = TEXTJOIN
THAIDIGIT = THAISIFFRA
THAINUMSOUND = THAITALLJUD
THAINUMSTRING = THAITALSTRÄNG
THAISTRINGLENGTH = THAISTRÄNGLÄNGD
TRIM = RENSA TRIM = RENSA
UNICHAR = UNITECKENKOD UNICHAR = UNITECKENKOD
UNICODE = UNICODE UNICODE = UNICODE

View File

@ -39,6 +39,7 @@ DVARP = VSEÇVARS
## ##
DATE = TARİH DATE = TARİH
DATEDIF = ETARİHLİ DATEDIF = ETARİHLİ
DATESTRING = TARİHDİZİ
DATEVALUE = TARİHSAYISI DATEVALUE = TARİHSAYISI
DAY = GÜN DAY = GÜN
DAYS = GÜNSAY DAYS = GÜNSAY
@ -53,6 +54,9 @@ NETWORKDAYS = TAMİŞGÜNÜ
NETWORKDAYS.INTL = TAMİŞGÜNÜ.ULUSL NETWORKDAYS.INTL = TAMİŞGÜNÜ.ULUSL
NOW = ŞİMDİ NOW = ŞİMDİ
SECOND = SANİYE SECOND = SANİYE
THAIDAYOFWEEK = TAYHAFTANINGÜNÜ
THAIMONTHOFYEAR = TAYYILINAYI
THAIYEAR = TAYYILI
TIME = ZAMAN TIME = ZAMAN
TIMEVALUE = ZAMANSAYISI TIMEVALUE = ZAMANSAYISI
TODAY = BUGÜN TODAY = BUGÜN
@ -301,6 +305,8 @@ RAND = S_SAYI_ÜRET
RANDBETWEEN = RASTGELEARADA RANDBETWEEN = RASTGELEARADA
ROMAN = ROMEN ROMAN = ROMEN
ROUND = YUVARLA ROUND = YUVARLA
ROUNDBAHTDOWN = BAHTAŞAĞIYUVARLA
ROUNDBAHTUP = BAHTYUKARIYUVARLA
ROUNDDOWN = AŞAĞIYUVARLA ROUNDDOWN = AŞAĞIYUVARLA
ROUNDUP = YUKARIYUVARLA ROUNDUP = YUKARIYUVARLA
SEC = SEC SEC = SEC
@ -450,10 +456,12 @@ DOLLAR = LİRA
EXACT = ÖZDEŞ EXACT = ÖZDEŞ
FIND = BUL FIND = BUL
FIXED = SAYIDÜZENLE FIXED = SAYIDÜZENLE
ISTHAIDIGIT = TAYRAKAMIYSA
LEFT = SOLDAN LEFT = SOLDAN
LEN = UZUNLUK LEN = UZUNLUK
LOWER = KÜÇÜKHARF LOWER = KÜÇÜKHARF
MID = PARÇAAL MID = PARÇAAL
NUMBERSTRING = SAYIDİZİ
NUMBERVALUE = SAYIDEĞERİ NUMBERVALUE = SAYIDEĞERİ
PHONETIC = SES PHONETIC = SES
PROPER = YAZIM.DÜZENİ PROPER = YAZIM.DÜZENİ
@ -465,6 +473,10 @@ SUBSTITUTE = YERİNEKOY
T = M T = M
TEXT = METNEÇEVİR TEXT = METNEÇEVİR
TEXTJOIN = METİNBİRLEŞTİR TEXTJOIN = METİNBİRLEŞTİR
THAIDIGIT = TAYRAKAM
THAINUMSOUND = TAYSAYISES
THAINUMSTRING = TAYSAYIDİZE
THAISTRINGLENGTH = TAYDİZEUZUNLUĞU
TRIM = KIRP TRIM = KIRP
UNICHAR = UNICODEKARAKTERİ UNICHAR = UNICODEKARAKTERİ
UNICODE = UNICODE UNICODE = UNICODE

View File

@ -50,156 +50,87 @@ class Security
/** /**
* Is some sort of document security enabled? * Is some sort of document security enabled?
*
* @return bool
*/ */
public function isSecurityEnabled() public function isSecurityEnabled(): bool
{ {
return $this->lockRevision || return $this->lockRevision ||
$this->lockStructure || $this->lockStructure ||
$this->lockWindows; $this->lockWindows;
} }
/** public function getLockRevision(): bool
* Get LockRevision.
*
* @return bool
*/
public function getLockRevision()
{ {
return $this->lockRevision; return $this->lockRevision;
} }
/** public function setLockRevision(?bool $pValue): self
* Set LockRevision.
*
* @param bool $pValue
*
* @return $this
*/
public function setLockRevision($pValue)
{ {
if ($pValue !== null) {
$this->lockRevision = $pValue; $this->lockRevision = $pValue;
}
return $this; return $this;
} }
/** public function getLockStructure(): bool
* Get LockStructure.
*
* @return bool
*/
public function getLockStructure()
{ {
return $this->lockStructure; return $this->lockStructure;
} }
/** public function setLockStructure(?bool $pValue): self
* Set LockStructure.
*
* @param bool $pValue
*
* @return $this
*/
public function setLockStructure($pValue)
{ {
if ($pValue !== null) {
$this->lockStructure = $pValue; $this->lockStructure = $pValue;
}
return $this; return $this;
} }
/** public function getLockWindows(): bool
* Get LockWindows.
*
* @return bool
*/
public function getLockWindows()
{ {
return $this->lockWindows; return $this->lockWindows;
} }
/** public function setLockWindows(?bool $pValue): self
* Set LockWindows.
*
* @param bool $pValue
*
* @return $this
*/
public function setLockWindows($pValue)
{ {
if ($pValue !== null) {
$this->lockWindows = $pValue; $this->lockWindows = $pValue;
}
return $this; return $this;
} }
/** public function getRevisionsPassword(): string
* Get RevisionsPassword (hashed).
*
* @return string
*/
public function getRevisionsPassword()
{ {
return $this->revisionsPassword; return $this->revisionsPassword;
} }
/** public function setRevisionsPassword(?string $pValue, bool $pAlreadyHashed = false): self
* Set RevisionsPassword.
*
* @param string $pValue
* @param bool $pAlreadyHashed If the password has already been hashed, set this to true
*
* @return $this
*/
public function setRevisionsPassword($pValue, $pAlreadyHashed = false)
{ {
if ($pValue !== null) {
if (!$pAlreadyHashed) { if (!$pAlreadyHashed) {
$pValue = PasswordHasher::hashPassword($pValue); $pValue = PasswordHasher::hashPassword($pValue);
} }
$this->revisionsPassword = $pValue; $this->revisionsPassword = $pValue;
}
return $this; return $this;
} }
/** public function getWorkbookPassword(): string
* Get WorkbookPassword (hashed).
*
* @return string
*/
public function getWorkbookPassword()
{ {
return $this->workbookPassword; return $this->workbookPassword;
} }
/** public function setWorkbookPassword(?string $pValue, bool $pAlreadyHashed = false): self
* Set WorkbookPassword.
*
* @param string $pValue
* @param bool $pAlreadyHashed If the password has already been hashed, set this to true
*
* @return $this
*/
public function setWorkbookPassword($pValue, $pAlreadyHashed = false)
{ {
if ($pValue !== null) {
if (!$pAlreadyHashed) { if (!$pAlreadyHashed) {
$pValue = PasswordHasher::hashPassword($pValue); $pValue = PasswordHasher::hashPassword($pValue);
} }
$this->workbookPassword = $pValue; $this->workbookPassword = $pValue;
}
return $this; return $this;
} }
/**
* Implement PHP __clone to create a deep clone, not just a shallow copy.
*/
public function __clone()
{
$vars = get_object_vars($this);
foreach ($vars as $key => $value) {
if (is_object($value)) {
$this->$key = clone $value;
} else {
$this->$key = $value;
}
}
}
} }

View File

@ -170,8 +170,15 @@ class HashTable
{ {
$vars = get_object_vars($this); $vars = get_object_vars($this);
foreach ($vars as $key => $value) { foreach ($vars as $key => $value) {
if (is_object($value)) { // each member of this class is an array
$this->$key = clone $value; if (is_array($value)) {
$array1 = $value;
foreach ($array1 as $key1 => $value1) {
if (is_object($value1)) {
$array1[$key1] = clone $value1;
}
}
$this->$key = $array1;
} }
} }
} }

View File

@ -10,6 +10,8 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet;
class Csv extends BaseReader class Csv extends BaseReader
{ {
const DEFAULT_FALLBACK_ENCODING = 'CP1252';
const GUESS_ENCODING = 'guess';
const UTF8_BOM = "\xEF\xBB\xBF"; const UTF8_BOM = "\xEF\xBB\xBF";
const UTF8_BOM_LEN = 3; const UTF8_BOM_LEN = 3;
const UTF16BE_BOM = "\xfe\xff"; const UTF16BE_BOM = "\xfe\xff";
@ -33,10 +35,17 @@ class Csv extends BaseReader
private $inputEncoding = 'UTF-8'; private $inputEncoding = 'UTF-8';
/** /**
* Delimiter. * Fallback encoding if 'guess' strikes out.
* *
* @var string * @var string
*/ */
private $fallbackEncoding = self::DEFAULT_FALLBACK_ENCODING;
/**
* Delimiter.
*
* @var ?string
*/
private $delimiter; private $delimiter;
/** /**
@ -67,38 +76,65 @@ class Csv extends BaseReader
*/ */
private $escapeCharacter = '\\'; private $escapeCharacter = '\\';
/**
* Callback for setting defaults in construction.
*
* @var ?callable
*/
private static $constructorCallback;
/** /**
* Create a new CSV Reader instance. * Create a new CSV Reader instance.
*/ */
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
$callback = self::$constructorCallback;
if ($callback !== null) {
$callback($this);
}
} }
/** /**
* Set input encoding. * Set a callback to change the defaults.
* *
* @param string $pValue Input encoding, eg: 'UTF-8' * The callback must accept the Csv Reader object as the first parameter,
* * and it should return void.
* @return $this
*/ */
public function setInputEncoding($pValue) public static function setConstructorCallback(?callable $callback): void
{
self::$constructorCallback = $callback;
}
public static function getConstructorCallback(): ?callable
{
return self::$constructorCallback;
}
public function setInputEncoding(string $pValue): self
{ {
$this->inputEncoding = $pValue; $this->inputEncoding = $pValue;
return $this; return $this;
} }
/** public function getInputEncoding(): string
* Get input encoding.
*
* @return string
*/
public function getInputEncoding()
{ {
return $this->inputEncoding; return $this->inputEncoding;
} }
public function setFallbackEncoding(string $pValue): self
{
$this->fallbackEncoding = $pValue;
return $this;
}
public function getFallbackEncoding(): string
{
return $this->fallbackEncoding;
}
/** /**
* Move filepointer past any BOM marker. * Move filepointer past any BOM marker.
*/ */
@ -161,12 +197,8 @@ class Csv extends BaseReader
/** /**
* Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns).
*
* @param string $pFilename
*
* @return array
*/ */
public function listWorksheetInfo($pFilename) public function listWorksheetInfo(string $pFilename): array
{ {
// Open file // Open file
$this->openFileOrMemory($pFilename); $this->openFileOrMemory($pFilename);
@ -185,9 +217,11 @@ class Csv extends BaseReader
$worksheetInfo[0]['totalColumns'] = 0; $worksheetInfo[0]['totalColumns'] = 0;
// Loop through each line of the file in turn // Loop through each line of the file in turn
while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure, $this->escapeCharacter)) !== false) { $rowData = fgetcsv($fileHandle, 0, $this->delimiter ?? '', $this->enclosure, $this->escapeCharacter);
while (is_array($rowData)) {
++$worksheetInfo[0]['totalRows']; ++$worksheetInfo[0]['totalRows'];
$worksheetInfo[0]['lastColumnIndex'] = max($worksheetInfo[0]['lastColumnIndex'], count($rowData) - 1); $worksheetInfo[0]['lastColumnIndex'] = max($worksheetInfo[0]['lastColumnIndex'], count($rowData) - 1);
$rowData = fgetcsv($fileHandle, 0, $this->delimiter ?? '', $this->enclosure, $this->escapeCharacter);
} }
$worksheetInfo[0]['lastColumnLetter'] = Coordinate::stringFromColumnIndex($worksheetInfo[0]['lastColumnIndex'] + 1); $worksheetInfo[0]['lastColumnLetter'] = Coordinate::stringFromColumnIndex($worksheetInfo[0]['lastColumnIndex'] + 1);
@ -215,34 +249,35 @@ class Csv extends BaseReader
return $this->loadIntoExisting($pFilename, $spreadsheet); return $this->loadIntoExisting($pFilename, $spreadsheet);
} }
private function openFileOrMemory($pFilename): void private function openFileOrMemory(string $pFilename): void
{ {
// Open file // Open file
$fhandle = $this->canRead($pFilename); $fhandle = $this->canRead($pFilename);
if (!$fhandle) { if (!$fhandle) {
throw new Exception($pFilename . ' is an Invalid Spreadsheet file.'); throw new Exception($pFilename . ' is an Invalid Spreadsheet file.');
} }
if ($this->inputEncoding === self::GUESS_ENCODING) {
$this->inputEncoding = self::guessEncoding($pFilename, $this->fallbackEncoding);
}
$this->openFile($pFilename); $this->openFile($pFilename);
if ($this->inputEncoding !== 'UTF-8') { if ($this->inputEncoding !== 'UTF-8') {
fclose($this->fileHandle); fclose($this->fileHandle);
$entireFile = file_get_contents($pFilename); $entireFile = file_get_contents($pFilename);
$this->fileHandle = fopen('php://memory', 'r+b'); $this->fileHandle = fopen('php://memory', 'r+b');
if ($this->fileHandle !== false && $entireFile !== false) {
$data = StringHelper::convertEncoding($entireFile, 'UTF-8', $this->inputEncoding); $data = StringHelper::convertEncoding($entireFile, 'UTF-8', $this->inputEncoding);
fwrite($this->fileHandle, $data); fwrite($this->fileHandle, $data);
$this->skipBOM(); $this->skipBOM();
} }
} }
}
/** /**
* Loads PhpSpreadsheet from file into PhpSpreadsheet instance. * Loads PhpSpreadsheet from file into PhpSpreadsheet instance.
*
* @param string $pFilename
*
* @return Spreadsheet
*/ */
public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet) public function loadIntoExisting(string $pFilename, Spreadsheet $spreadsheet): Spreadsheet
{ {
$lineEnding = ini_get('auto_detect_line_endings'); $lineEnding = ini_get('auto_detect_line_endings') ?: '0';
ini_set('auto_detect_line_endings', '1'); ini_set('auto_detect_line_endings', '1');
// Open file // Open file
@ -265,7 +300,8 @@ class Csv extends BaseReader
$outRow = 0; $outRow = 0;
// Loop through each line of the file in turn // Loop through each line of the file in turn
while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure, $this->escapeCharacter)) !== false) { $rowData = fgetcsv($fileHandle, 0, $this->delimiter ?? '', $this->enclosure, $this->escapeCharacter);
while (is_array($rowData)) {
$noOutputYet = true; $noOutputYet = true;
$columnLetter = 'A'; $columnLetter = 'A';
foreach ($rowData as $rowDatum) { foreach ($rowData as $rowDatum) {
@ -283,6 +319,7 @@ class Csv extends BaseReader
} }
++$columnLetter; ++$columnLetter;
} }
$rowData = fgetcsv($fileHandle, 0, $this->delimiter ?? '', $this->enclosure, $this->escapeCharacter);
++$currentRow; ++$currentRow;
} }
@ -295,48 +332,24 @@ class Csv extends BaseReader
return $spreadsheet; return $spreadsheet;
} }
/** public function getDelimiter(): ?string
* Get delimiter.
*
* @return string
*/
public function getDelimiter()
{ {
return $this->delimiter; return $this->delimiter;
} }
/** public function setDelimiter(string $delimiter): self
* Set delimiter.
*
* @param string $delimiter Delimiter, eg: ','
*
* @return $this
*/
public function setDelimiter($delimiter)
{ {
$this->delimiter = $delimiter; $this->delimiter = $delimiter;
return $this; return $this;
} }
/** public function getEnclosure(): string
* Get enclosure.
*
* @return string
*/
public function getEnclosure()
{ {
return $this->enclosure; return $this->enclosure;
} }
/** public function setEnclosure(string $enclosure): self
* Set enclosure.
*
* @param string $enclosure Enclosure, defaults to "
*
* @return $this
*/
public function setEnclosure($enclosure)
{ {
if ($enclosure == '') { if ($enclosure == '') {
$enclosure = '"'; $enclosure = '"';
@ -346,78 +359,55 @@ class Csv extends BaseReader
return $this; return $this;
} }
/** public function getSheetIndex(): int
* Get sheet index.
*
* @return int
*/
public function getSheetIndex()
{ {
return $this->sheetIndex; return $this->sheetIndex;
} }
/** public function setSheetIndex(int $pValue): self
* Set sheet index.
*
* @param int $pValue Sheet index
*
* @return $this
*/
public function setSheetIndex($pValue)
{ {
$this->sheetIndex = $pValue; $this->sheetIndex = $pValue;
return $this; return $this;
} }
/** public function setContiguous(bool $contiguous): self
* Set Contiguous.
*
* @param bool $contiguous
*
* @return $this
*/
public function setContiguous($contiguous)
{ {
$this->contiguous = (bool) $contiguous; $this->contiguous = (bool) $contiguous;
return $this; return $this;
} }
/** public function getContiguous(): bool
* Get Contiguous.
*
* @return bool
*/
public function getContiguous()
{ {
return $this->contiguous; return $this->contiguous;
} }
/** public function setEscapeCharacter(string $escapeCharacter): self
* Set escape backslashes.
*
* @param string $escapeCharacter
*
* @return $this
*/
public function setEscapeCharacter($escapeCharacter)
{ {
$this->escapeCharacter = $escapeCharacter; $this->escapeCharacter = $escapeCharacter;
return $this; return $this;
} }
/** public function getEscapeCharacter(): string
* Get escape backslashes.
*
* @return string
*/
public function getEscapeCharacter()
{ {
return $this->escapeCharacter; return $this->escapeCharacter;
} }
/**
* Scrutinizer believes, incorrectly, that the specific pathinfo
* call in canRead can return something other than an array.
* Phpstan knows better.
* This function satisfies both.
*
* @param mixed $extension
*/
private static function extractStringLower($extension): string
{
return is_string($extension) ? strtolower($extension) : '';
}
/** /**
* Can the current IReader read the file? * Can the current IReader read the file?
* *
@ -437,8 +427,7 @@ class Csv extends BaseReader
fclose($this->fileHandle); fclose($this->fileHandle);
// Trust file extension if any // Trust file extension if any
$extension = pathinfo($pFilename, PATHINFO_EXTENSION); $extension = self::extractStringLower(pathinfo($pFilename, PATHINFO_EXTENSION));
$extension = is_array($extension) ? '' : strtolower($extension);
if (in_array($extension, ['csv', 'tsv'])) { if (in_array($extension, ['csv', 'tsv'])) {
return true; return true;
} }
@ -504,7 +493,7 @@ class Csv extends BaseReader
return $encoding; return $encoding;
} }
public static function guessEncoding(string $filename, string $dflt = 'CP1252'): string public static function guessEncoding(string $filename, string $dflt = self::DEFAULT_FALLBACK_ENCODING): string
{ {
$encoding = self::guessEncodingBom($filename); $encoding = self::guessEncodingBom($filename);
if ($encoding === '') { if ($encoding === '') {

View File

@ -6,19 +6,28 @@ class Delimiter
{ {
protected const POTENTIAL_DELIMETERS = [',', ';', "\t", '|', ':', ' ', '~']; protected const POTENTIAL_DELIMETERS = [',', ';', "\t", '|', ':', ' ', '~'];
/** @var resource */
protected $fileHandle; protected $fileHandle;
/** @var string */
protected $escapeCharacter; protected $escapeCharacter;
/** @var string */
protected $enclosure; protected $enclosure;
/** @var array */
protected $counts = []; protected $counts = [];
/** @var int */
protected $numberLines = 0; protected $numberLines = 0;
/** @var ?string */
protected $delimiter; protected $delimiter;
public function __construct($fileHandle, $escapeCharacter, $enclosure) /**
* @param resource $fileHandle
*/
public function __construct($fileHandle, string $escapeCharacter, string $enclosure)
{ {
$this->fileHandle = $fileHandle; $this->fileHandle = $fileHandle;
$this->escapeCharacter = $escapeCharacter; $this->escapeCharacter = $escapeCharacter;
@ -52,10 +61,7 @@ class Delimiter
protected function countDelimiterValues(string $line, array $delimiterKeys): void protected function countDelimiterValues(string $line, array $delimiterKeys): void
{ {
$splitString = str_split($line, 1); $splitString = str_split($line, 1);
if (!is_array($splitString)) { if (is_array($splitString)) {
return;
}
$distribution = array_count_values($splitString); $distribution = array_count_values($splitString);
$countLine = array_intersect_key($distribution, $delimiterKeys); $countLine = array_intersect_key($distribution, $delimiterKeys);
@ -63,6 +69,7 @@ class Delimiter
$this->counts[$delimiter][] = $countLine[$delimiter] ?? 0; $this->counts[$delimiter][] = $countLine[$delimiter] ?? 0;
} }
} }
}
public function infer(): ?string public function infer(): ?string
{ {
@ -137,8 +144,8 @@ class Delimiter
// See if we have any enclosures left in the line // See if we have any enclosures left in the line
// if we still have an enclosure then we need to read the next line as well // if we still have an enclosure then we need to read the next line as well
} while (preg_match('/(' . $enclosure . ')/', $line) > 0); } while (preg_match('/(' . $enclosure . ')/', $line ?? '') > 0);
return $line; return $line ?? false;
} }
} }

View File

@ -1808,17 +1808,9 @@ class Xlsx extends BaseReader
return; return;
} }
if ($xmlWorkbook->workbookProtection['lockRevision']) { $excel->getSecurity()->setLockRevision(self::getLockValue($xmlWorkbook->workbookProtection, 'lockRevision'));
$excel->getSecurity()->setLockRevision((bool) $xmlWorkbook->workbookProtection['lockRevision']); $excel->getSecurity()->setLockStructure(self::getLockValue($xmlWorkbook->workbookProtection, 'lockStructure'));
} $excel->getSecurity()->setLockWindows(self::getLockValue($xmlWorkbook->workbookProtection, 'lockWindows'));
if ($xmlWorkbook->workbookProtection['lockStructure']) {
$excel->getSecurity()->setLockStructure((bool) $xmlWorkbook->workbookProtection['lockStructure']);
}
if ($xmlWorkbook->workbookProtection['lockWindows']) {
$excel->getSecurity()->setLockWindows((bool) $xmlWorkbook->workbookProtection['lockWindows']);
}
if ($xmlWorkbook->workbookProtection['revisionsPassword']) { if ($xmlWorkbook->workbookProtection['revisionsPassword']) {
$excel->getSecurity()->setRevisionsPassword( $excel->getSecurity()->setRevisionsPassword(
@ -1835,6 +1827,18 @@ class Xlsx extends BaseReader
} }
} }
private static function getLockValue(SimpleXmlElement $protection, string $key): ?bool
{
$returnValue = null;
$protectKey = $protection[$key];
if (!empty($protectKey)) {
$protectKey = (string) $protectKey;
$returnValue = $protectKey !== 'false' && (bool) $protectKey;
}
return $returnValue;
}
private function readFormControlProperties(Spreadsheet $excel, ZipArchive $zip, $dir, $fileWorksheet, $docSheet, array &$unparsedLoadedData): void private function readFormControlProperties(Spreadsheet $excel, ZipArchive $zip, $dir, $fileWorksheet, $docSheet, array &$unparsedLoadedData): void
{ {
if (!$zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) { if (!$zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {

View File

@ -213,20 +213,20 @@ class Font extends Supervisor
/** /**
* Set Name. * Set Name.
* *
* @param string $pValue * @param string $fontname
* *
* @return $this * @return $this
*/ */
public function setName($pValue) public function setName($fontname)
{ {
if ($pValue == '') { if ($fontname == '') {
$pValue = 'Calibri'; $fontname = 'Calibri';
} }
if ($this->isSupervisor) { if ($this->isSupervisor) {
$styleArray = $this->getStyleArray(['name' => $pValue]); $styleArray = $this->getStyleArray(['name' => $fontname]);
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
} else { } else {
$this->name = $pValue; $this->name = $fontname;
} }
return $this; return $this;
@ -249,20 +249,27 @@ class Font extends Supervisor
/** /**
* Set Size. * Set Size.
* *
* @param float $pValue * @param mixed $sizeInPoints A float representing the value of a positive measurement in points (1/72 of an inch)
* *
* @return $this * @return $this
*/ */
public function setSize($pValue) public function setSize($sizeInPoints)
{ {
if ($pValue == '') { if (is_string($sizeInPoints) || is_int($sizeInPoints)) {
$pValue = 10; $sizeInPoints = (float) $sizeInPoints; // $pValue = 0 if given string is not numeric
} }
// Size must be a positive floating point number
// ECMA-376-1:2016, part 1, chapter 18.4.11 sz (Font Size), p. 1536
if (!is_float($sizeInPoints) || !($sizeInPoints > 0)) {
$sizeInPoints = 10.0;
}
if ($this->isSupervisor) { if ($this->isSupervisor) {
$styleArray = $this->getStyleArray(['size' => $pValue]); $styleArray = $this->getStyleArray(['size' => $sizeInPoints]);
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
} else { } else {
$this->size = $pValue; $this->size = $sizeInPoints;
} }
return $this; return $this;

View File

@ -0,0 +1,75 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Document;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class SecurityTest extends AbstractFunctional
{
public function testSecurity(): void
{
$spreadsheet = new Spreadsheet();
$spreadsheet->getActiveSheet()->getCell('A1')->setValue('Hello');
$security = $spreadsheet->getSecurity();
$security->setLockRevision(true);
$revisionsPassword = 'revpasswd';
$security->setRevisionsPassword($revisionsPassword);
$hashedRevisionsPassword = $security->getRevisionsPassword();
self::assertNotEquals($revisionsPassword, $hashedRevisionsPassword);
$security->setLockWindows(true);
$security->setLockStructure(true);
$workbookPassword = 'wbpasswd';
$security->setWorkbookPassword($workbookPassword);
$hashedWorkbookPassword = $security->getWorkbookPassword();
self::assertNotEquals($workbookPassword, $hashedWorkbookPassword);
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
$reloadedSecurity = $reloadedSpreadsheet->getSecurity();
self::assertTrue($reloadedSecurity->getLockRevision());
self::assertTrue($reloadedSecurity->getLockWindows());
self::assertTrue($reloadedSecurity->getLockStructure());
self::assertSame($hashedWorkbookPassword, $reloadedSecurity->getWorkbookPassword());
self::assertSame($hashedRevisionsPassword, $reloadedSecurity->getRevisionsPassword());
$reloadedSecurity->setRevisionsPassword($hashedWorkbookPassword, true);
self::assertSame($hashedWorkbookPassword, $reloadedSecurity->getRevisionsPassword());
$reloadedSecurity->setWorkbookPassword($hashedRevisionsPassword, true);
self::assertSame($hashedRevisionsPassword, $reloadedSecurity->getWorkbookPassword());
}
public function providerLocks(): array
{
return [
[false, false, false],
[false, false, true],
[false, true, false],
[false, true, true],
[true, false, false],
[true, false, true],
[true, true, false],
[true, true, true],
];
}
/**
* @dataProvider providerLocks
*/
public function testLocks(bool $revision, bool $windows, bool $structure): void
{
$spreadsheet = new Spreadsheet();
$spreadsheet->getActiveSheet()->getCell('A1')->setValue('Hello');
$security = $spreadsheet->getSecurity();
$security->setLockRevision($revision);
$security->setLockWindows($windows);
$security->setLockStructure($structure);
$enabled = $security->isSecurityEnabled();
self::assertSame($enabled, $revision || $windows || $structure);
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
$reloadedSecurity = $reloadedSpreadsheet->getSecurity();
self::assertSame($revision, $reloadedSecurity->getLockRevision());
self::assertSame($windows, $reloadedSecurity->getLockWindows());
self::assertSame($structure, $reloadedSecurity->getLockStructure());
}
}

View File

@ -5,7 +5,7 @@ namespace PhpOffice\PhpSpreadsheetTests;
use PhpOffice\PhpSpreadsheet\Calculation\Category as Cat; use PhpOffice\PhpSpreadsheet\Calculation\Category as Cat;
use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Logical; use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PhpOffice\PhpSpreadsheet\DocumentGenerator; use PhpOffice\PhpSpreadsheetInfra\DocumentGenerator;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use UnexpectedValueException; use UnexpectedValueException;

View File

@ -0,0 +1,92 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests;
use PhpOffice\PhpSpreadsheet\Comment; // need Comparable object
use PhpOffice\PhpSpreadsheet\HashTable;
use PHPUnit\Framework\TestCase;
class HashTableTest extends TestCase
{
public static function createArray(): array
{
$comment1 = new Comment();
$comment1->setAuthor('Author1');
$comment2 = new Comment();
$comment2->setAuthor('Author2');
return [$comment1, $comment2];
}
/**
* @param mixed $comment
*/
public static function getAuthor($comment): string
{
return ($comment instanceof Comment) ? $comment->getAuthor() : '';
}
public function testAddRemoveClear(): void
{
$array1 = self::createArray();
$hash1 = new HashTable($array1);
self::assertSame(2, $hash1->count());
$comment3 = new Comment();
$comment3->setAuthor('Author3');
$hash1->add($comment3);
$comment4 = new Comment();
$comment4->setAuthor('Author4');
$hash1->add($comment4);
$comment5 = new Comment();
$comment5->setAuthor('Author5');
// don't add comment5
self::assertSame(4, $hash1->count());
self::assertNull($hash1->getByIndex(10));
$comment = $hash1->getByIndex(2);
self::assertSame('Author3', self::getAuthor($comment));
$hash1->remove($comment3);
self::assertSame(3, $hash1->count());
$comment = $hash1->getByIndex(2);
self::assertSame('Author4', self::getAuthor($comment));
$hash1->remove($comment5);
self::assertSame(3, $hash1->count(), 'Remove non-hash member');
$comment = $hash1->getByIndex(2);
self::assertSame('Author4', self::getAuthor($comment));
self::assertNull($hash1->getByHashCode('xyz'));
$hash1->clear();
self::AssertSame(0, $hash1->count());
}
public function testToArray(): void
{
$array1 = self::createArray();
$count1 = count($array1);
$hash1 = new HashTable($array1);
$array2 = $hash1->toArray();
self::assertCount($count1, $array2);
$idx = 0;
foreach ($array2 as $key => $value) {
self::assertEquals($array1[$idx], $value, "Item $idx");
self::assertSame($idx, $hash1->getIndexForHashCode($key));
++$idx;
}
}
public function testClone(): void
{
$array1 = self::createArray();
$hash1 = new HashTable($array1);
$hash2 = new HashTable();
self::assertSame(0, $hash2->count());
$hash2->addFromSource();
self::assertSame(0, $hash2->count());
$hash2->addFromSource($array1);
self::assertSame(2, $hash2->count());
self::assertEquals($hash1, $hash2, 'Add in constructor same as addFromSource');
$hash3 = clone $hash1;
self::assertEquals($hash1, $hash3, 'Clone equal to original');
self::assertSame($hash1->getByIndex(0), $hash2->getByIndex(0));
self::assertEquals($hash1->getByIndex(0), $hash3->getByIndex(0));
self::assertNotSame($hash1->getByIndex(0), $hash3->getByIndex(0));
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheetInfra\LocaleGenerator;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
class LocaleGeneratorTest extends TestCase
{
public function testLocaleGenerator(): void
{
$phpSpreadsheetFunctionsProperty = (new ReflectionClass(Calculation::class))
->getProperty('phpSpreadsheetFunctions');
$phpSpreadsheetFunctionsProperty->setAccessible(true);
$phpSpreadsheetFunctions = $phpSpreadsheetFunctionsProperty->getValue();
$localeGenerator = new LocaleGenerator(
(string) realpath(__DIR__ . '/../../src/PhpSpreadsheet/Calculation/locale/'),
'Translations.xlsx',
$phpSpreadsheetFunctions
);
$localeGenerator->generateLocales();
$testLocales = [
'fr',
'nl',
'pt',
'pt_br',
'ru',
];
foreach ($testLocales as $locale) {
$locale = str_replace('_', '/', $locale);
$path = realpath(__DIR__ . "/../../src/PhpSpreadsheet/Calculation/locale/{$locale}");
self::assertFileExists("{$path}/config");
self::assertFileExists("{$path}/functions");
}
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PHPUnit\Framework\TestCase;
class CsvCallbackTest extends TestCase
{
protected function tearDown(): void
{
Csv::setConstructorCallback(null);
}
/**
* @param mixed $obj
*/
public function callbackDoNothing($obj): void
{
self::assertInstanceOf(Csv::class, $obj);
}
public function testCallbackDoNothing(): void
{
Csv::setConstructorCallback([$this, 'callbackDoNothing']);
$filename = 'tests/data/Reader/CSV/encoding.iso88591.csv';
$reader = new Csv();
$reader->setInputEncoding(Csv::GUESS_ENCODING);
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('Å', $sheet->getCell('A1')->getValue());
}
public function callbackSetFallbackEncoding(Csv $reader): void
{
$reader->setFallbackEncoding('ISO-8859-2');
$reader->setInputEncoding(Csv::GUESS_ENCODING);
$reader->setEscapeCharacter((version_compare(PHP_VERSION, '7.4') < 0) ? "\x0" : '');
}
public function testFallbackEncodingDefltIso2(): void
{
Csv::setConstructorCallback([$this, 'callbackSetFallbackEncoding']);
$filename = 'tests/data/Reader/CSV/premiere.win1252.csv';
$reader = new Csv();
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('premičre', $sheet->getCell('A1')->getValue());
self::assertEquals('sixičme', $sheet->getCell('C2')->getValue());
}
public function testIOFactory(): void
{
Csv::setConstructorCallback([$this, 'callbackSetFallbackEncoding']);
$filename = 'tests/data/Reader/CSV/premiere.win1252.csv';
$spreadsheet = IOFactory::load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('premičre', $sheet->getCell('A1')->getValue());
self::assertEquals('sixičme', $sheet->getCell('C2')->getValue());
}
public function testNonFallbackEncoding(): void
{
Csv::setConstructorCallback([$this, 'callbackSetFallbackEncoding']);
$filename = 'tests/data/Reader/CSV/premiere.utf16be.csv';
$reader = new Csv();
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('première', $sheet->getCell('A1')->getValue());
self::assertEquals('sixième', $sheet->getCell('C2')->getValue());
}
public function testDefaultEscape(): void
{
self::assertNull(Csv::getConstructorCallback());
$filename = 'tests/data/Reader/CSV/escape.csv';
$spreadsheet = IOFactory::load($filename);
$sheet = $spreadsheet->getActiveSheet();
// this is not how Excel views the file
self::assertEquals('a\"hello', $sheet->getCell('A1')->getValue());
}
public function testBetterEscape(): void
{
Csv::setConstructorCallback([$this, 'callbackSetFallbackEncoding']);
$filename = 'tests/data/Reader/CSV/escape.csv';
$spreadsheet = IOFactory::load($filename);
$sheet = $spreadsheet->getActiveSheet();
// this is how Excel views the file
self::assertEquals('a\"hello;hello;hello;\"', $sheet->getCell('A1')->getValue());
}
}

View File

@ -1,6 +1,6 @@
<?php <?php
namespace PhpOffice\PhpSpreadsheetTests\Reader; namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\IReadFilter; use PhpOffice\PhpSpreadsheet\Reader\IReadFilter;
@ -34,18 +34,18 @@ class CsvContiguousFilter implements IReadFilter
$this->endRow = $startRow + $chunkSize; $this->endRow = $startRow + $chunkSize;
} }
public function setFilterType($type): void public function setFilterType(int $type): void
{ {
$this->filterType = $type; $this->filterType = $type;
} }
public function filter1($row) public function filter1(int $row): bool
{ {
// Include rows 1-10, followed by 100-110, etc. // Include rows 1-10, followed by 100-110, etc.
return $row % 100 <= 10; return $row % 100 <= 10;
} }
public function filter0($row) public function filter0(int $row): bool
{ {
// Only read the heading row, and the rows that are configured in $this->_startRow and $this->_endRow // Only read the heading row, and the rows that are configured in $this->_startRow and $this->_endRow
if (($row == 1) || ($row >= $this->startRow && $row < $this->endRow)) { if (($row == 1) || ($row >= $this->startRow && $row < $this->endRow)) {

View File

@ -1,6 +1,6 @@
<?php <?php
namespace PhpOffice\PhpSpreadsheetTests\Reader; namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\Csv; use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Spreadsheet;
@ -49,12 +49,19 @@ class CsvContiguousTest extends TestCase
$spreadsheet->getActiveSheet()->setTitle('Country Data #' . (++$sheet)); $spreadsheet->getActiveSheet()->setTitle('Country Data #' . (++$sheet));
} }
$sheet = $spreadsheet->getSheetByName('Country Data #1'); self::assertSame('Kabul', self::getCellValue($spreadsheet, 'Country Data #1', 'A2'));
self::assertEquals('Kabul', $sheet->getCell('A2')->getValue()); self::assertSame('Lesotho', self::getCellValue($spreadsheet, 'Country Data #2', 'B4'));
$sheet = $spreadsheet->getSheetByName('Country Data #2'); self::assertSame('-20.1', self::getCellValue($spreadsheet, 'Country Data #3', 'C6'));
self::assertEquals('Lesotho', $sheet->getCell('B4')->getValue()); }
$sheet = $spreadsheet->getSheetByName('Country Data #3');
self::assertEquals(-20.1, $sheet->getCell('C6')->getValue()); private static function getCellValue(Spreadsheet $spreadsheet, string $sheetName, string $cellAddress): string
{
$sheet = $spreadsheet->getSheetByName($sheetName);
if ($sheet === null) {
return '';
}
return (string) $sheet->getCell($cellAddress)->getValue();
} }
public function testContiguous2(): void public function testContiguous2(): void

View File

@ -0,0 +1,122 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PHPUnit\Framework\TestCase;
class CsvEncodingTest extends TestCase
{
/**
* @dataProvider providerEncodings
*
* @param string $filename
* @param string $encoding
*/
public function testEncodings($filename, $encoding): void
{
$reader = new Csv();
$reader->setInputEncoding($encoding);
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('Å', $sheet->getCell('A1')->getValue());
}
/**
* @dataProvider providerEncodings
*
* @param string $filename
* @param string $encoding
*/
public function testWorkSheetInfo($filename, $encoding): void
{
$reader = new Csv();
$reader->setInputEncoding($encoding);
$info = $reader->listWorksheetInfo($filename);
self::assertEquals('Worksheet', $info[0]['worksheetName']);
self::assertEquals('B', $info[0]['lastColumnLetter']);
self::assertEquals(1, $info[0]['lastColumnIndex']);
self::assertEquals(2, $info[0]['totalRows']);
self::assertEquals(2, $info[0]['totalColumns']);
}
public function providerEncodings(): array
{
return [
['tests/data/Reader/CSV/encoding.iso88591.csv', 'ISO-8859-1'],
['tests/data/Reader/CSV/encoding.utf8.csv', 'UTF-8'],
['tests/data/Reader/CSV/encoding.utf8bom.csv', 'UTF-8'],
['tests/data/Reader/CSV/encoding.utf16be.csv', 'UTF-16BE'],
['tests/data/Reader/CSV/encoding.utf16le.csv', 'UTF-16LE'],
['tests/data/Reader/CSV/encoding.utf32be.csv', 'UTF-32BE'],
['tests/data/Reader/CSV/encoding.utf32le.csv', 'UTF-32LE'],
];
}
/**
* @dataProvider providerGuessEncoding
*/
public function testGuessEncoding(string $filename): void
{
$reader = new Csv();
$reader->setInputEncoding(Csv::guessEncoding($filename));
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('première', $sheet->getCell('A1')->getValue());
self::assertEquals('sixième', $sheet->getCell('C2')->getValue());
}
/**
* @dataProvider providerGuessEncoding
*/
public function testFallbackEncoding(string $filename): void
{
$reader = new Csv();
$reader->setInputEncoding(Csv::GUESS_ENCODING);
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('première', $sheet->getCell('A1')->getValue());
self::assertEquals('sixième', $sheet->getCell('C2')->getValue());
}
public function providerGuessEncoding(): array
{
return [
['tests/data/Reader/CSV/premiere.utf8.csv'],
['tests/data/Reader/CSV/premiere.utf8bom.csv'],
['tests/data/Reader/CSV/premiere.utf16be.csv'],
['tests/data/Reader/CSV/premiere.utf16bebom.csv'],
['tests/data/Reader/CSV/premiere.utf16le.csv'],
['tests/data/Reader/CSV/premiere.utf16lebom.csv'],
['tests/data/Reader/CSV/premiere.utf32be.csv'],
['tests/data/Reader/CSV/premiere.utf32bebom.csv'],
['tests/data/Reader/CSV/premiere.utf32le.csv'],
['tests/data/Reader/CSV/premiere.utf32lebom.csv'],
['tests/data/Reader/CSV/premiere.win1252.csv'],
];
}
public function testGuessEncodingDefltIso2(): void
{
$filename = 'tests/data/Reader/CSV/premiere.win1252.csv';
$reader = new Csv();
$reader->setInputEncoding(Csv::guessEncoding($filename, 'ISO-8859-2'));
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('premičre', $sheet->getCell('A1')->getValue());
self::assertEquals('sixičme', $sheet->getCell('C2')->getValue());
}
public function testFallbackEncodingDefltIso2(): void
{
$filename = 'tests/data/Reader/CSV/premiere.win1252.csv';
$reader = new Csv();
self::assertSame('CP1252', $reader->getFallbackEncoding());
$reader->setInputEncoding(Csv::GUESS_ENCODING);
$reader->setFallbackEncoding('ISO-8859-2');
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('premičre', $sheet->getCell('A1')->getValue());
self::assertEquals('sixičme', $sheet->getCell('C2')->getValue());
}
}

View File

@ -1,6 +1,6 @@
<?php <?php
namespace PhpOffice\PhpSpreadsheetTests\Reader; namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\Csv; use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException; use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
@ -19,7 +19,8 @@ class CsvTest extends TestCase
public function testDelimiterDetection($filename, $expectedDelimiter, $cell, $expectedValue): void public function testDelimiterDetection($filename, $expectedDelimiter, $cell, $expectedValue): void
{ {
$reader = new Csv(); $reader = new Csv();
self::assertNull($reader->getDelimiter()); $delim1 = $reader->getDelimiter();
self::assertNull($delim1);
$spreadsheet = $reader->load($filename); $spreadsheet = $reader->load($filename);
@ -132,21 +133,6 @@ class CsvTest extends TestCase
self::assertSame($expected, $worksheet->toArray()); self::assertSame($expected, $worksheet->toArray());
} }
/**
* @dataProvider providerEncodings
*
* @param string $filename
* @param string $encoding
*/
public function testEncodings($filename, $encoding): void
{
$reader = new Csv();
$reader->setInputEncoding($encoding);
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('Å', $sheet->getCell('A1')->getValue());
}
public function testInvalidWorkSheetInfo(): void public function testInvalidWorkSheetInfo(): void
{ {
$this->expectException(ReaderException::class); $this->expectException(ReaderException::class);
@ -154,37 +140,6 @@ class CsvTest extends TestCase
$reader->listWorksheetInfo(''); $reader->listWorksheetInfo('');
} }
/**
* @dataProvider providerEncodings
*
* @param string $filename
* @param string $encoding
*/
public function testWorkSheetInfo($filename, $encoding): void
{
$reader = new Csv();
$reader->setInputEncoding($encoding);
$info = $reader->listWorksheetInfo($filename);
self::assertEquals('Worksheet', $info[0]['worksheetName']);
self::assertEquals('B', $info[0]['lastColumnLetter']);
self::assertEquals(1, $info[0]['lastColumnIndex']);
self::assertEquals(2, $info[0]['totalRows']);
self::assertEquals(2, $info[0]['totalColumns']);
}
public function providerEncodings(): array
{
return [
['tests/data/Reader/CSV/encoding.iso88591.csv', 'ISO-8859-1'],
['tests/data/Reader/CSV/encoding.utf8.csv', 'UTF-8'],
['tests/data/Reader/CSV/encoding.utf8bom.csv', 'UTF-8'],
['tests/data/Reader/CSV/encoding.utf16be.csv', 'UTF-16BE'],
['tests/data/Reader/CSV/encoding.utf16le.csv', 'UTF-16LE'],
['tests/data/Reader/CSV/encoding.utf32be.csv', 'UTF-32BE'],
['tests/data/Reader/CSV/encoding.utf32le.csv', 'UTF-32LE'],
];
}
public function testUtf16LineBreak(): void public function testUtf16LineBreak(): void
{ {
$reader = new Csv(); $reader = new Csv();
@ -296,45 +251,4 @@ EOF;
[(version_compare(PHP_VERSION, '7.4') < 0) ? "\x0" : '', ','], [(version_compare(PHP_VERSION, '7.4') < 0) ? "\x0" : '', ','],
]; ];
} }
/**
* @dataProvider providerGuessEncoding
*/
public function testGuessEncoding(string $filename): void
{
$reader = new Csv();
$reader->setInputEncoding(Csv::guessEncoding($filename));
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('première', $sheet->getCell('A1')->getValue());
self::assertEquals('sixième', $sheet->getCell('C2')->getValue());
}
public function providerGuessEncoding(): array
{
return [
['tests/data/Reader/CSV/premiere.utf8.csv'],
['tests/data/Reader/CSV/premiere.utf8bom.csv'],
['tests/data/Reader/CSV/premiere.utf16be.csv'],
['tests/data/Reader/CSV/premiere.utf16bebom.csv'],
['tests/data/Reader/CSV/premiere.utf16le.csv'],
['tests/data/Reader/CSV/premiere.utf16lebom.csv'],
['tests/data/Reader/CSV/premiere.utf32be.csv'],
['tests/data/Reader/CSV/premiere.utf32bebom.csv'],
['tests/data/Reader/CSV/premiere.utf32le.csv'],
['tests/data/Reader/CSV/premiere.utf32lebom.csv'],
['tests/data/Reader/CSV/premiere.win1252.csv'],
];
}
public function testGuessEncodingDefltIso2(): void
{
$filename = 'tests/data/Reader/CSV/premiere.win1252.csv';
$reader = new Csv();
$reader->setInputEncoding(Csv::guessEncoding($filename, 'ISO-8859-2'));
$spreadsheet = $reader->load($filename);
$sheet = $spreadsheet->getActiveSheet();
self::assertEquals('premičre', $sheet->getCell('A1')->getValue());
self::assertEquals('sixičme', $sheet->getCell('C2')->getValue());
}
} }

View File

@ -39,4 +39,36 @@ class FontTest extends TestCase
self::assertTrue($font->getSuperscript()); self::assertTrue($font->getSuperscript());
self::assertFalse($font->getSubscript(), 'False remains unchanged'); self::assertFalse($font->getSubscript(), 'False remains unchanged');
} }
public function testSize(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$cell = $sheet->getCell('A1');
$cell->setValue('Cell A1');
$font = $cell->getStyle()->getFont();
self::assertEquals(11, $font->getSize(), 'The default is 11');
$font->setSize(12);
self::assertEquals(12, $font->getSize(), 'Accepted new font size');
$invalidFontSizeValues = [
'',
false,
true,
'non_numeric_string',
'-1.0',
-1.0,
0,
[],
(object) [],
null,
];
foreach ($invalidFontSizeValues as $invalidFontSizeValue) {
$font->setSize(12);
$font->setSize($invalidFontSizeValue);
self::assertEquals(10, $font->getSize(), 'Set to 10 after trying to set an invalid value.');
}
}
} }

View File

@ -0,0 +1,208 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Writer;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Shared\File;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\ColumnDimension;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class PreCalcTest extends AbstractFunctional
{
/** @var string */
private $outfile = '';
protected function tearDown(): void
{
if ($this->outfile !== '') {
unlink($this->outfile);
$this->outfile = '';
}
}
public function providerPreCalc(): array
{
return [
[true, 'Xlsx'],
[false, 'Xlsx'],
[null, 'Xlsx'],
[true, 'Xls'],
[false, 'Xls'],
[null, 'Xls'],
[true, 'Ods'],
[false, 'Ods'],
[null, 'Ods'],
[true, 'Html'],
[false, 'Html'],
[null, 'Html'],
[true, 'Csv'],
[false, 'Csv'],
[null, 'Csv'],
];
}
private static function autoSize(?ColumnDimension $columnDimension): void
{
if ($columnDimension === null) {
self::fail('Unable to getColumnDimension');
} else {
$columnDimension->setAutoSize(true);
}
}
private static function verifyA2(Calculation $calculation, string $title, ?bool $preCalc): void
{
$cellValue = 0;
// A2 has no cached calculation value if preCalc is false
if ($preCalc === false) {
self::assertFalse($calculation->getValueFromCache("$title!A2", $cellValue));
} else {
self::assertTrue($calculation->getValueFromCache("$title!A2", $cellValue));
self::assertSame(3, $cellValue);
}
}
private const AUTOSIZE_TYPES = ['Xlsx', 'Xls', 'Html'];
private static function verifyA3B2(Calculation $calculation, string $title, ?bool $preCalc, string $type): void
{
$cellValue = 0;
if (in_array($type, self::AUTOSIZE_TYPES) || $preCalc !== false) {
// These 3 types support auto-sizing.
// A3 has cached calculation value because it is used in B2 calculation
self::assertTrue($calculation->getValueFromCache("$title!A3", $cellValue));
self::assertSame(11, $cellValue);
// B2 has cached calculation value because its column is auto-sized
self::assertTrue($calculation->getValueFromCache("$title!B2", $cellValue));
self::assertSame(14, $cellValue);
} else {
self::assertFalse($calculation->getValueFromCache("$title!A3", $cellValue));
self::assertFalse($calculation->getValueFromCache("$title!B2", $cellValue));
}
}
private static function readFile(string $file): string
{
$dataOut = '';
$data = file_get_contents($file);
// confirm that file contains B2 pre-calculated or not as appropriate
if ($data === false) {
self::fail("Unable to read $file");
} else {
$dataOut = $data;
}
return $dataOut;
}
private function verifyXlsx(?bool $preCalc, string $type): void
{
if ($type === 'Xlsx') {
$file = 'zip://';
$file .= $this->outfile;
$file .= '#xl/worksheets/sheet1.xml';
$data = self::readFile($file);
// confirm that file contains B2 pre-calculated or not as appropriate
if ($preCalc === false) {
self::assertStringContainsString('<c r="B2" t="str"><f>3+A3</f><v>0</v></c>', $data);
} else {
self::assertStringContainsString('<c r="B2"><f>3+A3</f><v>14</v></c>', $data);
}
$file = 'zip://';
$file .= $this->outfile;
$file .= '#xl/workbook.xml';
$data = self::readFile($file);
// confirm whether workbook is set to recalculate
if ($preCalc === false) {
self::assertStringContainsString('<calcPr calcId="999999" calcMode="auto" calcCompleted="0" fullCalcOnLoad="1" forceFullCalc="1"/>', $data);
} else {
self::assertStringContainsString('<calcPr calcId="999999" calcMode="auto" calcCompleted="1" fullCalcOnLoad="0" forceFullCalc="0"/>', $data);
}
}
}
private function verifyOds(?bool $preCalc, string $type): void
{
if ($type === 'Ods') {
$file = 'zip://';
$file .= $this->outfile;
$file .= '#content.xml';
$data = self::readFile($file);
// confirm that file contains B2 pre-calculated or not as appropriate
if ($preCalc === false) {
self::assertStringContainsString('table:formula="of:=3+[.A3]" office:value-type="string" office:value="=3+A3"', $data);
} else {
self::assertStringContainsString(' table:formula="of:=3+[.A3]" office:value-type="float" office:value="14"', $data);
}
}
}
private function verifyHtml(?bool $preCalc, string $type): void
{
if ($type === 'Html') {
$data = self::readFile($this->outfile);
// confirm that file contains B2 pre-calculated or not as appropriate
if ($preCalc === false) {
self::assertStringContainsString('>=1+2</td>', $data);
self::assertStringContainsString('>=3+A3</td>', $data);
self::assertStringContainsString('>=5+6</td>', $data);
} else {
self::assertStringContainsString('>3</td>', $data);
self::assertStringContainsString('>14</td>', $data);
self::assertStringContainsString('>11</td>', $data);
}
}
}
private function verifyCsv(?bool $preCalc, string $type): void
{
if ($type === 'Csv') {
$data = self::readFile($this->outfile);
// confirm that file contains B2 pre-calculated or not as appropriate
if ($preCalc === false) {
self::assertStringContainsString('"=1+2"', $data);
self::assertStringContainsString('"=3+A3"', $data);
self::assertStringContainsString('"=5+6"', $data);
} else {
self::assertStringContainsString('"3"', $data);
self::assertStringContainsString('"14"', $data);
self::assertStringContainsString('"11"', $data);
}
}
}
/**
* @dataProvider providerPreCalc
*/
public function testPreCalc(?bool $preCalc, string $type): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->getCell('A1')->setValue('Column not set to autoSize');
$sheet->getCell('B1')->setValue('Column set to autoSize');
$sheet->getCell('A2')->setValue('=1+2');
$sheet->getCell('A3')->setValue('=5+6');
$sheet->getCell('B2')->setValue('=3+A3');
$columnDimension = $sheet->getColumnDimension('B');
self::autoSize($columnDimension);
$writer = IOFactory::createWriter($spreadsheet, $type);
if ($preCalc !== null) {
$writer->setPreCalculateFormulas($preCalc);
}
$this->outfile = File::temporaryFilename();
$writer->save($this->outfile);
$title = $sheet->getTitle();
$calculation = Calculation::getInstance($spreadsheet);
// verify values in Calculation cache
self::verifyA2($calculation, $title, $preCalc);
self::verifyA3B2($calculation, $title, $preCalc, $type);
// verify values in output file
$this->verifyXlsx($preCalc, $type);
$this->verifyOds($preCalc, $type);
$this->verifyHtml($preCalc, $type);
$this->verifyCsv($preCalc, $type);
}
}

View File

@ -205,4 +205,18 @@ return [
4, 4,
4, 4,
], ],
[
5,
'05-Apr-2019',
'30-Sep-2021',
2,
0,
],
[
5,
'05-Oct-2019',
'31-Mar-2022',
2,
0,
],
]; ];

View File

@ -219,4 +219,18 @@ return [
4, 4,
4, 4,
], ],
[
180,
'05-Apr-2019',
'30-Sep-2021',
2,
0,
],
[
180,
'05-Oct-2019',
'31-Mar-2022',
2,
0,
],
]; ];

View File

@ -219,4 +219,21 @@ return [
4, 4,
4, 4,
], ],
[
175,
'05-Apr-2019',
'30-Sep-2021',
2,
0,
],
// Excel and LibreOffice return 175 for the following calculation.
// Gnumeric returns 176.
// My hand calculation, hardly guaranteed, agrees with Gnumeric.
[
176,
'05-Oct-2019',
'31-Mar-2022',
2,
0,
],
]; ];

View File

@ -219,4 +219,32 @@ return [
4, 4,
4, 4,
], ],
[
44651,
'30-Sep-2021',
'31-Mar-2022',
2,
0,
],
[
44834,
'31-Mar-2022',
'30-Sep-2022',
2,
0,
],
[
43738,
'05-Apr-2019',
'30-Sep-2021',
2,
0,
],
[
43921,
'05-Oct-2019',
'31-Mar-2022',
2,
0,
],
]; ];

View File

@ -219,4 +219,18 @@ return [
4, 4,
4, 4,
], ],
[
43555,
'05-Apr-2019',
'30-Sep-2021',
2,
0,
],
[
43738,
'05-Oct-2019',
'31-Mar-2022',
2,
0,
],
]; ];

View File

@ -44,10 +44,18 @@ return [
"'EXCEL SHEET'!R2C3", "'EXCEL SHEET'!R2C3",
2, 2,
3, 3,
1, null,
false, false,
'EXCEL SHEET', 'EXCEL SHEET',
], ],
[
"'EXCEL SHEET'!\$C\$2",
2,
3,
1,
null,
'EXCEL SHEET',
],
[ [
'#VALUE!', '#VALUE!',
-2, -2,

View File

@ -1,276 +1,94 @@
<?php <?php
function orderGrid(): array
{
return [
['Order ID', 10247, 10249, 10250, 10251, 10252, 10253],
['Unit Price', 14.00, 18.60, 7.70, 16.80, 16.80, 64.80],
['Quantity', 12, 9, 10, 6, 20, 40],
];
}
function partsGrid(): array
{
return [
['Axles', 'Bearings', 'Bolts'],
[4, 4, 9],
[5, 7, 10],
[6, 8, 11],
];
}
return [ return [
[ [
16.800000000000001, 16.80,
10251, 10251,
[ orderGrid(),
[
'Order ID',
10247,
10249,
10250,
10251,
10252,
10253,
],
[
'Unit Price',
14.0,
18.600000000000001,
7.7000000000000002,
16.800000000000001,
16.800000000000001,
64.799999999999997,
],
[
'Quantity',
12,
9,
10,
6,
20,
40,
],
],
2, 2,
false, false,
], ],
[ [
6.0, 6.0,
10251, 10251,
[ orderGrid(),
[
'Order ID',
10247,
10249,
10250,
10251,
10252,
10253,
],
[
'Unit Price',
14.0,
18.600000000000001,
7.7000000000000002,
16.800000000000001,
16.800000000000001,
64.799999999999997,
],
[
'Quantity',
12,
9,
10,
6,
20,
40,
],
],
3, 3,
false, false,
], ],
[ [
'#N/A', '#N/A',
10248, 10248,
[ orderGrid(),
[
'Order ID',
10247,
10249,
10250,
10251,
10252,
10253,
],
[
'Unit Price',
14.0,
18.600000000000001,
7.7000000000000002,
16.800000000000001,
16.800000000000001,
64.799999999999997,
],
[
'Quantity',
12,
9,
10,
6,
20,
40,
],
],
2, 2,
false, false,
], ],
[ [
14.0, 14.0,
10248, 10248,
[ orderGrid(),
[
'Order ID',
10247,
10249,
10250,
10251,
10252,
10253,
],
[
'Unit Price',
14.0,
18.600000000000001,
7.7000000000000002,
16.800000000000001,
16.800000000000001,
64.799999999999997,
],
[
'Quantity',
12,
9,
10,
6,
20,
40,
],
],
2, 2,
true, true,
], ],
[ [
4, 4,
'Axles', 'Axles',
[ partsGrid(),
[
'Axles',
'Bearings',
'Bolts',
],
[
4,
4,
9,
],
[
5,
7,
10,
],
[
6,
8,
11,
],
],
2, 2,
true, true,
], ],
[ [
7, 7,
'Bearings', 'Bearings',
[ partsGrid(),
[
'Axles',
'Bearings',
'Bolts',
],
[
4,
4,
9,
],
[
5,
7,
10,
],
[
6,
8,
11,
],
],
3, 3,
false, false,
], ],
[ [
5, 5,
'B', 'B',
[ partsGrid(),
[
'Axles',
'Bearings',
'Bolts',
],
[
4,
4,
9,
],
[
5,
7,
10,
],
[
6,
8,
11,
],
],
3, 3,
true, true,
], ],
[
11,
'Bolts',
[
[
'Axles',
'Bearings',
'Bolts',
],
[
4,
4,
9,
],
[ [
5, 5,
7, 'B',
10, partsGrid(),
3,
null,
], ],
[ [
6,
8,
11, 11,
], 'Bolts',
], partsGrid(),
4, 4,
], ],
[ [
'c', 'c',
3, 3,
[ [
[ [1, 2, 3],
1, ['a', 'b', 'c'],
2, ['d', 'e', 'f'],
3,
],
[
'a',
'b',
'c',
],
[
'd',
'e',
'f',
],
], ],
2, 2,
true, true,
@ -279,11 +97,7 @@ return [
3, 3,
3, 3,
[ [
[ [1, 2, 3],
1,
2,
3,
],
], ],
1, 1,
true, true,

View File

@ -1,293 +1,54 @@
<?php <?php
function densityGrid(): array
{
return [
['Density', 'Viscosity', 'Temperature'],
[0.457, 3.55, 500],
[0.525, 3.25, 400],
[0.616, 2.93, 300],
[0.675, 2.75, 250],
[0.746, 2.57, 200],
[0.835, 2.38, 150],
[0.946, 2.17, 100],
[1.090, 1.95, 50],
[1.290, 1.71, 0],
];
}
return [ return [
[ [
'#N/A', '#N/A',
1, 1,
[ densityGrid(),
[
'Density',
'Viscosity',
'Temperature',
],
[
0.45700000000000002,
3.5499999999999998,
500,
],
[
0.52500000000000002,
3.25,
400,
],
[
0.61599999999999999,
2.9300000000000002,
300,
],
[
0.67500000000000004,
2.75,
250,
],
[
0.746,
2.5699999999999998,
200,
],
[
0.83499999999999996,
2.3799999999999999,
150,
],
[
0.94599999999999995,
2.1699999999999999,
100,
],
[
1.0900000000000001,
1.95,
50,
],
[
1.29,
1.71,
0,
],
],
2, 2,
false, false,
], ],
[ [
100, 100,
1, 1,
[ densityGrid(),
[
'Density',
'Viscosity',
'Temperature',
],
[
0.45700000000000002,
3.5499999999999998,
500,
],
[
0.52500000000000002,
3.25,
400,
],
[
0.61599999999999999,
2.9300000000000002,
300,
],
[
0.67500000000000004,
2.75,
250,
],
[
0.746,
2.5699999999999998,
200,
],
[
0.83499999999999996,
2.3799999999999999,
150,
],
[
0.94599999999999995,
2.1699999999999999,
100,
],
[
1.0900000000000001,
1.95,
50,
],
[
1.29,
1.71,
0,
],
],
3, 3,
true, true,
], ],
[ [
'#N/A', '#N/A',
0.69999999999999996, 0.70,
[ densityGrid(),
[
'Density',
'Viscosity',
'Temperature',
],
[
0.45700000000000002,
3.5499999999999998,
500,
],
[
0.52500000000000002,
3.25,
400,
],
[
0.61599999999999999,
2.9300000000000002,
300,
],
[
0.67500000000000004,
2.75,
250,
],
[
0.746,
2.5699999999999998,
200,
],
[
0.83499999999999996,
2.3799999999999999,
150,
],
[
0.94599999999999995,
2.1699999999999999,
100,
],
[
1.0900000000000001,
1.95,
50,
],
[
1.29,
1.71,
0,
],
],
3, 3,
false, false,
], ],
[ [
'#N/A', '#N/A',
0.10000000000000001, 0.100,
[ densityGrid(),
[
'Density',
'Viscosity',
'Temperature',
],
[
0.45700000000000002,
3.5499999999999998,
500,
],
[
0.52500000000000002,
3.25,
400,
],
[
0.61599999999999999,
2.9300000000000002,
300,
],
[
0.67500000000000004,
2.75,
250,
],
[
0.746,
2.5699999999999998,
200,
],
[
0.83499999999999996,
2.3799999999999999,
150,
],
[
0.94599999999999995,
2.1699999999999999,
100,
],
[
1.0900000000000001,
1.95,
50,
],
[
1.29,
1.71,
0,
],
],
2, 2,
true, true,
], ],
[ [
1.71, 1.71,
2, 2,
[ densityGrid(),
[
'Density',
'Viscosity',
'Temperature',
],
[
0.45700000000000002,
3.5499999999999998,
500,
],
[
0.52500000000000002,
3.25,
400,
],
[
0.61599999999999999,
2.9300000000000002,
300,
],
[
0.67500000000000004,
2.75,
250,
],
[
0.746,
2.5699999999999998,
200,
],
[
0.83499999999999996,
2.3799999999999999,
150,
],
[
0.94599999999999995,
2.1699999999999999,
100,
],
[
1.0900000000000001,
1.95,
50,
],
[
1.29,
1.71,
0,
],
],
2, 2,
true, true,
], ],
@ -380,4 +141,19 @@ return [
3, 3,
true, true,
], ],
[
'E',
0.52,
[
['Lower', 'Upper', 'Grade'],
[0.00, 0.44, 'F'],
[0.45, 0.54, 'E'],
[0.55, 0.64, 'D'],
[0.65, 0.74, 'C'],
[0.75, 0.84, 'B'],
[0.85, 1.00, 'A'],
],
3,
null,
],
]; ];