Updates to 3rd party libraries

Add Dockerfile and specific docker-php.ini
This commit is contained in:
2018-08-28 21:27:13 -04:00
parent 9edd6c1c35
commit d52454d1bb
511 changed files with 45960 additions and 2739 deletions

View File

@ -0,0 +1,24 @@
<?php
use Sami\RemoteRepository\GitHubRemoteRepository;
use Sami\Sami;
use Sami\Version\GitVersionCollection;
use Symfony\Component\Finder\Finder;
$iterator = Finder::create()
->files()
->name('*.php')
->in($dir = __DIR__ . '/src');
$versions = GitVersionCollection::create($dir)
->addFromTags(function ($version) {
return preg_match('~^\d+\.\d+\.\d+$~', $version);
})
->add('master');
return new Sami($iterator, [
'title' => 'PhpSpreadsheet',
'versions' => $versions,
'build_dir' => __DIR__ . '/build/%version%',
'cache_dir' => __DIR__ . '/cache/%version%',
'remote_repository' => new GitHubRemoteRepository('PHPOffice/PhpSpreadsheet', dirname($dir)),
]);

View File

@ -10,6 +10,7 @@ php:
cache:
directories:
- cache
- vendor
- $HOME/.composer/cache
@ -28,7 +29,7 @@ jobs:
php: 7.1
script:
- ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run
- ./vendor/bin/phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=samples/Header.php --standard=PSR2 -n
- ./vendor/bin/phpcs --report-width=200 samples/ src/ tests/ --ignore=samples/Header.php --standard=PSR2 -n
- stage: Coverage
php: 7.1
@ -38,3 +39,21 @@ jobs:
after_script:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover tests/coverage-clover.xml
- stage: API documentation
php: 7.1
before_script:
- curl -O http://get.sensiolabs.org/sami.phar
script:
- git fetch origin master:master
- git fetch origin --tags
- php sami.phar update .sami.php
- echo '<html><head><meta http-equiv="Refresh" content="0; url=master/"></head><body><p>If you are not automatically redirected, please go to <a href="master/">the latest stable API documentation</a>.</p></body></html>' > build/index.html
deploy:
provider: pages
skip-cleanup: true
local-dir: build
github-token: $GITHUB_TOKEN
on:
all_branches: true
condition: $TRAVIS_BRANCH =~ ^master|develop$

View File

@ -5,6 +5,95 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.4.0] - 2018-08-06
### Added
- Add excel function EXACT(value1, value2) support - [#595](https://github.com/PHPOffice/PhpSpreadsheet/pull/595)
- Support workbook view attributes for Xlsx format - [#523](https://github.com/PHPOffice/PhpSpreadsheet/issues/523)
- Read and write hyperlink for drawing image - [#490](https://github.com/PHPOffice/PhpSpreadsheet/pull/490)
- Added calculation engine support for the new bitwise functions that were added in MS Excel 2013
- BITAND() Returns a Bitwise 'And' of two numbers
- BITOR() Returns a Bitwise 'Or' of two number
- BITXOR() Returns a Bitwise 'Exclusive Or' of two numbers
- BITLSHIFT() Returns a number shifted left by a specified number of bits
- BITRSHIFT() Returns a number shifted right by a specified number of bits
- Added calculation engine support for other new functions that were added in MS Excel 2013 and MS Excel 2016
- Text Functions
- CONCAT() Synonym for CONCATENATE()
- NUMBERVALUE() Converts text to a number, in a locale-independent way
- UNICHAR() Synonym for CHAR() in PHPSpreadsheet, which has always used UTF-8 internally
- UNIORD() Synonym for ORD() in PHPSpreadsheet, which has always used UTF-8 internally
- TEXTJOIN() Joins together two or more text strings, separated by a delimiter
- Logical Functions
- XOR() Returns a logical Exclusive Or of all arguments
- Date/Time Functions
- ISOWEEKNUM() Returns the ISO 8601 week number of the year for a given date
- Lookup and Reference Functions
- FORMULATEXT() Returns a formula as a string
- Financial Functions
- PDURATION() Calculates the number of periods required for an investment to reach a specified value
- RRI() Calculates the interest rate required for an investment to grow to a specified future value
- Engineering Functions
- ERF.PRECISE() Returns the error function integrated between 0 and a supplied limit
- ERFC.PRECISE() Synonym for ERFC
- Math and Trig Functions
- SEC() Returns the secant of an angle
- SECH() Returns the hyperbolic secant of an angle
- CSC() Returns the cosecant of an angle
- CSCH() Returns the hyperbolic cosecant of an angle
- COT() Returns the cotangent of an angle
- COTH() Returns the hyperbolic cotangent of an angle
- ACOT() Returns the cotangent of an angle
- ACOTH() Returns the hyperbolic cotangent of an angle
- Refactored Complex Engineering Functions to use external complex number library
- Added calculation engine support for the new complex number functions that were added in MS Excel 2013
- IMCOSH() Returns the hyperbolic cosine of a complex number
- IMCOT() Returns the cotangent of a complex number
- IMCSC() Returns the cosecant of a complex number
- IMCSCH() Returns the hyperbolic cosecant of a complex number
- IMSEC() Returns the secant of a complex number
- IMSECH() Returns the hyperbolic secant of a complex number
- IMSINH() Returns the hyperbolic sine of a complex number
- IMTAN() Returns the tangent of a complex number
### Fixed
- Fix ISFORMULA() function to work with a cell reference to another worksheet
- Xlsx reader crashed when reading a file with workbook protection - [#553](https://github.com/PHPOffice/PhpSpreadsheet/pull/553)
- Cell formats with escaped spaces were causing incorrect date formatting - [#557](https://github.com/PHPOffice/PhpSpreadsheet/issues/557)
- Could not open CSV file containing HTML fragment - [#564](https://github.com/PHPOffice/PhpSpreadsheet/issues/564)
- Exclude the vendor folder in migration - [#481](https://github.com/PHPOffice/PhpSpreadsheet/issues/481)
- Chained operations on cell ranges involving borders operated on last cell only [#428](https://github.com/PHPOffice/PhpSpreadsheet/issues/428)
- Avoid memory exhaustion when cloning worksheet with a drawing [#437](https://github.com/PHPOffice/PhpSpreadsheet/issues/437)
- Migration tool keep variables containing $PHPExcel untouched [#598](https://github.com/PHPOffice/PhpSpreadsheet/issues/598)
- Rowspans/colspans were incorrect when adding worksheet using loadIntoExisting [#619](https://github.com/PHPOffice/PhpSpreadsheet/issues/619)
## [1.3.1] - 2018-06-12
### Fixed
- Ranges across Z and AA columns incorrectly threw an exception - [#545](https://github.com/PHPOffice/PhpSpreadsheet/issues/545)
## [1.3.0] - 2018-06-10
### Added
- Support to read Xlsm templates with form elements, macros, printer settings, protected elements and back compatibility drawing, and save result without losing important elements of document - [#435](https://github.com/PHPOffice/PhpSpreadsheet/issues/435)
- Expose sheet title maximum length as `Worksheet::SHEET_TITLE_MAXIMUM_LENGTH` - [#482](https://github.com/PHPOffice/PhpSpreadsheet/issues/482)
- Allow escape character to be set in CSV reader [#492](https://github.com/PHPOffice/PhpSpreadsheet/issues/492)
### Fixed
- Subtotal 9 in a group that has other subtotals 9 exclude the totals of the other subtotals in the range - [#332](https://github.com/PHPOffice/PhpSpreadsheet/issues/332)
- `Helper\Html` support UTF-8 HTML input - [#444](https://github.com/PHPOffice/PhpSpreadsheet/issues/444)
- Xlsx loaded an extra empty comment for each real comment - [#375](https://github.com/PHPOffice/PhpSpreadsheet/issues/375)
- Xlsx reader do not read rows and columns filtered out in readFilter at all - [#370](https://github.com/PHPOffice/PhpSpreadsheet/issues/370)
- Make newer Excel versions properly recalculate formulas on document open - [#456](https://github.com/PHPOffice/PhpSpreadsheet/issues/456)
- `Coordinate::extractAllCellReferencesInRange()` throws an exception for an invalid range [#519](https://github.com/PHPOffice/PhpSpreadsheet/issues/519)
- Fixed parsing of conditionals in COUNTIF functions - [#526](https://github.com/PHPOffice/PhpSpreadsheet/issues/526)
- Corruption errors for saved Xlsx docs with frozen panes - [#532](https://github.com/PHPOffice/PhpSpreadsheet/issues/532)
## [1.2.1] - 2018-04-10
### Fixed

View File

@ -18,9 +18,7 @@ PhpSpreadsheet is a library written in pure PHP and providing a set of classes t
## Documentation
Read more about it, including install instructions, in the official documentation:
https://phpspreadsheet.readthedocs.io
Read more about it, including install instructions, in the [official documentation](https://phpspreadsheet.readthedocs.io). Or check out the [API documentation](https://phpoffice.github.io/PhpSpreadsheet/master).
Please ask your support questions on [StackOverflow](http://stackoverflow.com/questions/tagged/phpspreadsheet), or have a quick chat on [Gitter](https://gitter.im/PHPOffice/PhpSpreadsheet).

View File

@ -25,7 +25,7 @@
"scripts": {
"check": [
"php-cs-fixer fix --ansi --dry-run --diff",
"phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=samples/Header.php --standard=PSR2 -n",
"phpcs --report-width=200 samples/ src/ tests/ --ignore=samples/Header.php --standard=PSR2 -n",
"phpunit --color=always"
],
"fix": [
@ -46,16 +46,17 @@
"ext-xmlwriter": "*",
"ext-zip": "*",
"ext-zlib": "*",
"psr/simple-cache": "^1.0"
"psr/simple-cache": "^1.0",
"markbaker/complex": "^1.4.1"
},
"require-dev": {
"tecnickcom/tcpdf": "^6.2",
"squizlabs/php_codesniffer": "^2.7",
"phpunit/phpunit": "^5.7",
"dompdf/dompdf": "^0.8.0",
"mpdf/mpdf": "^7.0.0",
"jpgraph/jpgraph": "^4.0",
"friendsofphp/php-cs-fixer": "@stable"
"friendsofphp/php-cs-fixer": "@stable",
"squizlabs/php_codesniffer": "^3.3"
},
"suggest": {
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",

View File

@ -1,11 +1,106 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "e61a906bd83393400add286703f10557",
"content-hash": "66067b3ab7afd673a28cf0b31eb9ae20",
"packages": [
{
"name": "markbaker/complex",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/MarkBaker/PHPComplex.git",
"reference": "615f5443473cf37729666e2354fd8dfa2cb48e91"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/615f5443473cf37729666e2354fd8dfa2cb48e91",
"reference": "615f5443473cf37729666e2354fd8dfa2cb48e91",
"shasum": ""
},
"require": {
"php": "^5.6.0|^7.0.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.3",
"phpdocumentor/phpdocumentor": "2.*",
"phploc/phploc": "2.*",
"phpmd/phpmd": "2.*",
"phpunit/phpunit": "^4.8.35|^5.4.0",
"sebastian/phpcpd": "2.*",
"squizlabs/php_codesniffer": "^3.1.1",
"wimg/php-compatibility": "^8.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Complex\\": "classes/src/"
},
"files": [
"classes/src/functions/abs.php",
"classes/src/functions/acos.php",
"classes/src/functions/acosh.php",
"classes/src/functions/acot.php",
"classes/src/functions/acoth.php",
"classes/src/functions/acsc.php",
"classes/src/functions/acsch.php",
"classes/src/functions/argument.php",
"classes/src/functions/asec.php",
"classes/src/functions/asech.php",
"classes/src/functions/asin.php",
"classes/src/functions/asinh.php",
"classes/src/functions/atan.php",
"classes/src/functions/atanh.php",
"classes/src/functions/conjugate.php",
"classes/src/functions/cos.php",
"classes/src/functions/cosh.php",
"classes/src/functions/cot.php",
"classes/src/functions/coth.php",
"classes/src/functions/csc.php",
"classes/src/functions/csch.php",
"classes/src/functions/exp.php",
"classes/src/functions/inverse.php",
"classes/src/functions/ln.php",
"classes/src/functions/log2.php",
"classes/src/functions/log10.php",
"classes/src/functions/negative.php",
"classes/src/functions/pow.php",
"classes/src/functions/rho.php",
"classes/src/functions/sec.php",
"classes/src/functions/sech.php",
"classes/src/functions/sin.php",
"classes/src/functions/sinh.php",
"classes/src/functions/sqrt.php",
"classes/src/functions/tan.php",
"classes/src/functions/tanh.php",
"classes/src/functions/theta.php",
"classes/src/operations/add.php",
"classes/src/operations/subtract.php",
"classes/src/operations/multiply.php",
"classes/src/operations/divideby.php",
"classes/src/operations/divideinto.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mark Baker",
"email": "mark@lange.demon.co.uk"
}
],
"description": "PHP Class for working with complex numbers",
"homepage": "https://github.com/MarkBaker/PHPComplex",
"keywords": [
"complex",
"mathematics"
],
"time": "2018-07-24T19:47:28+00:00"
},
{
"name": "psr/simple-cache",
"version": "1.0.0",
@ -2106,64 +2201,37 @@
},
{
"name": "squizlabs/php_codesniffer",
"version": "2.8.1",
"version": "3.3.1",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "d7cf0d894e8aa4c73712ee4a331cc1eaa37cdc7d"
"reference": "628a481780561150481a9ec74709092b9759b3ec"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/d7cf0d894e8aa4c73712ee4a331cc1eaa37cdc7d",
"reference": "d7cf0d894e8aa4c73712ee4a331cc1eaa37cdc7d",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/628a481780561150481a9ec74709092b9759b3ec",
"reference": "628a481780561150481a9ec74709092b9759b3ec",
"shasum": ""
},
"require": {
"ext-simplexml": "*",
"ext-tokenizer": "*",
"ext-xmlwriter": "*",
"php": ">=5.1.2"
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
},
"bin": [
"scripts/phpcs",
"scripts/phpcbf"
"bin/phpcs",
"bin/phpcbf"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
"dev-master": "3.x-dev"
}
},
"autoload": {
"classmap": [
"CodeSniffer.php",
"CodeSniffer/CLI.php",
"CodeSniffer/Exception.php",
"CodeSniffer/File.php",
"CodeSniffer/Fixer.php",
"CodeSniffer/Report.php",
"CodeSniffer/Reporting.php",
"CodeSniffer/Sniff.php",
"CodeSniffer/Tokens.php",
"CodeSniffer/Reports/",
"CodeSniffer/Tokenizers/",
"CodeSniffer/DocGenerators/",
"CodeSniffer/Standards/AbstractPatternSniff.php",
"CodeSniffer/Standards/AbstractScopeSniff.php",
"CodeSniffer/Standards/AbstractVariableSniff.php",
"CodeSniffer/Standards/IncorrectPatternException.php",
"CodeSniffer/Standards/Generic/Sniffs/",
"CodeSniffer/Standards/MySource/Sniffs/",
"CodeSniffer/Standards/PEAR/Sniffs/",
"CodeSniffer/Standards/PSR1/Sniffs/",
"CodeSniffer/Standards/PSR2/Sniffs/",
"CodeSniffer/Standards/Squiz/Sniffs/",
"CodeSniffer/Standards/Zend/Sniffs/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
@ -2180,7 +2248,7 @@
"phpcs",
"standards"
],
"time": "2017-03-01T22:17:45+00:00"
"time": "2018-07-26T23:47:18+00:00"
},
{
"name": "symfony/console",

View File

@ -1,57 +0,0 @@
var nodemcu = nodemcu || {};
(function () {
'use strict';
$(document).ready(function () {
fixSearch();
});
/*
* RTD messes up MkDocs' search feature by tinkering with the search box defined in the theme, see
* https://github.com/rtfd/readthedocs.org/issues/1088. This function sets up a DOM4 MutationObserver
* to react to changes to the search form (triggered by RTD on doc ready). It then reverts everything
* the RTD JS code modified.
*/
function fixSearch() {
var target = document.getElementById('rtd-search-form');
var config = {attributes: true, childList: true};
var observer = new MutationObserver(function (mutations) {
// if it isn't disconnected it'll loop infinitely because the observed element is modified
observer.disconnect();
var form = $('#rtd-search-form');
form.empty();
form.attr('action', 'https://' + window.location.hostname + '/en/' + determineSelectedBranch() + '/search.html');
$('<input>').attr({
type: "text",
name: "q",
placeholder: "Search docs"
}).appendTo(form);
});
if (window.location.origin.indexOf('readthedocs') > -1) {
observer.observe(target, config);
}
}
/**
* Analyzes the URL of the current page to find out what the selected GitHub branch is. It's usually
* part of the location path. The code needs to distinguish between running MkDocs standalone
* and docs served from RTD. If no valid branch could be determined 'dev' returned.
*
* @returns GitHub branch name
*/
function determineSelectedBranch() {
var branch = 'dev', path = window.location.pathname;
if (window.location.origin.indexOf('readthedocs') > -1) {
// path is like /en/<branch>/<lang>/build/ -> extract 'lang'
// split[0] is an '' because the path starts with the separator
var thirdPathSegment = path.split('/')[2];
// 'latest' is an alias on RTD for the 'dev' branch - which is the default for 'branch' here
if (thirdPathSegment !== 'latest') {
branch = thirdPathSegment;
}
}
return branch;
}
}());

View File

@ -95,6 +95,8 @@ architecture](./topics/architecture.md),
[accessing cells](./topics/accessing-cells.md) and
[reading and writing to files](./topics/reading-and-writing-to-file.md).
Or browse the [API documentation](https://phpoffice.github.io/PhpSpreadsheet/master).
# Credits
Please refer to the [contributor

View File

@ -750,6 +750,24 @@
<td></td>
<td></td>
</tr>
<tr>
<td style="padding-left: 1em;">Drawing hyperlink</td>
<td></td>
<td style="text-align: center; color: green;"></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td style="text-align: center; color: green;"></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>$drawing->getHyperlink()->getUrl()</td>
<td>$drawing->setHyperlink()->setUrl($url)</td>
</tr>
<tr>
<td><strong>Cell Formatting</strong></td>
<td></td>

View File

@ -41,6 +41,7 @@ DAYS360 | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::DAYS360
EDATE | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::EDATE
EOMONTH | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::EOMONTH
HOUR | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::HOUROFDAY
ISOWEEKNUM | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::ISOWEEKNUM
MINUTE | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::MINUTE
MONTH | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::MONTHOFYEAR
NETWORKDAYS | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::NETWORKDAYS
@ -73,7 +74,9 @@ DEC2HEX | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::DECTOHE
DEC2OCT | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::DECTOOCT
DELTA | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::DELTA
ERF | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::ERF
ERF.PRECISE | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::ERFPRECISE
ERFC | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::ERFC
ERFC.PRECISE | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::ERFC
GESTEP | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::GESTEP
HEX2BIN | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::HEXTOBIN
HEX2DEC | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::HEXTODEC
@ -83,6 +86,10 @@ IMAGINARY | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMAGINA
IMARGUMENT | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMARGUMENT
IMCONJUGATE | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMCONJUGATE
IMCOS | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMCOS
IMCOSH | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMCOSH
IMCOT | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMCOT
IMCSC | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMCSC
IMCSCH | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMCSCH
IMDIV | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMDIV
IMEXP | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMEXP
IMLN | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMLN
@ -91,10 +98,14 @@ IMLOG2 | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMLOG2
IMPOWER | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMPOWER
IMPRODUCT | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMPRODUCT
IMREAL | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMREAL
IMSEC | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSEC
IMSECH | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSECH
IMSIN | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSIN
IMSINH | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSINH
IMSQRT | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSQRT
IMSUB | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSUB
IMSUM | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSUM
IMTAN | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMTAN
OCT2BIN | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::OCTTOBIN
OCT2DEC | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::OCTTODEC
OCT2HEX | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::OCTTOHEX
@ -137,6 +148,7 @@ ODDFPRICE | **Not yet Implemented**
ODDFYIELD | **Not yet Implemented**
ODDLPRICE | **Not yet Implemented**
ODDLYIELD | **Not yet Implemented**
PDURATION | \PhpOffice\PhpSpreadsheet\Calculation\Financial::PDURATION
PMT | \PhpOffice\PhpSpreadsheet\Calculation\Financial::PMT
PPMT | \PhpOffice\PhpSpreadsheet\Calculation\Financial::PPMT
PRICE | \PhpOffice\PhpSpreadsheet\Calculation\Financial::PRICE
@ -145,6 +157,7 @@ PRICEMAT | \PhpOffice\PhpSpreadsheet\Calculation\Financial::PRICEMAT
PV | \PhpOffice\PhpSpreadsheet\Calculation\Financial::PV
RATE | \PhpOffice\PhpSpreadsheet\Calculation\Financial::RATE
RECEIVED | \PhpOffice\PhpSpreadsheet\Calculation\Financial::RECEIVED
RRI | \PhpOffice\PhpSpreadsheet\Calculation\Financial::RRI
SLN | \PhpOffice\PhpSpreadsheet\Calculation\Financial::SLN
SYD | \PhpOffice\PhpSpreadsheet\Calculation\Financial::SYD
TBILLEQ | \PhpOffice\PhpSpreadsheet\Calculation\Financial::TBILLEQ
@ -169,6 +182,7 @@ ISBLANK | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_BLANK
ISERR | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_ERR
ISERROR | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_ERROR
ISEVEN | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_EVEN
ISFORMULA | \PhpOffice\PhpSpreadsheet\Calculation\Functions::ISFORMULA
ISLOGICAL | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_LOGICAL
ISNA | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_NA
ISNONTEXT | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_NONTEXT
@ -184,13 +198,14 @@ TYPE | \PhpOffice\PhpSpreadsheet\Calculation\Functions::TYPE
Excel Function | PhpSpreadsheet Function
--------------------|-------------------------------------------
AND | \PhpOffice\PhpSpreadsheet\Calculation\Logical::LOGICAL_AND
AND | \PhpOffice\PhpSpreadsheet\Calculation\Logical::logicalAnd
FALSE | \PhpOffice\PhpSpreadsheet\Calculation\Logical::FALSE
IF | \PhpOffice\PhpSpreadsheet\Calculation\Logical::STATEMENT_IF
IFERROR | \PhpOffice\PhpSpreadsheet\Calculation\Logical::IFERROR
NOT | \PhpOffice\PhpSpreadsheet\Calculation\Logical::NOT
OR | \PhpOffice\PhpSpreadsheet\Calculation\Logical::LOGICAL_OR
OR | \PhpOffice\PhpSpreadsheet\Calculation\Logical::logicalOr
TRUE | \PhpOffice\PhpSpreadsheet\Calculation\Logical::TRUE
XOR | \PhpOffice\PhpSpreadsheet\Calculation\Logical::logicalXor
## CATEGORY_LOOKUP_AND_REFERENCE
@ -201,8 +216,9 @@ AREAS | **Not yet Implemented**
CHOOSE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::CHOOSE
COLUMN | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::COLUMN
COLUMNS | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::COLUMNS
FORMULATEXT | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::FORMULATEXT
GETPIVOTDATA | **Not yet Implemented**
HLOOKUP | **Not yet Implemented**
HLOOKUP | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::HLOOKUP
HYPERLINK | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::HYPERLINK
INDEX | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::INDEX
INDIRECT | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::INDIRECT
@ -222,6 +238,8 @@ Excel Function | PhpSpreadsheet Function
ABS | abs
ACOS | acos
ACOSH | acosh
ACOT | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::ACOT
ACOTH | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::ACOTH
ASIN | asin
ASINH | asinh
ATAN | atan
@ -231,6 +249,10 @@ CEILING | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::CEILING
COMBIN | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::COMBIN
COS | cos
COSH | cosh
COT | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::COT
COTH | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::COTH
CSC | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::CSC
CSCH | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::CSCH
DEGREES | rad2deg
EVEN | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::EVEN
EXP | exp
@ -261,6 +283,8 @@ ROMAN | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::ROMAN
ROUND | round
ROUNDDOWN | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::ROUNDDOWN
ROUNDUP | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::ROUNDUP
SEC | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SEC
SECH | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SECH
SERIESSUM | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SERIESSUM
SIGN | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SIGN
SIN | sin
@ -270,7 +294,7 @@ SQRTPI | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SQRTPI
SUBTOTAL | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUBTOTAL
SUM | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUM
SUMIF | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUMIF
SUMIFS | **Not yet Implemented**
SUMIFS | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUMIFS
SUMPRODUCT | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUMPRODUCT
SUMSQ | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUMSQ
SUMX2MY2 | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUMX2MY2
@ -336,6 +360,7 @@ MIN | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::MIN
MINA | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::MINA
MINIF | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::MINIF
MODE | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::MODE
MODE.SNGL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::MODE
NEGBINOMDIST | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::NEGBINOMDIST
NORMDIST | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::NORMDIST
NORMINV | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::NORMINV
@ -355,6 +380,8 @@ SLOPE | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::SLOPE
SMALL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::SMALL
STANDARDIZE | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STANDARDIZE
STDEV | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STDEV
STDEV.S | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STDEV
STDEV.P | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STDEVP
STDEVA | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STDEVA
STDEVP | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STDEVP
STDEVPA | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STDEVPA
@ -365,6 +392,8 @@ TREND | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::TREND
TRIMMEAN | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::TRIMMEAN
TTEST | **Not yet Implemented**
VAR | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::VARFunc
VAR.P | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::VARP
VAR.S | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::VARFunc
VARA | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::VARA
VARP | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::VARP
VARPA | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::VARPA
@ -380,9 +409,10 @@ BAHTTEXT | **Not yet Implemented**
CHAR | \PhpOffice\PhpSpreadsheet\Calculation\TextData::CHARACTER
CLEAN | \PhpOffice\PhpSpreadsheet\Calculation\TextData::TRIMNONPRINTABLE
CODE | \PhpOffice\PhpSpreadsheet\Calculation\TextData::ASCIICODE
CONCAT | \PhpOffice\PhpSpreadsheet\Calculation\TextData::CONCATENATE
CONCATENATE | \PhpOffice\PhpSpreadsheet\Calculation\TextData::CONCATENATE
DOLLAR | \PhpOffice\PhpSpreadsheet\Calculation\TextData::DOLLAR
EXACT | **Not yet Implemented**
EXACT | \PhpOffice\PhpSpreadsheet\Calculation\TextData::EXACT
FIND | \PhpOffice\PhpSpreadsheet\Calculation\TextData::SEARCHSENSITIVE
FINDB | \PhpOffice\PhpSpreadsheet\Calculation\TextData::SEARCHSENSITIVE
FIXED | \PhpOffice\PhpSpreadsheet\Calculation\TextData::FIXEDFORMAT
@ -394,6 +424,7 @@ LENB | \PhpOffice\PhpSpreadsheet\Calculation\TextData::STRINGLENG
LOWER | \PhpOffice\PhpSpreadsheet\Calculation\TextData::LOWERCASE
MID | \PhpOffice\PhpSpreadsheet\Calculation\TextData::MID
MIDB | \PhpOffice\PhpSpreadsheet\Calculation\TextData::MID
NUMBERVALUE | \PhpOffice\PhpSpreadsheet\Calculation\TextData::NUMBERVALUE
PHONETIC | **Not yet Implemented**
PROPER | \PhpOffice\PhpSpreadsheet\Calculation\TextData::PROPERCASE
REPLACE | \PhpOffice\PhpSpreadsheet\Calculation\TextData::REPLACE
@ -406,6 +437,9 @@ SEARCHB | \PhpOffice\PhpSpreadsheet\Calculation\TextData::SEARCHINSE
SUBSTITUTE | \PhpOffice\PhpSpreadsheet\Calculation\TextData::SUBSTITUTE
T | \PhpOffice\PhpSpreadsheet\Calculation\TextData::RETURNSTRING
TEXT | \PhpOffice\PhpSpreadsheet\Calculation\TextData::TEXTFORMAT
TEXTJOIN | \PhpOffice\PhpSpreadsheet\Calculation\TextData::TEXTJOIN
TRIM | \PhpOffice\PhpSpreadsheet\Calculation\TextData::TRIMSPACES
UNICHAR | \PhpOffice\PhpSpreadsheet\Calculation\TextData::CHARACTER
UNICODE | \PhpOffice\PhpSpreadsheet\Calculation\TextData::ASCIICODE
UPPER | \PhpOffice\PhpSpreadsheet\Calculation\TextData::UPPERCASE
VALUE | **Not yet Implemented**
VALUE | \PhpOffice\PhpSpreadsheet\Calculation\TextData::VALUE

View File

@ -9,10 +9,12 @@ ACCRINT | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet
ACCRINTM | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::ACCRINTM
ACOS | CATEGORY_MATH_AND_TRIG | acos
ACOSH | CATEGORY_MATH_AND_TRIG | acosh
ACOT | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::ACOT
ACOTH | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::ACOTH
ADDRESS | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::CELL_ADDRESS
AMORDEGRC | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::AMORDEGRC
AMORLINC | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::AMORLINC
AND | CATEGORY_LOGICAL | \PhpOffice\PhpSpreadsheet\Calculation\Logical::LOGICAL_AND
AND | CATEGORY_LOGICAL | \PhpOffice\PhpSpreadsheet\Calculation\Logical::logicalAnd
AREAS | CATEGORY_LOOKUP_AND_REFERENCE | **Not yet Implemented**
ASC | CATEGORY_TEXT_AND_DATA | **Not yet Implemented**
ASIN | CATEGORY_MATH_AND_TRIG | asin
@ -59,12 +61,15 @@ COLUMN | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet
COLUMNS | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::COLUMNS
COMBIN | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::COMBIN
COMPLEX | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::COMPLEX
CONCAT | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData::CONCATENATE
CONCATENATE | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData::CONCATENATE
CONFIDENCE | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::CONFIDENCE
CONVERT | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::CONVERTUOM
CORREL | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::CORREL
COS | CATEGORY_MATH_AND_TRIG | cos
COSH | CATEGORY_MATH_AND_TRIG | cosh
COT | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::COT
COTH | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::COTH
COUNT | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::COUNT
COUNTA | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::COUNTA
COUNTBLANK | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::COUNTBLANK
@ -78,6 +83,8 @@ COUPNUM | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet
COUPPCD | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::COUPPCD
COVAR | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::COVAR
CRITBINOM | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::CRITBINOM
CSC | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::CSC
CSCH | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::CSCH
CUBEKPIMEMBER | CATEGORY_CUBE | **Not yet Implemented**
CUBEMEMBER | CATEGORY_CUBE | **Not yet Implemented**
CUBEMEMBERPROPERTY | CATEGORY_CUBE | **Not yet Implemented**
@ -131,10 +138,12 @@ EDATE | CATEGORY_DATE_AND_TIME | \PhpOffice\PhpSpreadsheet
EFFECT | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::EFFECT
EOMONTH | CATEGORY_DATE_AND_TIME | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::EOMONTH
ERF | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::ERF
ERF.PRECISE | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::ERFPRECISE
ERFC | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::ERFC
ERFC.PRECISE | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::ERFC
ERROR.TYPE | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet\Calculation\Functions::ERROR_TYPE
EVEN | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::EVEN
EXACT | CATEGORY_TEXT_AND_DATA | **Not yet Implemented**
EXACT | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData::EXACT
EXP | CATEGORY_MATH_AND_TRIG | exp
EXPONDIST | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::EXPONDIST
@ -154,6 +163,7 @@ FISHERINV | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet
FIXED | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData::FIXEDFORMAT
FLOOR | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::FLOOR
FORECAST | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::FORECAST
FORMULATEXT | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::FORMULATEXT
FREQUENCY | CATEGORY_STATISTICAL | **Not yet Implemented**
FTEST | CATEGORY_STATISTICAL | **Not yet Implemented**
FV | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::FV
@ -180,7 +190,7 @@ HARMEAN | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet
HEX2BIN | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::HEXTOBIN
HEX2DEC | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::HEXTODEC
HEX2OCT | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::HEXTOOCT
HLOOKUP | CATEGORY_LOOKUP_AND_REFERENCE | **Not yet Implemented**
HLOOKUP | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::HLOOKUP
HOUR | CATEGORY_DATE_AND_TIME | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::HOUROFDAY
HYPERLINK | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::HYPERLINK
HYPGEOMDIST | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::HYPGEOMDIST
@ -196,6 +206,10 @@ IMAGINARY | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet
IMARGUMENT | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMARGUMENT
IMCONJUGATE | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMCONJUGATE
IMCOS | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMCOS
IMCOSH | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMCOSH
IMCOT | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMCOT
IMCSC | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMCSC
IMCSCH | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMCSCH
IMDIV | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMDIV
IMEXP | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMEXP
IMLN | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMLN
@ -204,10 +218,14 @@ IMLOG2 | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet
IMPOWER | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMPOWER
IMPRODUCT | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMPRODUCT
IMREAL | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMREAL
IMSEC | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSEC
IMSECH | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSECH
IMSIN | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSIN
IMSINH | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSINH
IMSQRT | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSQRT
IMSUB | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSUB
IMSUM | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMSUM
IMTAN | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering::IMTAN
INDEX | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::INDEX
INDIRECT | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::INDIRECT
INFO | CATEGORY_INFORMATION | **Not yet Implemented**
@ -220,11 +238,13 @@ ISBLANK | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet
ISERR | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_ERR
ISERROR | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_ERROR
ISEVEN | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_EVEN
ISFORMULA | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet\Calculation\Functions::ISFORMULA
ISLOGICAL | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_LOGICAL
ISNA | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_NA
ISNONTEXT | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_NONTEXT
ISNUMBER | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_NUMBER
ISODD | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_ODD
ISOWEEKNUM | CATEGORY_DATE_AND_TIME | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::ISOWEEKNUM
ISPMT | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::ISPMT
ISREF | CATEGORY_INFORMATION | **Not yet Implemented**
ISTEXT | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet\Calculation\Functions::IS_TEXT
@ -284,6 +304,7 @@ MIRR | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet
MMULT | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::MMULT
MOD | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::MOD
MODE | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::MODE
MODE.SNGL | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::MODE
MONTH | CATEGORY_DATE_AND_TIME | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::MONTHOFYEAR
MROUND | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::MROUND
MULTINOMIAL | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::MULTINOMIAL
@ -305,6 +326,7 @@ NOT | CATEGORY_LOGICAL | \PhpOffice\PhpSpreadsheet
NOW | CATEGORY_DATE_AND_TIME | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::DATETIMENOW
NPER | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::NPER
NPV | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::NPV
NUMBERVALUE | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData::NUMBERVALUE
## O
@ -319,12 +341,13 @@ ODDFYIELD | CATEGORY_FINANCIAL | **Not yet Implemented**
ODDLPRICE | CATEGORY_FINANCIAL | **Not yet Implemented**
ODDLYIELD | CATEGORY_FINANCIAL | **Not yet Implemented**
OFFSET | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::OFFSET
OR | CATEGORY_LOGICAL | \PhpOffice\PhpSpreadsheet\Calculation\Logical::LOGICAL_OR
OR | CATEGORY_LOGICAL | \PhpOffice\PhpSpreadsheet\Calculation\Logical::logicalOr
## P
Excel Function | Category | PhpSpreadsheet Function
--------------------|--------------------------------|-------------------------------------------
PDURATION | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::PDURATION
PEARSON | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::CORREL
PERCENTILE | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::PERCENTILE
PERCENTRANK | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::PERCENTRANK
@ -371,6 +394,7 @@ ROUNDDOWN | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet
ROUNDUP | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::ROUNDUP
ROW | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::ROW
ROWS | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::ROWS
RRI | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::RRI
RSQ | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::RSQ
RTD | CATEGORY_LOOKUP_AND_REFERENCE | **Not yet Implemented**
@ -380,6 +404,8 @@ Excel Function | Category | PhpSpreadsheet Function
--------------------|--------------------------------|-------------------------------------------
SEARCH | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData::SEARCHINSENSITIVE
SEARCHB | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData::SEARCHINSENSITIVE
SEC | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SEC
SECH | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SECH
SECOND | CATEGORY_DATE_AND_TIME | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::SECOND
SERIESSUM | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SERIESSUM
SIGN | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SIGN
@ -393,6 +419,8 @@ SQRT | CATEGORY_MATH_AND_TRIG | sqrt
SQRTPI | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SQRTPI
STANDARDIZE | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STANDARDIZE
STDEV | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STDEV
STDEV.S | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STDEV
STDEV.P | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STDEVP
STDEVA | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STDEVA
STDEVP | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STDEVP
STDEVPA | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::STDEVPA
@ -401,7 +429,7 @@ SUBSTITUTE | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet
SUBTOTAL | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUBTOTAL
SUM | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUM
SUMIF | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUMIF
SUMIFS | CATEGORY_MATH_AND_TRIG | **Not yet Implemented**
SUMIFS | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUMIFS
SUMPRODUCT | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUMPRODUCT
SUMSQ | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUMSQ
SUMX2MY2 | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::SUMX2MY2
@ -421,6 +449,7 @@ TBILLPRICE | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet
TBILLYIELD | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::TBILLYIELD
TDIST | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::TDIST
TEXT | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData::TEXTFORMAT
TEXTJOIN | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData::TEXTJOIN
TIME | CATEGORY_DATE_AND_TIME | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::TIME
TIMEVALUE | CATEGORY_DATE_AND_TIME | \PhpOffice\PhpSpreadsheet\Calculation\DateTime::TIMEVALUE
TINV | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::TINV
@ -438,6 +467,8 @@ TYPE | CATEGORY_INFORMATION | \PhpOffice\PhpSpreadsheet
Excel Function | Category | PhpSpreadsheet Function
--------------------|--------------------------------|-------------------------------------------
UNICHAR | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData::CHARACTER
UNICODE | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData::ASCIICODE
UPPER | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData::UPPERCASE
USDOLLAR | CATEGORY_FINANCIAL | **Not yet Implemented**
@ -445,8 +476,10 @@ USDOLLAR | CATEGORY_FINANCIAL | **Not yet Implemented**
Excel Function | Category | PhpSpreadsheet Function
--------------------|--------------------------------|-------------------------------------------
VALUE | CATEGORY_TEXT_AND_DATA | **Not yet Implemented**
VALUE | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData::VALUE
VAR | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::VARFunc
VAR.P | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::VARP
VAR.S | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::VARFunc
VARA | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::VARA
VARP | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::VARP
VARPA | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical::VARPA
@ -468,6 +501,8 @@ Excel Function | Category | PhpSpreadsheet Function
--------------------|--------------------------------|-------------------------------------------
XIRR | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::XIRR
XNPV | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial::XNPV
XOR | CATEGORY_LOGICAL | \PhpOffice\PhpSpreadsheet\Calculation\Logical::logicalXor
## Y

View File

@ -426,9 +426,9 @@ for ($row = 1; $row <= $highestRow; ++$row) {
echo '</table>' . PHP_EOL;
```
Note that we can't use a &lt;= comparison here, because 'AA' would match
as &lt;= 'B', so we increment the highest column letter and then loop
while \$col != the incremented highest column.
Note that we can't use a `<=` comparison here, because `'AA'` would match
as `<= 'B'`, so we increment the highest column letter and then loop
while `$col !=` the incremented highest column.
## Using value binders to facilitate data entry

View File

@ -285,8 +285,8 @@ $columnFilter->createRule()
We also set the rule type to CUSTOMFILTER.
This defined two rules, filtering numbers that are &gt;= -20 OR &lt;=
20, so we also need to modify the join condition to reflect AND rather
This defined two rules, filtering numbers that are `>= -20` OR `<=
20`, so we also need to modify the join condition to reflect AND rather
than OR.
``` php

View File

@ -634,16 +634,16 @@ $writer->setSheetIndex(0);
#### Setting the images root of the HTML file
There might be situations where you want to explicitly set the included
images root. For example, one might want to see
images root. For example, instead of:
``` html
<img src="./images/logo.jpg">
```
You might want to see:
``` html
<img style="position: relative; left: 0px; top: 0px; width: 140px; height: 78px;" src="http://www.domain.com/*images/logo.jpg" border="0">
```
instead of
``` html
<img style="position: relative; left: 0px; top: 0px; width: 140px; height: 78px;" src="./images/logo.jpg" border="0">.
<img src="http://www.domain.com/images/logo.jpg">
```
You can use the following code to achieve this result:

View File

@ -3,12 +3,12 @@
The following pages offer you some widely-used PhpSpreadsheet recipes.
Please note that these do NOT offer complete documentation on specific
PhpSpreadsheet API functions, but just a bump to get you started. If you
need specific API functions, please refer to the API documentation.
need specific API functions, please refer to the [API documentation](https://phpoffice.github.io/PhpSpreadsheet/master).
For example, [setting a worksheet's page orientation and size
](#setting-a-worksheets-page-orientation-and-size) covers setting a page
orientation to A4. Other paper formats, like US Letter, are not covered
in this document, but in the PhpSpreadsheet API documentation.
in this document, but in the PhpSpreadsheet [API documentation](https://phpoffice.github.io/PhpSpreadsheet/master).
## Setting a spreadsheet's metadata
@ -132,7 +132,7 @@ will take care of displaying the formula according the applications
language. Translation is taken care of by the application!
The following line of code writes the formula
`=IF(C4&gt;500,"profit","loss")` into the cell B8. Note that the
`=IF(C4>500,"profit","loss")` into the cell B8. Note that the
formula must start with `=` to make PhpSpreadsheet recognise this as a
formula.
@ -301,7 +301,7 @@ $spreadsheet->getActiveSheet()->getPageSetup()
```
Note that there are additional page settings available. Please refer to
the API documentation for all possible options.
the [API documentation](https://phpoffice.github.io/PhpSpreadsheet/master) for all possible options.
### Page Setup: Scaling options

View File

@ -31,8 +31,6 @@ index, use the `getSheet()` method.
$spreadsheet->getSheet(1);
```
If you don't specify a sheet index, then the first worksheet will be
returned.
Methods also exist allowing you to reorder the worksheets in the
workbook.
@ -71,7 +69,7 @@ $spreadsheet->createSheet();
```
A new worksheet created using this method will be called
"Worksheet&lt;n&gt;" where "&lt;n&gt;" is the lowest number possible to
`Worksheet<n>` where `<n>` is the lowest number possible to
guarantee that the title is unique.
Alternatively, you can instantiate a new worksheet (setting the title to

View File

@ -5,7 +5,3 @@ edit_uri: edit/develop/docs/
theme: readthedocs
extra_css:
- extra/extra.css
extra_javascript:
- extra/extra.js

View File

@ -125,7 +125,7 @@ $autoFilter->getColumn('C')
)
->setRuleType(Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER);
// Filter the Date column on a filter value of the first day of every period of the current year
// We us a dateGroup ruletype for this, although it is still a standard filter
// We us a dateGroup ruletype for this, although it is still a standard filter
foreach ($periods as $period) {
$endDate = date('t', mktime(0, 0, 0, $period, 1, $currentYear));

View File

@ -108,7 +108,7 @@ $spreadsheet->getActiveSheet()->setAutoFilter($spreadsheet->getActiveSheet()->ca
$autoFilter = $spreadsheet->getActiveSheet()->getAutoFilter();
$helper->log('Set active filters');
// Filter the Country column on a filter value of Germany
// As it's just a simple value filter, we can use FILTERTYPE_FILTER
// As it's just a simple value filter, we can use FILTERTYPE_FILTER
$autoFilter->getColumn('C')
->setFilterType(Column::AUTOFILTER_FILTERTYPE_FILTER)
->createRule()

View File

@ -125,7 +125,7 @@ $autoFilter->getColumn('C')
)
->setRuleType(Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER);
// Filter the Date column on a filter value of the first day of every period of the current year
// We us a dateGroup ruletype for this, although it is still a standard filter
// We us a dateGroup ruletype for this, although it is still a standard filter
foreach ($periods as $period) {
$endDate = date('t', mktime(0, 0, 0, $period, 1, $currentYear));

View File

@ -84,7 +84,7 @@ $conditionalStyles[] = $conditional2;
$conditionalStyles[] = $conditional3;
$spreadsheet->getActiveSheet()->getStyle('B2')->setConditionalStyles($conditionalStyles);
// duplicate the conditional styles across a range of cells
// duplicate the conditional styles across a range of cells
$helper->log('Duplicate the conditional formatting across a range of cells');
$spreadsheet->getActiveSheet()->duplicateConditionalStyle(
$spreadsheet->getActiveSheet()->getStyle('B2')->getConditionalStyles(),

View File

@ -59,7 +59,7 @@ $conditionalStyles[] = $conditional1;
$conditionalStyles[] = $conditional3;
$spreadsheet->getActiveSheet()->getStyle('A1')->setConditionalStyles($conditionalStyles);
// duplicate the conditional styles across a range of cells
// duplicate the conditional styles across a range of cells
$helper->log('Duplicate the conditional formatting across a range of cells');
$spreadsheet->getActiveSheet()->duplicateConditionalStyle(
$spreadsheet->getActiveSheet()->getStyle('A1')->getConditionalStyles(),

View File

@ -5,7 +5,7 @@ use PhpOffice\PhpSpreadsheet\Settings;
require __DIR__ . '/../Header.php';
// Change these values to select the Rendering library that you wish to use
// Change these values to select the Rendering library that you wish to use
Settings::setChartRenderer(\PhpOffice\PhpSpreadsheet\Chart\Renderer\JpGraph::class);
$inputFileType = 'Xlsx';

View File

@ -7,7 +7,7 @@ require __DIR__ . '/../Header.php';
IOFactory::registerWriter('Pdf', \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf::class);
// Change these values to select the Rendering library that you wish to use
// Change these values to select the Rendering library that you wish to use
Settings::setChartRenderer(\PhpOffice\PhpSpreadsheet\Chart\Renderer\JpGraph::class);
$inputFileType = 'Xlsx';

View File

@ -23,42 +23,42 @@ $worksheet->fromArray(
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
// Build the dataseries
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_AREACHART, // plotType
DataSeries::GROUPING_PERCENT_STACKED, // plotGrouping
@ -68,15 +68,15 @@ $series = new DataSeries(
$dataSeriesValues // plotValues
);
// Set the series in the plot area
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
// Set the chart legend
$legend = new Legend(Legend::POSITION_TOPRIGHT, null, false);
$title = new Title('Test %age-Stacked Area Chart');
$yAxisLabel = new Title('Value ($k)');
// Create the chart
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
@ -88,11 +88,11 @@ $chart = new Chart(
$yAxisLabel // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('H20');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart);
// Save Excel 2007 file

View File

@ -23,42 +23,42 @@ $worksheet->fromArray(
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
// Build the dataseries
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_BARCHART, // plotType
DataSeries::GROUPING_STACKED, // plotGrouping
@ -67,19 +67,19 @@ $series = new DataSeries(
$xAxisTickValues, // plotCategory
$dataSeriesValues // plotValues
);
// Set additional dataseries parameters
// Make it a horizontal bar rather than a vertical column graph
// Set additional dataseries parameters
// Make it a horizontal bar rather than a vertical column graph
$series->setPlotDirection(DataSeries::DIRECTION_BAR);
// Set the series in the plot area
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
// Set the chart legend
$legend = new Legend(Legend::POSITION_RIGHT, null, false);
$title = new Title('Test Chart');
$yAxisLabel = new Title('Value ($k)');
// Create the chart
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
@ -91,11 +91,11 @@ $chart = new Chart(
$yAxisLabel // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('H20');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart);
// Save Excel 2007 file

View File

@ -23,42 +23,42 @@ $worksheet->fromArray(
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
// Build the dataseries
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_BARCHART, // plotType
DataSeries::GROUPING_STANDARD, // plotGrouping
@ -67,19 +67,19 @@ $series = new DataSeries(
$xAxisTickValues, // plotCategory
$dataSeriesValues // plotValues
);
// Set additional dataseries parameters
// Make it a vertical column rather than a horizontal bar graph
// Set additional dataseries parameters
// Make it a vertical column rather than a horizontal bar graph
$series->setPlotDirection(DataSeries::DIRECTION_COL);
// Set the series in the plot area
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
// Set the chart legend
$legend = new Legend(Legend::POSITION_RIGHT, null, false);
$title = new Title('Test Column Chart');
$yAxisLabel = new Title('Value ($k)');
// Create the chart
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
@ -91,11 +91,11 @@ $chart = new Chart(
$yAxisLabel // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('H20');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart);
// Save Excel 2007 file

View File

@ -31,42 +31,42 @@ $worksheet->fromArray(
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 'Budget'
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 'Forecast'
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$E$1', null, 1), // 'Actual'
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 'Budget'
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 'Forecast'
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$E$1', null, 1), // 'Actual'
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$B$13', null, 12), // Q1 to Q4 for 2010 to 2012
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$B$13', null, 12), // Q1 to Q4 for 2010 to 2012
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$13', null, 12),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$13', null, 12),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$E$2:$E$13', null, 12),
];
// Build the dataseries
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_BARCHART, // plotType
DataSeries::GROUPING_CLUSTERED, // plotGrouping
@ -75,20 +75,20 @@ $series = new DataSeries(
$xAxisTickValues, // plotCategory
$dataSeriesValues // plotValues
);
// Set additional dataseries parameters
// Make it a vertical column rather than a horizontal bar graph
// Set additional dataseries parameters
// Make it a vertical column rather than a horizontal bar graph
$series->setPlotDirection(DataSeries::DIRECTION_COL);
// Set the series in the plot area
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
// Set the chart legend
$legend = new Legend(Legend::POSITION_BOTTOM, null, false);
$title = new Title('Test Grouped Column Chart');
$xAxisLabel = new Title('Financial Period');
$yAxisLabel = new Title('Value ($k)');
// Create the chart
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
@ -100,11 +100,11 @@ $chart = new Chart(
$yAxisLabel // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('G2');
$chart->setBottomRightPosition('P20');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart);
// Save Excel 2007 file

View File

@ -31,46 +31,46 @@ $worksheet->fromArray(
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // Temperature
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // Temperature
];
$dataSeriesLabels2 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // Rainfall
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // Rainfall
];
$dataSeriesLabels3 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // Humidity
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // Humidity
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$13', null, 12), // Jan to Dec
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$13', null, 12), // Jan to Dec
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$13', null, 12),
];
// Build the dataseries
// Build the dataseries
$series1 = new DataSeries(
DataSeries::TYPE_BARCHART, // plotType
DataSeries::GROUPING_CLUSTERED, // plotGrouping
@ -79,22 +79,22 @@ $series1 = new DataSeries(
$xAxisTickValues, // plotCategory
$dataSeriesValues1 // plotValues
);
// Set additional dataseries parameters
// Make it a vertical column rather than a horizontal bar graph
// Set additional dataseries parameters
// Make it a vertical column rather than a horizontal bar graph
$series1->setPlotDirection(DataSeries::DIRECTION_COL);
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues2 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$13', null, 12),
];
// Build the dataseries
// Build the dataseries
$series2 = new DataSeries(
DataSeries::TYPE_LINECHART, // plotType
DataSeries::GROUPING_STANDARD, // plotGrouping
@ -104,18 +104,18 @@ $series2 = new DataSeries(
$dataSeriesValues2 // plotValues
);
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues3 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$13', null, 12),
];
// Build the dataseries
// Build the dataseries
$series3 = new DataSeries(
DataSeries::TYPE_AREACHART, // plotType
DataSeries::GROUPING_STANDARD, // plotGrouping
@ -125,14 +125,14 @@ $series3 = new DataSeries(
$dataSeriesValues3 // plotValues
);
// Set the series in the plot area
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series1, $series2, $series3]);
// Set the chart legend
// Set the chart legend
$legend = new Legend(Legend::POSITION_RIGHT, null, false);
$title = new Title('Average Weather Chart for Crete');
// Create the chart
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
@ -144,11 +144,11 @@ $chart = new Chart(
null // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('F2');
$chart->setBottomRightPosition('O16');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart);
// Save Excel 2007 file

View File

@ -23,35 +23,35 @@ $worksheet->fromArray(
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
@ -59,7 +59,7 @@ $dataSeriesValues = [
];
$dataSeriesValues[2]->setLineWidth(60000);
// Build the dataseries
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_LINECHART, // plotType
DataSeries::GROUPING_STACKED, // plotGrouping
@ -69,15 +69,15 @@ $series = new DataSeries(
$dataSeriesValues // plotValues
);
// Set the series in the plot area
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
// Set the chart legend
$legend = new Legend(Legend::POSITION_TOPRIGHT, null, false);
$title = new Title('Test Stacked Line Chart');
$yAxisLabel = new Title('Value ($k)');
// Create the chart
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
@ -89,11 +89,11 @@ $chart = new Chart(
$yAxisLabel // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('H20');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart);
// Save Excel 2007 file

View File

@ -23,42 +23,42 @@ $worksheet->fromArray(
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
// Build the dataseries
// Build the dataseries
$series1 = new DataSeries(
DataSeries::TYPE_AREACHART, // plotType
DataSeries::GROUPING_PERCENT_STACKED, // plotGrouping
@ -68,15 +68,15 @@ $series1 = new DataSeries(
$dataSeriesValues1 // plotValues
);
// Set the series in the plot area
// Set the series in the plot area
$plotArea1 = new PlotArea(null, [$series1]);
// Set the chart legend
// Set the chart legend
$legend1 = new Legend(Legend::POSITION_TOPRIGHT, null, false);
$title1 = new Title('Test %age-Stacked Area Chart');
$yAxisLabel1 = new Title('Value ($k)');
// Create the chart
// Create the chart
$chart1 = new Chart(
'chart1', // name
$title1, // title
@ -88,49 +88,49 @@ $chart1 = new Chart(
$yAxisLabel1 // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart1->setTopLeftPosition('A7');
$chart1->setBottomRightPosition('H20');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart1);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels2 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues2 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues2 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
// Build the dataseries
// Build the dataseries
$series2 = new DataSeries(
DataSeries::TYPE_BARCHART, // plotType
DataSeries::GROUPING_STANDARD, // plotGrouping
@ -139,19 +139,19 @@ $series2 = new DataSeries(
$xAxisTickValues2, // plotCategory
$dataSeriesValues2 // plotValues
);
// Set additional dataseries parameters
// Make it a vertical column rather than a horizontal bar graph
// Set additional dataseries parameters
// Make it a vertical column rather than a horizontal bar graph
$series2->setPlotDirection(DataSeries::DIRECTION_COL);
// Set the series in the plot area
// Set the series in the plot area
$plotArea2 = new PlotArea(null, [$series2]);
// Set the chart legend
// Set the chart legend
$legend2 = new Legend(Legend::POSITION_RIGHT, null, false);
$title2 = new Title('Test Column Chart');
$yAxisLabel2 = new Title('Value ($k)');
// Create the chart
// Create the chart
$chart2 = new Chart(
'chart2', // name
$title2, // title
@ -163,11 +163,11 @@ $chart2 = new Chart(
$yAxisLabel2 // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart2->setTopLeftPosition('I7');
$chart2->setBottomRightPosition('P20');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart2);
// Save Excel 2007 file

View File

@ -24,38 +24,38 @@ $worksheet->fromArray(
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
];
// Build the dataseries
// Build the dataseries
$series1 = new DataSeries(
DataSeries::TYPE_PIECHART, // plotType
null, // plotGrouping (Pie charts don't have any grouping)
@ -65,19 +65,19 @@ $series1 = new DataSeries(
$dataSeriesValues1 // plotValues
);
// Set up a layout object for the Pie chart
// Set up a layout object for the Pie chart
$layout1 = new Layout();
$layout1->setShowVal(true);
$layout1->setShowPercent(true);
// Set the series in the plot area
// Set the series in the plot area
$plotArea1 = new PlotArea($layout1, [$series1]);
// Set the chart legend
// Set the chart legend
$legend1 = new Legend(Legend::POSITION_RIGHT, null, false);
$title1 = new Title('Test Pie Chart');
// Create the chart
// Create the chart
$chart1 = new Chart(
'chart1', // name
$title1, // title
@ -86,48 +86,48 @@ $chart1 = new Chart(
true, // plotVisibleOnly
0, // displayBlanksAs
null, // xAxisLabel
null // yAxisLabel - Pie charts don't have a Y-Axis
null // yAxisLabel - Pie charts don't have a Y-Axis
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart1->setTopLeftPosition('A7');
$chart1->setBottomRightPosition('H20');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart1);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels2 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues2 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues2 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
];
// Build the dataseries
// Build the dataseries
$series2 = new DataSeries(
DataSeries::TYPE_DONUTCHART, // plotType
null, // plotGrouping (Donut charts don't have any grouping)
@ -137,17 +137,17 @@ $series2 = new DataSeries(
$dataSeriesValues2 // plotValues
);
// Set up a layout object for the Pie chart
// Set up a layout object for the Pie chart
$layout2 = new Layout();
$layout2->setShowVal(true);
$layout2->setShowCatName(true);
// Set the series in the plot area
// Set the series in the plot area
$plotArea2 = new PlotArea($layout2, [$series2]);
$title2 = new Title('Test Donut Chart');
// Create the chart
// Create the chart
$chart2 = new Chart(
'chart2', // name
$title2, // title
@ -156,14 +156,14 @@ $chart2 = new Chart(
true, // plotVisibleOnly
0, // displayBlanksAs
null, // xAxisLabel
null // yAxisLabel - Like Pie charts, Donut charts don't have a Y-Axis
null // yAxisLabel - Like Pie charts, Donut charts don't have a Y-Axis
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart2->setTopLeftPosition('I7');
$chart2->setBottomRightPosition('P20');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart2);
// Save Excel 2007 file

View File

@ -32,41 +32,41 @@ $worksheet->fromArray(
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$13', null, 12), // Jan to Dec
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$13', null, 12), // Jan to Dec
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$13', null, 12), // Jan to Dec
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$13', null, 12), // Jan to Dec
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$13', null, 12),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$13', null, 12),
];
// Build the dataseries
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_RADARCHART, // plotType
null, // plotGrouping (Radar charts don't have any grouping)
@ -79,17 +79,17 @@ $series = new DataSeries(
DataSeries::STYLE_MARKER // plotStyle
);
// Set up a layout object for the Pie chart
// Set up a layout object for the Pie chart
$layout = new Layout();
// Set the series in the plot area
// Set the series in the plot area
$plotArea = new PlotArea($layout, [$series]);
// Set the chart legend
// Set the chart legend
$legend = new Legend(Legend::POSITION_RIGHT, null, false);
$title = new Title('Test Radar Chart');
// Create the chart
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
@ -98,14 +98,14 @@ $chart = new Chart(
true, // plotVisibleOnly
0, // displayBlanksAs
null, // xAxisLabel
null // yAxisLabel - Radar charts don't have a Y-Axis
null // yAxisLabel - Radar charts don't have a Y-Axis
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('F2');
$chart->setBottomRightPosition('M15');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart);
// Save Excel 2007 file

View File

@ -23,36 +23,36 @@ $worksheet->fromArray(
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// Set the X-Axis Labels
// Set the X-Axis Labels
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
// Build the dataseries
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_SCATTERCHART, // plotType
null, // plotGrouping (Scatter charts don't have any grouping)
@ -65,15 +65,15 @@ $series = new DataSeries(
DataSeries::STYLE_LINEMARKER // plotStyle
);
// Set the series in the plot area
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
// Set the chart legend
$legend = new Legend(Legend::POSITION_TOPRIGHT, null, false);
$title = new Title('Test Scatter Chart');
$yAxisLabel = new Title('Value ($k)');
// Create the chart
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
@ -85,11 +85,11 @@ $chart = new Chart(
$yAxisLabel // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('H20');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart);
// Save Excel 2007 file

View File

@ -29,36 +29,36 @@ $worksheet->fromArray(
);
$worksheet->getStyle('B2:E6')->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_NUMBER_00);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), //Max / Open
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), //Min / Close
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), //Min Threshold / Min
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$E$1', null, 1), //Max Threshold / Max
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$6', null, 5), // Counts
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$6', null, 5), // Counts
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$6', null, 5),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$6', null, 5),
@ -66,7 +66,7 @@ $dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$E$2:$E$6', null, 5),
];
// Build the dataseries
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_STOCKCHART, // plotType
null, // plotGrouping - if we set this to not null, then xlsx throws error
@ -76,16 +76,16 @@ $series = new DataSeries(
$dataSeriesValues // plotValues
);
// Set the series in the plot area
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
// Set the chart legend
$legend = new Legend(Legend::POSITION_RIGHT, null, false);
$title = new Title('Test Stock Chart');
$xAxisLabel = new Title('Counts');
$yAxisLabel = new Title('Values');
// Create the chart
// Create the chart
$chart = new Chart(
'stock-chart', // name
$title, // title
@ -97,11 +97,11 @@ $chart = new Chart(
$yAxisLabel // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('H20');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart);
// Save Excel 2007 file

View File

@ -57,7 +57,7 @@ for ($startRow = 2; $startRow <= 240; $startRow += $chunkSize) {
// Load only the rows that match our filter from $inputFileName to a PhpSpreadsheet Object
$spreadsheet = $reader->load($inputFileName);
// Do some processing here
// Do some processing here
$sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true);
var_dump($sheetData);

View File

@ -60,7 +60,7 @@ for ($startRow = 2; $startRow <= 240; $startRow += $chunkSize) {
// Load only the rows that match our filter from $inputFileName to a PhpSpreadsheet Object
$spreadsheet = $reader->load($inputFileName);
// Do some processing here
// Do some processing here
$sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true);
var_dump($sheetData);

View File

@ -0,0 +1,54 @@
<?php
use PhpOffice\PhpSpreadsheet\Spreadsheet;
require __DIR__ . '/../Header.php';
$inputFileType = 'Xlsx';
$helper->log('Start');
$spreadsheet = new Spreadsheet();
$aSheet = $spreadsheet->getActiveSheet();
$gdImage = @imagecreatetruecolor(120, 20);
$textColor = imagecolorallocate($gdImage, 255, 255, 255);
imagestring($gdImage, 1, 5, 5, 'Created with PhpSpreadsheet', $textColor);
$baseUrl = 'https://phpspreadsheet.readthedocs.io/';
$drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing();
$drawing->setName('In-Memory image 1');
$drawing->setDescription('In-Memory image 1');
$drawing->setCoordinates('A1');
$drawing->setImageResource($gdImage);
$drawing->setRenderingFunction(
\PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::RENDERING_JPEG
);
$drawing->setMimeType(\PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing::MIMETYPE_DEFAULT);
$drawing->setHeight(36);
$helper->log('Write image');
$hyperLink = new \PhpOffice\PhpSpreadsheet\Cell\Hyperlink($baseUrl, 'test image');
$drawing->setHyperlink($hyperLink);
$helper->log('Write link: ' . $baseUrl);
$drawing->setWorksheet($aSheet);
$filename = tempnam(\PhpOffice\PhpSpreadsheet\Shared\File::sysGetTempDir(), 'phpspreadsheet-test');
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, $inputFileType);
$writer->save($filename);
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
$reloadedSpreadsheet = $reader->load($filename);
unlink($filename);
$helper->log('reloaded Spreadsheet');
foreach ($reloadedSpreadsheet->getActiveSheet()->getDrawingCollection() as $pDrawing) {
$helper->log('Read link: ' . $pDrawing->getHyperlink()->getUrl());
}
$helper->log('end');

View File

@ -25,24 +25,24 @@ foreach ($customPropertyList as $customPropertyName) {
// Manipulate properties as appropriate for display purposes
switch ($propertyType) {
case 'i': // integer
case 'i': // integer
$propertyType = 'integer number';
break;
case 'f': // float
case 'f': // float
$propertyType = 'floating point number';
break;
case 's': // string
case 's': // string
$propertyType = 'string';
break;
case 'd': // date
case 'd': // date
$propertyValue = date('l, d<\s\up>S</\s\up> F Y g:i A', $propertyValue);
$propertyType = 'date';
break;
case 'b': // boolean
case 'b': // boolean
$propertyValue = ($propertyValue) ? 'TRUE' : 'FALSE';
$propertyType = 'boolean';

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -20,42 +20,42 @@ $worksheet->fromArray(
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
// Build the dataseries
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_BARCHART, // plotType
DataSeries::GROUPING_CLUSTERED, // plotGrouping
@ -64,19 +64,19 @@ $series = new DataSeries(
$xAxisTickValues, // plotCategory
$dataSeriesValues // plotValues
);
// Set additional dataseries parameters
// Make it a horizontal bar rather than a vertical column graph
// Set additional dataseries parameters
// Make it a horizontal bar rather than a vertical column graph
$series->setPlotDirection(DataSeries::DIRECTION_BAR);
// Set the series in the plot area
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
// Set the chart legend
$legend = new Legend(Legend::POSITION_RIGHT, null, false);
$title = new Title('Test Bar Chart');
$yAxisLabel = new Title('Value ($k)');
// Create the chart
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
@ -88,11 +88,11 @@ $chart = new Chart(
$yAxisLabel // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('H20');
// Add the chart to the worksheet
// Add the chart to the worksheet
$worksheet->addChart($chart);
return $spreadsheet;

View File

@ -224,6 +224,16 @@ class Calculation
'functionCall' => 'acosh',
'argumentCount' => '1',
],
'ACOT' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'ACOT'],
'argumentCount' => '1',
],
'ACOTH' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'ACOTH'],
'argumentCount' => '1',
],
'ADDRESS' => [
'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE,
'functionCall' => [LookupRef::class, 'cellAddress'],
@ -359,6 +369,31 @@ class Calculation
'functionCall' => [Statistical::class, 'BINOMDIST'],
'argumentCount' => '4',
],
'BITAND' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'BITAND'],
'argumentCount' => '2',
],
'BITOR' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'BITOR'],
'argumentCount' => '2',
],
'BITXOR' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'BITOR'],
'argumentCount' => '2',
],
'BITLSHIFT' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'BITLSHIFT'],
'argumentCount' => '2',
],
'BITRSHIFT' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'BITRSHIFT'],
'argumentCount' => '2',
],
'CEILING' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'CEILING'],
@ -425,6 +460,11 @@ class Calculation
'functionCall' => [Engineering::class, 'COMPLEX'],
'argumentCount' => '2,3',
],
'CONCAT' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [TextData::class, 'CONCATENATE'],
'argumentCount' => '1+',
],
'CONCATENATE' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [TextData::class, 'CONCATENATE'],
@ -455,6 +495,16 @@ class Calculation
'functionCall' => 'cosh',
'argumentCount' => '1',
],
'COT' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'COT'],
'argumentCount' => '1',
],
'COTH' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'COTH'],
'argumentCount' => '1',
],
'COUNT' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Statistical::class, 'COUNT'],
@ -520,6 +570,16 @@ class Calculation
'functionCall' => [Statistical::class, 'CRITBINOM'],
'argumentCount' => '3',
],
'CSC' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'CSC'],
'argumentCount' => '1',
],
'CSCH' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'CSCH'],
'argumentCount' => '1',
],
'CUBEKPIMEMBER' => [
'category' => Category::CATEGORY_CUBE,
'functionCall' => [Functions::class, 'DUMMY'],
@ -735,11 +795,21 @@ class Calculation
'functionCall' => [Engineering::class, 'ERF'],
'argumentCount' => '1,2',
],
'ERF.PRECISE' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'ERFPRECISE'],
'argumentCount' => '1',
],
'ERFC' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'ERFC'],
'argumentCount' => '1',
],
'ERFC.PRECISE' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'ERFC'],
'argumentCount' => '1',
],
'ERROR.TYPE' => [
'category' => Category::CATEGORY_INFORMATION,
'functionCall' => [Functions::class, 'errorType'],
@ -752,7 +822,7 @@ class Calculation
],
'EXACT' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'functionCall' => [TextData::class, 'EXACT'],
'argumentCount' => '2',
],
'EXP' => [
@ -825,6 +895,13 @@ class Calculation
'functionCall' => [Statistical::class, 'FORECAST'],
'argumentCount' => '3',
],
'FORMULATEXT' => [
'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE,
'functionCall' => [LookupRef::class, 'FORMULATEXT'],
'argumentCount' => '1',
'passCellReference' => true,
'passByReference' => [true],
],
'FREQUENCY' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Functions::class, 'DUMMY'],
@ -961,6 +1038,26 @@ class Calculation
'functionCall' => [Engineering::class, 'IMCOS'],
'argumentCount' => '1',
],
'IMCOSH' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'IMCOSH'],
'argumentCount' => '1',
],
'IMCOT' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'IMCOT'],
'argumentCount' => '1',
],
'IMCSC' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'IMCSC'],
'argumentCount' => '1',
],
'IMCSCH' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'IMCSCH'],
'argumentCount' => '1',
],
'IMDIV' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'IMDIV'],
@ -1001,11 +1098,26 @@ class Calculation
'functionCall' => [Engineering::class, 'IMREAL'],
'argumentCount' => '1',
],
'IMSEC' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'IMSEC'],
'argumentCount' => '1',
],
'IMSECH' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'IMSECH'],
'argumentCount' => '1',
],
'IMSIN' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'IMSIN'],
'argumentCount' => '1',
],
'IMSINH' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'IMSINH'],
'argumentCount' => '1',
],
'IMSQRT' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'IMSQRT'],
@ -1021,6 +1133,11 @@ class Calculation
'functionCall' => [Engineering::class, 'IMSUM'],
'argumentCount' => '1+',
],
'IMTAN' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'IMTAN'],
'argumentCount' => '1',
],
'INDEX' => [
'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE,
'functionCall' => [LookupRef::class, 'INDEX'],
@ -1114,6 +1231,11 @@ class Calculation
'functionCall' => [Functions::class, 'isOdd'],
'argumentCount' => '1',
],
'ISOWEEKNUM' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'ISOWEEKNUM'],
'argumentCount' => '1',
],
'ISPMT' => [
'category' => Category::CATEGORY_FINANCIAL,
'functionCall' => [Financial::class, 'ISPMT'],
@ -1394,6 +1516,11 @@ class Calculation
'functionCall' => [Financial::class, 'NPV'],
'argumentCount' => '2+',
],
'NUMBERVALUE' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [TextData::class, 'NUMBERVALUE'],
'argumentCount' => '1+',
],
'OCT2BIN' => [
'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'OCTTOBIN'],
@ -1446,6 +1573,11 @@ class Calculation
'functionCall' => [Logical::class, 'logicalOr'],
'argumentCount' => '1+',
],
'PDURATION' => [
'category' => Category::CATEGORY_FINANCIAL,
'functionCall' => [Financial::class, 'PDURATION'],
'argumentCount' => '3',
],
'PEARSON' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Statistical::class, 'CORREL'],
@ -1627,6 +1759,11 @@ class Calculation
'functionCall' => [LookupRef::class, 'ROWS'],
'argumentCount' => '1',
],
'RRI' => [
'category' => Category::CATEGORY_FINANCIAL,
'functionCall' => [Financial::class, 'RRI'],
'argumentCount' => '3',
],
'RSQ' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Statistical::class, 'RSQ'],
@ -1647,6 +1784,16 @@ class Calculation
'functionCall' => [TextData::class, 'SEARCHINSENSITIVE'],
'argumentCount' => '2,3',
],
'SEC' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'SEC'],
'argumentCount' => '1',
],
'SECH' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'SECH'],
'argumentCount' => '1',
],
'SECOND' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'SECOND'],
@ -1838,6 +1985,11 @@ class Calculation
'functionCall' => [TextData::class, 'TEXTFORMAT'],
'argumentCount' => '2',
],
'TEXTJOIN' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [TextData::class, 'TEXTJOIN'],
'argumentCount' => '3+',
],
'TIME' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'TIME'],
@ -1898,6 +2050,16 @@ class Calculation
'functionCall' => [Functions::class, 'TYPE'],
'argumentCount' => '1',
],
'UNICHAR' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [TextData::class, 'CHARACTER'],
'argumentCount' => '1',
],
'UNICODE' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [TextData::class, 'ASCIICODE'],
'argumentCount' => '1',
],
'UPPER' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [TextData::class, 'UPPERCASE'],
@ -1918,6 +2080,16 @@ class Calculation
'functionCall' => [Statistical::class, 'VARFunc'],
'argumentCount' => '1+',
],
'VAR.P' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Statistical::class, 'VARP'],
'argumentCount' => '1+',
],
'VAR.S' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Statistical::class, 'VARFunc'],
'argumentCount' => '1+',
],
'VARA' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Statistical::class, 'VARA'],
@ -1973,6 +2145,11 @@ class Calculation
'functionCall' => [Financial::class, 'XNPV'],
'argumentCount' => '3',
],
'XOR' => [
'category' => Category::CATEGORY_LOGICAL,
'functionCall' => [Logical::class, 'logicalXor'],
'argumentCount' => '1+',
],
'YEAR' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'YEAR'],
@ -2395,10 +2572,10 @@ class Calculation
if (self::$functionReplaceToLocale === null) {
self::$functionReplaceToLocale = [];
foreach (array_values(self::$localeFunctions) as $localeFunctionName) {
foreach (self::$localeFunctions as $localeFunctionName) {
self::$functionReplaceToLocale[] = '$1' . trim($localeFunctionName) . '$2';
}
foreach (array_values(self::$localeBoolean) as $localeBoolean) {
foreach (self::$localeBoolean as $localeBoolean) {
self::$functionReplaceToLocale[] = '$1' . trim($localeBoolean) . '$2';
}
}
@ -2414,10 +2591,10 @@ class Calculation
{
if (self::$functionReplaceFromLocale === null) {
self::$functionReplaceFromLocale = [];
foreach (array_values(self::$localeFunctions) as $localeFunctionName) {
foreach (self::$localeFunctions as $localeFunctionName) {
self::$functionReplaceFromLocale[] = '/(@?[^\w\.])' . preg_quote($localeFunctionName, '/') . '([\s]*\()/Ui';
}
foreach (array_values(self::$localeBoolean) as $excelBoolean) {
foreach (self::$localeBoolean as $excelBoolean) {
self::$functionReplaceFromLocale[] = '/(@?[^\w\.])' . preg_quote($excelBoolean, '/') . '([^\w\.])/Ui';
}
}

View File

@ -10,7 +10,7 @@ class DateTime
/**
* Identify if a year is a leap year or not.
*
* @param int $year The year to test
* @param int|string $year The year to test
*
* @return bool TRUE if the year is a leap year, otherwise FALSE
*/
@ -70,7 +70,7 @@ class DateTime
(Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC)) {
return Functions::VALUE();
}
if ((is_object($dateValue)) && ($dateValue instanceof \DateTime)) {
if ((is_object($dateValue)) && ($dateValue instanceof \DateTimeImmutable)) {
$dateValue = Date::PHPToExcel($dateValue);
} else {
$saveReturnDateType = Functions::getReturnDateType();
@ -650,7 +650,7 @@ class DateTime
* or a standard date string
* @param string $unit
*
* @return int Interval between the dates
* @return int|string Interval between the dates
*/
public static function DATEDIF($startDate = 0, $endDate = 0, $unit = 'D')
{
@ -792,7 +792,7 @@ class DateTime
* occur on the 31st of a month become equal to the 30th of the
* same month.
*
* @return int Number of days between start date and end date
* @return int|string Number of days between start date and end date
*/
public static function DAYS360($startDate = 0, $endDate = 0, $method = false)
{
@ -942,7 +942,7 @@ class DateTime
* @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int Interval between the dates
* @return int|string Interval between the dates
*/
public static function NETWORKDAYS($startDate, $endDate, ...$dateArgs)
{
@ -1127,7 +1127,7 @@ class DateTime
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int Day of the month
* @return int|string Day of the month
*/
public static function DAYOFMONTH($dateValue = 1)
{
@ -1169,7 +1169,7 @@ class DateTime
* 2 Numbers 1 (Monday) through 7 (Sunday).
* 3 Numbers 0 (Monday) through 6 (Sunday).
*
* @return int Day of the week value
* @return int|string Day of the week value
*/
public static function WEEKDAY($dateValue = 1, $style = 1)
{
@ -1248,7 +1248,7 @@ class DateTime
* 1 or omitted Week begins on Sunday.
* 2 Week begins on Monday.
*
* @return int Week Number
* @return int|string Week Number
*/
public static function WEEKNUM($dateValue = 1, $method = 1)
{
@ -1286,6 +1286,37 @@ class DateTime
return (int) $weekOfYear;
}
/**
* ISOWEEKNUM.
*
* Returns the ISO 8601 week number of the year for a specified date.
*
* Excel Function:
* ISOWEEKNUM(dateValue)
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int|string Week Number
*/
public static function ISOWEEKNUM($dateValue = 1)
{
$dateValue = Functions::flattenSingleValue($dateValue);
if ($dateValue === null) {
$dateValue = 1;
} elseif (is_string($dateValue = self::getDateValue($dateValue))) {
return Functions::VALUE();
} elseif ($dateValue < 0.0) {
return Functions::NAN();
}
// Execute function
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
return (int) $PHPDateObject->format('W');
}
/**
* MONTHOFYEAR.
*
@ -1298,7 +1329,7 @@ class DateTime
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int Month of the year
* @return int|string Month of the year
*/
public static function MONTHOFYEAR($dateValue = 1)
{
@ -1331,7 +1362,7 @@ class DateTime
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int Year
* @return int|string Year
*/
public static function YEAR($dateValue = 1)
{
@ -1363,7 +1394,7 @@ class DateTime
* @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard time string
*
* @return int Hour
* @return int|string Hour
*/
public static function HOUROFDAY($timeValue = 0)
{
@ -1404,7 +1435,7 @@ class DateTime
* @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard time string
*
* @return int Minute
* @return int|string Minute
*/
public static function MINUTE($timeValue = 0)
{
@ -1445,7 +1476,7 @@ class DateTime
* @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard time string
*
* @return int Second
* @return int|string Second
*/
public static function SECOND($timeValue = 0)
{

View File

@ -2,6 +2,9 @@
namespace PhpOffice\PhpSpreadsheet\Calculation;
use Complex\Complex;
use Complex\Exception as ComplexException;
class Engineering
{
/**
@ -718,83 +721,23 @@ class Engineering
*
* Parses a complex number into its real and imaginary parts, and an I or J suffix
*
* @deprecated 2.0.0 No longer used by internal code. Please use the Complex\Complex class instead
*
* @param string $complexNumber The complex number
*
* @return string[] Indexed on "real", "imaginary" and "suffix"
* @return mixed[] Indexed on "real", "imaginary" and "suffix"
*/
public static function parseComplex($complexNumber)
{
$workString = (string) $complexNumber;
$realNumber = $imaginary = 0;
// Extract the suffix, if there is one
$suffix = substr($workString, -1);
if (!is_numeric($suffix)) {
$workString = substr($workString, 0, -1);
} else {
$suffix = '';
}
// Split the input into its Real and Imaginary components
$leadingSign = 0;
if (strlen($workString) > 0) {
$leadingSign = (($workString[0] == '+') || ($workString[0] == '-')) ? 1 : 0;
}
$power = '';
$realNumber = strtok($workString, '+-');
if (strtoupper(substr($realNumber, -1)) == 'E') {
$power = strtok('+-');
++$leadingSign;
}
$realNumber = substr($workString, 0, strlen($realNumber) + strlen($power) + $leadingSign);
if ($suffix != '') {
$imaginary = substr($workString, strlen($realNumber));
if (($imaginary == '') && (($realNumber == '') || ($realNumber == '+') || ($realNumber == '-'))) {
$imaginary = $realNumber . '1';
$realNumber = '0';
} elseif ($imaginary == '') {
$imaginary = $realNumber;
$realNumber = '0';
} elseif (($imaginary == '+') || ($imaginary == '-')) {
$imaginary .= '1';
}
}
$complex = new Complex($complexNumber);
return [
'real' => $realNumber,
'imaginary' => $imaginary,
'suffix' => $suffix,
'real' => $complex->getReal(),
'imaginary' => $complex->getImaginary(),
'suffix' => $complex->getSuffix(),
];
}
/**
* Cleans the leading characters in a complex number string.
*
* @param string $complexNumber The complex number to clean
*
* @return string The "cleaned" complex number
*/
private static function cleanComplex($complexNumber)
{
if ($complexNumber[0] == '+') {
$complexNumber = substr($complexNumber, 1);
}
if ($complexNumber[0] == '0') {
$complexNumber = substr($complexNumber, 1);
}
if ($complexNumber[0] == '.') {
$complexNumber = '0' . $complexNumber;
}
if ($complexNumber[0] == '+') {
$complexNumber = substr($complexNumber, 1);
}
return $complexNumber;
}
/**
* Formats a number base string value with leading zeroes.
*
@ -1745,10 +1688,10 @@ class Engineering
/**
* COMPLEX.
*
* Converts real and imaginary coefficients into a complex number of the form x + yi or x + yj.
* Converts real and imaginary coefficients into a complex number of the form x +/- yi or x +/- yj.
*
* Excel Function:
* COMPLEX(realNumber,imaginary[,places])
* COMPLEX(realNumber,imaginary[,suffix])
*
* @category Engineering Functions
*
@ -1768,34 +1711,9 @@ class Engineering
if (((is_numeric($realNumber)) && (is_numeric($imaginary))) &&
(($suffix == 'i') || ($suffix == 'j') || ($suffix == ''))
) {
$realNumber = (float) $realNumber;
$imaginary = (float) $imaginary;
$complex = new Complex($realNumber, $imaginary, $suffix);
if ($suffix == '') {
$suffix = 'i';
}
if ($realNumber == 0.0) {
if ($imaginary == 0.0) {
return (string) '0';
} elseif ($imaginary == 1.0) {
return (string) $suffix;
} elseif ($imaginary == -1.0) {
return (string) '-' . $suffix;
}
return (string) $imaginary . $suffix;
} elseif ($imaginary == 0.0) {
return (string) $realNumber;
} elseif ($imaginary == 1.0) {
return (string) $realNumber . '+' . $suffix;
} elseif ($imaginary == -1.0) {
return (string) $realNumber . '-' . $suffix;
}
if ($imaginary > 0) {
$imaginary = (string) '+' . $imaginary;
}
return (string) $realNumber . $imaginary . $suffix;
return (string) $complex;
}
return Functions::VALUE();
@ -1820,9 +1738,7 @@ class Engineering
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
$parsedComplex = self::parseComplex($complexNumber);
return $parsedComplex['imaginary'];
return (new Complex($complexNumber))->getImaginary();
}
/**
@ -1843,9 +1759,7 @@ class Engineering
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
$parsedComplex = self::parseComplex($complexNumber);
return $parsedComplex['real'];
return (new Complex($complexNumber))->getReal();
}
/**
@ -1864,12 +1778,7 @@ class Engineering
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
$parsedComplex = self::parseComplex($complexNumber);
return sqrt(
($parsedComplex['real'] * $parsedComplex['real']) +
($parsedComplex['imaginary'] * $parsedComplex['imaginary'])
);
return (new Complex($complexNumber))->abs();
}
/**
@ -1883,27 +1792,18 @@ class Engineering
*
* @param string $complexNumber the complex number for which you want the argument theta
*
* @return float
* @return float|string
*/
public static function IMARGUMENT($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
$parsedComplex = self::parseComplex($complexNumber);
if ($parsedComplex['real'] == 0.0) {
if ($parsedComplex['imaginary'] == 0.0) {
return Functions::DIV0();
} elseif ($parsedComplex['imaginary'] < 0.0) {
return M_PI / -2;
}
return M_PI / 2;
} elseif ($parsedComplex['real'] > 0.0) {
return atan($parsedComplex['imaginary'] / $parsedComplex['real']);
} elseif ($parsedComplex['imaginary'] < 0.0) {
return 0 - (M_PI - atan(abs($parsedComplex['imaginary']) / abs($parsedComplex['real'])));
$complex = new Complex($complexNumber);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return Functions::DIV0();
}
return M_PI - atan($parsedComplex['imaginary'] / abs($parsedComplex['real']));
return $complex->argument();
}
/**
@ -1922,19 +1822,7 @@ class Engineering
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
$parsedComplex = self::parseComplex($complexNumber);
if ($parsedComplex['imaginary'] == 0.0) {
return $parsedComplex['real'];
}
return self::cleanComplex(
self::COMPLEX(
$parsedComplex['real'],
0 - $parsedComplex['imaginary'],
$parsedComplex['suffix']
)
);
return (string) (new Complex($complexNumber))->conjugate();
}
/**
@ -1953,19 +1841,83 @@ class Engineering
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
$parsedComplex = self::parseComplex($complexNumber);
return (string) (new Complex($complexNumber))->cos();
}
if ($parsedComplex['imaginary'] == 0.0) {
return cos($parsedComplex['real']);
}
/**
* IMCOSH.
*
* Returns the hyperbolic cosine of a complex number in x + yi or x + yj text format.
*
* Excel Function:
* IMCOSH(complexNumber)
*
* @param string $complexNumber the complex number for which you want the hyperbolic cosine
*
* @return float|string
*/
public static function IMCOSH($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
return self::IMCONJUGATE(
self::COMPLEX(
cos($parsedComplex['real']) * cosh($parsedComplex['imaginary']),
sin($parsedComplex['real']) * sinh($parsedComplex['imaginary']),
$parsedComplex['suffix']
)
);
return (string) (new Complex($complexNumber))->cosh();
}
/**
* IMCOT.
*
* Returns the cotangent of a complex number in x + yi or x + yj text format.
*
* Excel Function:
* IMCOT(complexNumber)
*
* @param string $complexNumber the complex number for which you want the cotangent
*
* @return float|string
*/
public static function IMCOT($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
return (string) (new Complex($complexNumber))->cot();
}
/**
* IMCSC.
*
* Returns the cosecant of a complex number in x + yi or x + yj text format.
*
* Excel Function:
* IMCSC(complexNumber)
*
* @param string $complexNumber the complex number for which you want the cosecant
*
* @return float|string
*/
public static function IMCSC($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
return (string) (new Complex($complexNumber))->csc();
}
/**
* IMCSCH.
*
* Returns the hyperbolic cosecant of a complex number in x + yi or x + yj text format.
*
* Excel Function:
* IMCSCH(complexNumber)
*
* @param string $complexNumber the complex number for which you want the hyperbolic cosecant
*
* @return float|string
*/
public static function IMCSCH($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
return (string) (new Complex($complexNumber))->csch();
}
/**
@ -1984,17 +1936,83 @@ class Engineering
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
$parsedComplex = self::parseComplex($complexNumber);
return (string) (new Complex($complexNumber))->sin();
}
if ($parsedComplex['imaginary'] == 0.0) {
return sin($parsedComplex['real']);
}
/**
* IMSINH.
*
* Returns the hyperbolic sine of a complex number in x + yi or x + yj text format.
*
* Excel Function:
* IMSINH(complexNumber)
*
* @param string $complexNumber the complex number for which you want the hyperbolic sine
*
* @return float|string
*/
public static function IMSINH($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
return self::COMPLEX(
sin($parsedComplex['real']) * cosh($parsedComplex['imaginary']),
cos($parsedComplex['real']) * sinh($parsedComplex['imaginary']),
$parsedComplex['suffix']
);
return (string) (new Complex($complexNumber))->sinh();
}
/**
* IMSEC.
*
* Returns the secant of a complex number in x + yi or x + yj text format.
*
* Excel Function:
* IMSEC(complexNumber)
*
* @param string $complexNumber the complex number for which you want the secant
*
* @return float|string
*/
public static function IMSEC($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
return (string) (new Complex($complexNumber))->sec();
}
/**
* IMSECH.
*
* Returns the hyperbolic secant of a complex number in x + yi or x + yj text format.
*
* Excel Function:
* IMSECH(complexNumber)
*
* @param string $complexNumber the complex number for which you want the hyperbolic secant
*
* @return float|string
*/
public static function IMSECH($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
return (string) (new Complex($complexNumber))->sech();
}
/**
* IMTAN.
*
* Returns the tangent of a complex number in x + yi or x + yj text format.
*
* Excel Function:
* IMTAN(complexNumber)
*
* @param string $complexNumber the complex number for which you want the tangent
*
* @return float|string
*/
public static function IMTAN($complexNumber)
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
return (string) (new Complex($complexNumber))->tan();
}
/**
@ -2013,22 +2031,12 @@ class Engineering
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
$parsedComplex = self::parseComplex($complexNumber);
$theta = self::IMARGUMENT($complexNumber);
if ($theta === Functions::DIV0()) {
return '0';
}
$d1 = cos($theta / 2);
$d2 = sin($theta / 2);
$r = sqrt(sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])));
if ($parsedComplex['suffix'] == '') {
return self::COMPLEX($d1 * $r, $d2 * $r);
}
return self::COMPLEX($d1 * $r, $d2 * $r, $parsedComplex['suffix']);
return (string) (new Complex($complexNumber))->sqrt();
}
/**
@ -2047,20 +2055,12 @@ class Engineering
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
$parsedComplex = self::parseComplex($complexNumber);
if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
$complex = new Complex($complexNumber);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return Functions::NAN();
}
$logR = log(sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])));
$t = self::IMARGUMENT($complexNumber);
if ($parsedComplex['suffix'] == '') {
return self::COMPLEX($logR, $t);
}
return self::COMPLEX($logR, $t, $parsedComplex['suffix']);
return (string) (new Complex($complexNumber))->ln();
}
/**
@ -2079,15 +2079,12 @@ class Engineering
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
$parsedComplex = self::parseComplex($complexNumber);
if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
$complex = new Complex($complexNumber);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return Functions::NAN();
} elseif (($parsedComplex['real'] > 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
return log10($parsedComplex['real']);
}
return self::IMPRODUCT(log10(self::EULER), self::IMLN($complexNumber));
return (string) (new Complex($complexNumber))->log10();
}
/**
@ -2106,15 +2103,12 @@ class Engineering
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
$parsedComplex = self::parseComplex($complexNumber);
if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
$complex = new Complex($complexNumber);
if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
return Functions::NAN();
} elseif (($parsedComplex['real'] > 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
return log($parsedComplex['real'], 2);
}
return self::IMPRODUCT(log(self::EULER, 2), self::IMLN($complexNumber));
return (string) (new Complex($complexNumber))->log2();
}
/**
@ -2133,21 +2127,7 @@ class Engineering
{
$complexNumber = Functions::flattenSingleValue($complexNumber);
$parsedComplex = self::parseComplex($complexNumber);
if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
return '1';
}
$e = exp($parsedComplex['real']);
$eX = $e * cos($parsedComplex['imaginary']);
$eY = $e * sin($parsedComplex['imaginary']);
if ($parsedComplex['suffix'] == '') {
return self::COMPLEX($eX, $eY);
}
return self::COMPLEX($eX, $eY, $parsedComplex['suffix']);
return (string) (new Complex($complexNumber))->exp();
}
/**
@ -2172,18 +2152,7 @@ class Engineering
return Functions::VALUE();
}
$parsedComplex = self::parseComplex($complexNumber);
$r = sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary']));
$rPower = pow($r, $realNumber);
$theta = self::IMARGUMENT($complexNumber) * $realNumber;
if ($theta == 0) {
return 1;
} elseif ($parsedComplex['imaginary'] == 0.0) {
return self::COMPLEX($rPower * cos($theta), $rPower * sin($theta), $parsedComplex['suffix']);
}
return self::COMPLEX($rPower * cos($theta), $rPower * sin($theta), $parsedComplex['suffix']);
return (string) (new Complex($complexNumber))->pow($realNumber);
}
/**
@ -2204,32 +2173,11 @@ class Engineering
$complexDividend = Functions::flattenSingleValue($complexDividend);
$complexDivisor = Functions::flattenSingleValue($complexDivisor);
$parsedComplexDividend = self::parseComplex($complexDividend);
$parsedComplexDivisor = self::parseComplex($complexDivisor);
if (($parsedComplexDividend['suffix'] != '') && ($parsedComplexDivisor['suffix'] != '') &&
($parsedComplexDividend['suffix'] != $parsedComplexDivisor['suffix'])
) {
try {
return (string) (new Complex($complexDividend))->divideby(new Complex($complexDivisor));
} catch (ComplexException $e) {
return Functions::NAN();
}
if (($parsedComplexDividend['suffix'] != '') && ($parsedComplexDivisor['suffix'] == '')) {
$parsedComplexDivisor['suffix'] = $parsedComplexDividend['suffix'];
}
$d1 = ($parsedComplexDividend['real'] * $parsedComplexDivisor['real']) + ($parsedComplexDividend['imaginary'] * $parsedComplexDivisor['imaginary']);
$d2 = ($parsedComplexDividend['imaginary'] * $parsedComplexDivisor['real']) - ($parsedComplexDividend['real'] * $parsedComplexDivisor['imaginary']);
$d3 = ($parsedComplexDivisor['real'] * $parsedComplexDivisor['real']) + ($parsedComplexDivisor['imaginary'] * $parsedComplexDivisor['imaginary']);
$r = $d1 / $d3;
$i = $d2 / $d3;
if ($i > 0.0) {
return self::cleanComplex($r . '+' . $i . $parsedComplexDivisor['suffix']);
} elseif ($i < 0.0) {
return self::cleanComplex($r . $i . $parsedComplexDivisor['suffix']);
}
return $r;
}
/**
@ -2250,21 +2198,11 @@ class Engineering
$complexNumber1 = Functions::flattenSingleValue($complexNumber1);
$complexNumber2 = Functions::flattenSingleValue($complexNumber2);
$parsedComplex1 = self::parseComplex($complexNumber1);
$parsedComplex2 = self::parseComplex($complexNumber2);
if ((($parsedComplex1['suffix'] != '') && ($parsedComplex2['suffix'] != '')) &&
($parsedComplex1['suffix'] != $parsedComplex2['suffix'])
) {
try {
return (string) (new Complex($complexNumber1))->subtract(new Complex($complexNumber2));
} catch (ComplexException $e) {
return Functions::NAN();
} elseif (($parsedComplex1['suffix'] == '') && ($parsedComplex2['suffix'] != '')) {
$parsedComplex1['suffix'] = $parsedComplex2['suffix'];
}
$d1 = $parsedComplex1['real'] - $parsedComplex2['real'];
$d2 = $parsedComplex1['imaginary'] - $parsedComplex2['imaginary'];
return self::COMPLEX($d1, $d2, $parsedComplex1['suffix']);
}
/**
@ -2282,29 +2220,19 @@ class Engineering
public static function IMSUM(...$complexNumbers)
{
// Return value
$returnValue = self::parseComplex('0');
$activeSuffix = '';
// Loop through the arguments
$returnValue = new Complex(0.0);
$aArgs = Functions::flattenArray($complexNumbers);
foreach ($aArgs as $arg) {
$parsedComplex = self::parseComplex($arg);
if ($activeSuffix == '') {
$activeSuffix = $parsedComplex['suffix'];
} elseif (($parsedComplex['suffix'] != '') && ($activeSuffix != $parsedComplex['suffix'])) {
return Functions::NAN();
try {
// Loop through the arguments
foreach ($aArgs as $complex) {
$returnValue = $returnValue->add(new Complex($complex));
}
$returnValue['real'] += $parsedComplex['real'];
$returnValue['imaginary'] += $parsedComplex['imaginary'];
} catch (ComplexException $e) {
return Functions::NAN();
}
if ($returnValue['imaginary'] == 0.0) {
$activeSuffix = '';
}
return self::COMPLEX($returnValue['real'], $returnValue['imaginary'], $activeSuffix);
return (string) $returnValue;
}
/**
@ -2322,29 +2250,19 @@ class Engineering
public static function IMPRODUCT(...$complexNumbers)
{
// Return value
$returnValue = self::parseComplex('1');
$activeSuffix = '';
// Loop through the arguments
$returnValue = new Complex(1.0);
$aArgs = Functions::flattenArray($complexNumbers);
foreach ($aArgs as $arg) {
$parsedComplex = self::parseComplex($arg);
$workValue = $returnValue;
if (($parsedComplex['suffix'] != '') && ($activeSuffix == '')) {
$activeSuffix = $parsedComplex['suffix'];
} elseif (($parsedComplex['suffix'] != '') && ($activeSuffix != $parsedComplex['suffix'])) {
return Functions::NAN();
try {
// Loop through the arguments
foreach ($aArgs as $complex) {
$returnValue = $returnValue->multiply(new Complex($complex));
}
$returnValue['real'] = ($workValue['real'] * $parsedComplex['real']) - ($workValue['imaginary'] * $parsedComplex['imaginary']);
$returnValue['imaginary'] = ($workValue['real'] * $parsedComplex['imaginary']) + ($workValue['imaginary'] * $parsedComplex['real']);
} catch (ComplexException $e) {
return Functions::NAN();
}
if ($returnValue['imaginary'] == 0.0) {
$activeSuffix = '';
}
return self::COMPLEX($returnValue['real'], $returnValue['imaginary'], $activeSuffix);
return (string) $returnValue;
}
/**
@ -2423,6 +2341,179 @@ class Engineering
return self::$twoSqrtPi * $sum;
}
/**
* Validate arguments passed to the bitwise functions.
*
* @param mixed $value
*
* @throws Exception
*
* @return int
*/
private static function validateBitwiseArgument($value)
{
$value = Functions::flattenSingleValue($value);
if (is_int($value)) {
return $value;
} elseif (is_numeric($value)) {
if ($value == (int) ($value)) {
$value = (int) ($value);
if (($value > pow(2, 48) - 1) || ($value < 0)) {
throw new Exception(Functions::NAN());
}
return $value;
}
throw new Exception(Functions::NAN());
}
throw new Exception(Functions::VALUE());
}
/**
* BITAND.
*
* Returns the bitwise AND of two integer values.
*
* Excel Function:
* BITAND(number1, number2)
*
* @category Engineering Functions
*
* @param int $number1
* @param int $number2
*
* @return int|string
*/
public static function BITAND($number1, $number2)
{
try {
$number1 = self::validateBitwiseArgument($number1);
$number2 = self::validateBitwiseArgument($number2);
} catch (Exception $e) {
return $e->getMessage();
}
return $number1 & $number2;
}
/**
* BITOR.
*
* Returns the bitwise OR of two integer values.
*
* Excel Function:
* BITOR(number1, number2)
*
* @category Engineering Functions
*
* @param int $number1
* @param int $number2
*
* @return int|string
*/
public static function BITOR($number1, $number2)
{
try {
$number1 = self::validateBitwiseArgument($number1);
$number2 = self::validateBitwiseArgument($number2);
} catch (Exception $e) {
return $e->getMessage();
}
return $number1 | $number2;
}
/**
* BITXOR.
*
* Returns the bitwise XOR of two integer values.
*
* Excel Function:
* BITXOR(number1, number2)
*
* @category Engineering Functions
*
* @param int $number1
* @param int $number2
*
* @return int|string
*/
public static function BITXOR($number1, $number2)
{
try {
$number1 = self::validateBitwiseArgument($number1);
$number2 = self::validateBitwiseArgument($number2);
} catch (Exception $e) {
return $e->getMessage();
}
return $number1 ^ $number2;
}
/**
* BITLSHIFT.
*
* Returns the number value shifted left by shift_amount bits.
*
* Excel Function:
* BITLSHIFT(number, shift_amount)
*
* @category Engineering Functions
*
* @param int $number
* @param int $shiftAmount
*
* @return int|string
*/
public static function BITLSHIFT($number, $shiftAmount)
{
try {
$number = self::validateBitwiseArgument($number);
} catch (Exception $e) {
return $e->getMessage();
}
$shiftAmount = Functions::flattenSingleValue($shiftAmount);
$result = $number << $shiftAmount;
if ($result > pow(2, 48) - 1) {
return Functions::NAN();
}
return $result;
}
/**
* BITRSHIFT.
*
* Returns the number value shifted right by shift_amount bits.
*
* Excel Function:
* BITRSHIFT(number, shift_amount)
*
* @category Engineering Functions
*
* @param int $number
* @param int $shiftAmount
*
* @return int|string
*/
public static function BITRSHIFT($number, $shiftAmount)
{
try {
$number = self::validateBitwiseArgument($number);
} catch (Exception $e) {
return $e->getMessage();
}
$shiftAmount = Functions::flattenSingleValue($shiftAmount);
return $number >> $shiftAmount;
}
/**
* ERF.
*
@ -2431,7 +2522,7 @@ class Engineering
* Note: In Excel 2007 or earlier, if you input a negative value for the upper or lower bound arguments,
* the function would return a #NUM! error. However, in Excel 2010, the function algorithm was
* improved, so that it can now calculate the function for both positive and negative ranges.
* PhpSpreadsheet follows Excel 2010 behaviour, and accepts nagative arguments.
* PhpSpreadsheet follows Excel 2010 behaviour, and accepts negative arguments.
*
* Excel Function:
* ERF(lower[,upper])
@ -2440,7 +2531,7 @@ class Engineering
* @param float $upper upper bound for integrating ERF.
* If omitted, ERF integrates between zero and lower_limit
*
* @return float
* @return float|string
*/
public static function ERF($lower, $upper = null)
{
@ -2459,6 +2550,25 @@ class Engineering
return Functions::VALUE();
}
/**
* ERFPRECISE.
*
* Returns the error function integrated between the lower and upper bound arguments.
*
* Excel Function:
* ERF.PRECISE(limit)
*
* @param float $limit bound for integrating ERF
*
* @return float|string
*/
public static function ERFPRECISE($limit)
{
$limit = Functions::flattenSingleValue($limit);
return self::ERF($limit);
}
//
// Private method to calculate the erfc value
//
@ -2507,7 +2617,7 @@ class Engineering
*
* @param float $x The lower bound for integrating ERFC
*
* @return float
* @return float|string
*/
public static function ERFC($x)
{

View File

@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Shared\Date;
class Financial
{
const FINANCIAL_MAX_ITERATIONS = 128;
const FINANCIAL_MAX_ITERATIONS = 32;
const FINANCIAL_PRECISION = 1.0e-08;
@ -63,8 +63,8 @@ class Financial
*
* Returns the number of days in a specified year, as defined by the "basis" value
*
* @param int $year The year against which we're testing
* @param int $basis The type of day count:
* @param int|string $year The year against which we're testing
* @param int|string $basis The type of day count:
* 0 or omitted US (NASD) 360
* 1 Actual (365 or 366 in a leap year)
* 2 360
@ -144,7 +144,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float
* @return float|string
*/
public static function ACCRINT($issue, $firstinterest, $settlement, $rate, $par = 1000, $frequency = 1, $basis = 0)
{
@ -197,7 +197,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float
* @return float|string
*/
public static function ACCRINTM($issue, $settlement, $rate, $par = 1000, $basis = 0)
{
@ -401,7 +401,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float
* @return float|string
*/
public static function COUPDAYBS($settlement, $maturity, $frequency, $basis = 0)
{
@ -460,7 +460,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float
* @return float|string
*/
public static function COUPDAYS($settlement, $maturity, $frequency, $basis = 0)
{
@ -489,7 +489,7 @@ class Financial
case 1:
// Actual/actual
if ($frequency == 1) {
$daysPerYear = self::daysPerYear(DateTime::YEAR($maturity), $basis);
$daysPerYear = self::daysPerYear(DateTime::YEAR($settlement), $basis);
return $daysPerYear / $frequency;
}
@ -534,7 +534,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float
* @return float|string
*/
public static function COUPDAYSNC($settlement, $maturity, $frequency, $basis = 0)
{
@ -651,7 +651,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return int
* @return int|string
*/
public static function COUPNUM($settlement, $maturity, $frequency, $basis = 0)
{
@ -769,7 +769,7 @@ class Financial
* 0 or omitted At the end of the period.
* 1 At the beginning of the period.
*
* @return float
* @return float|string
*/
public static function CUMIPMT($rate, $nper, $pv, $start, $end, $type = 0)
{
@ -817,7 +817,7 @@ class Financial
* 0 or omitted At the end of the period.
* 1 At the beginning of the period.
*
* @return float
* @return float|string
*/
public static function CUMPRINC($rate, $nper, $pv, $start, $end, $type = 0)
{
@ -870,7 +870,7 @@ class Financial
* @param int $month Number of months in the first year. If month is omitted,
* it defaults to 12.
*
* @return float
* @return float|string
*/
public static function DB($cost, $salvage, $life, $period, $month = 12)
{
@ -940,7 +940,7 @@ class Financial
* If factor is omitted, it is assumed to be 2 (the
* double-declining balance method).
*
* @return float
* @return float|string
*/
public static function DDB($cost, $salvage, $life, $period, $factor = 2.0)
{
@ -1004,7 +1004,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float
* @return float|string
*/
public static function DISC($settlement, $maturity, $price, $redemption, $basis = 0)
{
@ -1049,7 +1049,7 @@ class Financial
* @param float $fractional_dollar Fractional Dollar
* @param int $fraction Fraction
*
* @return float
* @return float|string
*/
public static function DOLLARDE($fractional_dollar = null, $fraction = 0)
{
@ -1087,7 +1087,7 @@ class Financial
* @param float $decimal_dollar Decimal Dollar
* @param int $fraction Fraction
*
* @return float
* @return float|string
*/
public static function DOLLARFR($decimal_dollar = null, $fraction = 0)
{
@ -1124,7 +1124,7 @@ class Financial
* @param float $nominal_rate Nominal interest rate
* @param int $npery Number of compounding payments per year
*
* @return float
* @return float|string
*/
public static function EFFECT($nominal_rate = 0, $npery = 0)
{
@ -1160,7 +1160,7 @@ class Financial
* 0 or omitted At the end of the period.
* 1 At the beginning of the period.
*
* @return float
* @return float|string
*/
public static function FV($rate = 0, $nper = 0, $pmt = 0, $pv = 0, $type = 0)
{
@ -1230,7 +1230,7 @@ class Financial
* 3 Actual/365
* 4 European 30/360
*
* @return float
* @return float|string
*/
public static function INTRATE($settlement, $maturity, $investment, $redemption, $basis = 0)
{
@ -1275,7 +1275,7 @@ class Financial
* @param float $fv Future Value
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
*
* @return float
* @return float|string
*/
public static function IPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0)
{
@ -1318,7 +1318,7 @@ class Financial
* calculate the internal rate of return.
* @param float $guess A number that you guess is close to the result of IRR
*
* @return float
* @return float|string
*/
public static function IRR($values, $guess = 0.1)
{
@ -1428,7 +1428,7 @@ class Financial
* @param float $finance_rate The interest rate you pay on the money used in the cash flows
* @param float $reinvestment_rate The interest rate you receive on the cash flows as you reinvest them
*
* @return float
* @return float|string
*/
public static function MIRR($values, $finance_rate, $reinvestment_rate)
{
@ -1470,7 +1470,7 @@ class Financial
* @param float $effect_rate Effective interest rate
* @param int $npery Number of compounding payments per year
*
* @return float
* @return float|string
*/
public static function NOMINAL($effect_rate = 0, $npery = 0)
{
@ -1497,7 +1497,7 @@ class Financial
* @param float $fv Future Value
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
*
* @return float
* @return float|string
*/
public static function NPER($rate = 0, $pmt = 0, $pv = 0, $fv = 0, $type = 0)
{
@ -1556,6 +1556,33 @@ class Financial
return $returnValue;
}
/**
* PDURATION.
*
* Calculates the number of periods required for an investment to reach a specified value.
*
* @param float $rate Interest rate per period
* @param float $pv Present Value
* @param float $fv Future Value
*
* @return float|string
*/
public static function PDURATION($rate = 0, $pv = 0, $fv = 0)
{
$rate = Functions::flattenSingleValue($rate);
$pv = Functions::flattenSingleValue($pv);
$fv = Functions::flattenSingleValue($fv);
// Validate parameters
if (!is_numeric($rate) || !is_numeric($pv) || !is_numeric($fv)) {
return Functions::VALUE();
} elseif ($rate <= 0.0 || $pv <= 0.0 || $fv <= 0.0) {
return Functions::NAN();
}
return (log($fv) - log($pv)) / log(1 + $rate);
}
/**
* PMT.
*
@ -1933,6 +1960,33 @@ class Financial
return Functions::VALUE();
}
/**
* RRI.
*
* Calculates the interest rate required for an investment to grow to a specified future value .
*
* @param float $nper The number of periods over which the investment is made
* @param float $pv Present Value
* @param float $fv Future Value
*
* @return float|string
*/
public static function RRI($nper = 0, $pv = 0, $fv = 0)
{
$nper = Functions::flattenSingleValue($nper);
$pv = Functions::flattenSingleValue($pv);
$fv = Functions::flattenSingleValue($fv);
// Validate parameters
if (!is_numeric($nper) || !is_numeric($pv) || !is_numeric($fv)) {
return Functions::VALUE();
} elseif ($nper <= 0.0 || $pv <= 0.0 || $fv < 0.0) {
return Functions::NAN();
}
return pow($fv / $pv, 1 / $nper) - 1;
}
/**
* SLN.
*
@ -1942,7 +1996,7 @@ class Financial
* @param mixed $salvage Value at the end of the depreciation
* @param mixed $life Number of periods over which the asset is depreciated
*
* @return float
* @return float|string
*/
public static function SLN($cost, $salvage, $life)
{
@ -1972,7 +2026,7 @@ class Financial
* @param mixed $life Number of periods over which the asset is depreciated
* @param mixed $period Period
*
* @return float
* @return float|string
*/
public static function SYD($cost, $salvage, $life, $period)
{

View File

@ -277,7 +277,7 @@ class Functions
return '=' . $condition;
}
preg_match('/([<>=]+)(.*)/', $condition, $matches);
preg_match('/(=|<[>=]?|>=?)(.*)/', $condition, $matches);
list(, $operator, $operand) = $matches;
if (!is_numeric($operand)) {
@ -355,7 +355,7 @@ class Functions
return false;
}
return in_array($value, array_values(self::$errorCodes));
return in_array($value, self::$errorCodes);
}
/**
@ -648,17 +648,26 @@ class Functions
/**
* ISFORMULA.
*
* @param mixed $value The cell to check
* @param mixed $cellReference The cell to check
* @param Cell $pCell The current cell (containing this formula)
*
* @return bool|string
*/
public static function isFormula($value = '', Cell $pCell = null)
public static function isFormula($cellReference = '', Cell $pCell = null)
{
if ($pCell === null) {
return self::REF();
}
return substr($pCell->getWorksheet()->getCell($value)->getValue(), 0, 1) === '=';
preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellReference, $matches);
$cellReference = $matches[6] . $matches[7];
$worksheetName = trim($matches[3], "'");
$worksheet = (!empty($worksheetName))
? $pCell->getWorksheet()->getParent()->getSheetByName($worksheetName)
: $pCell->getWorksheet();
return $worksheet->getCell($cellReference)->isFormula();
}
}

View File

@ -38,6 +38,32 @@ class Logical
return false;
}
private static function countTrueValues(array $args)
{
$returnValue = 0;
foreach ($args as $arg) {
// Is it a boolean value?
if (is_bool($arg)) {
$returnValue += $arg;
} elseif ((is_numeric($arg)) && (!is_string($arg))) {
$returnValue += ((int) $arg != 0);
} elseif (is_string($arg)) {
$arg = strtoupper($arg);
if (($arg == 'TRUE') || ($arg == Calculation::getTRUE())) {
$arg = true;
} elseif (($arg == 'FALSE') || ($arg == Calculation::getFALSE())) {
$arg = false;
} else {
return Functions::VALUE();
}
$returnValue += ($arg != 0);
}
}
return $returnValue;
}
/**
* LOGICAL_AND.
*
@ -62,37 +88,23 @@ class Logical
*/
public static function logicalAnd(...$args)
{
// Return value
$returnValue = true;
$args = Functions::flattenArray($args);
// Loop through the arguments
$aArgs = Functions::flattenArray($args);
$argCount = -1;
foreach ($aArgs as $argCount => $arg) {
// Is it a boolean value?
if (is_bool($arg)) {
$returnValue = $returnValue && $arg;
} elseif ((is_numeric($arg)) && (!is_string($arg))) {
$returnValue = $returnValue && ($arg != 0);
} elseif (is_string($arg)) {
$arg = strtoupper($arg);
if (($arg == 'TRUE') || ($arg == Calculation::getTRUE())) {
$arg = true;
} elseif (($arg == 'FALSE') || ($arg == Calculation::getFALSE())) {
$arg = false;
} else {
return Functions::VALUE();
}
$returnValue = $returnValue && ($arg != 0);
}
}
// Return
if ($argCount < 0) {
if (count($args) == 0) {
return Functions::VALUE();
}
return $returnValue;
$args = array_filter($args, function ($value) {
return $value !== null || (is_string($value) && trim($value) == '');
});
$argCount = count($args);
$returnValue = self::countTrueValues($args);
if (is_string($returnValue)) {
return $returnValue;
}
return ($returnValue > 0) && ($returnValue == $argCount);
}
/**
@ -119,37 +131,65 @@ class Logical
*/
public static function logicalOr(...$args)
{
// Return value
$returnValue = false;
$args = Functions::flattenArray($args);
// Loop through the arguments
$aArgs = Functions::flattenArray($args);
$argCount = -1;
foreach ($aArgs as $argCount => $arg) {
// Is it a boolean value?
if (is_bool($arg)) {
$returnValue = $returnValue || $arg;
} elseif ((is_numeric($arg)) && (!is_string($arg))) {
$returnValue = $returnValue || ($arg != 0);
} elseif (is_string($arg)) {
$arg = strtoupper($arg);
if (($arg == 'TRUE') || ($arg == Calculation::getTRUE())) {
$arg = true;
} elseif (($arg == 'FALSE') || ($arg == Calculation::getFALSE())) {
$arg = false;
} else {
return Functions::VALUE();
}
$returnValue = $returnValue || ($arg != 0);
}
}
// Return
if ($argCount < 0) {
if (count($args) == 0) {
return Functions::VALUE();
}
return $returnValue;
$args = array_filter($args, function ($value) {
return $value !== null || (is_string($value) && trim($value) == '');
});
$returnValue = self::countTrueValues($args);
if (is_string($returnValue)) {
return $returnValue;
}
return $returnValue > 0;
}
/**
* LOGICAL_XOR.
*
* Returns the Exclusive Or logical operation for one or more supplied conditions.
* i.e. the Xor function returns TRUE if an odd number of the supplied conditions evaluate to TRUE, and FALSE otherwise.
*
* Excel Function:
* =XOR(logical1[,logical2[, ...]])
*
* The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays
* or references that contain logical values.
*
* Boolean arguments are treated as True or False as appropriate
* Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
* If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
* the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
*
* @category Logical Functions
*
* @param mixed $args Data values
*
* @return bool|string the logical XOR of the arguments
*/
public static function logicalXor(...$args)
{
$args = Functions::flattenArray($args);
if (count($args) == 0) {
return Functions::VALUE();
}
$args = array_filter($args, function ($value) {
return $value !== null || (is_string($value) && trim($value) == '');
});
$returnValue = self::countTrueValues($args);
if (is_string($returnValue)) {
return $returnValue;
}
return $returnValue % 2 == 1;
}
/**
@ -176,6 +216,7 @@ class Logical
public static function NOT($logical = false)
{
$logical = Functions::flattenSingleValue($logical);
if (is_string($logical)) {
$logical = strtoupper($logical);
if (($logical == 'TRUE') || ($logical == Calculation::getTRUE())) {

View File

@ -866,4 +866,33 @@ class LookupRef
return self::VLOOKUP($lookup_value, $lookup_vector, 2);
}
/**
* FORMULATEXT.
*
* @param mixed $cellReference The cell to check
* @param Cell $pCell The current cell (containing this formula)
*
* @return string
*/
public static function FORMULATEXT($cellReference = '', Cell $pCell = null)
{
if ($pCell === null) {
return Functions::REF();
}
preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellReference, $matches);
$cellReference = $matches[6] . $matches[7];
$worksheetName = trim($matches[3], "'");
$worksheet = (!empty($worksheetName))
? $pCell->getWorksheet()->getParent()->getSheetByName($worksheetName)
: $pCell->getWorksheet();
if (!$worksheet->getCell($cellReference)->isFormula()) {
return Functions::NA();
}
return $worksheet->getCell($cellReference)->getValue();
}
}

View File

@ -1081,30 +1081,55 @@ class MathTrig
);
}
protected static function filterFormulaArgs($cellReference, $args)
{
return array_filter(
$args,
function ($index) use ($cellReference) {
list(, $row, $column) = explode('.', $index);
if ($cellReference->getWorksheet()->cellExists($column . $row)) {
//take this cell out if it contains the SUBTOTAL or AGGREGATE functions in a formula
$isFormula = $cellReference->getWorksheet()->getCell($column . $row)->isFormula();
$cellFormula = !preg_match('/^=.*\b(SUBTOTAL|AGGREGATE)\s*\(/i', $cellReference->getWorksheet()->getCell($column . $row)->getValue());
return !$isFormula || $cellFormula;
}
return true;
},
ARRAY_FILTER_USE_KEY
);
}
/**
* SUBTOTAL.
*
* Returns a subtotal in a list or database.
*
* @param int the number 1 to 11 that specifies which function to
* use in calculating subtotals within a list
* use in calculating subtotals within a range
* list
* Numbers 101 to 111 shadow the functions of 1 to 11
* but ignore any values in the range that are
* in hidden rows or columns
* @param array of mixed Data Series
*
* @return float
*/
public static function SUBTOTAL(...$args)
{
$cellReference = array_pop($args);
$aArgs = Functions::flattenArrayIndexed($args);
$cellReference = array_pop($aArgs);
$subtotal = array_shift($aArgs);
// Calculate
if ((is_numeric($subtotal)) && (!is_string($subtotal))) {
if ($subtotal > 100) {
$aArgs = self::filterHiddenArgs($cellReference, $aArgs);
$subtotal = $subtotal - 100;
$subtotal -= 100;
}
$aArgs = self::filterFormulaArgs($cellReference, $aArgs);
switch ($subtotal) {
case 1:
return Statistical::AVERAGE($aArgs);
@ -1433,4 +1458,178 @@ class MathTrig
return ((int) ($value * $adjust)) / $adjust;
}
/**
* SEC.
*
* Returns the secant of an angle.
*
* @param float $angle Number
*
* @return float|string The secant of the angle
*/
public static function SEC($angle)
{
$angle = Functions::flattenSingleValue($angle);
if (!is_numeric($angle)) {
return Functions::VALUE();
}
$result = cos($angle);
return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
}
/**
* SECH.
*
* Returns the hyperbolic secant of an angle.
*
* @param float $angle Number
*
* @return float|string The hyperbolic secant of the angle
*/
public static function SECH($angle)
{
$angle = Functions::flattenSingleValue($angle);
if (!is_numeric($angle)) {
return Functions::VALUE();
}
$result = cosh($angle);
return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
}
/**
* CSC.
*
* Returns the cosecant of an angle.
*
* @param float $angle Number
*
* @return float|string The cosecant of the angle
*/
public static function CSC($angle)
{
$angle = Functions::flattenSingleValue($angle);
if (!is_numeric($angle)) {
return Functions::VALUE();
}
$result = sin($angle);
return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
}
/**
* CSCH.
*
* Returns the hyperbolic cosecant of an angle.
*
* @param float $angle Number
*
* @return float|string The hyperbolic cosecant of the angle
*/
public static function CSCH($angle)
{
$angle = Functions::flattenSingleValue($angle);
if (!is_numeric($angle)) {
return Functions::VALUE();
}
$result = sinh($angle);
return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
}
/**
* COT.
*
* Returns the cotangent of an angle.
*
* @param float $angle Number
*
* @return float|string The cotangent of the angle
*/
public static function COT($angle)
{
$angle = Functions::flattenSingleValue($angle);
if (!is_numeric($angle)) {
return Functions::VALUE();
}
$result = tan($angle);
return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
}
/**
* COTH.
*
* Returns the hyperbolic cotangent of an angle.
*
* @param float $angle Number
*
* @return float|string The hyperbolic cotangent of the angle
*/
public static function COTH($angle)
{
$angle = Functions::flattenSingleValue($angle);
if (!is_numeric($angle)) {
return Functions::VALUE();
}
$result = tanh($angle);
return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
}
/**
* ACOT.
*
* Returns the arccotangent of a number.
*
* @param float $number Number
*
* @return float|string The arccotangent of the number
*/
public static function ACOT($number)
{
$number = Functions::flattenSingleValue($number);
if (!is_numeric($number)) {
return Functions::VALUE();
}
return (M_PI / 2) - atan($number);
}
/**
* ACOTH.
*
* Returns the hyperbolic arccotangent of a number.
*
* @param float $number Number
*
* @return float|string The hyperbolic arccotangent of the number
*/
public static function ACOTH($number)
{
$number = Functions::flattenSingleValue($number);
if (!is_numeric($number)) {
return Functions::VALUE();
}
$result = log(($number + 1) / ($number - 1)) / 2;
return is_nan($result) ? Functions::NAN() : $result;
}
}

View File

@ -577,4 +577,96 @@ class TextData
return (float) $value;
}
/**
* NUMBERVALUE.
*
* @param mixed $value Value to check
* @param string $decimalSeparator decimal separator, defaults to locale defined value
* @param string $groupSeparator group/thosands separator, defaults to locale defined value
*
* @return float|string
*/
public static function NUMBERVALUE($value = '', $decimalSeparator = null, $groupSeparator = null)
{
$value = Functions::flattenSingleValue($value);
$decimalSeparator = Functions::flattenSingleValue($decimalSeparator);
$groupSeparator = Functions::flattenSingleValue($groupSeparator);
if (!is_numeric($value)) {
$decimalSeparator = empty($decimalSeparator) ? StringHelper::getDecimalSeparator() : $decimalSeparator;
$groupSeparator = empty($groupSeparator) ? StringHelper::getThousandsSeparator() : $groupSeparator;
$decimalPositions = preg_match_all('/' . preg_quote($decimalSeparator) . '/', $value, $matches, PREG_OFFSET_CAPTURE);
if ($decimalPositions > 1) {
return Functions::VALUE();
}
$decimalOffset = array_pop($matches[0])[1];
if (strpos($value, $groupSeparator, $decimalOffset) !== false) {
return Functions::VALUE();
}
$value = str_replace([$groupSeparator, $decimalSeparator], ['', '.'], $value);
// Handle the special case of trailing % signs
$percentageString = rtrim($value, '%');
if (!is_numeric($percentageString)) {
return Functions::VALUE();
}
$percentageAdjustment = strlen($value) - strlen($percentageString);
if ($percentageAdjustment) {
$value = (float) $percentageString;
$value /= pow(10, $percentageAdjustment * 2);
}
}
return (float) $value;
}
/**
* Compares two text strings and returns TRUE if they are exactly the same, FALSE otherwise.
* EXACT is case-sensitive but ignores formatting differences.
* Use EXACT to test text being entered into a document.
*
* @param $value1
* @param $value2
*
* @return bool
*/
public static function EXACT($value1, $value2)
{
$value1 = Functions::flattenSingleValue($value1);
$value2 = Functions::flattenSingleValue($value2);
return (string) $value2 === (string) $value1;
}
/**
* TEXTJOIN.
*
* @param mixed $delimiter
* @param mixed $ignoreEmpty
* @param mixed $args
*
* @return string
*/
public static function TEXTJOIN($delimiter, $ignoreEmpty, ...$args)
{
// Loop through arguments
$aArgs = Functions::flattenArray($args);
foreach ($aArgs as $key => &$arg) {
if ($ignoreEmpty && trim($arg) == '') {
unset($aArgs[$key]);
} elseif (is_bool($arg)) {
if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
$arg = (int) $arg;
} else {
$arg = ($arg) ? Calculation::getTRUE() : Calculation::getFALSE();
}
}
}
return implode($delimiter, $aArgs);
}
}

View File

@ -3,6 +3,8 @@ ACCRINT
ACCRINTM
ACOS
ACOSH
ACOT
ACOTH
ADDRESS
AMORDEGRC
AMORLINC
@ -30,6 +32,11 @@ BIN2DEC
BIN2HEX
BIN2OCT
BINOMDIST
BITAND
BITLSHIFT
BITOR
BITRSHIFT
BITXOR
CEILING
CELL
CHAR
@ -43,12 +50,15 @@ COLUMN
COLUMNS
COMBIN
COMPLEX
CONCAT
CONCATENATE
CONFIDENCE
CONVERT
CORREL
COS
COSH
COT
COTH
COUNT
COUNTA
COUNTBLANK
@ -62,6 +72,8 @@ COUPNUM
COUPPCD
COVAR
CRITBINOM
CSC
CSCH
CUBEKPIMEMBER
CUBEMEMBER
CUBEMEMBERPROPERTY
@ -105,7 +117,9 @@ EDATE
EFFECT
EOMONTH
ERF
ERF.PRECISE
ERFC
ERFC.PRECISE
ERROR.TYPE
EVEN
EXACT
@ -149,6 +163,10 @@ IMAGINARY
IMARGUMENT
IMCONJUGATE
IMCOS
IMCOSH
IMCOT
IMCSC
IMCSCH
IMEXP
IMLN
IMLOG10
@ -156,10 +174,14 @@ IMLOG2
IMPOWER
IMPRODUCT
IMREAL
IMSEC
IMSECH
IMSIN
IMSINH
IMSQRT
IMSUB
IMSUM
IMTAN
INDEX
INDIRECT
INFO
@ -177,6 +199,7 @@ ISNA
ISNONTEXT
ISNUMBER
ISODD
ISOWEEKNUM
ISPMT
ISREF
ISTEXT
@ -229,6 +252,7 @@ NOT
NOW
NPER
NPV
NUMBERVALUE
OCT2BIN
OCT2DEC
OCT2HEX
@ -239,6 +263,7 @@ ODDLPRICE
ODDLYIELD
OFFSET
OR
PDURATION
PEARSON
PERCENTILE
PERCENTRANK
@ -275,10 +300,13 @@ ROUNDDOWN
ROUNDUP
ROW
ROWS
RRI
RSQ
RTD
SEARCH
SEARCHB
SEC
SECH
SECOND
SERIESSUM
SIGN
@ -292,6 +320,8 @@ SQRT
SQRTPI
STANDARDIZE
STDEV
STDEV.A
STDEV.P
STDEVA
STDEVP
STDEVPA
@ -315,6 +345,7 @@ TBILLPRICE
TBILLYIELD
TDIST
TEXT
TEXTJOIN
TIME
TIMEVALUE
TINV
@ -327,6 +358,8 @@ TRUE
TRUNC
TTEST
TYPE
UNICHAR
UNIORD
UPPER
USDOLLAR
VALUE
@ -342,6 +375,7 @@ WEIBULL
WORKDAY
XIRR
XNPV
XOR
YEAR
YEARFRAC
YIELD

View File

@ -327,7 +327,7 @@ abstract class Coordinate
}
/**
* Extract all cell references in range.
* Extract all cell references in range, which may be comprised of multiple cell ranges.
*
* @param string $pRange Range (e.g. A1 or A1:C10 or A1:E10 A20:E25)
*
@ -335,49 +335,12 @@ abstract class Coordinate
*/
public static function extractAllCellReferencesInRange($pRange)
{
// Returnvalue
$returnValue = [];
// Explode spaces
$cellBlocks = explode(' ', str_replace('$', '', strtoupper($pRange)));
$cellBlocks = self::getCellBlocksFromRangeString($pRange);
foreach ($cellBlocks as $cellBlock) {
// Single cell?
if (!self::coordinateIsRange($cellBlock)) {
$returnValue[] = $cellBlock;
continue;
}
// Range...
$ranges = self::splitRange($cellBlock);
foreach ($ranges as $range) {
// Single cell?
if (!isset($range[1])) {
$returnValue[] = $range[0];
continue;
}
// Range...
list($rangeStart, $rangeEnd) = $range;
sscanf($rangeStart, '%[A-Z]%d', $startCol, $startRow);
sscanf($rangeEnd, '%[A-Z]%d', $endCol, $endRow);
++$endCol;
// Current data
$currentCol = $startCol;
$currentRow = $startRow;
// Loop cells
while ($currentCol != $endCol) {
while ($currentRow <= $endRow) {
$returnValue[] = $currentCol . $currentRow;
++$currentRow;
}
++$currentCol;
$currentRow = $startRow;
}
}
$returnValue = array_merge($returnValue, self::getReferencesForCellBlock($cellBlock));
}
// Sort the result by column and row
@ -392,6 +355,60 @@ abstract class Coordinate
return array_values($sortKeys);
}
/**
* Get all cell references for an individual cell block.
*
* @param string $cellBlock A cell range e.g. A4:B5
*
* @return array All individual cells in that range
*/
private static function getReferencesForCellBlock($cellBlock)
{
$returnValue = [];
// Single cell?
if (!self::coordinateIsRange($cellBlock)) {
return (array) $cellBlock;
}
// Range...
$ranges = self::splitRange($cellBlock);
foreach ($ranges as $range) {
// Single cell?
if (!isset($range[1])) {
$returnValue[] = $range[0];
continue;
}
// Range...
list($rangeStart, $rangeEnd) = $range;
list($startColumn, $startRow) = self::coordinateFromString($rangeStart);
list($endColumn, $endRow) = self::coordinateFromString($rangeEnd);
$startColumnIndex = self::columnIndexFromString($startColumn);
$endColumnIndex = self::columnIndexFromString($endColumn);
++$endColumnIndex;
// Current data
$currentColumnIndex = $startColumnIndex;
$currentRow = $startRow;
self::validateRange($cellBlock, $startColumnIndex, $endColumnIndex, $currentRow, $endRow);
// Loop cells
while ($currentColumnIndex < $endColumnIndex) {
while ($currentRow <= $endRow) {
$returnValue[] = self::stringFromColumnIndex($currentColumnIndex) . $currentRow;
++$currentRow;
}
++$currentColumnIndex;
$currentRow = $startRow;
}
}
return $returnValue;
}
/**
* Convert an associative array of single cell coordinates to values to an associative array
* of cell ranges to values. Only adjacent cell coordinates with the same
@ -477,4 +494,33 @@ abstract class Coordinate
return $mergedCoordCollection;
}
/**
* Get the individual cell blocks from a range string, splitting by space and removing any $ characters.
*
* @param string $pRange
*
* @return string[]
*/
private static function getCellBlocksFromRangeString($pRange)
{
return explode(' ', str_replace('$', '', strtoupper($pRange)));
}
/**
* Check that the given range is valid, i.e. that the start column and row are not greater than the end column and
* row.
*
* @param string $cellBlock The original range, for displaying a meaningful error message
* @param int $startColumnIndex
* @param int $endColumnIndex
* @param int $currentRow
* @param int $endRow
*/
private static function validateRange($cellBlock, $startColumnIndex, $endColumnIndex, $currentRow, $endRow)
{
if ($startColumnIndex >= $endColumnIndex || $currentRow > $endRow) {
throw new Exception('Invalid range: "' . $cellBlock . '"');
}
}
}

View File

@ -89,6 +89,14 @@ class Hyperlink
return strpos($this->url, 'sheet://') !== false;
}
/**
* @return string
*/
public function getTypeHyperlink()
{
return $this->isInternal() ? '' : 'External';
}
/**
* Get hash code.
*

View File

@ -217,7 +217,7 @@ class DataSeries
/**
* Get Plot Order.
*
* @return string
* @return int[]
*/
public function getPlotOrder()
{

View File

@ -603,6 +603,13 @@ class Html
$this->stringData = '';
}
/**
* Parse HTML formatting and return the resulting RichText.
*
* @param string $html
*
* @return RichText
*/
public function toRichTextObject($html)
{
$this->initialise();
@ -611,8 +618,8 @@ class Html
$dom = new DOMDocument();
// Load the HTML file into the DOM object
// Note the use of error suppression, because typically this will be an html fragment, so not fully valid markup
@$dom->loadHTML($html);
$prefix = '<?xml encoding="UTF-8">';
@$dom->loadHTML($prefix . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
// Discard excess white space
$dom->preserveWhiteSpace = false;

View File

@ -4,6 +4,22 @@ namespace PhpOffice\PhpSpreadsheet\Helper;
class Migrator
{
/**
* @var string[]
*/
private $from;
/**
* @var string[]
*/
private $to;
public function __construct()
{
$this->from = array_keys($this->getMapping());
$this->to = array_values($this->getMapping());
}
/**
* Return the ordered mapping from old PHPExcel class names to new PhpSpreadsheet one.
*
@ -204,7 +220,6 @@ class Migrator
'PHPExcel_Settings' => \PhpOffice\PhpSpreadsheet\Settings::class,
'PHPExcel_Style' => \PhpOffice\PhpSpreadsheet\Style\Style::class,
'PHPExcel_Worksheet' => \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::class,
'PHPExcel' => \PhpOffice\PhpSpreadsheet\Spreadsheet::class,
];
$methods = [
@ -249,19 +264,25 @@ class Migrator
{
$patterns = [
'/*.md',
'/*.php',
'/*.phtml',
'/*.txt',
'/*.TXT',
'/*.php',
'/*.phpt',
'/*.php3',
'/*.php4',
'/*.php5',
'/*.phtml',
];
$from = array_keys($this->getMapping());
$to = array_values($this->getMapping());
foreach ($patterns as $pattern) {
foreach (glob($path . $pattern) as $file) {
if (strpos($path, '/vendor/') !== false) {
echo $file . " skipped\n";
continue;
}
$original = file_get_contents($file);
$converted = str_replace($from, $to, $original);
$converted = $this->replace($original);
if ($original !== $converted) {
echo $file . " converted\n";
@ -290,4 +311,23 @@ class Migrator
$this->recursiveReplace($path);
}
}
/**
* Migrate the given code from PHPExcel to PhpSpreadsheet.
*
* @param string $original
*
* @return string
*/
public function replace($original)
{
$converted = str_replace($this->from, $this->to, $original);
// The string "PHPExcel" gets special treatment because of how common it might be.
// This regex requires a word boundary around the string, and it can't be
// preceded by $ or -> (goal is to filter out cases where a variable is named $PHPExcel or similar)
$converted = preg_replace('~(?<!\$|->)(\b|\\\\)PHPExcel\b~', '\\' . \PhpOffice\PhpSpreadsheet\Spreadsheet::class, $converted);
return $converted;
}
}

View File

@ -50,6 +50,13 @@ class Csv extends BaseReader
*/
private $contiguousRow = -1;
/**
* The character that can escape the enclosure.
*
* @var string
*/
private $escapeCharacter = '\\';
/**
* Create a new CSV Reader instance.
*/
@ -254,7 +261,7 @@ class Csv extends BaseReader
$worksheetInfo[0]['totalColumns'] = 0;
// Loop through each line of the file in turn
while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure)) !== false) {
while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure, $this->escapeCharacter)) !== false) {
++$worksheetInfo[0]['totalRows'];
$worksheetInfo[0]['lastColumnIndex'] = max($worksheetInfo[0]['lastColumnIndex'], count($rowData) - 1);
}
@ -326,7 +333,7 @@ class Csv extends BaseReader
}
// Loop through each line of the file in turn
while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure)) !== false) {
while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure, $this->escapeCharacter)) !== false) {
$columnLetter = 'A';
foreach ($rowData as $rowDatum) {
if ($rowDatum != '' && $this->readFilter->readCell($columnLetter, $currentRow)) {
@ -458,6 +465,30 @@ class Csv extends BaseReader
return $this->contiguous;
}
/**
* Set escape backslashes.
*
* @param string $escapeCharacter
*
* @return $this
*/
public function setEscapeCharacter($escapeCharacter)
{
$this->escapeCharacter = $escapeCharacter;
return $this;
}
/**
* Get escape backslashes.
*
* @return string
*/
public function getEscapeCharacter()
{
return $this->escapeCharacter;
}
/**
* Can the current IReader read the file?
*
@ -476,6 +507,12 @@ class Csv extends BaseReader
fclose($this->fileHandle);
// Trust file extension if any
if (strtolower(pathinfo($pFilename, PATHINFO_EXTENSION)) === 'csv') {
return true;
}
// Attempt to guess mimetype
$type = mime_content_type($pFilename);
$supportedTypes = [
'text/csv',

View File

@ -554,6 +554,7 @@ class Html extends BaseReader
$row = 0;
$column = 'A';
$content = '';
$this->rowspan = [];
$this->processDomElement($dom, $spreadsheet->getActiveSheet(), $row, $column, $content);
// Return

View File

@ -7,9 +7,9 @@ interface IReadFilter
/**
* Should this cell be read?
*
* @param $column string Column address (as a string value like "A", or "IV")
* @param $row int Row number
* @param $worksheetName string Optional worksheet name
* @param string $column Column address (as a string value like "A", or "IV")
* @param int $row Row number
* @param string $worksheetName Optional worksheet name
*
* @return bool
*/

View File

@ -3,6 +3,7 @@
namespace PhpOffice\PhpSpreadsheet\Reader;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\Hyperlink;
use PhpOffice\PhpSpreadsheet\Document\Properties;
use PhpOffice\PhpSpreadsheet\NamedRange;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Chart;
@ -25,6 +26,7 @@ use PhpOffice\PhpSpreadsheet\Style\Style;
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column;
use PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooterDrawing;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use SimpleXMLElement;
use XMLReader;
use ZipArchive;
@ -115,15 +117,17 @@ class Xlsx extends BaseReader
$zip->open($pFilename);
// The files we're looking at here are small enough that simpleXML is more efficient than XMLReader
//~ http://schemas.openxmlformats.org/package/2006/relationships");
$rels = simplexml_load_string(
$this->securityScan($this->getFromZipArchive($zip, '_rels/.rels'))
); //~ http://schemas.openxmlformats.org/package/2006/relationships");
);
foreach ($rels->Relationship as $rel) {
switch ($rel['Type']) {
case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
$xmlWorkbook = simplexml_load_string(
$this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}"))
); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
);
if ($xmlWorkbook->sheets) {
foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
@ -157,8 +161,8 @@ class Xlsx extends BaseReader
$zip = new ZipArchive();
$zip->open($pFilename);
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$rels = simplexml_load_string(
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$this->securityScan($this->getFromZipArchive($zip, '_rels/.rels')),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
@ -166,8 +170,9 @@ class Xlsx extends BaseReader
foreach ($rels->Relationship as $rel) {
if ($rel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument') {
$dir = dirname($rel['Target']);
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$relsWorkbook = simplexml_load_string(
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$this->securityScan(
$this->getFromZipArchive($zip, "$dir/_rels/" . basename($rel['Target']) . '.rels')
),
@ -183,8 +188,8 @@ class Xlsx extends BaseReader
}
}
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
$xmlWorkbook = simplexml_load_string(
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
$this->securityScan(
$this->getFromZipArchive($zip, "{$rel['Target']}")
),
@ -193,7 +198,7 @@ class Xlsx extends BaseReader
);
if ($xmlWorkbook->sheets) {
$dir = dirname($rel['Target']);
/** @var \SimpleXMLElement $eleSheet */
/** @var SimpleXMLElement $eleSheet */
foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
$tmpInfo = [
'worksheetName' => (string) $eleSheet['name'],
@ -316,6 +321,60 @@ class Xlsx extends BaseReader
return $contents;
}
/**
* Set Worksheet column attributes by attributes array passed.
*
* @param Worksheet $docSheet
* @param string $column A, B, ... DX, ...
* @param array $columnAttributes array of attributes (indexes are attribute name, values are value)
* 'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'width', ... ?
*/
private function setColumnAttributes(Worksheet $docSheet, $column, array $columnAttributes)
{
if (isset($columnAttributes['xfIndex'])) {
$docSheet->getColumnDimension($column)->setXfIndex($columnAttributes['xfIndex']);
}
if (isset($columnAttributes['visible'])) {
$docSheet->getColumnDimension($column)->setVisible($columnAttributes['visible']);
}
if (isset($columnAttributes['collapsed'])) {
$docSheet->getColumnDimension($column)->setCollapsed($columnAttributes['collapsed']);
}
if (isset($columnAttributes['outlineLevel'])) {
$docSheet->getColumnDimension($column)->setOutlineLevel($columnAttributes['outlineLevel']);
}
if (isset($columnAttributes['width'])) {
$docSheet->getColumnDimension($column)->setWidth($columnAttributes['width']);
}
}
/**
* Set Worksheet row attributes by attributes array passed.
*
* @param Worksheet $docSheet
* @param int $row 1, 2, 3, ... 99, ...
* @param array $rowAttributes array of attributes (indexes are attribute name, values are value)
* 'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'rowHeight', ... ?
*/
private function setRowAttributes(Worksheet $docSheet, $row, array $rowAttributes)
{
if (isset($rowAttributes['xfIndex'])) {
$docSheet->getRowDimension($row)->setXfIndex($rowAttributes['xfIndex']);
}
if (isset($rowAttributes['visible'])) {
$docSheet->getRowDimension($row)->setVisible($rowAttributes['visible']);
}
if (isset($rowAttributes['collapsed'])) {
$docSheet->getRowDimension($row)->setCollapsed($rowAttributes['collapsed']);
}
if (isset($rowAttributes['outlineLevel'])) {
$docSheet->getRowDimension($row)->setOutlineLevel($rowAttributes['outlineLevel']);
}
if (isset($rowAttributes['rowHeight'])) {
$docSheet->getRowDimension($row)->setRowHeight($rowAttributes['rowHeight']);
}
}
/**
* Loads Spreadsheet from file.
*
@ -336,13 +395,14 @@ class Xlsx extends BaseReader
$excel->removeCellStyleXfByIndex(0); // remove the default style
$excel->removeCellXfByIndex(0); // remove the default style
}
$unparsedLoadedData = [];
$zip = new ZipArchive();
$zip->open($pFilename);
// Read the theme first, because we need the colour scheme when reading the styles
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$wbRels = simplexml_load_string(
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$this->securityScan($this->getFromZipArchive($zip, 'xl/_rels/workbook.xml.rels')),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
@ -388,8 +448,8 @@ class Xlsx extends BaseReader
}
}
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$rels = simplexml_load_string(
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$this->securityScan($this->getFromZipArchive($zip, '_rels/.rels')),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
@ -444,7 +504,7 @@ class Xlsx extends BaseReader
);
if (is_object($xmlCore)) {
$docProps = $excel->getProperties();
/** @var \SimpleXMLElement $xmlProperty */
/** @var SimpleXMLElement $xmlProperty */
foreach ($xmlCore as $xmlProperty) {
$cellDataOfficeAttributes = $xmlProperty->attributes();
if (isset($cellDataOfficeAttributes['name'])) {
@ -470,8 +530,8 @@ class Xlsx extends BaseReader
break;
case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
$dir = dirname($rel['Target']);
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$relsWorkbook = simplexml_load_string(
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$this->securityScan($this->getFromZipArchive($zip, "$dir/_rels/" . basename($rel['Target']) . '.rels')),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
@ -480,8 +540,8 @@ class Xlsx extends BaseReader
$sharedStrings = [];
$xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings']"));
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
$xmlStrings = simplexml_load_string(
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
$this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
@ -527,8 +587,8 @@ class Xlsx extends BaseReader
$styles = [];
$cellStyles = [];
$xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles']"));
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
$xmlStyles = simplexml_load_string(
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
$this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
@ -638,8 +698,8 @@ class Xlsx extends BaseReader
}
}
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
$xmlWorkbook = simplexml_load_string(
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
$this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
@ -655,6 +715,9 @@ class Xlsx extends BaseReader
}
}
// Set protection
$this->readProtection($excel, $xmlWorkbook);
$sheetId = 0; // keep track of new sheet id in final workbook
$oldSheetId = -1; // keep track of old sheet id in final workbook
$countSkippedSheets = 0; // keep track of number of skipped sheets
@ -663,7 +726,7 @@ class Xlsx extends BaseReader
$charts = $chartDetails = [];
if ($xmlWorkbook->sheets) {
/** @var \SimpleXMLElement $eleSheet */
/** @var SimpleXMLElement $eleSheet */
foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
++$oldSheetId;
@ -687,8 +750,8 @@ class Xlsx extends BaseReader
// reverse
$docSheet->setTitle((string) $eleSheet['name'], false, false);
$fileWorksheet = $worksheets[(string) self::getArrayItem($eleSheet->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
$xmlSheet = simplexml_load_string(
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
$this->securityScan($this->getFromZipArchive($zip, "$dir/$fileWorksheet")),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
@ -811,30 +874,6 @@ class Xlsx extends BaseReader
}
}
if (isset($xmlSheet->cols) && !$this->readDataOnly) {
foreach ($xmlSheet->cols->col as $col) {
for ($i = (int) ($col['min']); $i <= (int) ($col['max']); ++$i) {
if ($col['style'] && !$this->readDataOnly) {
$docSheet->getColumnDimension(Coordinate::stringFromColumnIndex($i))->setXfIndex((int) ($col['style']));
}
if (self::boolean($col['hidden'])) {
$docSheet->getColumnDimension(Coordinate::stringFromColumnIndex($i))->setVisible(false);
}
if (self::boolean($col['collapsed'])) {
$docSheet->getColumnDimension(Coordinate::stringFromColumnIndex($i))->setCollapsed(true);
}
if ($col['outlineLevel'] > 0) {
$docSheet->getColumnDimension(Coordinate::stringFromColumnIndex($i))->setOutlineLevel((int) ($col['outlineLevel']));
}
$docSheet->getColumnDimension(Coordinate::stringFromColumnIndex($i))->setWidth((float) ($col['width']));
if ((int) ($col['max']) == 16384) {
break;
}
}
}
}
if (isset($xmlSheet->printOptions) && !$this->readDataOnly) {
if (self::boolean((string) $xmlSheet->printOptions['gridLinesSet'])) {
$docSheet->setShowGridlines(true);
@ -850,25 +889,11 @@ class Xlsx extends BaseReader
}
}
$this->readColumnsAndRowsAttributes($xmlSheet, $docSheet);
if ($xmlSheet && $xmlSheet->sheetData && $xmlSheet->sheetData->row) {
$cIndex = 1; // Cell Start from 1
foreach ($xmlSheet->sheetData->row as $row) {
if ($row['ht'] && !$this->readDataOnly) {
$docSheet->getRowDimension((int) ($row['r']))->setRowHeight((float) ($row['ht']));
}
if (self::boolean($row['hidden']) && !$this->readDataOnly) {
$docSheet->getRowDimension((int) ($row['r']))->setVisible(false);
}
if (self::boolean($row['collapsed'])) {
$docSheet->getRowDimension((int) ($row['r']))->setCollapsed(true);
}
if ($row['outlineLevel'] > 0) {
$docSheet->getRowDimension((int) ($row['r']))->setOutlineLevel((int) ($row['outlineLevel']));
}
if ($row['s'] && !$this->readDataOnly) {
$docSheet->getRowDimension((int) ($row['r']))->setXfIndex((int) ($row['s']));
}
$rowIndex = 1;
foreach ($row->c as $c) {
$r = (string) $c['r'];
@ -883,7 +908,7 @@ class Xlsx extends BaseReader
if ($this->getReadFilter() !== null) {
$coordinates = Coordinate::coordinateFromString($r);
if (!$this->getReadFilter()->readCell($coordinates[0], $coordinates[1], $docSheet->getTitle())) {
if (!$this->getReadFilter()->readCell($coordinates[0], (int) $coordinates[1], $docSheet->getTitle())) {
continue;
}
}
@ -1068,8 +1093,8 @@ class Xlsx extends BaseReader
}
// Or Date Group elements
foreach ($filters->dateGroupItem as $dateGroupItem) {
// Operator is undefined, but always treated as EQUAL
$column->createRule()->setRule(
// Operator is undefined, but always treated as EQUAL
null,
[
'year' => (string) $dateGroupItem['year'],
@ -1106,8 +1131,8 @@ class Xlsx extends BaseReader
$column->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER);
// We should only ever have one dynamic filter
foreach ($filterColumn->dynamicFilter as $filterRule) {
// Operator is undefined, but always treated as EQUAL
$column->createRule()->setRule(
// Operator is undefined, but always treated as EQUAL
null,
(string) $filterRule['val'],
(string) $filterRule['type']
@ -1185,6 +1210,11 @@ class Xlsx extends BaseReader
self::boolean((string) $xmlSheet->pageSetup['useFirstPageNumber'])) {
$docPageSetup->setFirstPageNumber((int) ($xmlSheet->pageSetup['firstPageNumber']));
}
$relAttributes = $xmlSheet->pageSetup->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
if (isset($relAttributes['id'])) {
$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['pageSetupRelId'] = (string) $relAttributes['id'];
}
}
if ($xmlSheet && $xmlSheet->headerFooter && !$this->readDataOnly) {
@ -1268,13 +1298,23 @@ class Xlsx extends BaseReader
}
}
// unparsed sheet AlternateContent
if ($xmlSheet && !$this->readDataOnly) {
$mc = $xmlSheet->children('http://schemas.openxmlformats.org/markup-compatibility/2006');
if ($mc->AlternateContent) {
foreach ($mc->AlternateContent as $alternateContent) {
$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['AlternateContents'][] = $alternateContent->asXML();
}
}
}
// Add hyperlinks
$hyperlinks = [];
if (!$this->readDataOnly) {
// Locate hyperlink relations
if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$relsWorksheet = simplexml_load_string(
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$this->securityScan(
$this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
),
@ -1290,7 +1330,7 @@ class Xlsx extends BaseReader
// Loop through hyperlinks
if ($xmlSheet && $xmlSheet->hyperlinks) {
/** @var \SimpleXMLElement $hyperlink */
/** @var SimpleXMLElement $hyperlink */
foreach ($xmlSheet->hyperlinks->hyperlink as $hyperlink) {
// Link url
$linkRel = $hyperlink->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
@ -1322,8 +1362,8 @@ class Xlsx extends BaseReader
if (!$this->readDataOnly) {
// Locate comment relations
if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$relsWorksheet = simplexml_load_string(
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$this->securityScan(
$this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
),
@ -1367,6 +1407,9 @@ class Xlsx extends BaseReader
}
}
// later we will remove from it real vmlComments
$unparsedVmlDrawings = $vmlComments;
// Loop through VML comments
foreach ($vmlComments as $relName => $relPath) {
// Load VML comments file
@ -1407,7 +1450,7 @@ class Xlsx extends BaseReader
if (($column !== null) && ($row !== null)) {
// Set comment properties
$comment = $docSheet->getCommentByColumnAndRow((string) $column, $row + 1);
$comment = $docSheet->getCommentByColumnAndRow($column + 1, $row + 1);
$comment->getFillColor()->setRGB($fillColor);
// Parse style
@ -1431,16 +1474,31 @@ class Xlsx extends BaseReader
$comment->setVisible($stylePair[1] == 'visible');
}
}
unset($unparsedVmlDrawings[$relName]);
}
}
}
}
// unparsed vmlDrawing
if ($unparsedVmlDrawings) {
foreach ($unparsedVmlDrawings as $rId => $relPath) {
$rId = substr($rId, 3); // rIdXXX
$unparsedVmlDrawing = &$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['vmlDrawings'];
$unparsedVmlDrawing[$rId] = [];
$unparsedVmlDrawing[$rId]['filePath'] = self::dirAdd("$dir/$fileWorksheet", $relPath);
$unparsedVmlDrawing[$rId]['relFilePath'] = $relPath;
$unparsedVmlDrawing[$rId]['content'] = $this->securityScan($this->getFromZipArchive($zip, $unparsedVmlDrawing[$rId]['filePath']));
unset($unparsedVmlDrawing);
}
}
// Header/footer images
if ($xmlSheet && $xmlSheet->legacyDrawingHF && !$this->readDataOnly) {
if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$relsWorksheet = simplexml_load_string(
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$this->securityScan(
$this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
),
@ -1457,8 +1515,8 @@ class Xlsx extends BaseReader
if ($vmlRelationship != '') {
// Fetch linked images
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$relsVML = simplexml_load_string(
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$this->securityScan(
$this->getFromZipArchive($zip, dirname($vmlRelationship) . '/_rels/' . basename($vmlRelationship) . '.rels')
),
@ -1520,8 +1578,8 @@ class Xlsx extends BaseReader
// TODO: Autoshapes from twoCellAnchors!
if ($zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$relsWorksheet = simplexml_load_string(
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$this->securityScan(
$this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
),
@ -1537,8 +1595,8 @@ class Xlsx extends BaseReader
if ($xmlSheet->drawing && !$this->readDataOnly) {
foreach ($xmlSheet->drawing as $drawing) {
$fileDrawing = $drawings[(string) self::getArrayItem($drawing->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id')];
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$relsDrawing = simplexml_load_string(
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$this->securityScan(
$this->getFromZipArchive($zip, dirname($fileDrawing) . '/_rels/' . basename($fileDrawing) . '.rels')
),
@ -1546,9 +1604,12 @@ class Xlsx extends BaseReader
Settings::getLibXmlLoaderOptions()
);
$images = [];
$hyperlinks = [];
if ($relsDrawing && $relsDrawing->Relationship) {
foreach ($relsDrawing->Relationship as $ele) {
if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink') {
$hyperlinks[(string) $ele['Id']] = (string) $ele['Target'];
}
if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
$images[(string) $ele['Id']] = self::dirAdd($fileDrawing, $ele['Target']);
} elseif ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart') {
@ -1570,12 +1631,15 @@ class Xlsx extends BaseReader
if ($xmlDrawing->oneCellAnchor) {
foreach ($xmlDrawing->oneCellAnchor as $oneCellAnchor) {
if ($oneCellAnchor->pic->blipFill) {
/** @var \SimpleXMLElement $blip */
/** @var SimpleXMLElement $blip */
$blip = $oneCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
/** @var \SimpleXMLElement $xfrm */
/** @var SimpleXMLElement $xfrm */
$xfrm = $oneCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
/** @var \SimpleXMLElement $outerShdw */
/** @var SimpleXMLElement $outerShdw */
$outerShdw = $oneCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->effectLst->outerShdw;
/** @var \SimpleXMLElement $hlinkClick */
$hlinkClick = $oneCellAnchor->pic->nvPicPr->cNvPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->hlinkClick;
$objDrawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
$objDrawing->setName((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name'));
$objDrawing->setDescription((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'descr'));
@ -1606,6 +1670,9 @@ class Xlsx extends BaseReader
$shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), 'val'));
$shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), 'val') / 1000);
}
$this->readHyperLinkDrawing($objDrawing, $oneCellAnchor, $hyperlinks);
$objDrawing->setWorksheet($docSheet);
} else {
// ? Can charts be positioned with a oneCellAnchor ?
@ -1623,6 +1690,7 @@ class Xlsx extends BaseReader
$blip = $twoCellAnchor->pic->blipFill->children('http://schemas.openxmlformats.org/drawingml/2006/main')->blip;
$xfrm = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->xfrm;
$outerShdw = $twoCellAnchor->pic->spPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->effectLst->outerShdw;
$hlinkClick = $twoCellAnchor->pic->nvPicPr->cNvPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->hlinkClick;
$objDrawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
$objDrawing->setName((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name'));
$objDrawing->setDescription((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'descr'));
@ -1654,6 +1722,9 @@ class Xlsx extends BaseReader
$shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), 'val'));
$shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), 'val') / 1000);
}
$this->readHyperLinkDrawing($objDrawing, $twoCellAnchor, $hyperlinks);
$objDrawing->setWorksheet($docSheet);
} elseif (($this->includeCharts) && ($twoCellAnchor->graphicFrame)) {
$fromCoordinate = Coordinate::stringFromColumnIndex(((string) $twoCellAnchor->from->col) + 1) . ($twoCellAnchor->from->row + 1);
@ -1663,7 +1734,7 @@ class Xlsx extends BaseReader
$toOffsetX = Drawing::EMUToPixels($twoCellAnchor->to->colOff);
$toOffsetY = Drawing::EMUToPixels($twoCellAnchor->to->rowOff);
$graphic = $twoCellAnchor->graphicFrame->children('http://schemas.openxmlformats.org/drawingml/2006/main')->graphic;
/** @var \SimpleXMLElement $chartRef */
/** @var SimpleXMLElement $chartRef */
$chartRef = $graphic->graphicData->children('http://schemas.openxmlformats.org/drawingml/2006/chart')->chart;
$thisChart = (string) $chartRef->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
@ -1680,9 +1751,33 @@ class Xlsx extends BaseReader
}
}
}
// store original rId of drawing files
$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingOriginalIds'] = [];
foreach ($relsWorksheet->Relationship as $ele) {
if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing') {
$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingOriginalIds'][(string) $ele['Target']] = (string) $ele['Id'];
}
}
// unparsed drawing AlternateContent
$xmlAltDrawing = simplexml_load_string(
$this->securityScan($this->getFromZipArchive($zip, $fileDrawing)),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
)->children('http://schemas.openxmlformats.org/markup-compatibility/2006');
if ($xmlAltDrawing->AlternateContent) {
foreach ($xmlAltDrawing->AlternateContent as $alternateContent) {
$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['drawingAlternateContents'][] = $alternateContent->asXML();
}
}
}
}
$this->readFormControlProperties($excel, $zip, $dir, $fileWorksheet, $docSheet, $unparsedLoadedData);
$this->readPrinterSettings($excel, $zip, $dir, $fileWorksheet, $docSheet, $unparsedLoadedData);
// Loop through definedNames
if ($xmlWorkbook->definedNames) {
foreach ($xmlWorkbook->definedNames->definedName as $definedName) {
@ -1826,8 +1921,10 @@ class Xlsx extends BaseReader
}
if ((!$this->readDataOnly) || (!empty($this->loadSheetsOnly))) {
$workbookView = $xmlWorkbook->bookViews->workbookView;
// active sheet index
$activeTab = (int) ($xmlWorkbook->bookViews->workbookView['activeTab']); // refers to old sheet index
$activeTab = (int) ($workbookView['activeTab']); // refers to old sheet index
// keep active sheet index if sheet is still loaded, else first sheet is set as the active
if (isset($mapSheetId[$activeTab]) && $mapSheetId[$activeTab] !== null) {
@ -1838,6 +1935,46 @@ class Xlsx extends BaseReader
}
$excel->setActiveSheetIndex(0);
}
if (isset($workbookView['showHorizontalScroll'])) {
$showHorizontalScroll = (string) $workbookView['showHorizontalScroll'];
$excel->setShowHorizontalScroll($this->castXsdBooleanToBool($showHorizontalScroll));
}
if (isset($workbookView['showVerticalScroll'])) {
$showVerticalScroll = (string) $workbookView['showVerticalScroll'];
$excel->setShowVerticalScroll($this->castXsdBooleanToBool($showVerticalScroll));
}
if (isset($workbookView['showSheetTabs'])) {
$showSheetTabs = (string) $workbookView['showSheetTabs'];
$excel->setShowSheetTabs($this->castXsdBooleanToBool($showSheetTabs));
}
if (isset($workbookView['minimized'])) {
$minimized = (string) $workbookView['minimized'];
$excel->setMinimized($this->castXsdBooleanToBool($minimized));
}
if (isset($workbookView['autoFilterDateGrouping'])) {
$autoFilterDateGrouping = (string) $workbookView['autoFilterDateGrouping'];
$excel->setAutoFilterDateGrouping($this->castXsdBooleanToBool($autoFilterDateGrouping));
}
if (isset($workbookView['firstSheet'])) {
$firstSheet = (string) $workbookView['firstSheet'];
$excel->setFirstSheetIndex((int) $firstSheet);
}
if (isset($workbookView['visibility'])) {
$visibility = (string) $workbookView['visibility'];
$excel->setVisibility($visibility);
}
if (isset($workbookView['tabRatio'])) {
$tabRatio = (string) $workbookView['tabRatio'];
$excel->setTabRatio((int) $tabRatio);
}
}
break;
@ -1852,6 +1989,18 @@ class Xlsx extends BaseReader
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
);
// Default content types
foreach ($contentTypes->Default as $contentType) {
switch ($contentType['ContentType']) {
case 'application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings':
$unparsedLoadedData['default_content_types'][(string) $contentType['Extension']] = (string) $contentType['ContentType'];
break;
}
}
// Override content types
foreach ($contentTypes->Override as $contentType) {
switch ($contentType['ContentType']) {
case 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml':
@ -1876,10 +2025,20 @@ class Xlsx extends BaseReader
}
}
}
break;
// unparsed
case 'application/vnd.ms-excel.controlproperties+xml':
$unparsedLoadedData['override_content_types'][(string) $contentType['PartName']] = (string) $contentType['ContentType'];
break;
}
}
}
$excel->setUnparsedLoadedData($unparsedLoadedData);
$zip->close();
return $excel;
@ -1912,7 +2071,7 @@ class Xlsx extends BaseReader
/**
* @param Style $docStyle
* @param \SimpleXMLElement|\stdClass $style
* @param SimpleXMLElement|\stdClass $style
*/
private static function readStyle(Style $docStyle, $style)
{
@ -1953,7 +2112,7 @@ class Xlsx extends BaseReader
// fill
if (isset($style->fill)) {
if ($style->fill->gradientFill) {
/** @var \SimpleXMLElement $gradientFill */
/** @var SimpleXMLElement $gradientFill */
$gradientFill = $style->fill->gradientFill[0];
if (!empty($gradientFill['type'])) {
$docStyle->getFill()->setFillType((string) $gradientFill['type']);
@ -2042,7 +2201,7 @@ class Xlsx extends BaseReader
/**
* @param Border $docBorder
* @param \SimpleXMLElement $eleBorder
* @param SimpleXMLElement $eleBorder
*/
private static function readBorder(Border $docBorder, $eleBorder)
{
@ -2055,7 +2214,7 @@ class Xlsx extends BaseReader
}
/**
* @param \SimpleXMLElement | null $is
* @param SimpleXMLElement | null $is
*
* @return RichText
*/
@ -2215,4 +2374,227 @@ class Xlsx extends BaseReader
return $value === 'true' || $value === 'TRUE';
}
/**
* @param \PhpOffice\PhpSpreadsheet\Worksheet\Drawing $objDrawing
* @param \SimpleXMLElement $cellAnchor
* @param array $hyperlinks
*/
private function readHyperLinkDrawing($objDrawing, $cellAnchor, $hyperlinks)
{
$hlinkClick = $cellAnchor->pic->nvPicPr->cNvPr->children('http://schemas.openxmlformats.org/drawingml/2006/main')->hlinkClick;
if ($hlinkClick->count() === 0) {
return;
}
$hlinkId = (string) $hlinkClick->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships')['id'];
$hyperlink = new Hyperlink(
$hyperlinks[$hlinkId],
(string) self::getArrayItem($cellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name')
);
$objDrawing->setHyperlink($hyperlink);
}
private function readProtection(Spreadsheet $excel, SimpleXMLElement $xmlWorkbook)
{
if (!$xmlWorkbook->workbookProtection) {
return;
}
if ($xmlWorkbook->workbookProtection['lockRevision']) {
$excel->getSecurity()->setLockRevision((bool) $xmlWorkbook->workbookProtection['lockRevision']);
}
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']) {
$excel->getSecurity()->setRevisionsPassword((string) $xmlWorkbook->workbookProtection['revisionsPassword'], true);
}
if ($xmlWorkbook->workbookProtection['workbookPassword']) {
$excel->getSecurity()->setWorkbookPassword((string) $xmlWorkbook->workbookProtection['workbookPassword'], true);
}
}
private function readFormControlProperties(Spreadsheet $excel, ZipArchive $zip, $dir, $fileWorksheet, $docSheet, array &$unparsedLoadedData)
{
if (!$zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
return;
}
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$relsWorksheet = simplexml_load_string(
$this->securityScan(
$this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
);
$ctrlProps = [];
foreach ($relsWorksheet->Relationship as $ele) {
if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp') {
$ctrlProps[(string) $ele['Id']] = $ele;
}
}
$unparsedCtrlProps = &$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['ctrlProps'];
foreach ($ctrlProps as $rId => $ctrlProp) {
$rId = substr($rId, 3); // rIdXXX
$unparsedCtrlProps[$rId] = [];
$unparsedCtrlProps[$rId]['filePath'] = self::dirAdd("$dir/$fileWorksheet", $ctrlProp['Target']);
$unparsedCtrlProps[$rId]['relFilePath'] = (string) $ctrlProp['Target'];
$unparsedCtrlProps[$rId]['content'] = $this->securityScan($this->getFromZipArchive($zip, $unparsedCtrlProps[$rId]['filePath']));
}
unset($unparsedCtrlProps);
}
private function readPrinterSettings(Spreadsheet $excel, ZipArchive $zip, $dir, $fileWorksheet, $docSheet, array &$unparsedLoadedData)
{
if (!$zip->locateName(dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')) {
return;
}
//~ http://schemas.openxmlformats.org/package/2006/relationships"
$relsWorksheet = simplexml_load_string(
$this->securityScan(
$this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . '/_rels/' . basename($fileWorksheet) . '.rels')
),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
);
$sheetPrinterSettings = [];
foreach ($relsWorksheet->Relationship as $ele) {
if ($ele['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings') {
$sheetPrinterSettings[(string) $ele['Id']] = $ele;
}
}
$unparsedPrinterSettings = &$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['printerSettings'];
foreach ($sheetPrinterSettings as $rId => $printerSettings) {
$rId = substr($rId, 3); // rIdXXX
$unparsedPrinterSettings[$rId] = [];
$unparsedPrinterSettings[$rId]['filePath'] = self::dirAdd("$dir/$fileWorksheet", $printerSettings['Target']);
$unparsedPrinterSettings[$rId]['relFilePath'] = (string) $printerSettings['Target'];
$unparsedPrinterSettings[$rId]['content'] = $this->securityScan($this->getFromZipArchive($zip, $unparsedPrinterSettings[$rId]['filePath']));
}
unset($unparsedPrinterSettings);
}
/**
* Convert an 'xsd:boolean' XML value to a PHP boolean value.
* A valid 'xsd:boolean' XML value can be one of the following
* four values: 'true', 'false', '1', '0'. It is case sensitive.
*
* Note that just doing '(bool) $xsdBoolean' is not safe,
* since '(bool) "false"' returns true.
*
* @see https://www.w3.org/TR/xmlschema11-2/#boolean
*
* @param string $xsdBoolean An XML string value of type 'xsd:boolean'
*
* @return bool Boolean value
*/
private function castXsdBooleanToBool($xsdBoolean)
{
if ($xsdBoolean === 'false') {
return false;
}
return (bool) $xsdBoolean;
}
/**
* Read columns and rows attributes from XML and set them on the worksheet.
*
* @param SimpleXMLElement $xmlSheet
* @param Worksheet $docSheet
*/
private function readColumnsAndRowsAttributes(SimpleXMLElement $xmlSheet, Worksheet $docSheet)
{
$columnsAttributes = [];
$rowsAttributes = [];
if (isset($xmlSheet->cols) && !$this->readDataOnly) {
foreach ($xmlSheet->cols->col as $col) {
for ($i = (int) ($col['min']); $i <= (int) ($col['max']); ++$i) {
if ($col['style'] && !$this->readDataOnly) {
$columnsAttributes[Coordinate::stringFromColumnIndex($i)]['xfIndex'] = (int) $col['style'];
}
if (self::boolean($col['hidden'])) {
$columnsAttributes[Coordinate::stringFromColumnIndex($i)]['visible'] = false;
}
if (self::boolean($col['collapsed'])) {
$columnsAttributes[Coordinate::stringFromColumnIndex($i)]['collapsed'] = true;
}
if ($col['outlineLevel'] > 0) {
$columnsAttributes[Coordinate::stringFromColumnIndex($i)]['outlineLevel'] = (int) $col['outlineLevel'];
}
$columnsAttributes[Coordinate::stringFromColumnIndex($i)]['width'] = (float) $col['width'];
if ((int) ($col['max']) == 16384) {
break;
}
}
}
}
if ($xmlSheet && $xmlSheet->sheetData && $xmlSheet->sheetData->row) {
foreach ($xmlSheet->sheetData->row as $row) {
if ($row['ht'] && !$this->readDataOnly) {
$rowsAttributes[(int) $row['r']]['rowHeight'] = (float) $row['ht'];
}
if (self::boolean($row['hidden']) && !$this->readDataOnly) {
$rowsAttributes[(int) $row['r']]['visible'] = false;
}
if (self::boolean($row['collapsed'])) {
$rowsAttributes[(int) $row['r']]['collapsed'] = true;
}
if ($row['outlineLevel'] > 0) {
$rowsAttributes[(int) $row['r']]['outlineLevel'] = (int) $row['outlineLevel'];
}
if ($row['s'] && !$this->readDataOnly) {
$rowsAttributes[(int) $row['r']]['xfIndex'] = (int) $row['s'];
}
}
}
// set columns/rows attributes
$columnsAttributesSet = [];
$rowsAttributesSet = [];
foreach ($columnsAttributes as $coordColumn => $columnAttributes) {
foreach ($rowsAttributes as $coordRow => $rowAttributes) {
if ($this->getReadFilter() !== null) {
if (!$this->getReadFilter()->readCell($coordColumn, $coordRow, $docSheet->getTitle())) {
continue 2;
}
}
}
if (!isset($columnsAttributesSet[$coordColumn])) {
$this->setColumnAttributes($docSheet, $coordColumn, $columnAttributes);
$columnsAttributesSet[$coordColumn] = true;
}
}
foreach ($rowsAttributes as $coordRow => $rowAttributes) {
foreach ($columnsAttributes as $coordColumn => $columnAttributes) {
if ($this->getReadFilter() !== null) {
if (!$this->getReadFilter()->readCell($coordColumn, $coordRow, $docSheet->getTitle())) {
continue 2;
}
}
}
if (!isset($rowsAttributesSet[$coordRow])) {
$this->setRowAttributes($docSheet, $coordRow, $rowAttributes);
$rowsAttributesSet[$coordRow] = true;
}
}
}
}

View File

@ -76,7 +76,7 @@ class Xml extends BaseReader
// Read sample data (first 2 KB will do)
$data = fread($fileHandle, 2048);
fclose($fileHandle);
$data = strtr($data, "'", '"'); // fix headers with single quote
$data = str_replace("'", '"', $data); // fix headers with single quote
$valid = true;
foreach ($signature as $match) {

View File

@ -256,7 +256,7 @@ class Date
/**
* Convert a Unix timestamp to an MS Excel serialized date/time value.
*
* @param DateTimeInterface $dateValue Unix Timestamp
* @param int $dateValue Unix Timestamp
*
* @return float MS Excel serialized date/time value
*/

View File

@ -1000,7 +1000,7 @@ class Matrix
*/
public function times(...$args)
{
if (count() > 0) {
if (count($args) > 0) {
$match = implode(',', array_map('gettype', $args));
switch ($match) {
@ -1094,7 +1094,7 @@ class Matrix
*/
public function power(...$args)
{
if (count() > 0) {
if (count($args) > 0) {
$match = implode(',', array_map('gettype', $args));
switch ($match) {

View File

@ -142,7 +142,7 @@ class BestFit
*
* @param int $dp Number of places of decimal precision to display
*
* @return string
* @return float
*/
public function getSlope($dp = 0)
{
@ -158,7 +158,7 @@ class BestFit
*
* @param int $dp Number of places of decimal precision to display
*
* @return string
* @return float
*/
public function getSlopeSE($dp = 0)
{
@ -174,7 +174,7 @@ class BestFit
*
* @param int $dp Number of places of decimal precision to display
*
* @return string
* @return float
*/
public function getIntersect($dp = 0)
{
@ -190,7 +190,7 @@ class BestFit
*
* @param int $dp Number of places of decimal precision to display
*
* @return string
* @return float
*/
public function getIntersectSE($dp = 0)
{
@ -217,6 +217,13 @@ class BestFit
return $this->goodnessOfFit;
}
/**
* Return the goodness of fit for this regression.
*
* @param int $dp Number of places of decimal precision to return
*
* @return float
*/
public function getGoodnessOfFitPercent($dp = 0)
{
if ($dp != 0) {
@ -242,6 +249,11 @@ class BestFit
return $this->stdevOfResiduals;
}
/**
* @param int $dp Number of places of decimal precision to return
*
* @return float
*/
public function getSSRegression($dp = 0)
{
if ($dp != 0) {
@ -251,6 +263,11 @@ class BestFit
return $this->SSRegression;
}
/**
* @param int $dp Number of places of decimal precision to return
*
* @return float
*/
public function getSSResiduals($dp = 0)
{
if ($dp != 0) {
@ -260,6 +277,11 @@ class BestFit
return $this->SSResiduals;
}
/**
* @param int $dp Number of places of decimal precision to return
*
* @return float
*/
public function getDFResiduals($dp = 0)
{
if ($dp != 0) {
@ -269,6 +291,11 @@ class BestFit
return $this->DFResiduals;
}
/**
* @param int $dp Number of places of decimal precision to return
*
* @return float
*/
public function getF($dp = 0)
{
if ($dp != 0) {
@ -278,6 +305,11 @@ class BestFit
return $this->f;
}
/**
* @param int $dp Number of places of decimal precision to return
*
* @return float
*/
public function getCovariance($dp = 0)
{
if ($dp != 0) {
@ -287,6 +319,11 @@ class BestFit
return $this->covariance;
}
/**
* @param int $dp Number of places of decimal precision to return
*
* @return float
*/
public function getCorrelation($dp = 0)
{
if ($dp != 0) {
@ -296,6 +333,9 @@ class BestFit
return $this->correlation;
}
/**
* @return float[]
*/
public function getYBestFitValues()
{
return $this->yBestFitValues;

View File

@ -164,7 +164,7 @@ class PolynomialBestFit extends BestFit
$this->intersect = array_shift($coefficients);
$this->slope = $coefficients;
$this->calculateGoodnessOfFit($x_sum, $y_sum, $xx_sum, $yy_sum, $xy_sum);
$this->calculateGoodnessOfFit($x_sum, $y_sum, $xx_sum, $yy_sum, $xy_sum, 0, 0, 0);
foreach ($this->xValues as $xKey => $xValue) {
$this->yBestFitValues[$xKey] = $this->getValueOfYForX($xValue);
}

View File

@ -9,6 +9,17 @@ use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class Spreadsheet
{
// Allowable values for workbook window visilbity
const VISIBILITY_VISIBLE = 'visible';
const VISIBILITY_HIDDEN = 'hidden';
const VISIBILITY_VERY_HIDDEN = 'veryHidden';
private static $workbookViewVisibilityValues = [
self::VISIBILITY_VISIBLE,
self::VISIBILITY_HIDDEN,
self::VISIBILITY_VERY_HIDDEN,
];
/**
* Unique ID.
*
@ -115,6 +126,75 @@ class Spreadsheet
*/
private $ribbonBinObjects;
/**
* List of unparsed loaded data for export to same format with better compatibility.
* It has to be minimized when the library start to support currently unparsed data.
*
* @var array
*/
private $unparsedLoadedData = [];
/**
* Controls visibility of the horizonal scroll bar in the application.
*
* @var bool
*/
private $showHorizontalScroll = true;
/**
* Controls visibility of the horizonal scroll bar in the application.
*
* @var bool
*/
private $showVerticalScroll = true;
/**
* Controls visibility of the sheet tabs in the application.
*
* @var bool
*/
private $showSheetTabs = true;
/**
* Specifies a boolean value that indicates whether the workbook window
* is minimized.
*
* @var bool
*/
private $minimized = false;
/**
* Specifies a boolean value that indicates whether to group dates
* when presenting the user with filtering optiomd in the user
* interface.
*
* @var bool
*/
private $autoFilterDateGrouping = true;
/**
* Specifies the index to the first sheet in the book view.
*
* @var int
*/
private $firstSheetIndex = 0;
/**
* Specifies the visible status of the workbook.
*
* @var string
*/
private $visibility = self::VISIBILITY_VISIBLE;
/**
* Specifies the ratio between the workbook tabs bar and the horizontal
* scroll bar. TabRatio is assumed to be out of 1000 of the horizontal
* window width.
*
* @var int
*/
private $tabRatio = 600;
/**
* The workbook has macros ?
*
@ -256,6 +336,32 @@ class Spreadsheet
}
}
/**
* List of unparsed loaded data for export to same format with better compatibility.
* It has to be minimized when the library start to support currently unparsed data.
*
* @internal
*
* @return array
*/
public function getUnparsedLoadedData()
{
return $this->unparsedLoadedData;
}
/**
* List of unparsed loaded data for export to same format with better compatibility.
* It has to be minimized when the library start to support currently unparsed data.
*
* @internal
*
* @param array $unparsedLoadedData
*/
public function setUnparsedLoadedData(array $unparsedLoadedData)
{
$this->unparsedLoadedData = $unparsedLoadedData;
}
/**
* return the extension of a filename. Internal use for a array_map callback (php<5.3 don't like lambda function).
*
@ -1182,4 +1288,203 @@ class Spreadsheet
{
return $this->uniqueID;
}
/**
* Get the visibility of the horizonal scroll bar in the application.
*
* @return bool True if horizonal scroll bar is visible
*/
public function getShowHorizontalScroll()
{
return $this->showHorizontalScroll;
}
/**
* Set the visibility of the horizonal scroll bar in the application.
*
* @param bool $showHorizontalScroll True if horizonal scroll bar is visible
*/
public function setShowHorizontalScroll($showHorizontalScroll)
{
$this->showHorizontalScroll = (bool) $showHorizontalScroll;
}
/**
* Get the visibility of the vertical scroll bar in the application.
*
* @return bool True if vertical scroll bar is visible
*/
public function getShowVerticalScroll()
{
return $this->showVerticalScroll;
}
/**
* Set the visibility of the vertical scroll bar in the application.
*
* @param bool $showVerticalScroll True if vertical scroll bar is visible
*/
public function setShowVerticalScroll($showVerticalScroll)
{
$this->showVerticalScroll = (bool) $showVerticalScroll;
}
/**
* Get the visibility of the sheet tabs in the application.
*
* @return bool True if the sheet tabs are visible
*/
public function getShowSheetTabs()
{
return $this->showSheetTabs;
}
/**
* Set the visibility of the sheet tabs in the application.
*
* @param bool $showSheetTabs True if sheet tabs are visible
*/
public function setShowSheetTabs($showSheetTabs)
{
$this->showSheetTabs = (bool) $showSheetTabs;
}
/**
* Return whether the workbook window is minimized.
*
* @return bool true if workbook window is minimized
*/
public function getMinimized()
{
return $this->minimized;
}
/**
* Set whether the workbook window is minimized.
*
* @param bool $minimized true if workbook window is minimized
*/
public function setMinimized($minimized)
{
$this->minimized = (bool) $minimized;
}
/**
* Return whether to group dates when presenting the user with
* filtering optiomd in the user interface.
*
* @return bool true if workbook window is minimized
*/
public function getAutoFilterDateGrouping()
{
return $this->autoFilterDateGrouping;
}
/**
* Set whether to group dates when presenting the user with
* filtering optiomd in the user interface.
*
* @param bool $autoFilterDateGrouping true if workbook window is minimized
*/
public function setAutoFilterDateGrouping($autoFilterDateGrouping)
{
$this->autoFilterDateGrouping = (bool) $autoFilterDateGrouping;
}
/**
* Return the first sheet in the book view.
*
* @return int First sheet in book view
*/
public function getFirstSheetIndex()
{
return $this->firstSheetIndex;
}
/**
* Set the first sheet in the book view.
*
* @param int $firstSheetIndex First sheet in book view
*
* @throws Exception if the given value is invalid
*/
public function setFirstSheetIndex($firstSheetIndex)
{
if ($firstSheetIndex >= 0) {
$this->firstSheetIndex = (int) $firstSheetIndex;
} else {
throw new Exception('First sheet index must be a positive integer.');
}
}
/**
* Return the visibility status of the workbook.
*
* This may be one of the following three values:
* - visibile
*
* @return string Visible status
*/
public function getVisibility()
{
return $this->visibility;
}
/**
* Set the visibility status of the workbook.
*
* Valid values are:
* - 'visible' (self::VISIBILITY_VISIBLE):
* Workbook window is visible
* - 'hidden' (self::VISIBILITY_HIDDEN):
* Workbook window is hidden, but can be shown by the user
* via the user interface
* - 'veryHidden' (self::VISIBILITY_VERY_HIDDEN):
* Workbook window is hidden and cannot be shown in the
* user interface.
*
* @param string $visibility visibility status of the workbook
*
* @throws Exception if the given value is invalid
*/
public function setVisibility($visibility)
{
if ($visibility === null) {
$visibility = self::VISIBILITY_VISIBLE;
}
if (in_array($visibility, self::$workbookViewVisibilityValues)) {
$this->visibility = $visibility;
} else {
throw new Exception('Invalid visibility value.');
}
}
/**
* Get the ratio between the workbook tabs bar and the horizontal scroll bar.
* TabRatio is assumed to be out of 1000 of the horizontal window width.
*
* @return int Ratio between the workbook tabs bar and the horizontal scroll bar
*/
public function getTabRatio()
{
return $this->tabRatio;
}
/**
* Set the ratio between the workbook tabs bar and the horizontal scroll bar
* TabRatio is assumed to be out of 1000 of the horizontal window width.
*
* @param int $tabRatio Ratio between the tabs bar and the horizontal scroll bar
*
* @throws Exception if the given value is invalid
*/
public function setTabRatio($tabRatio)
{
if ($tabRatio >= 0 || $tabRatio <= 1000) {
$this->tabRatio = (int) $tabRatio;
} else {
throw new Exception('Tab ratio must be between 0 and 1000.');
}
}
}

View File

@ -589,7 +589,7 @@ class NumberFormat extends Supervisor
}
// Convert any other escaped characters to quoted strings, e.g. (\T to "T")
$format = preg_replace('/(\\\(.))(?=(?:[^"]|"[^"]*")*$)/u', '"${2}"', $format);
$format = preg_replace('/(\\\([^ ]))(?=(?:[^"]|"[^"]*")*$)/u', '"${2}"', $format);
// Get the sections, there can be up to four sections, separated with a semi-colon (but only if not a quoted literal)
$sections = preg_split('/(;)(?=(?:[^"]|"[^"]*")*$)/u', $format);

View File

@ -333,6 +333,9 @@ class Style extends Supervisor
}
}
// restore initial cell selection range
$this->getActiveSheet()->getStyle($pRange);
return $this;
}

View File

@ -841,7 +841,7 @@ class AutoFilter
$vars = get_object_vars($this);
foreach ($vars as $key => $value) {
if (is_object($value)) {
if ($key == 'workSheet') {
if ($key === 'workSheet') {
// Detach from worksheet
$this->{$key} = null;
} else {

View File

@ -2,6 +2,7 @@
namespace PhpOffice\PhpSpreadsheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Cell\Hyperlink;
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
use PhpOffice\PhpSpreadsheet\IComparable;
@ -98,6 +99,13 @@ class BaseDrawing implements IComparable
*/
protected $shadow;
/**
* Image hyperlink.
*
* @var null|Hyperlink
*/
private $hyperlink;
/**
* Create a new BaseDrawing.
*/
@ -501,11 +509,29 @@ class BaseDrawing implements IComparable
{
$vars = get_object_vars($this);
foreach ($vars as $key => $value) {
if (is_object($value)) {
if ($key == 'worksheet') {
$this->worksheet = null;
} elseif (is_object($value)) {
$this->$key = clone $value;
} else {
$this->$key = $value;
}
}
}
/**
* @param null|Hyperlink $pHyperlink
*/
public function setHyperlink(Hyperlink $pHyperlink = null)
{
$this->hyperlink = $pHyperlink;
}
/**
* @return null|Hyperlink
*/
public function getHyperlink()
{
return $this->hyperlink;
}
}

View File

@ -37,6 +37,13 @@ class Worksheet implements IComparable
const SHEETSTATE_HIDDEN = 'hidden';
const SHEETSTATE_VERYHIDDEN = 'veryHidden';
/**
* Maximum 31 characters allowed for sheet title.
*
* @var int
*/
const SHEET_TITLE_MAXIMUM_LENGTH = 31;
/**
* Invalid characters in sheet title.
*
@ -434,9 +441,9 @@ class Worksheet implements IComparable
throw new Exception('Invalid character found in sheet code name');
}
// Maximum 31 characters allowed for sheet title
if ($CharCount > 31) {
throw new Exception('Maximum 31 characters allowed in sheet code name.');
// Enforce maximum characters allowed for sheet title
if ($CharCount > self::SHEET_TITLE_MAXIMUM_LENGTH) {
throw new Exception('Maximum ' . self::SHEET_TITLE_MAXIMUM_LENGTH . ' characters allowed in sheet code name.');
}
return $pValue;
@ -458,9 +465,9 @@ class Worksheet implements IComparable
throw new Exception('Invalid character found in sheet title');
}
// Maximum 31 characters allowed for sheet title
if (Shared\StringHelper::countCharacters($pValue) > 31) {
throw new Exception('Maximum 31 characters allowed in sheet title.');
// Enforce maximum characters allowed for sheet title
if (Shared\StringHelper::countCharacters($pValue) > self::SHEET_TITLE_MAXIMUM_LENGTH) {
throw new Exception('Maximum ' . self::SHEET_TITLE_MAXIMUM_LENGTH . ' characters allowed in sheet title.');
}
return $pValue;
@ -2956,13 +2963,14 @@ class Worksheet implements IComparable
$newCollection = $this->cellCollection->cloneCellCollection($this);
$this->cellCollection = $newCollection;
} elseif ($key == 'drawingCollection') {
$newCollection = new ArrayObject();
foreach ($this->drawingCollection as $id => $item) {
$currentCollection = $this->drawingCollection;
$this->drawingCollection = new ArrayObject();
foreach ($currentCollection as $item) {
if (is_object($item)) {
$newCollection[$id] = clone $this->drawingCollection[$id];
$newDrawing = clone $item;
$newDrawing->setWorksheet($this);
}
}
$this->drawingCollection = $newCollection;
} elseif (($key == 'autoFilter') && ($this->autoFilter instanceof AutoFilter)) {
$newAutoFilter = clone $this->autoFilter;
$this->autoFilter = $newAutoFilter;

View File

@ -827,7 +827,7 @@ class Worksheet extends BIFFwriter
$formula = substr($formula, 1);
} else {
// Error handling
$this->writeString($row, $col, 'Unrecognised character for formula');
$this->writeString($row, $col, 'Unrecognised character for formula', 0);
return -1;
}

View File

@ -137,9 +137,9 @@ class Xlsx extends BaseWriter
}
$hashTablesArray = ['stylesConditionalHashTable', 'fillHashTable', 'fontHashTable',
'bordersHashTable', 'numFmtHashTable', 'drawingHashTable',
'styleHashTable',
];
'bordersHashTable', 'numFmtHashTable', 'drawingHashTable',
'styleHashTable',
];
// Set HashTable variables
foreach ($hashTablesArray as $tableName) {
@ -290,12 +290,26 @@ class Xlsx extends BaseWriter
}
}
$chartRef1 = $chartRef2 = 0;
$chartRef1 = 0;
// Add worksheet relationships (drawings, ...)
for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) {
// Add relationships
$zip->addFromString('xl/worksheets/_rels/sheet' . ($i + 1) . '.xml.rels', $this->getWriterPart('Rels')->writeWorksheetRelationships($this->spreadSheet->getSheet($i), ($i + 1), $this->includeCharts));
// Add unparsedLoadedData
$sheetCodeName = $this->spreadSheet->getSheet($i)->getCodeName();
$unparsedLoadedData = $this->spreadSheet->getUnparsedLoadedData();
if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'])) {
foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'] as $ctrlProp) {
$zip->addFromString($ctrlProp['filePath'], $ctrlProp['content']);
}
}
if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'])) {
foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'] as $ctrlProp) {
$zip->addFromString($ctrlProp['filePath'], $ctrlProp['content']);
}
}
$drawings = $this->spreadSheet->getSheet($i)->getDrawingCollection();
$drawingCount = count($drawings);
if ($this->includeCharts) {
@ -307,6 +321,9 @@ class Xlsx extends BaseWriter
// Drawing relationships
$zip->addFromString('xl/drawings/_rels/drawing' . ($i + 1) . '.xml.rels', $this->getWriterPart('Rels')->writeDrawingRelationships($this->spreadSheet->getSheet($i), $chartRef1, $this->includeCharts));
// Drawings
$zip->addFromString('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts));
} elseif (isset($unparsedLoadedData['sheets'][$sheetCodeName]['drawingAlternateContents'])) {
// Drawings
$zip->addFromString('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts));
}
@ -320,6 +337,13 @@ class Xlsx extends BaseWriter
$zip->addFromString('xl/comments' . ($i + 1) . '.xml', $this->getWriterPart('Comments')->writeComments($this->spreadSheet->getSheet($i)));
}
// Add unparsed relationship parts
if (isset($unparsedLoadedData['sheets'][$this->spreadSheet->getSheet($i)->getCodeName()]['vmlDrawings'])) {
foreach ($unparsedLoadedData['sheets'][$this->spreadSheet->getSheet($i)->getCodeName()]['vmlDrawings'] as $vmlDrawing) {
$zip->addFromString($vmlDrawing['filePath'], $vmlDrawing['content']);
}
}
// Add header/footer relationship parts
if (count($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages()) > 0) {
// VML Drawings

View File

@ -57,7 +57,8 @@ class ContentTypes extends WriterPart
// Yes : not standard content but "macroEnabled"
$this->writeOverrideContentType($objWriter, '/xl/workbook.xml', 'application/vnd.ms-excel.sheet.macroEnabled.main+xml');
//... and define a new type for the VBA project
$this->writeDefaultContentType($objWriter, 'bin', 'application/vnd.ms-office.vbaProject');
// Better use Override, because we can use 'bin' also for xl\printerSettings\printerSettings1.bin
$this->writeOverrideContentType($objWriter, '/xl/vbaProject.bin', 'application/vnd.ms-office.vbaProject');
if ($spreadsheet->hasMacrosCertificate()) {
// signed macros ?
// Yes : add needed information
@ -88,14 +89,16 @@ class ContentTypes extends WriterPart
$this->writeOverrideContentType($objWriter, '/xl/sharedStrings.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml');
// Add worksheet relationship content types
$unparsedLoadedData = $spreadsheet->getUnparsedLoadedData();
$chart = 1;
for ($i = 0; $i < $sheetCount; ++$i) {
$drawings = $spreadsheet->getSheet($i)->getDrawingCollection();
$drawingCount = count($drawings);
$chartCount = ($includeCharts) ? $spreadsheet->getSheet($i)->getChartCount() : 0;
$hasUnparsedDrawing = isset($unparsedLoadedData['sheets'][$spreadsheet->getSheet($i)->getCodeName()]['drawingOriginalIds']);
// We need a drawing relationship for the worksheet if we have either drawings or charts
if (($drawingCount > 0) || ($chartCount > 0)) {
if (($drawingCount > 0) || ($chartCount > 0) || $hasUnparsedDrawing) {
$this->writeOverrideContentType($objWriter, '/xl/drawings/drawing' . ($i + 1) . '.xml', 'application/vnd.openxmlformats-officedocument.drawing+xml');
}
@ -160,6 +163,20 @@ class ContentTypes extends WriterPart
}
}
// unparsed defaults
if (isset($unparsedLoadedData['default_content_types'])) {
foreach ($unparsedLoadedData['default_content_types'] as $extName => $contentType) {
$this->writeDefaultContentType($objWriter, $extName, $contentType);
}
}
// unparsed overrides
if (isset($unparsedLoadedData['override_content_types'])) {
foreach ($unparsedLoadedData['override_content_types'] as $partName => $overrideType) {
$this->writeOverrideContentType($objWriter, $partName, $overrideType);
}
}
$objWriter->endElement();
// Return

View File

@ -43,7 +43,12 @@ class Drawing extends WriterPart
$i = 1;
$iterator = $pWorksheet->getDrawingCollection()->getIterator();
while ($iterator->valid()) {
$this->writeDrawing($objWriter, $iterator->current(), $i);
/** @var BaseDrawing $pDrawing */
$pDrawing = $iterator->current();
$pRelationId = $i;
$hlinkClickId = $pDrawing->getHyperlink() === null ? null : ++$i;
$this->writeDrawing($objWriter, $pDrawing, $pRelationId, $hlinkClickId);
$iterator->next();
++$i;
@ -59,6 +64,14 @@ class Drawing extends WriterPart
}
}
// unparsed AlternateContent
$unparsedLoadedData = $pWorksheet->getParent()->getUnparsedLoadedData();
if (isset($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()]['drawingAlternateContents'])) {
foreach ($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()]['drawingAlternateContents'] as $drawingAlternateContent) {
$objWriter->writeRaw($drawingAlternateContent);
}
}
$objWriter->endElement();
// Return
@ -142,10 +155,11 @@ class Drawing extends WriterPart
* @param XMLWriter $objWriter XML Writer
* @param BaseDrawing $pDrawing
* @param int $pRelationId
* @param null|int $hlinkClickId
*
* @throws WriterException
*/
public function writeDrawing(XMLWriter $objWriter, BaseDrawing $pDrawing, $pRelationId = -1)
public function writeDrawing(XMLWriter $objWriter, BaseDrawing $pDrawing, $pRelationId = -1, $hlinkClickId = null)
{
if ($pRelationId >= 0) {
// xdr:oneCellAnchor
@ -179,6 +193,10 @@ class Drawing extends WriterPart
$objWriter->writeAttribute('id', $pRelationId);
$objWriter->writeAttribute('name', $pDrawing->getName());
$objWriter->writeAttribute('descr', $pDrawing->getDescription());
//a:hlinkClick
$this->writeHyperLinkDrawing($objWriter, $hlinkClickId);
$objWriter->endElement();
// xdr:cNvPicPr
@ -482,4 +500,20 @@ class Drawing extends WriterPart
return $aDrawings;
}
/**
* @param XMLWriter $objWriter
* @param null|int $hlinkClickId
*/
private function writeHyperLinkDrawing(XMLWriter $objWriter, $hlinkClickId)
{
if ($hlinkClickId === null) {
return;
}
$objWriter->startElement('a:hlinkClick');
$objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
$objWriter->writeAttribute('r:id', 'rId' . $hlinkClickId);
$objWriter->endElement();
}
}

View File

@ -195,18 +195,31 @@ class Rels extends WriterPart
// Write drawing relationships?
$d = 0;
$drawingOriginalIds = [];
$unparsedLoadedData = $pWorksheet->getParent()->getUnparsedLoadedData();
if (isset($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()]['drawingOriginalIds'])) {
$drawingOriginalIds = $unparsedLoadedData['sheets'][$pWorksheet->getCodeName()]['drawingOriginalIds'];
}
if ($includeCharts) {
$charts = $pWorksheet->getChartCollection();
} else {
$charts = [];
}
if (($pWorksheet->getDrawingCollection()->count() > 0) ||
(count($charts) > 0)) {
if (($pWorksheet->getDrawingCollection()->count() > 0) || (count($charts) > 0) || $drawingOriginalIds) {
$relPath = '../drawings/drawing' . $pWorksheetId . '.xml';
$rId = ++$d;
if (isset($drawingOriginalIds[$relPath])) {
$rId = (int) (substr($drawingOriginalIds[$relPath], 3));
}
$this->writeRelationship(
$objWriter,
++$d,
$rId,
'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing',
'../drawings/drawing' . $pWorksheetId . '.xml'
$relPath
);
}
@ -255,11 +268,32 @@ class Rels extends WriterPart
);
}
$this->writeUnparsedRelationship($pWorksheet, $objWriter, 'ctrlProps', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp');
$this->writeUnparsedRelationship($pWorksheet, $objWriter, 'vmlDrawings', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing');
$this->writeUnparsedRelationship($pWorksheet, $objWriter, 'printerSettings', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings');
$objWriter->endElement();
return $objWriter->getData();
}
private function writeUnparsedRelationship(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet, XMLWriter $objWriter, $relationship, $type)
{
$unparsedLoadedData = $pWorksheet->getParent()->getUnparsedLoadedData();
if (!isset($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()][$relationship])) {
return;
}
foreach ($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()][$relationship] as $rId => $value) {
$this->writeRelationship(
$objWriter,
$rId,
$type,
$value['relFilePath']
);
}
}
/**
* Write drawing relationships to XML format.
*
@ -295,12 +329,16 @@ class Rels extends WriterPart
if ($iterator->current() instanceof \PhpOffice\PhpSpreadsheet\Worksheet\Drawing
|| $iterator->current() instanceof MemoryDrawing) {
// Write relationship for image drawing
/** @var \PhpOffice\PhpSpreadsheet\Worksheet\Drawing $drawing */
$drawing = $iterator->current();
$this->writeRelationship(
$objWriter,
$i,
'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
'../media/' . str_replace(' ', '', $iterator->current()->getIndexedFilename())
'../media/' . str_replace(' ', '', $drawing->getIndexedFilename())
);
$i = $this->writeDrawingHyperLink($objWriter, $drawing, $i);
}
$iterator->next();
@ -398,4 +436,31 @@ class Rels extends WriterPart
throw new WriterException('Invalid parameters passed.');
}
}
/**
* @param $objWriter
* @param \PhpOffice\PhpSpreadsheet\Worksheet\Drawing $drawing
* @param $i
*
* @throws WriterException
*
* @return int
*/
private function writeDrawingHyperLink($objWriter, $drawing, $i)
{
if ($drawing->getHyperlink() === null) {
return $i;
}
++$i;
$this->writeRelationship(
$objWriter,
$i,
'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink',
$drawing->getHyperlink()->getUrl(),
$drawing->getHyperlink()->getTypeHyperlink()
);
return $i;
}
}

View File

@ -117,14 +117,14 @@ class Workbook extends WriterPart
$objWriter->startElement('workbookView');
$objWriter->writeAttribute('activeTab', $spreadsheet->getActiveSheetIndex());
$objWriter->writeAttribute('autoFilterDateGrouping', '1');
$objWriter->writeAttribute('firstSheet', '0');
$objWriter->writeAttribute('minimized', '0');
$objWriter->writeAttribute('showHorizontalScroll', '1');
$objWriter->writeAttribute('showSheetTabs', '1');
$objWriter->writeAttribute('showVerticalScroll', '1');
$objWriter->writeAttribute('tabRatio', '600');
$objWriter->writeAttribute('visibility', 'visible');
$objWriter->writeAttribute('autoFilterDateGrouping', ($spreadsheet->getAutoFilterDateGrouping() ? 'true' : 'false'));
$objWriter->writeAttribute('firstSheet', $spreadsheet->getFirstSheetIndex());
$objWriter->writeAttribute('minimized', ($spreadsheet->getMinimized() ? 'true' : 'false'));
$objWriter->writeAttribute('showHorizontalScroll', ($spreadsheet->getShowHorizontalScroll() ? 'true' : 'false'));
$objWriter->writeAttribute('showSheetTabs', ($spreadsheet->getShowSheetTabs() ? 'true' : 'false'));
$objWriter->writeAttribute('showVerticalScroll', ($spreadsheet->getShowVerticalScroll() ? 'true' : 'false'));
$objWriter->writeAttribute('tabRatio', $spreadsheet->getTabRatio());
$objWriter->writeAttribute('visibility', $spreadsheet->getVisibility());
$objWriter->endElement();
@ -175,6 +175,7 @@ class Workbook extends WriterPart
// fullCalcOnLoad isn't needed if we've recalculating for the save
$objWriter->writeAttribute('calcCompleted', ($recalcRequired) ? 1 : 0);
$objWriter->writeAttribute('fullCalcOnLoad', ($recalcRequired) ? 0 : 1);
$objWriter->writeAttribute('forceFullCalc', ($recalcRequired) ? 0 : 1);
$objWriter->endElement();
}

View File

@ -51,6 +51,12 @@ class Worksheet extends WriterPart
$objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
$objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
$objWriter->writeAttribute('xmlns:xdr', 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
$objWriter->writeAttribute('xmlns:x14', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/main');
$objWriter->writeAttribute('xmlns:mc', 'http://schemas.openxmlformats.org/markup-compatibility/2006');
$objWriter->writeAttribute('mc:Ignorable', 'x14ac');
$objWriter->writeAttribute('xmlns:x14ac', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac');
// sheetPr
$this->writeSheetPr($objWriter, $pSheet);
@ -114,6 +120,9 @@ class Worksheet extends WriterPart
// LegacyDrawingHF
$this->writeLegacyDrawingHF($objWriter, $pSheet);
// AlternateContent
$this->writeAlternateContent($objWriter, $pSheet);
$objWriter->endElement();
// Return
@ -237,6 +246,7 @@ class Worksheet extends WriterPart
}
$activeCell = $pSheet->getActiveCell();
$sqref = $pSheet->getSelectedCells();
// Pane
$pane = '';
@ -248,6 +258,7 @@ class Worksheet extends WriterPart
$topLeftCell = $pSheet->getTopLeftCell();
$activeCell = $topLeftCell;
$sqref = $topLeftCell;
// pane
$pane = 'topRight';
@ -283,7 +294,7 @@ class Worksheet extends WriterPart
$objWriter->writeAttribute('pane', $pane);
}
$objWriter->writeAttribute('activeCell', $activeCell);
$objWriter->writeAttribute('sqref', $activeCell);
$objWriter->writeAttribute('sqref', $sqref);
$objWriter->endElement();
$objWriter->endElement();
@ -843,6 +854,11 @@ class Worksheet extends WriterPart
$objWriter->writeAttribute('useFirstPageNumber', '1');
}
$getUnparsedLoadedData = $pSheet->getParent()->getUnparsedLoadedData();
if (isset($getUnparsedLoadedData['sheets'][$pSheet->getCodeName()]['pageSetupRelId'])) {
$objWriter->writeAttribute('r:id', $getUnparsedLoadedData['sheets'][$pSheet->getCodeName()]['pageSetupRelId']);
}
$objWriter->endElement();
}
@ -1142,16 +1158,27 @@ class Worksheet extends WriterPart
* @param PhpspreadsheetWorksheet $pSheet Worksheet
* @param bool $includeCharts Flag indicating if we should include drawing details for charts
*/
private function writeDrawings(XMLWriter $objWriter = null, PhpspreadsheetWorksheet $pSheet = null, $includeCharts = false)
private function writeDrawings(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet, $includeCharts = false)
{
$unparsedLoadedData = $pSheet->getParent()->getUnparsedLoadedData();
$hasUnparsedDrawing = isset($unparsedLoadedData['sheets'][$pSheet->getCodeName()]['drawingOriginalIds']);
$chartCount = ($includeCharts) ? $pSheet->getChartCollection()->count() : 0;
// If sheet contains drawings, add the relationships
if (($pSheet->getDrawingCollection()->count() > 0) ||
($chartCount > 0)) {
$objWriter->startElement('drawing');
$objWriter->writeAttribute('r:id', 'rId1');
$objWriter->endElement();
if ($chartCount == 0 && $pSheet->getDrawingCollection()->count() == 0 && !$hasUnparsedDrawing) {
return;
}
// If sheet contains drawings, add the relationships
$objWriter->startElement('drawing');
$rId = 'rId1';
if (isset($unparsedLoadedData['sheets'][$pSheet->getCodeName()]['drawingOriginalIds'])) {
$drawingOriginalIds = $unparsedLoadedData['sheets'][$pSheet->getCodeName()]['drawingOriginalIds'];
// take first. In future can be overriten
$rId = reset($drawingOriginalIds);
}
$objWriter->writeAttribute('r:id', $rId);
$objWriter->endElement();
}
/**
@ -1185,4 +1212,15 @@ class Worksheet extends WriterPart
$objWriter->endElement();
}
}
private function writeAlternateContent(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
{
if (empty($pSheet->getParent()->getUnparsedLoadedData()['sheets'][$pSheet->getCodeName()]['AlternateContents'])) {
return;
}
foreach ($pSheet->getParent()->getUnparsedLoadedData()['sheets'][$pSheet->getCodeName()]['AlternateContents'] as $alternateContent) {
$objWriter->writeRaw($alternateContent);
}
}
}

View File

@ -0,0 +1,120 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PHPUnit\Framework\TestCase;
class CalculationTest extends TestCase
{
public function setUp()
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
public function tearDown()
{
$calculation = Calculation::getInstance();
$calculation->setLocale('en_us');
}
/**
* @dataProvider providerBinaryComparisonOperation
*
* @param mixed $formula
* @param mixed $expectedResultExcel
* @param mixed $expectedResultOpenOffice
*/
public function testBinaryComparisonOperation($formula, $expectedResultExcel, $expectedResultOpenOffice)
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
$resultExcel = Calculation::getInstance()->_calculateFormulaValue($formula);
self::assertEquals($expectedResultExcel, $resultExcel, 'should be Excel compatible');
Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE);
$resultOpenOffice = Calculation::getInstance()->_calculateFormulaValue($formula);
self::assertEquals($expectedResultOpenOffice, $resultOpenOffice, 'should be OpenOffice compatible');
}
public function providerBinaryComparisonOperation()
{
return require 'data/CalculationBinaryComparisonOperation.php';
}
/**
* @dataProvider providerGetFunctions
*
* @param string $category
* @param array|string $functionCall
* @param string $argumentCount
*/
public function testGetFunctions($category, $functionCall, $argumentCount)
{
self::assertInternalType('callable', $functionCall);
}
public function providerGetFunctions()
{
return Calculation::getInstance()->getFunctions();
}
public function testIsImplemented()
{
$calculation = Calculation::getInstance();
self::assertFalse($calculation->isImplemented('non-existing-function'));
self::assertFalse($calculation->isImplemented('AREAS'));
self::assertTrue($calculation->isImplemented('coUNt'));
self::assertTrue($calculation->isImplemented('abs'));
}
/**
* @dataProvider providerCanLoadAllSupportedLocales
*
* @param string $locale
*/
public function testCanLoadAllSupportedLocales($locale)
{
$calculation = Calculation::getInstance();
self::assertTrue($calculation->setLocale($locale));
}
public function providerCanLoadAllSupportedLocales()
{
return [
['bg'],
['cs'],
['da'],
['de'],
['en_us'],
['es'],
['fi'],
['fr'],
['hu'],
['it'],
['nl'],
['no'],
['pl'],
['pt'],
['pt_br'],
['ru'],
['sv'],
['tr'],
];
}
public function testDoesHandleXlfnFunctions()
{
$calculation = Calculation::getInstance();
$tree = $calculation->parseFormula('=_xlfn.ISFORMULA(A1)');
self::assertCount(3, $tree);
$function = $tree[2];
self::assertEquals('Function', $function['type']);
$tree = $calculation->parseFormula('=_xlfn.STDEV.S(A1:B2)');
self::assertCount(5, $tree);
$function = $tree[4];
self::assertEquals('Function', $function['type']);
}
}

View File

@ -0,0 +1,487 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
/**
* Class DateTimeTest.
*/
class DateTimeTest extends TestCase
{
public function setUp()
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerDATE
*
* @param mixed $expectedResult
*/
public function testDATE($expectedResult, ...$args)
{
$result = DateTime::DATE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerDATE()
{
return require 'data/Calculation/DateTime/DATE.php';
}
public function testDATEtoPHP()
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_NUMERIC);
$result = DateTime::DATE(2012, 1, 31);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
self::assertEquals(1327968000, $result, null, 1E-8);
}
public function testDATEtoPHPObject()
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_OBJECT);
$result = DateTime::DATE(2012, 1, 31);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
// Must return an object...
self::assertInternalType('object', $result);
// ... of the correct type
self::assertTrue(is_a($result, 'DateTime'));
// ... with the correct value
self::assertEquals($result->format('d-M-Y'), '31-Jan-2012');
}
public function testDATEwith1904Calendar()
{
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
$result = DateTime::DATE(1918, 11, 11);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
self::assertEquals($result, 5428);
}
public function testDATEwith1904CalendarError()
{
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
$result = DateTime::DATE(1901, 1, 31);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
self::assertEquals($result, '#NUM!');
}
/**
* @dataProvider providerDATEVALUE
*
* @param mixed $expectedResult
*/
public function testDATEVALUE($expectedResult, ...$args)
{
$result = DateTime::DATEVALUE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerDATEVALUE()
{
return require 'data/Calculation/DateTime/DATEVALUE.php';
}
public function testDATEVALUEtoPHP()
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_NUMERIC);
$result = DateTime::DATEVALUE('2012-1-31');
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
self::assertEquals(1327968000, $result, null, 1E-8);
}
public function testDATEVALUEtoPHPObject()
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_OBJECT);
$result = DateTime::DATEVALUE('2012-1-31');
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
// Must return an object...
self::assertInternalType('object', $result);
// ... of the correct type
self::assertTrue(is_a($result, 'DateTime'));
// ... with the correct value
self::assertEquals($result->format('d-M-Y'), '31-Jan-2012');
}
/**
* @dataProvider providerYEAR
*
* @param mixed $expectedResult
*/
public function testYEAR($expectedResult, ...$args)
{
$result = DateTime::YEAR(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerYEAR()
{
return require 'data/Calculation/DateTime/YEAR.php';
}
/**
* @dataProvider providerMONTH
*
* @param mixed $expectedResult
*/
public function testMONTH($expectedResult, ...$args)
{
$result = DateTime::MONTHOFYEAR(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerMONTH()
{
return require 'data/Calculation/DateTime/MONTH.php';
}
/**
* @dataProvider providerWEEKNUM
*
* @param mixed $expectedResult
*/
public function testWEEKNUM($expectedResult, ...$args)
{
$result = DateTime::WEEKNUM(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerWEEKNUM()
{
return require 'data/Calculation/DateTime/WEEKNUM.php';
}
/**
* @dataProvider providerISOWEEKNUM
*
* @param mixed $expectedResult
* @param mixed $dateValue
*/
public function testISOWEEKNUM($expectedResult, $dateValue)
{
$result = DateTime::ISOWEEKNUM($dateValue);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerISOWEEKNUM()
{
return require 'data/Calculation/DateTime/ISOWEEKNUM.php';
}
/**
* @dataProvider providerWEEKDAY
*
* @param mixed $expectedResult
*/
public function testWEEKDAY($expectedResult, ...$args)
{
$result = DateTime::WEEKDAY(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerWEEKDAY()
{
return require 'data/Calculation/DateTime/WEEKDAY.php';
}
/**
* @dataProvider providerDAY
*
* @param mixed $expectedResultExcel
* @param mixed $expectedResultOpenOffice
*/
public function testDAY($expectedResultExcel, $expectedResultOpenOffice, ...$args)
{
$resultExcel = DateTime::DAYOFMONTH(...$args);
self::assertEquals($expectedResultExcel, $resultExcel, null, 1E-8);
Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE);
$resultOpenOffice = DateTime::DAYOFMONTH(...$args);
self::assertEquals($expectedResultOpenOffice, $resultOpenOffice, null, 1E-8);
}
public function providerDAY()
{
return require 'data/Calculation/DateTime/DAY.php';
}
/**
* @dataProvider providerTIME
*
* @param mixed $expectedResult
*/
public function testTIME($expectedResult, ...$args)
{
$result = DateTime::TIME(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerTIME()
{
return require 'data/Calculation/DateTime/TIME.php';
}
public function testTIMEtoPHP()
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_NUMERIC);
$result = DateTime::TIME(7, 30, 20);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
self::assertEquals(27020, $result, null, 1E-8);
}
public function testTIMEtoPHPObject()
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_OBJECT);
$result = DateTime::TIME(7, 30, 20);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
// Must return an object...
self::assertInternalType('object', $result);
// ... of the correct type
self::assertTrue(is_a($result, 'DateTime'));
// ... with the correct value
self::assertEquals($result->format('H:i:s'), '07:30:20');
}
/**
* @dataProvider providerTIMEVALUE
*
* @param mixed $expectedResult
*/
public function testTIMEVALUE($expectedResult, ...$args)
{
$result = DateTime::TIMEVALUE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerTIMEVALUE()
{
return require 'data/Calculation/DateTime/TIMEVALUE.php';
}
public function testTIMEVALUEtoPHP()
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_NUMERIC);
$result = DateTime::TIMEVALUE('7:30:20');
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
self::assertEquals(23420, $result, null, 1E-8);
}
public function testTIMEVALUEtoPHPObject()
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_OBJECT);
$result = DateTime::TIMEVALUE('7:30:20');
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
// Must return an object...
self::assertInternalType('object', $result);
// ... of the correct type
self::assertTrue(is_a($result, 'DateTime'));
// ... with the correct value
self::assertEquals($result->format('H:i:s'), '07:30:20');
}
/**
* @dataProvider providerHOUR
*
* @param mixed $expectedResult
*/
public function testHOUR($expectedResult, ...$args)
{
$result = DateTime::HOUROFDAY(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerHOUR()
{
return require 'data/Calculation/DateTime/HOUR.php';
}
/**
* @dataProvider providerMINUTE
*
* @param mixed $expectedResult
*/
public function testMINUTE($expectedResult, ...$args)
{
$result = DateTime::MINUTE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerMINUTE()
{
return require 'data/Calculation/DateTime/MINUTE.php';
}
/**
* @dataProvider providerSECOND
*
* @param mixed $expectedResult
*/
public function testSECOND($expectedResult, ...$args)
{
$result = DateTime::SECOND(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerSECOND()
{
return require 'data/Calculation/DateTime/SECOND.php';
}
/**
* @dataProvider providerNETWORKDAYS
*
* @param mixed $expectedResult
*/
public function testNETWORKDAYS($expectedResult, ...$args)
{
$result = DateTime::NETWORKDAYS(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerNETWORKDAYS()
{
return require 'data/Calculation/DateTime/NETWORKDAYS.php';
}
/**
* @dataProvider providerWORKDAY
*
* @param mixed $expectedResult
*/
public function testWORKDAY($expectedResult, ...$args)
{
$result = DateTime::WORKDAY(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerWORKDAY()
{
return require 'data/Calculation/DateTime/WORKDAY.php';
}
/**
* @dataProvider providerEDATE
*
* @param mixed $expectedResult
*/
public function testEDATE($expectedResult, ...$args)
{
$result = DateTime::EDATE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerEDATE()
{
return require 'data/Calculation/DateTime/EDATE.php';
}
public function testEDATEtoPHP()
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_NUMERIC);
$result = DateTime::EDATE('2012-1-26', -1);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
self::assertEquals(1324857600, $result, null, 1E-8);
}
public function testEDATEtoPHPObject()
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_OBJECT);
$result = DateTime::EDATE('2012-1-26', -1);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
// Must return an object...
self::assertInternalType('object', $result);
// ... of the correct type
self::assertTrue(is_a($result, 'DateTime'));
// ... with the correct value
self::assertEquals($result->format('d-M-Y'), '26-Dec-2011');
}
/**
* @dataProvider providerEOMONTH
*
* @param mixed $expectedResult
*/
public function testEOMONTH($expectedResult, ...$args)
{
$result = DateTime::EOMONTH(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerEOMONTH()
{
return require 'data/Calculation/DateTime/EOMONTH.php';
}
public function testEOMONTHtoPHP()
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_NUMERIC);
$result = DateTime::EOMONTH('2012-1-26', -1);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
self::assertEquals(1325289600, $result, null, 1E-8);
}
public function testEOMONTHtoPHPObject()
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_OBJECT);
$result = DateTime::EOMONTH('2012-1-26', -1);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
// Must return an object...
self::assertInternalType('object', $result);
// ... of the correct type
self::assertTrue(is_a($result, 'DateTime'));
// ... with the correct value
self::assertEquals($result->format('d-M-Y'), '31-Dec-2011');
}
/**
* @dataProvider providerDATEDIF
*
* @param mixed $expectedResult
*/
public function testDATEDIF($expectedResult, ...$args)
{
$result = DateTime::DATEDIF(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerDATEDIF()
{
return require 'data/Calculation/DateTime/DATEDIF.php';
}
/**
* @dataProvider providerDAYS360
*
* @param mixed $expectedResult
*/
public function testDAYS360($expectedResult, ...$args)
{
$result = DateTime::DAYS360(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerDAYS360()
{
return require 'data/Calculation/DateTime/DAYS360.php';
}
/**
* @dataProvider providerYEARFRAC
*
* @param mixed $expectedResult
*/
public function testYEARFRAC($expectedResult, ...$args)
{
$result = DateTime::YEARFRAC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerYEARFRAC()
{
return require 'data/Calculation/DateTime/YEARFRAC.php';
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,613 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Financial;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PHPUnit\Framework\TestCase;
class FinancialTest extends TestCase
{
public function setUp()
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerACCRINT
*
* @param mixed $expectedResult
*/
public function testACCRINT($expectedResult, ...$args)
{
$result = Financial::ACCRINT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerACCRINT()
{
return require 'data/Calculation/Financial/ACCRINT.php';
}
/**
* @dataProvider providerACCRINTM
*
* @param mixed $expectedResult
*/
public function testACCRINTM($expectedResult, ...$args)
{
$result = Financial::ACCRINTM(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerACCRINTM()
{
return require 'data/Calculation/Financial/ACCRINTM.php';
}
/**
* @dataProvider providerAMORDEGRC
*
* @param mixed $expectedResult
*/
public function testAMORDEGRC($expectedResult, ...$args)
{
$result = Financial::AMORDEGRC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerAMORDEGRC()
{
return require 'data/Calculation/Financial/AMORDEGRC.php';
}
/**
* @dataProvider providerAMORLINC
*
* @param mixed $expectedResult
*/
public function testAMORLINC($expectedResult, ...$args)
{
$result = Financial::AMORLINC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerAMORLINC()
{
return require 'data/Calculation/Financial/AMORLINC.php';
}
/**
* @dataProvider providerCOUPDAYBS
*
* @param mixed $expectedResult
*/
public function testCOUPDAYBS($expectedResult, ...$args)
{
$result = Financial::COUPDAYBS(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerCOUPDAYBS()
{
return require 'data/Calculation/Financial/COUPDAYBS.php';
}
/**
* @dataProvider providerCOUPDAYS
*
* @param mixed $expectedResult
*/
public function testCOUPDAYS($expectedResult, ...$args)
{
$result = Financial::COUPDAYS(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerCOUPDAYS()
{
return require 'data/Calculation/Financial/COUPDAYS.php';
}
/**
* @dataProvider providerCOUPDAYSNC
*
* @param mixed $expectedResult
*/
public function testCOUPDAYSNC($expectedResult, ...$args)
{
$result = Financial::COUPDAYSNC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerCOUPDAYSNC()
{
return require 'data/Calculation/Financial/COUPDAYSNC.php';
}
/**
* @dataProvider providerCOUPNCD
*
* @param mixed $expectedResult
*/
public function testCOUPNCD($expectedResult, ...$args)
{
$result = Financial::COUPNCD(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerCOUPNCD()
{
return require 'data/Calculation/Financial/COUPNCD.php';
}
/**
* @dataProvider providerCOUPNUM
*
* @param mixed $expectedResult
*/
public function testCOUPNUM($expectedResult, ...$args)
{
$result = Financial::COUPNUM(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerCOUPNUM()
{
return require 'data/Calculation/Financial/COUPNUM.php';
}
/**
* @dataProvider providerCOUPPCD
*
* @param mixed $expectedResult
*/
public function testCOUPPCD($expectedResult, ...$args)
{
$result = Financial::COUPPCD(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerCOUPPCD()
{
return require 'data/Calculation/Financial/COUPPCD.php';
}
/**
* @dataProvider providerCUMIPMT
*
* @param mixed $expectedResult
*/
public function testCUMIPMT($expectedResult, ...$args)
{
$result = Financial::CUMIPMT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerCUMIPMT()
{
return require 'data/Calculation/Financial/CUMIPMT.php';
}
/**
* @dataProvider providerCUMPRINC
*
* @param mixed $expectedResult
*/
public function testCUMPRINC($expectedResult, ...$args)
{
$result = Financial::CUMPRINC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerCUMPRINC()
{
return require 'data/Calculation/Financial/CUMPRINC.php';
}
/**
* @dataProvider providerDB
*
* @param mixed $expectedResult
*/
public function testDB($expectedResult, ...$args)
{
$result = Financial::DB(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerDB()
{
return require 'data/Calculation/Financial/DB.php';
}
/**
* @dataProvider providerDDB
*
* @param mixed $expectedResult
*/
public function testDDB($expectedResult, ...$args)
{
$result = Financial::DDB(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerDDB()
{
return require 'data/Calculation/Financial/DDB.php';
}
/**
* @dataProvider providerDISC
*
* @param mixed $expectedResult
*/
public function testDISC($expectedResult, ...$args)
{
$result = Financial::DISC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerDISC()
{
return require 'data/Calculation/Financial/DISC.php';
}
/**
* @dataProvider providerDOLLARDE
*
* @param mixed $expectedResult
*/
public function testDOLLARDE($expectedResult, ...$args)
{
$result = Financial::DOLLARDE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerDOLLARDE()
{
return require 'data/Calculation/Financial/DOLLARDE.php';
}
/**
* @dataProvider providerDOLLARFR
*
* @param mixed $expectedResult
*/
public function testDOLLARFR($expectedResult, ...$args)
{
$result = Financial::DOLLARFR(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerDOLLARFR()
{
return require 'data/Calculation/Financial/DOLLARFR.php';
}
/**
* @dataProvider providerEFFECT
*
* @param mixed $expectedResult
*/
public function testEFFECT($expectedResult, ...$args)
{
$result = Financial::EFFECT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerEFFECT()
{
return require 'data/Calculation/Financial/EFFECT.php';
}
/**
* @dataProvider providerFV
*
* @param mixed $expectedResult
*/
public function testFV($expectedResult, ...$args)
{
$result = Financial::FV(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerFV()
{
return require 'data/Calculation/Financial/FV.php';
}
/**
* @dataProvider providerFVSCHEDULE
*
* @param mixed $expectedResult
*/
public function testFVSCHEDULE($expectedResult, ...$args)
{
$result = Financial::FVSCHEDULE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerFVSCHEDULE()
{
return require 'data/Calculation/Financial/FVSCHEDULE.php';
}
/**
* @dataProvider providerINTRATE
*
* @param mixed $expectedResult
*/
public function testINTRATE($expectedResult, ...$args)
{
$result = Financial::INTRATE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerINTRATE()
{
return require 'data/Calculation/Financial/INTRATE.php';
}
/**
* @dataProvider providerIPMT
*
* @param mixed $expectedResult
*/
public function testIPMT($expectedResult, ...$args)
{
$result = Financial::IPMT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerIPMT()
{
return require 'data/Calculation/Financial/IPMT.php';
}
/**
* @dataProvider providerIRR
*
* @param mixed $expectedResult
*/
public function testIRR($expectedResult, ...$args)
{
$result = Financial::IRR(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerIRR()
{
return require 'data/Calculation/Financial/IRR.php';
}
/**
* @dataProvider providerISPMT
*
* @param mixed $expectedResult
*/
public function testISPMT($expectedResult, ...$args)
{
$result = Financial::ISPMT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerISPMT()
{
return require 'data/Calculation/Financial/ISPMT.php';
}
/**
* @dataProvider providerMIRR
*
* @param mixed $expectedResult
*/
public function testMIRR($expectedResult, ...$args)
{
$result = Financial::MIRR(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerMIRR()
{
return require 'data/Calculation/Financial/MIRR.php';
}
/**
* @dataProvider providerNOMINAL
*
* @param mixed $expectedResult
*/
public function testNOMINAL($expectedResult, ...$args)
{
$result = Financial::NOMINAL(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerNOMINAL()
{
return require 'data/Calculation/Financial/NOMINAL.php';
}
/**
* @dataProvider providerNPER
*
* @param mixed $expectedResult
*/
public function testNPER($expectedResult, ...$args)
{
$result = Financial::NPER(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerNPER()
{
return require 'data/Calculation/Financial/NPER.php';
}
/**
* @dataProvider providerNPV
*
* @param mixed $expectedResult
*/
public function testNPV($expectedResult, ...$args)
{
$result = Financial::NPV(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerNPV()
{
return require 'data/Calculation/Financial/NPV.php';
}
/**
* @dataProvider providerPRICE
*
* @param mixed $expectedResult
*/
public function testPRICE($expectedResult, ...$args)
{
$this->markTestIncomplete('TODO: This test should be fixed');
$result = Financial::PRICE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerPRICE()
{
return require 'data/Calculation/Financial/PRICE.php';
}
/**
* @dataProvider providerPRICEDISC
*
* @param mixed $expectedResult
*/
public function testPRICEDISC($expectedResult, array $args)
{
$result = Financial::PRICEDISC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerPRICEDISC()
{
return require 'data/Calculation/Financial/PRICEDISC.php';
}
/**
* @dataProvider providerPV
*
* @param mixed $expectedResult
*/
public function testPV($expectedResult, array $args)
{
$result = Financial::PV(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerPV()
{
return require 'data/Calculation/Financial/PV.php';
}
/**
* @dataProvider providerRATE
*
* @param mixed $expectedResult
*/
public function testRATE($expectedResult, ...$args)
{
$this->markTestIncomplete('TODO: This test should be fixed');
$result = Financial::RATE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerRATE()
{
return require 'data/Calculation/Financial/RATE.php';
}
/**
* @dataProvider providerXIRR
*
* @param mixed $expectedResult
*/
public function testXIRR($expectedResult, ...$args)
{
$this->markTestIncomplete('TODO: This test should be fixed');
$result = Financial::XIRR(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerXIRR()
{
return require 'data/Calculation/Financial/XIRR.php';
}
/**
* @dataProvider providerPDURATION
*
* @param mixed $expectedResult
*/
public function testPDURATION($expectedResult, array $args)
{
$result = Financial::PDURATION(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerPDURATION()
{
return require 'data/Calculation/Financial/PDURATION.php';
}
/**
* @dataProvider providerRRI
*
* @param mixed $expectedResult
*/
public function testRRI($expectedResult, array $args)
{
$result = Financial::RRI(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerRRI()
{
return require 'data/Calculation/Financial/RRI.php';
}
/**
* @dataProvider providerSLN
*
* @param mixed $expectedResult
*/
public function testSLN($expectedResult, array $args)
{
$result = Financial::SLN(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerSLN()
{
return require 'data/Calculation/Financial/SLN.php';
}
/**
* @dataProvider providerSYD
*
* @param mixed $expectedResult
*/
public function testSYD($expectedResult, array $args)
{
$result = Financial::SYD(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerSYD()
{
return require 'data/Calculation/Financial/SYD.php';
}
}

View File

@ -0,0 +1,385 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PHPUnit\Framework\TestCase;
class FunctionsTest extends TestCase
{
public function setUp()
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
}
public function tearDown()
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
}
public function testCompatibilityMode()
{
$result = Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC);
// Test for a true response for success
$this->assertTrue($result);
// Test that mode has been changed
$this->assertEquals(Functions::COMPATIBILITY_GNUMERIC, Functions::getCompatibilityMode());
}
public function testInvalidCompatibilityMode()
{
$result = Functions::setCompatibilityMode('INVALIDMODE');
// Test for a false response for failure
$this->assertFalse($result);
// Test that mode has not been changed
$this->assertEquals(Functions::COMPATIBILITY_EXCEL, Functions::getCompatibilityMode());
}
public function testReturnDateType()
{
$result = Functions::setReturnDateType(Functions::RETURNDATE_PHP_OBJECT);
// Test for a true response for success
$this->assertTrue($result);
// Test that mode has been changed
$this->assertEquals(Functions::RETURNDATE_PHP_OBJECT, Functions::getReturnDateType());
}
public function testInvalidReturnDateType()
{
$result = Functions::setReturnDateType('INVALIDTYPE');
// Test for a false response for failure
$this->assertFalse($result);
// Test that mode has not been changed
$this->assertEquals(Functions::RETURNDATE_EXCEL, Functions::getReturnDateType());
}
public function testDUMMY()
{
$result = Functions::DUMMY();
self::assertEquals('#Not Yet Implemented', $result);
}
public function testDIV0()
{
$result = Functions::DIV0();
self::assertEquals('#DIV/0!', $result);
}
public function testNA()
{
$result = Functions::NA();
self::assertEquals('#N/A', $result);
}
public function testNAN()
{
$result = Functions::NAN();
self::assertEquals('#NUM!', $result);
}
public function testNAME()
{
$result = Functions::NAME();
self::assertEquals('#NAME?', $result);
}
public function testREF()
{
$result = Functions::REF();
self::assertEquals('#REF!', $result);
}
public function testNULL()
{
$result = Functions::null();
self::assertEquals('#NULL!', $result);
}
public function testVALUE()
{
$result = Functions::VALUE();
self::assertEquals('#VALUE!', $result);
}
/**
* @dataProvider providerIsBlank
*
* @param mixed $expectedResult
*/
public function testIsBlank($expectedResult, ...$args)
{
$result = Functions::isBlank(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerIsBlank()
{
return require 'data/Calculation/Functions/IS_BLANK.php';
}
/**
* @dataProvider providerIsErr
*
* @param mixed $expectedResult
*/
public function testIsErr($expectedResult, ...$args)
{
$result = Functions::isErr(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerIsErr()
{
return require 'data/Calculation/Functions/IS_ERR.php';
}
/**
* @dataProvider providerIsError
*
* @param mixed $expectedResult
*/
public function testIsError($expectedResult, ...$args)
{
$result = Functions::isError(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerIsError()
{
return require 'data/Calculation/Functions/IS_ERROR.php';
}
/**
* @dataProvider providerErrorType
*
* @param mixed $expectedResult
*/
public function testErrorType($expectedResult, ...$args)
{
$result = Functions::errorType(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerErrorType()
{
return require 'data/Calculation/Functions/ERROR_TYPE.php';
}
/**
* @dataProvider providerIsLogical
*
* @param mixed $expectedResult
*/
public function testIsLogical($expectedResult, ...$args)
{
$result = Functions::isLogical(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerIsLogical()
{
return require 'data/Calculation/Functions/IS_LOGICAL.php';
}
/**
* @dataProvider providerIsNa
*
* @param mixed $expectedResult
*/
public function testIsNa($expectedResult, ...$args)
{
$result = Functions::isNa(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerIsNa()
{
return require 'data/Calculation/Functions/IS_NA.php';
}
/**
* @dataProvider providerIsNumber
*
* @param mixed $expectedResult
*/
public function testIsNumber($expectedResult, ...$args)
{
$result = Functions::isNumber(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerIsNumber()
{
return require 'data/Calculation/Functions/IS_NUMBER.php';
}
/**
* @dataProvider providerIsText
*
* @param mixed $expectedResult
*/
public function testIsText($expectedResult, ...$args)
{
$result = Functions::isText(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerIsText()
{
return require 'data/Calculation/Functions/IS_TEXT.php';
}
/**
* @dataProvider providerIsNonText
*
* @param mixed $expectedResult
*/
public function testIsNonText($expectedResult, ...$args)
{
$result = Functions::isNonText(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerIsNonText()
{
return require 'data/Calculation/Functions/IS_NONTEXT.php';
}
/**
* @dataProvider providerIsEven
*
* @param mixed $expectedResult
*/
public function testIsEven($expectedResult, ...$args)
{
$result = Functions::isEven(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerIsEven()
{
return require 'data/Calculation/Functions/IS_EVEN.php';
}
/**
* @dataProvider providerIsOdd
*
* @param mixed $expectedResult
*/
public function testIsOdd($expectedResult, ...$args)
{
$result = Functions::isOdd(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerIsOdd()
{
return require 'data/Calculation/Functions/IS_ODD.php';
}
/**
* @dataProvider providerTYPE
*
* @param mixed $expectedResult
*/
public function testTYPE($expectedResult, ...$args)
{
$result = Functions::TYPE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerTYPE()
{
return require 'data/Calculation/Functions/TYPE.php';
}
/**
* @dataProvider providerN
*
* @param mixed $expectedResult
*/
public function testN($expectedResult, ...$args)
{
$result = Functions::n(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerN()
{
return require 'data/Calculation/Functions/N.php';
}
/**
* @dataProvider providerIsFormula
*
* @param mixed $expectedResult
* @param mixed $reference Reference to the cell we wish to test
* @param mixed $value Value of the cell we wish to test
*/
public function testIsFormula($expectedResult, $reference, $value = 'undefined')
{
$ourCell = null;
if ($value !== 'undefined') {
$remoteCell = $this->getMockBuilder(Cell::class)
->disableOriginalConstructor()
->getMock();
$remoteCell->method('isFormula')
->will($this->returnValue(substr($value, 0, 1) == '='));
$remoteSheet = $this->getMockBuilder(Worksheet::class)
->disableOriginalConstructor()
->getMock();
$remoteSheet->method('getCell')
->will($this->returnValue($remoteCell));
$workbook = $this->getMockBuilder(Spreadsheet::class)
->disableOriginalConstructor()
->getMock();
$workbook->method('getSheetByName')
->will($this->returnValue($remoteSheet));
$sheet = $this->getMockBuilder(Worksheet::class)
->disableOriginalConstructor()
->getMock();
$sheet->method('getCell')
->will($this->returnValue($remoteCell));
$sheet->method('getParent')
->will($this->returnValue($workbook));
$ourCell = $this->getMockBuilder(Cell::class)
->disableOriginalConstructor()
->getMock();
$ourCell->method('getWorksheet')
->will($this->returnValue($sheet));
}
$result = Functions::isFormula($reference, $ourCell);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerIsFormula()
{
return require 'data/Calculation/Functions/ISFORMULA.php';
}
/**
* @dataProvider providerIfCondition
*
* @param mixed $expectedResult
*/
public function testIfCondition($expectedResult, ...$args)
{
$result = Functions::ifCondition(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerIfCondition()
{
return require 'data/Calculation/Functions/IF_CONDITION.php';
}
}

View File

@ -0,0 +1,123 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;
class LogicalTest extends TestCase
{
public function setUp()
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
public function testTRUE()
{
$result = Logical::TRUE();
self::assertTrue($result);
}
public function testFALSE()
{
$result = Logical::FALSE();
self::assertFalse($result);
}
/**
* @dataProvider providerAND
*
* @param mixed $expectedResult
*/
public function testAND($expectedResult, ...$args)
{
$result = Logical::logicalAnd(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerAND()
{
return require 'data/Calculation/Logical/AND.php';
}
/**
* @dataProvider providerOR
*
* @param mixed $expectedResult
*/
public function testOR($expectedResult, ...$args)
{
$result = Logical::logicalOr(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerOR()
{
return require 'data/Calculation/Logical/OR.php';
}
/**
* @dataProvider providerXOR
*
* @param mixed $expectedResult
*/
public function testXOR($expectedResult, ...$args)
{
$result = Logical::logicalXor(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerXOR()
{
return require 'data/Calculation/Logical/XOR.php';
}
/**
* @dataProvider providerNOT
*
* @param mixed $expectedResult
*/
public function testNOT($expectedResult, ...$args)
{
$result = Logical::NOT(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerNOT()
{
return require 'data/Calculation/Logical/NOT.php';
}
/**
* @dataProvider providerIF
*
* @param mixed $expectedResult
*/
public function testIF($expectedResult, ...$args)
{
$result = Logical::statementIf(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerIF()
{
return require 'data/Calculation/Logical/IF.php';
}
/**
* @dataProvider providerIFERROR
*
* @param mixed $expectedResult
*/
public function testIFERROR($expectedResult, ...$args)
{
$result = Logical::IFERROR(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerIFERROR()
{
return require 'data/Calculation/Logical/IFERROR.php';
}
}

View File

@ -0,0 +1,172 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PHPUnit\Framework\TestCase;
/**
* Class LookupRefTest.
*/
class LookupRefTest extends TestCase
{
public function setUp()
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerHLOOKUP
*
* @param mixed $expectedResult
*/
public function testHLOOKUP($expectedResult, ...$args)
{
$result = LookupRef::HLOOKUP(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerHLOOKUP()
{
return require 'data/Calculation/LookupRef/HLOOKUP.php';
}
/**
* @dataProvider providerVLOOKUP
*
* @param mixed $expectedResult
*/
public function testVLOOKUP($expectedResult, ...$args)
{
$result = LookupRef::VLOOKUP(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerVLOOKUP()
{
return require 'data/Calculation/LookupRef/VLOOKUP.php';
}
/**
* @dataProvider providerMATCH
*
* @param mixed $expectedResult
*/
public function testMATCH($expectedResult, ...$args)
{
$result = LookupRef::MATCH(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerMATCH()
{
return require 'data/Calculation/LookupRef/MATCH.php';
}
/**
* @dataProvider providerINDEX
*
* @param mixed $expectedResult
*/
public function testINDEX($expectedResult, ...$args)
{
$result = LookupRef::INDEX(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerINDEX()
{
return require 'data/Calculation/LookupRef/INDEX.php';
}
/**
* @dataProvider providerCOLUMNS
*
* @param mixed $expectedResult
*/
public function testCOLUMNS($expectedResult, ...$args)
{
$result = LookupRef::COLUMNS(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerCOLUMNS()
{
return require 'data/Calculation/LookupRef/COLUMNS.php';
}
/**
* @dataProvider providerROWS
*
* @param mixed $expectedResult
*/
public function testROWS($expectedResult, ...$args)
{
$result = LookupRef::ROWS(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerROWS()
{
return require 'data/Calculation/LookupRef/ROWS.php';
}
/**
* @dataProvider providerFormulaText
*
* @param mixed $expectedResult
* @param mixed $reference Reference to the cell we wish to test
* @param mixed $value Value of the cell we wish to test
*/
public function testFormulaText($expectedResult, $reference, $value = 'undefined')
{
$ourCell = null;
if ($value !== 'undefined') {
$remoteCell = $this->getMockBuilder(Cell::class)
->disableOriginalConstructor()
->getMock();
$remoteCell->method('isFormula')
->will($this->returnValue(substr($value, 0, 1) == '='));
$remoteCell->method('getValue')
->will($this->returnValue($value));
$remoteSheet = $this->getMockBuilder(Worksheet::class)
->disableOriginalConstructor()
->getMock();
$remoteSheet->method('getCell')
->will($this->returnValue($remoteCell));
$workbook = $this->getMockBuilder(Spreadsheet::class)
->disableOriginalConstructor()
->getMock();
$workbook->method('getSheetByName')
->will($this->returnValue($remoteSheet));
$sheet = $this->getMockBuilder(Worksheet::class)
->disableOriginalConstructor()
->getMock();
$sheet->method('getCell')
->will($this->returnValue($remoteCell));
$sheet->method('getParent')
->will($this->returnValue($workbook));
$ourCell = $this->getMockBuilder(Cell::class)
->disableOriginalConstructor()
->getMock();
$ourCell->method('getWorksheet')
->will($this->returnValue($sheet));
}
$result = LookupRef::FORMULATEXT($reference, $ourCell);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerFormulaText()
{
return require 'data/Calculation/LookupRef/FORMULATEXT.php';
}
}

View File

@ -0,0 +1,881 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Worksheet\ColumnDimension;
use PhpOffice\PhpSpreadsheet\Worksheet\RowDimension;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PHPUnit\Framework\TestCase;
class MathTrigTest extends TestCase
{
public function setUp()
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerATAN2
*
* @param mixed $expectedResult
*/
public function testATAN2($expectedResult, ...$args)
{
$result = MathTrig::ATAN2(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerATAN2()
{
return require 'data/Calculation/MathTrig/ATAN2.php';
}
/**
* @dataProvider providerCEILING
*
* @param mixed $expectedResult
*/
public function testCEILING($expectedResult, ...$args)
{
$result = MathTrig::CEILING(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerCEILING()
{
return require 'data/Calculation/MathTrig/CEILING.php';
}
/**
* @dataProvider providerCOMBIN
*
* @param mixed $expectedResult
*/
public function testCOMBIN($expectedResult, ...$args)
{
$result = MathTrig::COMBIN(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerCOMBIN()
{
return require 'data/Calculation/MathTrig/COMBIN.php';
}
/**
* @dataProvider providerEVEN
*
* @param mixed $expectedResult
*/
public function testEVEN($expectedResult, ...$args)
{
$result = MathTrig::EVEN(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerEVEN()
{
return require 'data/Calculation/MathTrig/EVEN.php';
}
/**
* @dataProvider providerODD
*
* @param mixed $expectedResult
*/
public function testODD($expectedResult, ...$args)
{
$result = MathTrig::ODD(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerODD()
{
return require 'data/Calculation/MathTrig/ODD.php';
}
/**
* @dataProvider providerFACT
*
* @param mixed $expectedResult
*/
public function testFACT($expectedResult, ...$args)
{
$result = MathTrig::FACT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerFACT()
{
return require 'data/Calculation/MathTrig/FACT.php';
}
/**
* @dataProvider providerFACTDOUBLE
*
* @param mixed $expectedResult
*/
public function testFACTDOUBLE($expectedResult, ...$args)
{
$result = MathTrig::FACTDOUBLE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerFACTDOUBLE()
{
return require 'data/Calculation/MathTrig/FACTDOUBLE.php';
}
/**
* @dataProvider providerFLOOR
*
* @param mixed $expectedResult
*/
public function testFLOOR($expectedResult, ...$args)
{
$result = MathTrig::FLOOR(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerFLOOR()
{
return require 'data/Calculation/MathTrig/FLOOR.php';
}
/**
* @dataProvider providerGCD
*
* @param mixed $expectedResult
*/
public function testGCD($expectedResult, ...$args)
{
$result = MathTrig::GCD(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerGCD()
{
return require 'data/Calculation/MathTrig/GCD.php';
}
/**
* @dataProvider providerLCM
*
* @param mixed $expectedResult
*/
public function testLCM($expectedResult, ...$args)
{
$result = MathTrig::LCM(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerLCM()
{
return require 'data/Calculation/MathTrig/LCM.php';
}
/**
* @dataProvider providerINT
*
* @param mixed $expectedResult
*/
public function testINT($expectedResult, ...$args)
{
$result = MathTrig::INT(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerINT()
{
return require 'data/Calculation/MathTrig/INT.php';
}
/**
* @dataProvider providerSIGN
*
* @param mixed $expectedResult
*/
public function testSIGN($expectedResult, ...$args)
{
$result = MathTrig::SIGN(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerSIGN()
{
return require 'data/Calculation/MathTrig/SIGN.php';
}
/**
* @dataProvider providerPOWER
*
* @param mixed $expectedResult
*/
public function testPOWER($expectedResult, ...$args)
{
$result = MathTrig::POWER(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerPOWER()
{
return require 'data/Calculation/MathTrig/POWER.php';
}
/**
* @dataProvider providerLOG
*
* @param mixed $expectedResult
*/
public function testLOG($expectedResult, ...$args)
{
$result = MathTrig::logBase(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerLOG()
{
return require 'data/Calculation/MathTrig/LOG.php';
}
/**
* @dataProvider providerMOD
*
* @param mixed $expectedResult
*/
public function testMOD($expectedResult, ...$args)
{
$result = MathTrig::MOD(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerMOD()
{
return require 'data/Calculation/MathTrig/MOD.php';
}
/**
* @dataProvider providerMDETERM
*
* @param mixed $expectedResult
*/
public function testMDETERM($expectedResult, ...$args)
{
$result = MathTrig::MDETERM(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerMDETERM()
{
return require 'data/Calculation/MathTrig/MDETERM.php';
}
/**
* @dataProvider providerMINVERSE
*
* @param mixed $expectedResult
*/
public function testMINVERSE($expectedResult, ...$args)
{
$this->markTestIncomplete('TODO: This test should be fixed');
$result = MathTrig::MINVERSE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerMINVERSE()
{
return require 'data/Calculation/MathTrig/MINVERSE.php';
}
/**
* @dataProvider providerMMULT
*
* @param mixed $expectedResult
*/
public function testMMULT($expectedResult, ...$args)
{
$this->markTestIncomplete('TODO: This test should be fixed');
$result = MathTrig::MMULT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerMMULT()
{
return require 'data/Calculation/MathTrig/MMULT.php';
}
/**
* @dataProvider providerMULTINOMIAL
*
* @param mixed $expectedResult
*/
public function testMULTINOMIAL($expectedResult, ...$args)
{
$result = MathTrig::MULTINOMIAL(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerMULTINOMIAL()
{
return require 'data/Calculation/MathTrig/MULTINOMIAL.php';
}
/**
* @dataProvider providerMROUND
*
* @param mixed $expectedResult
*/
public function testMROUND($expectedResult, ...$args)
{
Calculation::setArrayReturnType(Calculation::RETURN_ARRAY_AS_VALUE);
$result = MathTrig::MROUND(...$args);
Calculation::setArrayReturnType(Calculation::RETURN_ARRAY_AS_ARRAY);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerMROUND()
{
return require 'data/Calculation/MathTrig/MROUND.php';
}
/**
* @dataProvider providerPRODUCT
*
* @param mixed $expectedResult
*/
public function testPRODUCT($expectedResult, ...$args)
{
$result = MathTrig::PRODUCT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerPRODUCT()
{
return require 'data/Calculation/MathTrig/PRODUCT.php';
}
/**
* @dataProvider providerQUOTIENT
*
* @param mixed $expectedResult
*/
public function testQUOTIENT($expectedResult, ...$args)
{
$result = MathTrig::QUOTIENT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerQUOTIENT()
{
return require 'data/Calculation/MathTrig/QUOTIENT.php';
}
/**
* @dataProvider providerROUNDUP
*
* @param mixed $expectedResult
*/
public function testROUNDUP($expectedResult, ...$args)
{
$result = MathTrig::ROUNDUP(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerROUNDUP()
{
return require 'data/Calculation/MathTrig/ROUNDUP.php';
}
/**
* @dataProvider providerROUNDDOWN
*
* @param mixed $expectedResult
*/
public function testROUNDDOWN($expectedResult, ...$args)
{
$result = MathTrig::ROUNDDOWN(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerROUNDDOWN()
{
return require 'data/Calculation/MathTrig/ROUNDDOWN.php';
}
/**
* @dataProvider providerSERIESSUM
*
* @param mixed $expectedResult
*/
public function testSERIESSUM($expectedResult, ...$args)
{
$result = MathTrig::SERIESSUM(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerSERIESSUM()
{
return require 'data/Calculation/MathTrig/SERIESSUM.php';
}
/**
* @dataProvider providerSUMSQ
*
* @param mixed $expectedResult
*/
public function testSUMSQ($expectedResult, ...$args)
{
$result = MathTrig::SUMSQ(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerSUMSQ()
{
return require 'data/Calculation/MathTrig/SUMSQ.php';
}
/**
* @dataProvider providerSUMPRODUCT
*
* @param mixed $expectedResult
*/
public function testSUMPRODUCT($expectedResult, ...$args)
{
$result = MathTrig::SUMPRODUCT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerSUMPRODUCT()
{
return require 'data/Calculation/MathTrig/SUMPRODUCT.php';
}
/**
* @dataProvider providerSUMX2MY2
*
* @param mixed $expectedResult
*/
public function testSUMX2MY2($expectedResult, ...$args)
{
$result = MathTrig::SUMX2MY2(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerSUMX2MY2()
{
return require 'data/Calculation/MathTrig/SUMX2MY2.php';
}
/**
* @dataProvider providerSUMX2PY2
*
* @param mixed $expectedResult
*/
public function testSUMX2PY2($expectedResult, ...$args)
{
$result = MathTrig::SUMX2PY2(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerSUMX2PY2()
{
return require 'data/Calculation/MathTrig/SUMX2PY2.php';
}
/**
* @dataProvider providerSUMXMY2
*
* @param mixed $expectedResult
*/
public function testSUMXMY2($expectedResult, ...$args)
{
$result = MathTrig::SUMXMY2(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerSUMXMY2()
{
return require 'data/Calculation/MathTrig/SUMXMY2.php';
}
/**
* @dataProvider providerTRUNC
*
* @param mixed $expectedResult
*/
public function testTRUNC($expectedResult, ...$args)
{
$result = MathTrig::TRUNC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerTRUNC()
{
return require 'data/Calculation/MathTrig/TRUNC.php';
}
/**
* @dataProvider providerROMAN
*
* @param mixed $expectedResult
*/
public function testROMAN($expectedResult, ...$args)
{
$result = MathTrig::ROMAN(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerROMAN()
{
return require 'data/Calculation/MathTrig/ROMAN.php';
}
/**
* @dataProvider providerSQRTPI
*
* @param mixed $expectedResult
*/
public function testSQRTPI($expectedResult, ...$args)
{
$result = MathTrig::SQRTPI(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerSQRTPI()
{
return require 'data/Calculation/MathTrig/SQRTPI.php';
}
/**
* @dataProvider providerSUMIF
*
* @param mixed $expectedResult
*/
public function testSUMIF($expectedResult, ...$args)
{
$result = MathTrig::SUMIF(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerSUMIF()
{
return require 'data/Calculation/MathTrig/SUMIF.php';
}
/**
* @dataProvider providerSUBTOTAL
*
* @param mixed $expectedResult
*/
public function testSUBTOTAL($expectedResult, ...$args)
{
$cell = $this->getMockBuilder(Cell::class)
->setMethods(['getValue'])
->disableOriginalConstructor()
->getMock();
$cell->method('getValue')
->willReturn(null);
$worksheet = $this->getMockBuilder(Worksheet::class)
->setMethods(['cellExists', 'getCell'])
->disableOriginalConstructor()
->getMock();
$worksheet->method('cellExists')
->willReturn(true);
$worksheet->method('getCell')
->willReturn($cell);
$cellReference = $this->getMockBuilder(Cell::class)
->setMethods(['getWorksheet'])
->disableOriginalConstructor()
->getMock();
$cellReference->method('getWorksheet')
->willReturn($worksheet);
array_push($args, $cellReference);
$result = MathTrig::SUBTOTAL(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerSUBTOTAL()
{
return require 'data/Calculation/MathTrig/SUBTOTAL.php';
}
protected function rowVisibility()
{
$data = [1 => false, 2 => true, 3 => false, 4 => true, 5 => false, 6 => false, 7 => false, 8 => true, 9 => false, 10 => true, 11 => true];
foreach ($data as $k => $v) {
yield $k => $v;
}
}
/**
* @dataProvider providerHiddenSUBTOTAL
*
* @param mixed $expectedResult
*/
public function testHiddenSUBTOTAL($expectedResult, ...$args)
{
$visibilityGenerator = $this->rowVisibility();
$rowDimension = $this->getMockBuilder(RowDimension::class)
->setMethods(['getVisible'])
->disableOriginalConstructor()
->getMock();
$rowDimension->method('getVisible')
->will($this->returnCallback(function () use ($visibilityGenerator) {
$result = $visibilityGenerator->current();
$visibilityGenerator->next();
return $result;
}));
$columnDimension = $this->getMockBuilder(ColumnDimension::class)
->setMethods(['getVisible'])
->disableOriginalConstructor()
->getMock();
$columnDimension->method('getVisible')
->willReturn(true);
$cell = $this->getMockBuilder(Cell::class)
->setMethods(['getValue'])
->disableOriginalConstructor()
->getMock();
$cell->method('getValue')
->willReturn('');
$worksheet = $this->getMockBuilder(Worksheet::class)
->setMethods(['cellExists', 'getCell', 'getRowDimension', 'getColumnDimension'])
->disableOriginalConstructor()
->getMock();
$worksheet->method('cellExists')
->willReturn(true);
$worksheet->method('getCell')
->willReturn($cell);
$worksheet->method('getRowDimension')
->willReturn($rowDimension);
$worksheet->method('getColumnDimension')
->willReturn($columnDimension);
$cellReference = $this->getMockBuilder(Cell::class)
->setMethods(['getWorksheet'])
->disableOriginalConstructor()
->getMock();
$cellReference->method('getWorksheet')
->willReturn($worksheet);
array_push($args, $cellReference);
$result = MathTrig::SUBTOTAL(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerHiddenSUBTOTAL()
{
return require 'data/Calculation/MathTrig/SUBTOTALHIDDEN.php';
}
protected function cellValues(array $cellValues)
{
foreach ($cellValues as $k => $v) {
yield $k => $v;
}
}
protected function cellIsFormula(array $cellValues)
{
foreach ($cellValues as $cellValue) {
yield $cellValue[0] === '=';
}
}
/**
* @dataProvider providerNestedSUBTOTAL
*
* @param mixed $expectedResult
*/
public function testNestedSUBTOTAL($expectedResult, ...$args)
{
$cellValueGenerator = $this->cellValues(Functions::flattenArray(array_slice($args, 1)));
$cellIsFormulaGenerator = $this->cellIsFormula(Functions::flattenArray(array_slice($args, 1)));
$cell = $this->getMockBuilder(Cell::class)
->setMethods(['getValue', 'isFormula'])
->disableOriginalConstructor()
->getMock();
$cell->method('getValue')
->will($this->returnCallback(function () use ($cellValueGenerator) {
$result = $cellValueGenerator->current();
$cellValueGenerator->next();
return $result;
}));
$cell->method('isFormula')
->will($this->returnCallback(function () use ($cellIsFormulaGenerator) {
$result = $cellIsFormulaGenerator->current();
$cellIsFormulaGenerator->next();
return $result;
}));
$worksheet = $this->getMockBuilder(Worksheet::class)
->setMethods(['cellExists', 'getCell'])
->disableOriginalConstructor()
->getMock();
$worksheet->method('cellExists')
->willReturn(true);
$worksheet->method('getCell')
->willReturn($cell);
$cellReference = $this->getMockBuilder(Cell::class)
->setMethods(['getWorksheet'])
->disableOriginalConstructor()
->getMock();
$cellReference->method('getWorksheet')
->willReturn($worksheet);
array_push($args, $cellReference);
$result = MathTrig::SUBTOTAL(...$args);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerNestedSUBTOTAL()
{
return require 'data/Calculation/MathTrig/SUBTOTALNESTED.php';
}
/**
* @dataProvider providerSEC
*
* @param mixed $expectedResult
* @param mixed $angle
*/
public function testSEC($expectedResult, $angle)
{
$result = MathTrig::SEC($angle);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerSEC()
{
return require 'data/Calculation/MathTrig/SEC.php';
}
/**
* @dataProvider providerSECH
*
* @param mixed $expectedResult
* @param mixed $angle
*/
public function testSECH($expectedResult, $angle)
{
$result = MathTrig::SECH($angle);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerSECH()
{
return require 'data/Calculation/MathTrig/SECH.php';
}
/**
* @dataProvider providerCSC
*
* @param mixed $expectedResult
* @param mixed $angle
*/
public function testCSC($expectedResult, $angle)
{
$result = MathTrig::CSC($angle);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerCSC()
{
return require 'data/Calculation/MathTrig/CSC.php';
}
/**
* @dataProvider providerCSCH
*
* @param mixed $expectedResult
* @param mixed $angle
*/
public function testCSCH($expectedResult, $angle)
{
$result = MathTrig::CSCH($angle);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerCSCH()
{
return require 'data/Calculation/MathTrig/CSCH.php';
}
/**
* @dataProvider providerCOT
*
* @param mixed $expectedResult
* @param mixed $angle
*/
public function testCOT($expectedResult, $angle)
{
$result = MathTrig::COT($angle);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerCOT()
{
return require 'data/Calculation/MathTrig/COT.php';
}
/**
* @dataProvider providerCOTH
*
* @param mixed $expectedResult
* @param mixed $angle
*/
public function testCOTH($expectedResult, $angle)
{
$result = MathTrig::COTH($angle);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerCOTH()
{
return require 'data/Calculation/MathTrig/COTH.php';
}
/**
* @dataProvider providerACOT
*
* @param mixed $expectedResult
* @param mixed $number
*/
public function testACOT($expectedResult, $number)
{
$result = MathTrig::ACOT($number);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerACOT()
{
return require 'data/Calculation/MathTrig/ACOT.php';
}
/**
* @dataProvider providerACOTH
*
* @param mixed $expectedResult
* @param mixed $number
*/
public function testACOTH($expectedResult, $number)
{
$result = MathTrig::ACOTH($number);
self::assertEquals($expectedResult, $result, null, 1E-12);
}
public function providerACOTH()
{
return require 'data/Calculation/MathTrig/ACOTH.php';
}
}

View File

@ -0,0 +1,431 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\TextData;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
use PHPUnit\Framework\TestCase;
class TextDataTest extends TestCase
{
public function setUp()
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
StringHelper::setDecimalSeparator('.');
StringHelper::setThousandsSeparator(',');
StringHelper::setCurrencyCode('$');
}
public function tearDown()
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
StringHelper::setDecimalSeparator('.');
StringHelper::setThousandsSeparator(',');
StringHelper::setCurrencyCode('$');
}
/**
* @dataProvider providerCHAR
*
* @param mixed $expectedResult
*/
public function testCHAR($expectedResult, ...$args)
{
$result = TextData::CHARACTER(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerCHAR()
{
return require 'data/Calculation/TextData/CHAR.php';
}
/**
* @dataProvider providerCODE
*
* @param mixed $expectedResult
*/
public function testCODE($expectedResult, ...$args)
{
$result = TextData::ASCIICODE(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerCODE()
{
return require 'data/Calculation/TextData/CODE.php';
}
/**
* @dataProvider providerCONCATENATE
*
* @param mixed $expectedResult
*/
public function testCONCATENATE($expectedResult, ...$args)
{
$result = TextData::CONCATENATE(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerCONCATENATE()
{
return require 'data/Calculation/TextData/CONCATENATE.php';
}
/**
* @dataProvider providerLEFT
*
* @param mixed $expectedResult
*/
public function testLEFT($expectedResult, ...$args)
{
$result = TextData::LEFT(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerLEFT()
{
return require 'data/Calculation/TextData/LEFT.php';
}
/**
* @dataProvider providerMID
*
* @param mixed $expectedResult
*/
public function testMID($expectedResult, ...$args)
{
$result = TextData::MID(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerMID()
{
return require 'data/Calculation/TextData/MID.php';
}
/**
* @dataProvider providerRIGHT
*
* @param mixed $expectedResult
*/
public function testRIGHT($expectedResult, ...$args)
{
$result = TextData::RIGHT(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerRIGHT()
{
return require 'data/Calculation/TextData/RIGHT.php';
}
/**
* @dataProvider providerLOWER
*
* @param mixed $expectedResult
*/
public function testLOWER($expectedResult, ...$args)
{
$result = TextData::LOWERCASE(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerLOWER()
{
return require 'data/Calculation/TextData/LOWER.php';
}
/**
* @dataProvider providerUPPER
*
* @param mixed $expectedResult
*/
public function testUPPER($expectedResult, ...$args)
{
$result = TextData::UPPERCASE(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerUPPER()
{
return require 'data/Calculation/TextData/UPPER.php';
}
/**
* @dataProvider providerPROPER
*
* @param mixed $expectedResult
*/
public function testPROPER($expectedResult, ...$args)
{
$result = TextData::PROPERCASE(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerPROPER()
{
return require 'data/Calculation/TextData/PROPER.php';
}
/**
* @dataProvider providerLEN
*
* @param mixed $expectedResult
*/
public function testLEN($expectedResult, ...$args)
{
$result = TextData::STRINGLENGTH(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerLEN()
{
return require 'data/Calculation/TextData/LEN.php';
}
/**
* @dataProvider providerSEARCH
*
* @param mixed $expectedResult
*/
public function testSEARCH($expectedResult, ...$args)
{
$result = TextData::SEARCHINSENSITIVE(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerSEARCH()
{
return require 'data/Calculation/TextData/SEARCH.php';
}
/**
* @dataProvider providerFIND
*
* @param mixed $expectedResult
*/
public function testFIND($expectedResult, ...$args)
{
$result = TextData::SEARCHSENSITIVE(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerFIND()
{
return require 'data/Calculation/TextData/FIND.php';
}
/**
* @dataProvider providerREPLACE
*
* @param mixed $expectedResult
*/
public function testREPLACE($expectedResult, ...$args)
{
$result = TextData::REPLACE(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerREPLACE()
{
return require 'data/Calculation/TextData/REPLACE.php';
}
/**
* @dataProvider providerSUBSTITUTE
*
* @param mixed $expectedResult
*/
public function testSUBSTITUTE($expectedResult, ...$args)
{
$result = TextData::SUBSTITUTE(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerSUBSTITUTE()
{
return require 'data/Calculation/TextData/SUBSTITUTE.php';
}
/**
* @dataProvider providerTRIM
*
* @param mixed $expectedResult
*/
public function testTRIM($expectedResult, ...$args)
{
$result = TextData::TRIMSPACES(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerTRIM()
{
return require 'data/Calculation/TextData/TRIM.php';
}
/**
* @dataProvider providerCLEAN
*
* @param mixed $expectedResult
*/
public function testCLEAN($expectedResult, ...$args)
{
$result = TextData::TRIMNONPRINTABLE(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerCLEAN()
{
return require 'data/Calculation/TextData/CLEAN.php';
}
/**
* @dataProvider providerDOLLAR
*
* @param mixed $expectedResult
*/
public function testDOLLAR($expectedResult, ...$args)
{
$result = TextData::DOLLAR(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerDOLLAR()
{
return require 'data/Calculation/TextData/DOLLAR.php';
}
/**
* @dataProvider providerFIXED
*
* @param mixed $expectedResult
*/
public function testFIXED($expectedResult, ...$args)
{
$result = TextData::FIXEDFORMAT(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerFIXED()
{
return require 'data/Calculation/TextData/FIXED.php';
}
/**
* @dataProvider providerT
*
* @param mixed $expectedResult
*/
public function testT($expectedResult, ...$args)
{
$result = TextData::RETURNSTRING(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerT()
{
return require 'data/Calculation/TextData/T.php';
}
/**
* @dataProvider providerTEXT
*
* @param mixed $expectedResult
*/
public function testTEXT($expectedResult, ...$args)
{
// Enforce decimal and thousands separator values to UK/US, and currency code to USD
StringHelper::setDecimalSeparator('.');
StringHelper::setThousandsSeparator(',');
StringHelper::setCurrencyCode('$');
$result = TextData::TEXTFORMAT(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerTEXT()
{
return require 'data/Calculation/TextData/TEXT.php';
}
/**
* @dataProvider providerVALUE
*
* @param mixed $expectedResult
*/
public function testVALUE($expectedResult, ...$args)
{
StringHelper::setDecimalSeparator('.');
StringHelper::setThousandsSeparator(' ');
StringHelper::setCurrencyCode('$');
$result = TextData::VALUE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8);
}
public function providerVALUE()
{
return require 'data/Calculation/TextData/VALUE.php';
}
/**
* @dataProvider providerEXACT
*
* @param mixed $expectedResult
* @param array $args
*/
public function testEXACT($expectedResult, ...$args)
{
StringHelper::setDecimalSeparator('.');
StringHelper::setThousandsSeparator(' ');
StringHelper::setCurrencyCode('$');
$result = TextData::EXACT(...$args);
self::assertSame($expectedResult, $result, null);
}
/**
* @return array
*/
public function providerEXACT()
{
return require 'data/Calculation/TextData/EXACT.php';
}
/**
* @dataProvider providerTEXTJOIN
*
* @param mixed $expectedResult
* @param array $args
*/
public function testTEXTJOIN($expectedResult, array $args)
{
$result = TextData::TEXTJOIN(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerTEXTJOIN()
{
return require 'data/Calculation/TextData/TEXTJOIN.php';
}
/**
* @dataProvider providerNUMBERVALUE
*
* @param mixed $expectedResult
* @param array $args
*/
public function testNUMBERVALUE($expectedResult, array $args)
{
$result = TextData::NUMBERVALUE(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerNUMBERVALUE()
{
return require 'data/Calculation/TextData/NUMBERVALUE.php';
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Cell;
use PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Collection\Cells;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PHPUnit\Framework\TestCase;
class AdvancedValueBinderTest extends TestCase
{
public function provider()
{
$currencyUSD = NumberFormat::FORMAT_CURRENCY_USD_SIMPLE;
$currencyEURO = str_replace('$', '€', NumberFormat::FORMAT_CURRENCY_USD_SIMPLE);
return [
['10%', 0.1, NumberFormat::FORMAT_PERCENTAGE_00, ',', '.', '$'],
['$10.11', 10.11, $currencyUSD, ',', '.', '$'],
['$1,010.12', 1010.12, $currencyUSD, ',', '.', '$'],
['$20,20', 20.2, $currencyUSD, '.', ',', '$'],
['$2.020,20', 2020.2, $currencyUSD, '.', ',', '$'],
['€2.020,20', 2020.2, $currencyEURO, '.', ',', '€'],
['€ 2.020,20', 2020.2, $currencyEURO, '.', ',', '€'],
['€2,020.22', 2020.22, $currencyEURO, ',', '.', '€'],
];
}
/**
* @dataProvider provider
*
* @param mixed $value
* @param mixed $valueBinded
* @param mixed $format
* @param mixed $thousandsSeparator
* @param mixed $decimalSeparator
* @param mixed $currencyCode
*/
public function testCurrency($value, $valueBinded, $format, $thousandsSeparator, $decimalSeparator, $currencyCode)
{
$sheet = $this->getMockBuilder(Worksheet::class)
->setMethods(['getStyle', 'getNumberFormat', 'setFormatCode', 'getCellCollection'])
->getMock();
$cellCollection = $this->getMockBuilder(Cells::class)
->disableOriginalConstructor()
->getMock();
$cellCollection->expects($this->any())
->method('getParent')
->will($this->returnValue($sheet));
$sheet->expects($this->once())
->method('getStyle')
->will($this->returnSelf());
$sheet->expects($this->once())
->method('getNumberFormat')
->will($this->returnSelf());
$sheet->expects($this->once())
->method('setFormatCode')
->with($format)
->will($this->returnSelf());
$sheet->expects($this->any())
->method('getCellCollection')
->will($this->returnValue($cellCollection));
StringHelper::setCurrencyCode($currencyCode);
StringHelper::setDecimalSeparator($decimalSeparator);
StringHelper::setThousandsSeparator($thousandsSeparator);
$cell = new Cell(null, DataType::TYPE_STRING, $sheet);
$binder = new AdvancedValueBinder();
$binder->bindValue($cell, $value);
self::assertEquals($valueBinded, $cell->getValue());
}
}

View File

@ -0,0 +1,367 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Cell;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Exception;
use PHPUnit\Framework\TestCase;
class CoordinateTest extends TestCase
{
/**
* @dataProvider providerColumnString
*
* @param mixed $expectedResult
* @param mixed $string
*/
public function testColumnIndexFromString($expectedResult, $string)
{
$columnIndex = Coordinate::columnIndexFromString($string);
self::assertEquals($expectedResult, $columnIndex);
$stringBack = Coordinate::stringFromColumnIndex($columnIndex);
self::assertEquals($stringBack, $string, 'should be able to get the original input with opposite method');
}
public function providerColumnString()
{
return require 'data/ColumnString.php';
}
public function testColumnIndexFromStringTooLong()
{
$cellAddress = 'ABCD';
try {
Coordinate::columnIndexFromString($cellAddress);
} catch (\Exception $e) {
self::assertInstanceOf(Exception::class, $e);
self::assertEquals($e->getMessage(), 'Column string index can not be longer than 3 characters');
return;
}
$this->fail('An expected exception has not been raised.');
}
public function testColumnIndexFromStringTooShort()
{
$cellAddress = '';
try {
Coordinate::columnIndexFromString($cellAddress);
} catch (\Exception $e) {
self::assertInstanceOf(Exception::class, $e);
self::assertEquals($e->getMessage(), 'Column string index can not be empty');
return;
}
$this->fail('An expected exception has not been raised.');
}
/**
* @dataProvider providerColumnIndex
*
* @param mixed $expectedResult
* @param int $columnIndex
*/
public function testStringFromColumnIndex($expectedResult, $columnIndex)
{
$string = Coordinate::stringFromColumnIndex($columnIndex);
self::assertEquals($expectedResult, $string);
$columnIndexBack = Coordinate::columnIndexFromString($string);
self::assertEquals($columnIndexBack, $columnIndex, 'should be able to get the original input with opposite method');
}
public function providerColumnIndex()
{
return require 'data/ColumnIndex.php';
}
/**
* @dataProvider providerCoordinates
*
* @param mixed $expectedResult
*/
public function testCoordinateFromString($expectedResult, ...$args)
{
$result = Coordinate::coordinateFromString(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerCoordinates()
{
return require 'data/CellCoordinates.php';
}
public function testCoordinateFromStringWithRangeAddress()
{
$cellAddress = 'A1:AI2012';
try {
Coordinate::coordinateFromString($cellAddress);
} catch (\Exception $e) {
self::assertInstanceOf(Exception::class, $e);
self::assertEquals($e->getMessage(), 'Cell coordinate string can not be a range of cells');
return;
}
$this->fail('An expected exception has not been raised.');
}
public function testCoordinateFromStringWithEmptyAddress()
{
$cellAddress = '';
try {
Coordinate::coordinateFromString($cellAddress);
} catch (\Exception $e) {
self::assertInstanceOf(Exception::class, $e);
self::assertEquals($e->getMessage(), 'Cell coordinate can not be zero-length string');
return;
}
$this->fail('An expected exception has not been raised.');
}
public function testCoordinateFromStringWithInvalidAddress()
{
$cellAddress = 'AI';
try {
Coordinate::coordinateFromString($cellAddress);
} catch (\Exception $e) {
self::assertInstanceOf(Exception::class, $e);
self::assertEquals($e->getMessage(), 'Invalid cell coordinate ' . $cellAddress);
return;
}
$this->fail('An expected exception has not been raised.');
}
/**
* @dataProvider providerAbsoluteCoordinates
*
* @param mixed $expectedResult
*/
public function testAbsoluteCoordinateFromString($expectedResult, ...$args)
{
$result = Coordinate::absoluteCoordinate(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerAbsoluteCoordinates()
{
return require 'data/CellAbsoluteCoordinate.php';
}
public function testAbsoluteCoordinateFromStringWithRangeAddress()
{
$cellAddress = 'A1:AI2012';
try {
Coordinate::absoluteCoordinate($cellAddress);
} catch (\Exception $e) {
self::assertInstanceOf(Exception::class, $e);
self::assertEquals($e->getMessage(), 'Cell coordinate string can not be a range of cells');
return;
}
$this->fail('An expected exception has not been raised.');
}
/**
* @dataProvider providerAbsoluteReferences
*
* @param mixed $expectedResult
*/
public function testAbsoluteReferenceFromString($expectedResult, ...$args)
{
$result = Coordinate::absoluteReference(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerAbsoluteReferences()
{
return require 'data/CellAbsoluteReference.php';
}
public function testAbsoluteReferenceFromStringWithRangeAddress()
{
$cellAddress = 'A1:AI2012';
try {
Coordinate::absoluteReference($cellAddress);
} catch (\Exception $e) {
self::assertInstanceOf(Exception::class, $e);
self::assertEquals($e->getMessage(), 'Cell coordinate string can not be a range of cells');
return;
}
$this->fail('An expected exception has not been raised.');
}
/**
* @dataProvider providerSplitRange
*
* @param mixed $expectedResult
*/
public function testSplitRange($expectedResult, ...$args)
{
$result = Coordinate::splitRange(...$args);
foreach ($result as $key => $split) {
if (!is_array($expectedResult[$key])) {
self::assertEquals($expectedResult[$key], $split[0]);
} else {
self::assertEquals($expectedResult[$key], $split);
}
}
}
public function providerSplitRange()
{
return require 'data/CellSplitRange.php';
}
/**
* @dataProvider providerBuildRange
*
* @param mixed $expectedResult
*/
public function testBuildRange($expectedResult, ...$args)
{
$result = Coordinate::buildRange(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerBuildRange()
{
return require 'data/CellBuildRange.php';
}
public function testBuildRangeInvalid()
{
$this->expectException(\TypeError::class);
if (PHP_MAJOR_VERSION < 7) {
$this->markTestSkipped('Cannot catch type hinting error with PHP 5.6');
}
$cellRange = '';
Coordinate::buildRange($cellRange);
}
/**
* @dataProvider providerRangeBoundaries
*
* @param mixed $expectedResult
*/
public function testRangeBoundaries($expectedResult, ...$args)
{
$result = Coordinate::rangeBoundaries(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerRangeBoundaries()
{
return require 'data/CellRangeBoundaries.php';
}
/**
* @dataProvider providerRangeDimension
*
* @param mixed $expectedResult
*/
public function testRangeDimension($expectedResult, ...$args)
{
$result = Coordinate::rangeDimension(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerRangeDimension()
{
return require 'data/CellRangeDimension.php';
}
/**
* @dataProvider providerGetRangeBoundaries
*
* @param mixed $expectedResult
*/
public function testGetRangeBoundaries($expectedResult, ...$args)
{
$result = Coordinate::getRangeBoundaries(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerGetRangeBoundaries()
{
return require 'data/CellGetRangeBoundaries.php';
}
/**
* @dataProvider providerExtractAllCellReferencesInRange
*
* @param mixed $expectedResult
*/
public function testExtractAllCellReferencesInRange($expectedResult, ...$args)
{
$result = Coordinate::extractAllCellReferencesInRange(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerExtractAllCellReferencesInRange()
{
return require 'data/CellExtractAllCellReferencesInRange.php';
}
/**
* @dataProvider providerInvalidRange
*
* @param string $range
*/
public function testExtractAllCellReferencesInRangeInvalidRange($range)
{
$this->expectException(Exception::class);
$this->expectExceptionMessage('Invalid range: "' . $range . '"');
Coordinate::extractAllCellReferencesInRange($range);
}
public function providerInvalidRange()
{
return [['Z1:A1'], ['A4:A1'], ['B1:A1'], ['AA1:Z1']];
}
/**
* @dataProvider providerMergeRangesInCollection
*
* @param mixed $expectedResult
*/
public function testMergeRangesInCollection($expectedResult, ...$args)
{
$result = Coordinate::mergeRangesInCollection(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerMergeRangesInCollection()
{
return require 'data/CellMergeRangesInCollection.php';
}
/**
* @dataProvider providerCoordinateIsRange
*
* @param mixed $expectedResult
*/
public function testCoordinateIsRange($expectedResult, ...$args)
{
$result = Coordinate::coordinateIsRange(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerCoordinateIsRange()
{
return require 'data/CoordinateIsRange.php';
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Cell;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PHPUnit\Framework\TestCase;
class DataTypeTest extends TestCase
{
public function testGetErrorCodes()
{
$result = DataType::getErrorCodes();
self::assertInternalType('array', $result);
self::assertGreaterThan(0, count($result));
self::assertArrayHasKey('#NULL!', $result);
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Cell;
use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
use PHPUnit\Framework\TestCase;
class DataValidationTest extends TestCase
{
public function testNoValidation()
{
$dataValidation = new DataValidation();
self::assertSame('090624f04837265d79323c4a1b7e89d1', $dataValidation->getHashCode());
$dataValidation->setType(DataValidation::TYPE_CUSTOM);
self::assertSame('778f6c9e0ffcd5eaa7d8e1432d67f919', $dataValidation->getHashCode());
self::assertSame('778f6c9e0ffcd5eaa7d8e1432d67f919', $dataValidation->getHashCode(), 'getHashCode() should not have side effect');
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Cell;
use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class DataValidatorTest extends TestCase
{
public function testNoValidation()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$testCell = $sheet->getCell('A1');
self::assertTrue($testCell->hasValidValue(), 'a cell without any validation data is always valid');
}
public function testUnsupportedType()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$testCell = $sheet->getCell('A1');
$validation = $testCell->getDataValidation();
$validation->setType(DataValidation::TYPE_CUSTOM);
$validation->setAllowBlank(true);
self::assertFalse($testCell->hasValidValue(), 'cannot assert that value is valid when the validation type is not supported');
}
public function testList()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$testCell = $sheet->getCell('A1');
$validation = $testCell->getDataValidation();
$validation->setType(DataValidation::TYPE_LIST);
// blank value
$testCell->setValue('');
$validation->setAllowBlank(true);
self::assertTrue($testCell->hasValidValue(), 'cell can be empty');
$validation->setAllowBlank(false);
self::assertFalse($testCell->hasValidValue(), 'cell can not be empty');
// inline list
$validation->setFormula1('"yes,no"');
$testCell->setValue('foo');
self::assertFalse($testCell->hasValidValue(), "cell value ('foo') is not allowed");
$testCell->setValue('yes');
self::assertTrue($testCell->hasValidValue(), "cell value ('yes') has to be allowed");
// list from cells
$sheet->getCell('B1')->setValue(5);
$sheet->getCell('B2')->setValue(6);
$sheet->getCell('B3')->setValue(7);
$testCell = $sheet->getCell('A1'); // redefine $testCell, because it has broken coordinates after using other cells
$validation->setFormula1('B1:B3');
$testCell->setValue('10');
self::assertFalse($testCell->hasValidValue(), "cell value ('10') is not allowed");
$testCell = $sheet->getCell('A1'); // redefine $testCell, because it has broken coordinates after using other cells
$testCell->setValue('5');
self::assertTrue($testCell->hasValidValue(), "cell value ('5') has to be allowed");
$testCell = $sheet->getCell('A1'); // redefine $testCell, because it has broken coordinates after using other cells
$validation->setFormula1('broken : cell : coordinates');
self::assertFalse($testCell->hasValidValue(), 'invalid formula should not throw exceptions');
}
}

View File

@ -0,0 +1,86 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Cell;
use DateTime;
use DateTimeImmutable;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PHPUnit\Framework\TestCase;
class DefaultValueBinderTest extends TestCase
{
private $cellStub;
private function createCellStub()
{
// Create a stub for the Cell class.
$this->cellStub = $this->getMockBuilder(Cell::class)
->disableOriginalConstructor()
->getMock();
// Configure the stub.
$this->cellStub->expects($this->any())
->method('setValueExplicit')
->will($this->returnValue(true));
}
/**
* @dataProvider binderProvider
*
* @param mixed $value
*/
public function testBindValue($value)
{
$this->createCellStub();
$binder = new DefaultValueBinder();
$result = $binder->bindValue($this->cellStub, $value);
self::assertTrue($result);
}
public function binderProvider()
{
return [
[null],
[''],
['ABC'],
['=SUM(A1:B2)'],
[true],
[false],
[123],
[-123.456],
['123'],
['-123.456'],
['#REF!'],
[new DateTime()],
[new DateTimeImmutable()],
];
}
/**
* @dataProvider providerDataTypeForValue
*
* @param mixed $expectedResult
*/
public function testDataTypeForValue($expectedResult, ...$args)
{
$result = DefaultValueBinder::dataTypeForValue(...$args);
self::assertEquals($expectedResult, $result);
}
public function providerDataTypeForValue()
{
return require 'data/Cell/DefaultValueBinder.php';
}
public function testDataTypeForRichTextObject()
{
$objRichText = new RichText();
$objRichText->createText('Hello World');
$expectedResult = DataType::TYPE_INLINE;
$result = DefaultValueBinder::dataTypeForValue($objRichText);
self::assertEquals($expectedResult, $result);
}
}

View File

@ -0,0 +1,81 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Cell;
use PhpOffice\PhpSpreadsheet\Cell\Hyperlink;
use PHPUnit\Framework\TestCase;
class HyperlinkTest extends TestCase
{
public function testGetUrl()
{
$urlValue = 'https://www.example.com';
$testInstance = new Hyperlink($urlValue);
$result = $testInstance->getUrl();
self::assertEquals($urlValue, $result);
}
public function testSetUrl()
{
$initialUrlValue = 'https://www.example.com';
$newUrlValue = 'http://github.com/PHPOffice/PhpSpreadsheet';
$testInstance = new Hyperlink($initialUrlValue);
$result = $testInstance->setUrl($newUrlValue);
self::assertInstanceOf(Hyperlink::class, $result);
$result = $testInstance->getUrl();
self::assertEquals($newUrlValue, $result);
}
public function testGetTooltip()
{
$tooltipValue = 'PhpSpreadsheet Web Site';
$testInstance = new Hyperlink(null, $tooltipValue);
$result = $testInstance->getTooltip();
self::assertEquals($tooltipValue, $result);
}
public function testSetTooltip()
{
$initialTooltipValue = 'PhpSpreadsheet Web Site';
$newTooltipValue = 'PhpSpreadsheet Repository on Github';
$testInstance = new Hyperlink(null, $initialTooltipValue);
$result = $testInstance->setTooltip($newTooltipValue);
self::assertInstanceOf(Hyperlink::class, $result);
$result = $testInstance->getTooltip();
self::assertEquals($newTooltipValue, $result);
}
public function testIsInternal()
{
$initialUrlValue = 'https://www.example.com';
$newUrlValue = 'sheet://Worksheet1!A1';
$testInstance = new Hyperlink($initialUrlValue);
$result = $testInstance->isInternal();
self::assertFalse($result);
$testInstance->setUrl($newUrlValue);
$result = $testInstance->isInternal();
self::assertTrue($result);
}
public function testGetHashCode()
{
$urlValue = 'https://www.example.com';
$tooltipValue = 'PhpSpreadsheet Web Site';
$initialExpectedHash = '3a8d5a682dba27276dce538c39402437';
$testInstance = new Hyperlink($urlValue, $tooltipValue);
$result = $testInstance->getHashCode();
self::assertEquals($initialExpectedHash, $result);
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Exception;
use PHPUnit\Framework\TestCase;
class DataSeriesValuesTest extends TestCase
{
public function testSetDataType()
{
$dataTypeValues = [
'Number',
'String',
];
$testInstance = new DataSeriesValues();
foreach ($dataTypeValues as $dataTypeValue) {
$result = $testInstance->setDataType($dataTypeValue);
self::assertInstanceOf(DataSeriesValues::class, $result);
}
}
public function testSetInvalidDataTypeThrowsException()
{
$testInstance = new DataSeriesValues();
try {
$testInstance->setDataType('BOOLEAN');
} catch (Exception $e) {
self::assertEquals($e->getMessage(), 'Invalid datatype for chart data series values');
return;
}
$this->fail('An expected exception has not been raised.');
}
public function testGetDataType()
{
$dataTypeValue = 'String';
$testInstance = new DataSeriesValues();
$testInstance->setDataType($dataTypeValue);
$result = $testInstance->getDataType();
self::assertEquals($dataTypeValue, $result);
}
public function testGetLineWidth()
{
$testInstance = new DataSeriesValues();
self::assertEquals(12700, $testInstance->getLineWidth(), 'should have default');
$testInstance->setLineWidth(40000);
self::assertEquals(40000, $testInstance->getLineWidth());
$testInstance->setLineWidth(1);
self::assertEquals(12700, $testInstance->getLineWidth(), 'should enforce minimum width');
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Layout;
use PHPUnit\Framework\TestCase;
class LayoutTest extends TestCase
{
public function testSetLayoutTarget()
{
$LayoutTargetValue = 'String';
$testInstance = new Layout();
$result = $testInstance->setLayoutTarget($LayoutTargetValue);
self::assertInstanceOf(Layout::class, $result);
}
public function testGetLayoutTarget()
{
$LayoutTargetValue = 'String';
$testInstance = new Layout();
$testInstance->setLayoutTarget($LayoutTargetValue);
$result = $testInstance->getLayoutTarget();
self::assertEquals($LayoutTargetValue, $result);
}
}

View File

@ -0,0 +1,127 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Legend;
use PHPUnit\Framework\TestCase;
class LegendTest extends TestCase
{
public function testSetPosition()
{
$positionValues = [
Legend::POSITION_RIGHT,
Legend::POSITION_LEFT,
Legend::POSITION_TOP,
Legend::POSITION_BOTTOM,
Legend::POSITION_TOPRIGHT,
];
$testInstance = new Legend();
foreach ($positionValues as $positionValue) {
$result = $testInstance->setPosition($positionValue);
self::assertTrue($result);
}
}
public function testSetInvalidPositionReturnsFalse()
{
$testInstance = new Legend();
$result = $testInstance->setPosition('BottomLeft');
self::assertFalse($result);
// Ensure that value is unchanged
$result = $testInstance->getPosition();
self::assertEquals(Legend::POSITION_RIGHT, $result);
}
public function testGetPosition()
{
$PositionValue = Legend::POSITION_BOTTOM;
$testInstance = new Legend();
$testInstance->setPosition($PositionValue);
$result = $testInstance->getPosition();
self::assertEquals($PositionValue, $result);
}
public function testSetPositionXL()
{
$positionValues = [
Legend::XL_LEGEND_POSITION_BOTTOM,
Legend::XL_LEGEND_POSITION_CORNER,
Legend::XL_LEGEND_POSITION_CUSTOM,
Legend::XL_LEGEND_POSITION_LEFT,
Legend::XL_LEGEND_POSITION_RIGHT,
Legend::XL_LEGEND_POSITION_TOP,
];
$testInstance = new Legend();
foreach ($positionValues as $positionValue) {
$result = $testInstance->setPositionXL($positionValue);
self::assertTrue($result);
}
}
public function testSetInvalidXLPositionReturnsFalse()
{
$testInstance = new Legend();
$result = $testInstance->setPositionXL(999);
self::assertFalse($result);
// Ensure that value is unchanged
$result = $testInstance->getPositionXL();
self::assertEquals(Legend::XL_LEGEND_POSITION_RIGHT, $result);
}
public function testGetPositionXL()
{
$PositionValue = Legend::XL_LEGEND_POSITION_CORNER;
$testInstance = new Legend();
$testInstance->setPositionXL($PositionValue);
$result = $testInstance->getPositionXL();
self::assertEquals($PositionValue, $result);
}
public function testSetOverlay()
{
$overlayValues = [
true,
false,
];
$testInstance = new Legend();
foreach ($overlayValues as $overlayValue) {
$result = $testInstance->setOverlay($overlayValue);
self::assertTrue($result);
}
}
public function testSetInvalidOverlayReturnsFalse()
{
$testInstance = new Legend();
$result = $testInstance->setOverlay('INVALID');
self::assertFalse($result);
$result = $testInstance->getOverlay();
self::assertFalse($result);
}
public function testGetOverlay()
{
$OverlayValue = true;
$testInstance = new Legend();
$testInstance->setOverlay($OverlayValue);
$result = $testInstance->getOverlay();
self::assertEquals($OverlayValue, $result);
}
}

View File

@ -0,0 +1,117 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Collection;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Collection\Cells;
use PhpOffice\PhpSpreadsheet\Collection\Memory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PHPUnit\Framework\TestCase;
class CellsTest extends TestCase
{
public function testCollectionCell()
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$collection = $sheet->getCellCollection();
// Assert empty state
self::assertEquals([], $collection->getCoordinates(), 'cell list should be empty');
self::assertEquals([], $collection->getSortedCoordinates(), 'sorted cell list should be empty');
self::assertNull($collection->get('B2'), 'getting non-existing cell must return null');
self::assertFalse($collection->has('B2'), 'non-existing cell should be non-existent');
// Add one cell
$cell1 = $sheet->getCell('B2');
self::assertSame($cell1, $collection->add('B2', $cell1), 'adding a cell should return the cell');
// Assert cell presence
self::assertEquals(['B2'], $collection->getCoordinates(), 'cell list should contains the cell');
self::assertEquals(['B2'], $collection->getSortedCoordinates(), 'sorted cell list contains the cell');
self::assertSame($cell1, $collection->get('B2'), 'should get exact same object');
self::assertTrue($collection->has('B2'), 'cell should exists');
// Add a second cell
$cell2 = $sheet->getCell('A1');
self::assertSame($cell2, $collection->add('A1', $cell2), 'adding a second cell should return the cell');
self::assertEquals(['B2', 'A1'], $collection->getCoordinates(), 'cell list should contains the cell');
self::assertEquals(['A1', 'B2'], $collection->getSortedCoordinates(), 'sorted cell list contains the cell');
// Assert collection copy
$sheet2 = $spreadsheet->createSheet();
$collection2 = $collection->cloneCellCollection($sheet2);
self::assertTrue($collection2->has('A1'));
$copiedCell2 = $collection2->get('A1');
self::assertNotSame($cell2, $copiedCell2, 'copied cell should not be the same object any more');
self::assertSame($collection2, $copiedCell2->getParent(), 'copied cell should be owned by the copied collection');
self::assertSame('A1', $copiedCell2->getCoordinate(), 'copied cell should keep attributes');
// Assert deletion
$collection->delete('B2');
self::assertFalse($collection->has('B2'), 'cell should have been deleted');
self::assertEquals(['A1'], $collection->getCoordinates(), 'cell list should contains the cell');
// Assert update
$cell2 = $sheet->getCell('A1');
self::assertSame($sheet->getCellCollection(), $collection);
self::assertSame($cell2, $collection->update($cell2), 'should update existing cell');
$cell3 = $sheet->getCell('C3');
self::assertSame($cell3, $collection->update($cell3), 'should silently add non-existing cell');
self::assertEquals(['A1', 'C3'], $collection->getCoordinates(), 'cell list should contains the cell');
}
public function testCacheLastCell()
{
$workbook = new Spreadsheet();
$cells = ['A1', 'A2'];
$sheet = $workbook->getActiveSheet();
$sheet->setCellValue('A1', 1);
$sheet->setCellValue('A2', 2);
self::assertEquals($cells, $sheet->getCoordinates(), 'list should include last added cell');
}
public function testCanGetCellAfterAnotherIsDeleted()
{
$workbook = new Spreadsheet();
$sheet = $workbook->getActiveSheet();
$collection = $sheet->getCellCollection();
$sheet->setCellValue('A1', 1);
$sheet->setCellValue('A2', 1);
$collection->delete('A1');
$sheet->setCellValue('A3', 1);
self::assertNotNull($collection->get('A2'), 'should be able to get back the cell even when another cell was deleted while this one was the current one');
}
public function testThrowsWhenCellCannotBeRetrievedFromCache()
{
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
$collection = $this->getMockBuilder(Cells::class)
->setConstructorArgs([new Worksheet(), new Memory()])
->setMethods(['has'])
->getMock();
$collection->method('has')
->willReturn(true);
$collection->get('A2');
}
public function testThrowsWhenCellCannotBeStoredInCache()
{
$this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class);
$cache = $this->createMock(Memory::class);
$cell = $this->createMock(Cell::class);
$cache->method('set')
->willReturn(false);
$collection = new Cells(new Worksheet(), $cache);
$collection->add('A1', $cell);
$collection->add('A2', $cell);
}
}

View File

@ -0,0 +1,82 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Custom;
use Complex\Complex;
class ComplexAssert
{
private $errorMessage = '';
private function testExpectedExceptions($expected, $actual)
{
// Expecting an error, so we do a straight string comparison
if ($expected === $actual) {
return true;
} elseif ($expected === INF && $actual === 'INF') {
return true;
}
$this->errorMessage = 'Expected Error: ' . $actual . ' !== ' . $expected;
return false;
}
private function adjustDelta($expected, $actual, $delta)
{
$adjustedDelta = $delta;
if (abs($actual) > 10 && abs($expected) > 10) {
$variance = floor(log10(abs($expected)));
$adjustedDelta *= pow(10, $variance);
}
return $adjustedDelta > 1.0 ? 1.0 : $adjustedDelta;
}
public function assertComplexEquals($expected, $actual, $delta = 0)
{
if ($expected === INF || $expected[0] === '#') {
return $this->testExpectedExceptions($expected, $actual);
}
$expectedComplex = new Complex($expected);
$actualComplex = new Complex($actual);
if (!is_numeric($actualComplex->getReal()) || !is_numeric($expectedComplex->getReal())) {
if ($actualComplex->getReal() !== $expectedComplex->getReal()) {
$this->errorMessage = 'Mismatched String: ' . $actualComplex->getReal() . ' !== ' . $expectedComplex->getReal();
return false;
}
return true;
}
$adjustedDelta = $this->adjustDelta($expectedComplex->getReal(), $actualComplex->getReal(), $delta);
if (abs($actualComplex->getReal() - $expectedComplex->getReal()) > $adjustedDelta) {
$this->errorMessage = 'Mismatched Real part: ' . $actualComplex->getReal() . ' != ' . $expectedComplex->getReal();
return false;
}
$adjustedDelta = $this->adjustDelta($expectedComplex->getImaginary(), $actualComplex->getImaginary(), $delta);
if (abs($actualComplex->getImaginary() - $expectedComplex->getImaginary()) > $adjustedDelta) {
$this->errorMessage = 'Mismatched Imaginary part: ' . $actualComplex->getImaginary() . ' != ' . $expectedComplex->getImaginary();
return false;
}
if ($actualComplex->getSuffix() !== $actualComplex->getSuffix()) {
$this->errorMessage = 'Mismatched Suffix: ' . $actualComplex->getSuffix() . ' != ' . $expectedComplex->getSuffix();
return false;
}
return true;
}
public function getErrorMessage()
{
return $this->errorMessage;
}
}

Some files were not shown because too many files have changed in this diff Show More