Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into
develop
This commit is contained in:
parent
764ce03d10
commit
2663c8f2f2
5
composer.json
Normal file
5
composer.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"require": {
|
||||||
|
"phpoffice/phpspreadsheet": "^1.12"
|
||||||
|
}
|
||||||
|
}
|
||||||
339
composer.lock
generated
Normal file
339
composer.lock
generated
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
{
|
||||||
|
"_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#installing-dependencies",
|
||||||
|
"This file is @generated automatically"
|
||||||
|
],
|
||||||
|
"content-hash": "a68ce168cd747e78b793f2d2d0bb89b9",
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "markbaker/complex",
|
||||||
|
"version": "1.5.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/MarkBaker/PHPComplex.git",
|
||||||
|
"reference": "c3131244e29c08d44fefb49e0dd35021e9e39dd2"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/c3131244e29c08d44fefb49e0dd35021e9e39dd2",
|
||||||
|
"reference": "c3131244e29c08d44fefb49e0dd35021e9e39dd2",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^5.6.0|^7.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": "^0.5.0",
|
||||||
|
"phpcompatibility/php-compatibility": "^9.0",
|
||||||
|
"phpdocumentor/phpdocumentor": "2.*",
|
||||||
|
"phploc/phploc": "^4.0|^5.0|^6.0|^7.0",
|
||||||
|
"phpmd/phpmd": "2.*",
|
||||||
|
"phpunit/phpunit": "^4.8.35|^5.0|^6.0|^7.0",
|
||||||
|
"sebastian/phpcpd": "2.*",
|
||||||
|
"squizlabs/php_codesniffer": "^3.4.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"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"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Complex\\": "classes/src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/MarkBaker/PHPComplex/issues",
|
||||||
|
"source": "https://github.com/MarkBaker/PHPComplex/tree/1.5.0"
|
||||||
|
},
|
||||||
|
"time": "2020-08-26T19:47:57+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "markbaker/matrix",
|
||||||
|
"version": "1.2.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/MarkBaker/PHPMatrix.git",
|
||||||
|
"reference": "44bb1ab01811116f01fe216ab37d921dccc6c10d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/44bb1ab01811116f01fe216ab37d921dccc6c10d",
|
||||||
|
"reference": "44bb1ab01811116f01fe216ab37d921dccc6c10d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^5.6.0|^7.0.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
|
||||||
|
"phpcompatibility/php-compatibility": "dev-master",
|
||||||
|
"phploc/phploc": "^4",
|
||||||
|
"phpmd/phpmd": "dev-master",
|
||||||
|
"phpunit/phpunit": "^5.7|^6.0|7.0",
|
||||||
|
"sebastian/phpcpd": "^3.0",
|
||||||
|
"squizlabs/php_codesniffer": "^3.0@dev"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"classes/src/Functions/adjoint.php",
|
||||||
|
"classes/src/Functions/antidiagonal.php",
|
||||||
|
"classes/src/Functions/cofactors.php",
|
||||||
|
"classes/src/Functions/determinant.php",
|
||||||
|
"classes/src/Functions/diagonal.php",
|
||||||
|
"classes/src/Functions/identity.php",
|
||||||
|
"classes/src/Functions/inverse.php",
|
||||||
|
"classes/src/Functions/minors.php",
|
||||||
|
"classes/src/Functions/trace.php",
|
||||||
|
"classes/src/Functions/transpose.php",
|
||||||
|
"classes/src/Operations/add.php",
|
||||||
|
"classes/src/Operations/directsum.php",
|
||||||
|
"classes/src/Operations/subtract.php",
|
||||||
|
"classes/src/Operations/multiply.php",
|
||||||
|
"classes/src/Operations/divideby.php",
|
||||||
|
"classes/src/Operations/divideinto.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Matrix\\": "classes/src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Mark Baker",
|
||||||
|
"email": "mark@lange.demon.co.uk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP Class for working with matrices",
|
||||||
|
"homepage": "https://github.com/MarkBaker/PHPMatrix",
|
||||||
|
"keywords": [
|
||||||
|
"mathematics",
|
||||||
|
"matrix",
|
||||||
|
"vector"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/MarkBaker/PHPMatrix/issues",
|
||||||
|
"source": "https://github.com/MarkBaker/PHPMatrix/tree/1.2.3"
|
||||||
|
},
|
||||||
|
"time": "2021-01-26T14:36:01+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "phpoffice/phpspreadsheet",
|
||||||
|
"version": "1.12.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
|
||||||
|
"reference": "f79611d6dc1f6b7e8e30b738fc371b392001dbfd"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/f79611d6dc1f6b7e8e30b738fc371b392001dbfd",
|
||||||
|
"reference": "f79611d6dc1f6b7e8e30b738fc371b392001dbfd",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-ctype": "*",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-fileinfo": "*",
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"ext-libxml": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
|
"ext-xml": "*",
|
||||||
|
"ext-xmlreader": "*",
|
||||||
|
"ext-xmlwriter": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"ext-zlib": "*",
|
||||||
|
"markbaker/complex": "^1.4",
|
||||||
|
"markbaker/matrix": "^1.2",
|
||||||
|
"php": "^7.1",
|
||||||
|
"psr/simple-cache": "^1.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"dompdf/dompdf": "^0.8.3",
|
||||||
|
"friendsofphp/php-cs-fixer": "^2.16",
|
||||||
|
"jpgraph/jpgraph": "^4.0",
|
||||||
|
"mpdf/mpdf": "^8.0",
|
||||||
|
"phpcompatibility/php-compatibility": "^9.3",
|
||||||
|
"phpunit/phpunit": "^7.5",
|
||||||
|
"squizlabs/php_codesniffer": "^3.5",
|
||||||
|
"tecnickcom/tcpdf": "^6.3"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"dompdf/dompdf": "Option for rendering PDF with PDF Writer",
|
||||||
|
"jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
|
||||||
|
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
|
||||||
|
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Maarten Balliauw",
|
||||||
|
"homepage": "https://blog.maartenballiauw.be"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mark Baker",
|
||||||
|
"homepage": "https://markbakeruk.net"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Franck Lefevre",
|
||||||
|
"homepage": "https://rootslabs.net"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Erik Tilt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Adrien Crivelli"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
|
||||||
|
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
|
||||||
|
"keywords": [
|
||||||
|
"OpenXML",
|
||||||
|
"excel",
|
||||||
|
"gnumeric",
|
||||||
|
"ods",
|
||||||
|
"php",
|
||||||
|
"spreadsheet",
|
||||||
|
"xls",
|
||||||
|
"xlsx"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
|
||||||
|
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.12.0"
|
||||||
|
},
|
||||||
|
"time": "2020-04-27T08:12:48+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "psr/simple-cache",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-fig/simple-cache.git",
|
||||||
|
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
|
||||||
|
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Psr\\SimpleCache\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "PHP-FIG",
|
||||||
|
"homepage": "http://www.php-fig.org/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Common interfaces for simple caching",
|
||||||
|
"keywords": [
|
||||||
|
"cache",
|
||||||
|
"caching",
|
||||||
|
"psr",
|
||||||
|
"psr-16",
|
||||||
|
"simple-cache"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/php-fig/simple-cache/tree/master"
|
||||||
|
},
|
||||||
|
"time": "2017-10-23T01:57:42+00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": [],
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": [],
|
||||||
|
"platform-dev": [],
|
||||||
|
"plugin-api-version": "2.0.0"
|
||||||
|
}
|
||||||
@ -92,7 +92,7 @@ class ExportExcel2007 extends ModeleExports
|
|||||||
if (empty($this->disabled)) {
|
if (empty($this->disabled)) {
|
||||||
require_once PHPEXCELNEW_PATH.'Spreadsheet.php';
|
require_once PHPEXCELNEW_PATH.'Spreadsheet.php';
|
||||||
$this->label_lib = 'PhpSpreadSheet';
|
$this->label_lib = 'PhpSpreadSheet';
|
||||||
$this->version_lib = '1.6.0'; // No way to get info from library
|
$this->version_lib = '1.12.0'; // No way to get info from library
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->row = 0;
|
$this->row = 0;
|
||||||
|
|||||||
@ -41,7 +41,7 @@ class modFournisseur extends DolibarrModules
|
|||||||
*/
|
*/
|
||||||
public function __construct($db)
|
public function __construct($db)
|
||||||
{
|
{
|
||||||
global $conf, $user;
|
global $conf, $langs, $user;
|
||||||
|
|
||||||
$this->db = $db;
|
$this->db = $db;
|
||||||
$this->numero = 40;
|
$this->numero = 40;
|
||||||
@ -309,6 +309,8 @@ class modFournisseur extends DolibarrModules
|
|||||||
//--------
|
//--------
|
||||||
$r = 0;
|
$r = 0;
|
||||||
|
|
||||||
|
$langs->loadLangs(array("suppliers", "multicurrency"));
|
||||||
|
|
||||||
$r++;
|
$r++;
|
||||||
$this->export_code[$r] = $this->rights_class.'_'.$r;
|
$this->export_code[$r] = $this->rights_class.'_'.$r;
|
||||||
$this->export_label[$r] = 'Vendor invoices and lines of invoices';
|
$this->export_label[$r] = 'Vendor invoices and lines of invoices';
|
||||||
|
|||||||
@ -765,7 +765,7 @@ class modProduct extends DolibarrModules
|
|||||||
'sp.quantity' => "QtyMin*",
|
'sp.quantity' => "QtyMin*",
|
||||||
'sp.tva_tx' => 'VATRate',
|
'sp.tva_tx' => 'VATRate',
|
||||||
'sp.default_vat_code' => 'VATCode',
|
'sp.default_vat_code' => 'VATCode',
|
||||||
'sp.delivery_time_days' => 'DeliveryDelay',
|
'sp.delivery_time_days' => 'NbDaysToDelivery',
|
||||||
'sp.supplier_reputation' => 'SupplierReputation',
|
'sp.supplier_reputation' => 'SupplierReputation',
|
||||||
'sp.status' => 'Status'
|
'sp.status' => 'Status'
|
||||||
);
|
);
|
||||||
|
|||||||
@ -722,7 +722,7 @@ class modService extends DolibarrModules
|
|||||||
'sp.quantity' => "QtyMin*",
|
'sp.quantity' => "QtyMin*",
|
||||||
'sp.tva_tx' => 'VATRate',
|
'sp.tva_tx' => 'VATRate',
|
||||||
'sp.default_vat_code' => 'VATCode',
|
'sp.default_vat_code' => 'VATCode',
|
||||||
'sp.delivery_time_days' => 'DeliveryDelay',
|
'sp.delivery_time_days' => 'NbDaysToDelivery',
|
||||||
'sp.supplier_reputation' => 'SupplierReputation'
|
'sp.supplier_reputation' => 'SupplierReputation'
|
||||||
);
|
);
|
||||||
if (is_object($mysoc) && $usenpr) {
|
if (is_object($mysoc) && $usenpr) {
|
||||||
|
|||||||
@ -36,7 +36,6 @@ include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php';
|
|||||||
*/
|
*/
|
||||||
class modSupplierProposal extends DolibarrModules
|
class modSupplierProposal extends DolibarrModules
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor. Define names, constants, directories, boxes, permissions
|
* Constructor. Define names, constants, directories, boxes, permissions
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1180,7 +1180,8 @@ if ($step == 5 && $datatoexport) {
|
|||||||
print '<br>';
|
print '<br>';
|
||||||
|
|
||||||
// List of available export formats
|
// List of available export formats
|
||||||
$htmltabloflibs = '<table class="noborder centpercent">';
|
$htmltabloflibs = '<!-- Table with available export formats --><br>';
|
||||||
|
$htmltabloflibs .= '<table class="noborder centpercent nomarginbottom">';
|
||||||
$htmltabloflibs .= '<tr class="liste_titre">';
|
$htmltabloflibs .= '<tr class="liste_titre">';
|
||||||
$htmltabloflibs .= '<td>'.$langs->trans("AvailableFormats").'</td>';
|
$htmltabloflibs .= '<td>'.$langs->trans("AvailableFormats").'</td>';
|
||||||
$htmltabloflibs .= '<td>'.$langs->trans("LibraryUsed").'</td>';
|
$htmltabloflibs .= '<td>'.$langs->trans("LibraryUsed").'</td>';
|
||||||
@ -1204,7 +1205,7 @@ if ($step == 5 && $datatoexport) {
|
|||||||
$htmltabloflibs .= '<td class="right">'.$objmodelexport->getLibVersionForKey($key).'</td>';
|
$htmltabloflibs .= '<td class="right">'.$objmodelexport->getLibVersionForKey($key).'</td>';
|
||||||
$htmltabloflibs .= '</tr>'."\n";
|
$htmltabloflibs .= '</tr>'."\n";
|
||||||
}
|
}
|
||||||
$htmltabloflibs .= '</table>';
|
$htmltabloflibs .= '</table><br>';
|
||||||
|
|
||||||
print '<span class="opacitymedium">'.$form->textwithpicto($langs->trans("NowClickToGenerateToBuildExportFile"), $htmltabloflibs, 1, 'help', '', 0, 2, 'helphonformat').'</span>';
|
print '<span class="opacitymedium">'.$form->textwithpicto($langs->trans("NowClickToGenerateToBuildExportFile"), $htmltabloflibs, 1, 'help', '', 0, 2, 'helphonformat').'</span>';
|
||||||
//print $htmltabloflibs;
|
//print $htmltabloflibs;
|
||||||
|
|||||||
4
htdocs/includes/phpoffice/phpspreadsheet/.gitattributes
vendored
Normal file
4
htdocs/includes/phpoffice/phpspreadsheet/.gitattributes
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/tests export-ignore
|
||||||
|
README.md export-ignore
|
||||||
|
*.min.js binary
|
||||||
|
/.github export-ignore
|
||||||
10
htdocs/includes/phpoffice/phpspreadsheet/.gitignore
vendored
Normal file
10
htdocs/includes/phpoffice/phpspreadsheet/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/tests/codeCoverage
|
||||||
|
/analysis
|
||||||
|
/vendor/
|
||||||
|
/phpunit.xml
|
||||||
|
|
||||||
|
## IDE support
|
||||||
|
*.buildpath
|
||||||
|
*.project
|
||||||
|
/.settings
|
||||||
|
/.idea
|
||||||
183
htdocs/includes/phpoffice/phpspreadsheet/.php_cs.dist
Normal file
183
htdocs/includes/phpoffice/phpspreadsheet/.php_cs.dist
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$finder = PhpCsFixer\Finder::create()
|
||||||
|
->exclude(['vendor', 'tests/data/Calculation'])
|
||||||
|
->in('samples')
|
||||||
|
->in('src')
|
||||||
|
->in('tests/PhpSpreadsheetTests')
|
||||||
|
;
|
||||||
|
|
||||||
|
return PhpCsFixer\Config::create()
|
||||||
|
->setRiskyAllowed(true)
|
||||||
|
->setFinder($finder)
|
||||||
|
->setCacheFile(sys_get_temp_dir() . '/php-cs-fixer' . preg_replace('~\W~', '-', __DIR__))
|
||||||
|
->setRules([
|
||||||
|
'align_multiline_comment' => true,
|
||||||
|
'array_syntax' => ['syntax' => 'short'],
|
||||||
|
'backtick_to_shell_exec' => true,
|
||||||
|
'binary_operator_spaces' => true,
|
||||||
|
'blank_line_after_namespace' => true,
|
||||||
|
'blank_line_after_opening_tag' => true,
|
||||||
|
'blank_line_before_statement' => true,
|
||||||
|
'braces' => true,
|
||||||
|
'cast_spaces' => true,
|
||||||
|
'class_attributes_separation' => ['elements' => ['method', 'property']], // const are often grouped with other related const
|
||||||
|
'class_definition' => true,
|
||||||
|
'class_keyword_remove' => false, // ::class keyword gives us beter support in IDE
|
||||||
|
'combine_consecutive_issets' => true,
|
||||||
|
'combine_consecutive_unsets' => true,
|
||||||
|
'compact_nullable_typehint' => true,
|
||||||
|
'concat_space' => ['spacing' => 'one'],
|
||||||
|
'declare_equal_normalize' => true,
|
||||||
|
'declare_strict_types' => false, // Too early to adopt strict types
|
||||||
|
'dir_constant' => true,
|
||||||
|
'doctrine_annotation_array_assignment' => true,
|
||||||
|
'doctrine_annotation_braces' => true,
|
||||||
|
'doctrine_annotation_indentation' => true,
|
||||||
|
'doctrine_annotation_spaces' => true,
|
||||||
|
'elseif' => true,
|
||||||
|
'encoding' => true,
|
||||||
|
'ereg_to_preg' => true,
|
||||||
|
'escape_implicit_backslashes' => true,
|
||||||
|
'explicit_indirect_variable' => false, // I feel it makes the code actually harder to read
|
||||||
|
'explicit_string_variable' => false, // I feel it makes the code actually harder to read
|
||||||
|
'final_internal_class' => true,
|
||||||
|
'full_opening_tag' => true,
|
||||||
|
'function_declaration' => true,
|
||||||
|
'function_to_constant' => true,
|
||||||
|
'function_typehint_space' => true,
|
||||||
|
'general_phpdoc_annotation_remove' => false, // No use for that
|
||||||
|
'hash_to_slash_comment' => true,
|
||||||
|
'header_comment' => false, // We don't use common header in all our files
|
||||||
|
'heredoc_to_nowdoc' => false, // Not sure about this one
|
||||||
|
'include' => true,
|
||||||
|
'increment_style' => true,
|
||||||
|
'indentation_type' => true,
|
||||||
|
'is_null' => ['use_yoda_style' => false],
|
||||||
|
'linebreak_after_opening_tag' => true,
|
||||||
|
'line_ending' => true,
|
||||||
|
'list_syntax' => ['syntax' => 'short'],
|
||||||
|
'lowercase_cast' => true,
|
||||||
|
'lowercase_constants' => true,
|
||||||
|
'lowercase_keywords' => true,
|
||||||
|
'magic_constant_casing' => true,
|
||||||
|
'mb_str_functions' => false, // No, too dangerous to change that
|
||||||
|
'method_argument_space' => true,
|
||||||
|
'method_chaining_indentation' => true,
|
||||||
|
'method_separation' => true,
|
||||||
|
'modernize_types_casting' => true,
|
||||||
|
'multiline_comment_opening_closing' => true,
|
||||||
|
'native_function_casing' => true,
|
||||||
|
'native_function_invocation' => false, // This is risky and seems to be micro-optimization that make code uglier so not worth it, at least for now
|
||||||
|
'new_with_braces' => true,
|
||||||
|
'no_alias_functions' => true,
|
||||||
|
'no_blank_lines_after_class_opening' => true,
|
||||||
|
'no_blank_lines_after_phpdoc' => true,
|
||||||
|
'no_blank_lines_before_namespace' => false, // we want 1 blank line before namespace
|
||||||
|
'no_break_comment' => true,
|
||||||
|
'no_closing_tag' => true,
|
||||||
|
'no_empty_comment' => true,
|
||||||
|
'no_empty_phpdoc' => true,
|
||||||
|
'no_empty_statement' => true,
|
||||||
|
'no_extra_blank_lines' => true,
|
||||||
|
'no_homoglyph_names' => true,
|
||||||
|
'no_leading_import_slash' => true,
|
||||||
|
'no_leading_namespace_whitespace' => true,
|
||||||
|
'no_mixed_echo_print' => true,
|
||||||
|
'no_multiline_whitespace_around_double_arrow' => true,
|
||||||
|
'no_multiline_whitespace_before_semicolons' => true,
|
||||||
|
'non_printable_character' => true,
|
||||||
|
'no_null_property_initialization' => true,
|
||||||
|
'no_php4_constructor' => true,
|
||||||
|
'normalize_index_brace' => true,
|
||||||
|
'no_short_bool_cast' => true,
|
||||||
|
'no_short_echo_tag' => true,
|
||||||
|
'no_singleline_whitespace_before_semicolons' => true,
|
||||||
|
'no_spaces_after_function_name' => true,
|
||||||
|
'no_spaces_around_offset' => true,
|
||||||
|
'no_spaces_inside_parenthesis' => true,
|
||||||
|
'no_superfluous_elseif' => false, // Might be risky on a huge code base
|
||||||
|
'not_operator_with_space' => false, // No we prefer to keep '!' without spaces
|
||||||
|
'not_operator_with_successor_space' => false, // idem
|
||||||
|
'no_trailing_comma_in_list_call' => true,
|
||||||
|
'no_trailing_comma_in_singleline_array' => true,
|
||||||
|
'no_trailing_whitespace_in_comment' => true,
|
||||||
|
'no_trailing_whitespace' => true,
|
||||||
|
'no_unneeded_control_parentheses' => true,
|
||||||
|
'no_unneeded_curly_braces' => true,
|
||||||
|
'no_unneeded_final_method' => true,
|
||||||
|
'no_unreachable_default_argument_value' => true,
|
||||||
|
'no_unused_imports' => true,
|
||||||
|
'no_useless_else' => true,
|
||||||
|
'no_useless_return' => true,
|
||||||
|
'no_whitespace_before_comma_in_array' => true,
|
||||||
|
'no_whitespace_in_blank_line' => true,
|
||||||
|
'object_operator_without_whitespace' => true,
|
||||||
|
'ordered_class_elements' => false, // We prefer to keep some freedom
|
||||||
|
'ordered_imports' => true,
|
||||||
|
'phpdoc_add_missing_param_annotation' => true,
|
||||||
|
'phpdoc_align' => false, // Waste of time
|
||||||
|
'phpdoc_annotation_without_dot' => true,
|
||||||
|
'phpdoc_indent' => true,
|
||||||
|
'phpdoc_inline_tag' => true,
|
||||||
|
'phpdoc_no_access' => true,
|
||||||
|
'phpdoc_no_alias_tag' => true,
|
||||||
|
'phpdoc_no_empty_return' => true,
|
||||||
|
'phpdoc_no_package' => true,
|
||||||
|
'phpdoc_no_useless_inheritdoc' => true,
|
||||||
|
'phpdoc_order' => true,
|
||||||
|
'phpdoc_return_self_reference' => true,
|
||||||
|
'phpdoc_scalar' => true,
|
||||||
|
'phpdoc_separation' => true,
|
||||||
|
'phpdoc_single_line_var_spacing' => true,
|
||||||
|
'phpdoc_summary' => true,
|
||||||
|
'phpdoc_to_comment' => true,
|
||||||
|
'phpdoc_trim' => true,
|
||||||
|
'phpdoc_types_order' => true,
|
||||||
|
'phpdoc_types' => true,
|
||||||
|
'phpdoc_var_without_name' => true,
|
||||||
|
'php_unit_construct' => true,
|
||||||
|
'php_unit_dedicate_assert' => true,
|
||||||
|
'php_unit_expectation' => true,
|
||||||
|
'php_unit_fqcn_annotation' => true,
|
||||||
|
'php_unit_mock' => true,
|
||||||
|
'php_unit_namespaced' => true,
|
||||||
|
'php_unit_no_expectation_annotation' => true,
|
||||||
|
'php_unit_strict' => false, // We sometime actually need assertEquals
|
||||||
|
'php_unit_test_annotation' => true,
|
||||||
|
'php_unit_test_class_requires_covers' => false, // We don't care as much as we should about coverage
|
||||||
|
'pow_to_exponentiation' => false,
|
||||||
|
'protected_to_private' => true,
|
||||||
|
'psr0' => true,
|
||||||
|
'psr4' => true,
|
||||||
|
'random_api_migration' => false, // This breaks our unit tests
|
||||||
|
'return_type_declaration' => true,
|
||||||
|
'self_accessor' => true,
|
||||||
|
'semicolon_after_instruction' => false, // Buggy in `samples/index.php`
|
||||||
|
'short_scalar_cast' => true,
|
||||||
|
'silenced_deprecation_error' => true,
|
||||||
|
'simplified_null_return' => false, // While technically correct we prefer to be explicit when returning null
|
||||||
|
'single_blank_line_at_eof' => true,
|
||||||
|
'single_blank_line_before_namespace' => true,
|
||||||
|
'single_class_element_per_statement' => true,
|
||||||
|
'single_import_per_statement' => true,
|
||||||
|
'single_line_after_imports' => true,
|
||||||
|
'single_line_comment_style' => true,
|
||||||
|
'single_quote' => true,
|
||||||
|
'space_after_semicolon' => true,
|
||||||
|
'standardize_not_equals' => true,
|
||||||
|
'static_lambda' => false, // Risky if we can't guarantee nobody use `bindTo()`
|
||||||
|
'strict_comparison' => false, // No, too dangerous to change that
|
||||||
|
'strict_param' => false, // No, too dangerous to change that
|
||||||
|
'switch_case_semicolon_to_colon' => true,
|
||||||
|
'switch_case_space' => true,
|
||||||
|
'ternary_operator_spaces' => true,
|
||||||
|
'ternary_to_null_coalescing' => true,
|
||||||
|
'trailing_comma_in_multiline_array' => true,
|
||||||
|
'trim_array_spaces' => true,
|
||||||
|
'unary_operator_spaces' => true,
|
||||||
|
'visibility_required' => true,
|
||||||
|
'void_return' => false, // Cannot use that with PHP 5.6
|
||||||
|
'whitespace_after_comma_in_array' => true,
|
||||||
|
'yoda_style' => false,
|
||||||
|
]);
|
||||||
27
htdocs/includes/phpoffice/phpspreadsheet/.scrutinizer.yml
Normal file
27
htdocs/includes/phpoffice/phpspreadsheet/.scrutinizer.yml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
checks:
|
||||||
|
php: true
|
||||||
|
|
||||||
|
coding_style:
|
||||||
|
php:
|
||||||
|
spaces:
|
||||||
|
before_parentheses:
|
||||||
|
closure_definition: true
|
||||||
|
around_operators:
|
||||||
|
concatenation: true
|
||||||
|
|
||||||
|
build:
|
||||||
|
nodes:
|
||||||
|
analysis:
|
||||||
|
tests:
|
||||||
|
override:
|
||||||
|
- php-scrutinizer-run
|
||||||
|
|
||||||
|
tools:
|
||||||
|
external_code_coverage:
|
||||||
|
timeout: 3600
|
||||||
|
|
||||||
|
build_failure_conditions:
|
||||||
|
- 'elements.rating(<= C).new.exists' # No new classes/methods with a rating of C or worse allowed
|
||||||
|
- 'issues.severity(>= MAJOR).new.exists' # New issues of major or higher severity
|
||||||
|
- 'project.metric_change("scrutinizer.test_coverage", < 0)' # Code Coverage decreased from previous inspection
|
||||||
|
- 'patches.label("Unused Use Statements").new.exists' # No new unused imports patches allowed
|
||||||
57
htdocs/includes/phpoffice/phpspreadsheet/.travis.yml
Normal file
57
htdocs/includes/phpoffice/phpspreadsheet/.travis.yml
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
language: php
|
||||||
|
dist: bionic
|
||||||
|
|
||||||
|
php:
|
||||||
|
- 7.1
|
||||||
|
- 7.2
|
||||||
|
- 7.3
|
||||||
|
- 7.4
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- vendor
|
||||||
|
- $HOME/.composer/cache
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
# Deactivate xdebug
|
||||||
|
- phpenv config-rm xdebug.ini
|
||||||
|
- composer install --ignore-platform-reqs
|
||||||
|
|
||||||
|
script:
|
||||||
|
- ./vendor/bin/phpunit
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
include:
|
||||||
|
|
||||||
|
- stage: Code style
|
||||||
|
php: 7.2
|
||||||
|
script:
|
||||||
|
- ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run
|
||||||
|
- ./vendor/bin/phpcs --report-width=200 samples/ src/ tests/ --ignore=samples/Header.php --standard=PSR2 -n
|
||||||
|
|
||||||
|
- stage: Coverage
|
||||||
|
php: 7.2
|
||||||
|
script:
|
||||||
|
- pecl install pcov
|
||||||
|
- composer require pcov/clobber --dev
|
||||||
|
- ./vendor/bin/pcov clobber
|
||||||
|
- ./vendor/bin/phpunit --coverage-clover coverage-clover.xml
|
||||||
|
after_script:
|
||||||
|
- wget https://scrutinizer-ci.com/ocular.phar
|
||||||
|
- php ocular.phar code-coverage:upload --format=php-clover tests/coverage-clover.xml
|
||||||
|
|
||||||
|
- stage: API documentations
|
||||||
|
if: tag is present
|
||||||
|
php: 7.4
|
||||||
|
before_script:
|
||||||
|
- curl -O https://github.com/phpDocumentor/phpDocumentor/releases/download/v3.0.0-rc/phpDocumentor.phar
|
||||||
|
script:
|
||||||
|
- php phpDocumentor.phar --directory src/ --target docs/api
|
||||||
|
deploy:
|
||||||
|
provider: pages
|
||||||
|
skip-cleanup: true
|
||||||
|
local-dir: docs/api
|
||||||
|
github-token: $GITHUB_TOKEN
|
||||||
|
on:
|
||||||
|
all_branches: true
|
||||||
|
condition: $TRAVIS_BRANCH =~ ^master$
|
||||||
1593
htdocs/includes/phpoffice/phpspreadsheet/CHANGELOG.PHPExcel.md
Normal file
1593
htdocs/includes/phpoffice/phpspreadsheet/CHANGELOG.PHPExcel.md
Normal file
File diff suppressed because it is too large
Load Diff
471
htdocs/includes/phpoffice/phpspreadsheet/CHANGELOG.md
Normal file
471
htdocs/includes/phpoffice/phpspreadsheet/CHANGELOG.md
Normal file
@ -0,0 +1,471 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com)
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org).
|
||||||
|
|
||||||
|
## [1.12.0] - 2020-04-27
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Improved the ARABIC function to also handle short-hand roman numerals
|
||||||
|
- Added support for the FLOOR.MATH and FLOOR.PRECISE functions [#1351](https://github.com/PHPOffice/PhpSpreadsheet/pull/1351)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix ROUNDUP and ROUNDDOWN for floating-point rounding error [#1404](https://github.com/PHPOffice/PhpSpreadsheet/pull/1404)
|
||||||
|
- Fix ROUNDUP and ROUNDDOWN for negative number [#1417](https://github.com/PHPOffice/PhpSpreadsheet/pull/1417)
|
||||||
|
- Fix loading styles from vmlDrawings when containing whitespace [#1347](https://github.com/PHPOffice/PhpSpreadsheet/issues/1347)
|
||||||
|
- Fix incorrect behavior when removing last row [#1365](https://github.com/PHPOffice/PhpSpreadsheet/pull/1365)
|
||||||
|
- MATCH with a static array should return the position of the found value based on the values submitted [#1332](https://github.com/PHPOffice/PhpSpreadsheet/pull/1332)
|
||||||
|
- Fix Xlsx Reader's handling of undefined fill color [#1353](https://github.com/PHPOffice/PhpSpreadsheet/pull/1353)
|
||||||
|
|
||||||
|
## [1.11.0] - 2020-03-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added support for the BASE function
|
||||||
|
- Added support for the ARABIC function
|
||||||
|
- Conditionals - Extend Support for (NOT)CONTAINSBLANKS [#1278](https://github.com/PHPOffice/PhpSpreadsheet/pull/1278)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Handle Error in Formula Processing Better for Xls [#1267](https://github.com/PHPOffice/PhpSpreadsheet/pull/1267)
|
||||||
|
- Handle ConditionalStyle NumberFormat When Reading Xlsx File [#1296](https://github.com/PHPOffice/PhpSpreadsheet/pull/1296)
|
||||||
|
- Fix Xlsx Writer's handling of decimal commas [#1282](https://github.com/PHPOffice/PhpSpreadsheet/pull/1282)
|
||||||
|
- Fix for issue by removing test code mistakenly left in [#1328](https://github.com/PHPOffice/PhpSpreadsheet/pull/1328)
|
||||||
|
- Fix for Xls writer wrong selected cells and active sheet [#1256](https://github.com/PHPOffice/PhpSpreadsheet/pull/1256)
|
||||||
|
- Fix active cell when freeze pane is used [#1323](https://github.com/PHPOffice/PhpSpreadsheet/pull/1323)
|
||||||
|
- Fix XLSX file loading with autofilter containing '$' [#1326](https://github.com/PHPOffice/PhpSpreadsheet/pull/1326)
|
||||||
|
- PHPDoc - Use `@return $this` for fluent methods [#1362](https://github.com/PHPOffice/PhpSpreadsheet/pull/1362)
|
||||||
|
|
||||||
|
## [1.10.1] - 2019-12-02
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- PHP 7.4 compatibility
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- FLOOR() function accept negative number and negative significance [#1245](https://github.com/PHPOffice/PhpSpreadsheet/pull/1245)
|
||||||
|
- Correct column style even when using rowspan [#1249](https://github.com/PHPOffice/PhpSpreadsheet/pull/1249)
|
||||||
|
- Do not confuse defined names and cell refs [#1263](https://github.com/PHPOffice/PhpSpreadsheet/pull/1263)
|
||||||
|
- XLSX reader/writer keep decimal for floats with a zero decimal part [#1262](https://github.com/PHPOffice/PhpSpreadsheet/pull/1262)
|
||||||
|
- ODS writer prevent invalid numeric value if locale decimal separator is comma [#1268](https://github.com/PHPOffice/PhpSpreadsheet/pull/1268)
|
||||||
|
- Xlsx writer actually writes plotVisOnly and dispBlanksAs from chart properties [#1266](https://github.com/PHPOffice/PhpSpreadsheet/pull/1266)
|
||||||
|
|
||||||
|
## [1.10.0] - 2019-11-18
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Change license from LGPL 2.1 to MIT [#140](https://github.com/PHPOffice/PhpSpreadsheet/issues/140)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Implementation of IFNA() logical function
|
||||||
|
- Support "showZeros" worksheet option to change how Excel shows and handles "null" values returned from a calculation
|
||||||
|
- Allow HTML Reader to accept HTML as a string into an existing spreadsheet [#1212](https://github.com/PHPOffice/PhpSpreadsheet/pull/1212)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- IF implementation properly handles the value `#N/A` [#1165](https://github.com/PHPOffice/PhpSpreadsheet/pull/1165)
|
||||||
|
- Formula Parser: Wrong line count for stuff like "MyOtherSheet!A:D" [#1215](https://github.com/PHPOffice/PhpSpreadsheet/issues/1215)
|
||||||
|
- Call garbage collector after removing a column to prevent stale cached values
|
||||||
|
- Trying to remove a column that doesn't exist deletes the latest column
|
||||||
|
- Keep big integer as integer instead of lossely casting to float [#874](https://github.com/PHPOffice/PhpSpreadsheet/pull/874)
|
||||||
|
- Fix branch pruning handling of non boolean conditions [#1167](https://github.com/PHPOffice/PhpSpreadsheet/pull/1167)
|
||||||
|
- Fix ODS Reader when no DC namespace are defined [#1182](https://github.com/PHPOffice/PhpSpreadsheet/pull/1182)
|
||||||
|
- Fixed Functions->ifCondition for allowing <> and empty condition [#1206](https://github.com/PHPOffice/PhpSpreadsheet/pull/1206)
|
||||||
|
- Validate XIRR inputs and return correct error values [#1120](https://github.com/PHPOffice/PhpSpreadsheet/issues/1120)
|
||||||
|
- Allow to read xlsx files with exotic workbook names like "workbook2.xml" [#1183](https://github.com/PHPOffice/PhpSpreadsheet/pull/1183)
|
||||||
|
|
||||||
|
## [1.9.0] - 2019-08-17
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Drop support for PHP 5.6 and 7.0, according to https://phpspreadsheet.readthedocs.io/en/latest/#php-version-support
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- When <br> appears in a table cell, set the cell to wrap [#1071](https://github.com/PHPOffice/PhpSpreadsheet/issues/1071) and [#1070](https://github.com/PHPOffice/PhpSpreadsheet/pull/1070)
|
||||||
|
- Add MAXIFS, MINIFS, COUNTIFS and Remove MINIF, MAXIF [#1056](https://github.com/PHPOffice/PhpSpreadsheet/issues/1056)
|
||||||
|
- HLookup needs an ordered list even if range_lookup is set to false [#1055](https://github.com/PHPOffice/PhpSpreadsheet/issues/1055) and [#1076](https://github.com/PHPOffice/PhpSpreadsheet/pull/1076)
|
||||||
|
- Improve performance of IF function calls via ranch pruning to avoid resolution of every branches [#844](https://github.com/PHPOffice/PhpSpreadsheet/pull/844)
|
||||||
|
- MATCH function supports `*?~` Excel functionality, when match_type=0 [#1116](https://github.com/PHPOffice/PhpSpreadsheet/issues/1116)
|
||||||
|
- Allow HTML Reader to accept HTML as a string [#1136](https://github.com/PHPOffice/PhpSpreadsheet/pull/1136)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix to AVERAGEIF() function when called with a third argument
|
||||||
|
- Eliminate duplicate fill none style entries [#1066](https://github.com/PHPOffice/PhpSpreadsheet/issues/1066)
|
||||||
|
- Fix number format masks containing literal (non-decimal point) dots [#1079](https://github.com/PHPOffice/PhpSpreadsheet/issues/1079)
|
||||||
|
- Fix number format masks containing named colours that were being misinterpreted as date formats; and add support for masks that fully replace the value with a full text string [#1009](https://github.com/PHPOffice/PhpSpreadsheet/issues/1009)
|
||||||
|
- Stricter-typed comparison testing in COUNTIF() and COUNTIFS() evaluation [#1046](https://github.com/PHPOffice/PhpSpreadsheet/issues/1046)
|
||||||
|
- COUPNUM should not return zero when settlement is in the last period [#1020](https://github.com/PHPOffice/PhpSpreadsheet/issues/1020) and [#1021](https://github.com/PHPOffice/PhpSpreadsheet/pull/1021)
|
||||||
|
- Fix handling of named ranges referencing sheets with spaces or "!" in their title
|
||||||
|
- Cover `getSheetByName()` with tests for name with quote and spaces [#739](https://github.com/PHPOffice/PhpSpreadsheet/issues/739)
|
||||||
|
- Best effort to support invalid colspan values in HTML reader - [#878](https://github.com/PHPOffice/PhpSpreadsheet/pull/878)
|
||||||
|
- Fixes incorrect rows deletion [#868](https://github.com/PHPOffice/PhpSpreadsheet/issues/868)
|
||||||
|
- MATCH function fix (value search by type, stop search when match_type=-1 and unordered element encountered) [#1116](https://github.com/PHPOffice/PhpSpreadsheet/issues/1116)
|
||||||
|
- Fix `getCalculatedValue()` error with more than two INDIRECT [#1115](https://github.com/PHPOffice/PhpSpreadsheet/pull/1115)
|
||||||
|
- Writer\Html did not hide columns [#985](https://github.com/PHPOffice/PhpSpreadsheet/pull/985)
|
||||||
|
|
||||||
|
## [1.8.2] - 2019-07-08
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Uncaught error when opening ods file and properties aren't defined [#1047](https://github.com/PHPOffice/PhpSpreadsheet/issues/1047)
|
||||||
|
- Xlsx Reader Cell datavalidations bug [#1052](https://github.com/PHPOffice/PhpSpreadsheet/pull/1052)
|
||||||
|
|
||||||
|
## [1.8.1] - 2019-07-02
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Allow nullable theme for Xlsx Style Reader class [#1043](https://github.com/PHPOffice/PhpSpreadsheet/issues/1043)
|
||||||
|
|
||||||
|
## [1.8.0] - 2019-07-01
|
||||||
|
|
||||||
|
### Security Fix (CVE-2019-12331)
|
||||||
|
|
||||||
|
- Detect double-encoded xml in the Security scanner, and reject as suspicious.
|
||||||
|
- This change also broadens the scope of the `libxml_disable_entity_loader` setting when reading XML-based formats, so that it is enabled while the xml is being parsed and not simply while it is loaded.
|
||||||
|
On some versions of PHP, this can cause problems because it is not thread-safe, and can affect other PHP scripts running on the same server. This flag is set to true when instantiating a loader, and back to its original setting when the Reader is no longer in scope, or manually unset.
|
||||||
|
- Provide a check to identify whether libxml_disable_entity_loader is thread-safe or not.
|
||||||
|
|
||||||
|
`XmlScanner::threadSafeLibxmlDisableEntityLoaderAvailability()`
|
||||||
|
- Provide an option to disable the libxml_disable_entity_loader call through settings. This is not recommended as it reduces the security of the XML-based readers, and should only be used if you understand the consequences and have no other choice.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added support for the SWITCH function [#963](https://github.com/PHPOffice/PhpSpreadsheet/issues/963) and [#983](https://github.com/PHPOffice/PhpSpreadsheet/pull/983)
|
||||||
|
- Add accounting number format style [#974](https://github.com/PHPOffice/PhpSpreadsheet/pull/974)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Whitelist `tsv` extension when opening CSV files [#429](https://github.com/PHPOffice/PhpSpreadsheet/issues/429)
|
||||||
|
- Fix a SUMIF warning with some versions of PHP when having different length of arrays provided as input [#873](https://github.com/PHPOffice/PhpSpreadsheet/pull/873)
|
||||||
|
- Fix incorrectly handled backslash-escaped space characters in number format
|
||||||
|
|
||||||
|
## [1.7.0] - 2019-05-26
|
||||||
|
|
||||||
|
- Added support for inline styles in Html reader (borders, alignment, width, height)
|
||||||
|
- QuotedText cells no longer treated as formulae if the content begins with a `=`
|
||||||
|
- Clean handling for DDE in formulae
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix handling for escaped enclosures and new lines in CSV Separator Inference
|
||||||
|
- Fix MATCH an error was appearing when comparing strings against 0 (always true)
|
||||||
|
- Fix wrong calculation of highest column with specified row [#700](https://github.com/PHPOffice/PhpSpreadsheet/issues/700)
|
||||||
|
- Fix VLOOKUP
|
||||||
|
- Fix return type hint
|
||||||
|
|
||||||
|
## [1.6.0] - 2019-01-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Refactored Matrix Functions to use external Matrix library
|
||||||
|
- Possibility to specify custom colors of values for pie and donut charts [#768](https://github.com/PHPOffice/PhpSpreadsheet/pull/768)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Improve XLSX parsing speed if no readFilter is applied [#772](https://github.com/PHPOffice/PhpSpreadsheet/issues/772)
|
||||||
|
- Fix column names if read filter calls in XLSX reader skip columns [#777](https://github.com/PHPOffice/PhpSpreadsheet/pull/777)
|
||||||
|
- XLSX reader can now ignore blank cells, using the setReadEmptyCells(false) method. [#810](https://github.com/PHPOffice/PhpSpreadsheet/issues/810)
|
||||||
|
- Fix LOOKUP function which was breaking on edge cases [#796](https://github.com/PHPOffice/PhpSpreadsheet/issues/796)
|
||||||
|
- Fix VLOOKUP with exact matches [#809](https://github.com/PHPOffice/PhpSpreadsheet/pull/809)
|
||||||
|
- Support COUNTIFS multiple arguments [#830](https://github.com/PHPOffice/PhpSpreadsheet/pull/830)
|
||||||
|
- Change `libxml_disable_entity_loader()` as shortly as possible [#819](https://github.com/PHPOffice/PhpSpreadsheet/pull/819)
|
||||||
|
- Improved memory usage and performance when loading large spreadsheets [#822](https://github.com/PHPOffice/PhpSpreadsheet/pull/822)
|
||||||
|
- Improved performance when loading large spreadsheets [#825](https://github.com/PHPOffice/PhpSpreadsheet/pull/825)
|
||||||
|
- Improved performance when loading large spreadsheets [#824](https://github.com/PHPOffice/PhpSpreadsheet/pull/824)
|
||||||
|
- Fix color from CSS when reading from HTML [#831](https://github.com/PHPOffice/PhpSpreadsheet/pull/831)
|
||||||
|
- Fix infinite loop when reading invalid ODS files [#832](https://github.com/PHPOffice/PhpSpreadsheet/pull/832)
|
||||||
|
- Fix time format for duration is incorrect [#666](https://github.com/PHPOffice/PhpSpreadsheet/pull/666)
|
||||||
|
- Fix iconv unsupported `//IGNORE//TRANSLIT` on IBM i [#791](https://github.com/PHPOffice/PhpSpreadsheet/issues/791)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- `master` is the new default branch, `develop` does not exist anymore
|
||||||
|
|
||||||
|
## [1.5.2] - 2018-11-25
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Improvements to the design of the XML Security Scanner [#771](https://github.com/PHPOffice/PhpSpreadsheet/issues/771)
|
||||||
|
|
||||||
|
## [1.5.1] - 2018-11-20
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Fix and improve XXE security scanning for XML-based and HTML Readers [#771](https://github.com/PHPOffice/PhpSpreadsheet/issues/771)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Support page margin in mPDF [#750](https://github.com/PHPOffice/PhpSpreadsheet/issues/750)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Support numeric condition in SUMIF, SUMIFS, AVERAGEIF, COUNTIF, MAXIF and MINIF [#683](https://github.com/PHPOffice/PhpSpreadsheet/issues/683)
|
||||||
|
- SUMIFS containing multiple conditions [#704](https://github.com/PHPOffice/PhpSpreadsheet/issues/704)
|
||||||
|
- Csv reader avoid notice when the file is empty [#743](https://github.com/PHPOffice/PhpSpreadsheet/pull/743)
|
||||||
|
- Fix print area parser for XLSX reader [#734](https://github.com/PHPOffice/PhpSpreadsheet/pull/734)
|
||||||
|
- Support overriding `DefaultValueBinder::dataTypeForValue()` without overriding `DefaultValueBinder::bindValue()` [#735](https://github.com/PHPOffice/PhpSpreadsheet/pull/735)
|
||||||
|
- Mpdf export can exceed pcre.backtrack_limit [#637](https://github.com/PHPOffice/PhpSpreadsheet/issues/637)
|
||||||
|
- Fix index overflow on data values array [#748](https://github.com/PHPOffice/PhpSpreadsheet/pull/748)
|
||||||
|
|
||||||
|
## [1.5.0] - 2018-10-21
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- PHP 7.3 support
|
||||||
|
- Add the DAYS() function [#594](https://github.com/PHPOffice/PhpSpreadsheet/pull/594)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Sheet title can contain exclamation mark [#325](https://github.com/PHPOffice/PhpSpreadsheet/issues/325)
|
||||||
|
- Xls file cause the exception during open by Xls reader [#402](https://github.com/PHPOffice/PhpSpreadsheet/issues/402)
|
||||||
|
- Skip non numeric value in SUMIF [#618](https://github.com/PHPOffice/PhpSpreadsheet/pull/618)
|
||||||
|
- OFFSET should allow omitted height and width [#561](https://github.com/PHPOffice/PhpSpreadsheet/issues/561)
|
||||||
|
- Correctly determine delimiter when CSV contains line breaks inside enclosures [#716](https://github.com/PHPOffice/PhpSpreadsheet/issues/716)
|
||||||
|
|
||||||
|
## [1.4.1] - 2018-09-30
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Remove locale from formatting string [#644](https://github.com/PHPOffice/PhpSpreadsheet/pull/644)
|
||||||
|
- Allow iterators to go out of bounds with prev [#587](https://github.com/PHPOffice/PhpSpreadsheet/issues/587)
|
||||||
|
- Fix warning when reading xlsx without styles [#631](https://github.com/PHPOffice/PhpSpreadsheet/pull/631)
|
||||||
|
- Fix broken sample links on windows due to $baseDir having backslash [#653](https://github.com/PHPOffice/PhpSpreadsheet/pull/653)
|
||||||
|
|
||||||
|
## [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
|
||||||
|
|
||||||
|
- Plain text and richtext mixed in same cell can be read [#442](https://github.com/PHPOffice/PhpSpreadsheet/issues/442)
|
||||||
|
|
||||||
|
## [1.2.0] - 2018-03-04
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- HTML writer creates a generator meta tag [#312](https://github.com/PHPOffice/PhpSpreadsheet/issues/312)
|
||||||
|
- Support invalid zoom value in XLSX format [#350](https://github.com/PHPOffice/PhpSpreadsheet/pull/350)
|
||||||
|
- Support for `_xlfn.` prefixed functions and `ISFORMULA`, `MODE.SNGL`, `STDEV.S`, `STDEV.P` [#390](https://github.com/PHPOffice/PhpSpreadsheet/pull/390)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Avoid potentially unsupported PSR-16 cache keys [#354](https://github.com/PHPOffice/PhpSpreadsheet/issues/354)
|
||||||
|
- Check for MIME type to know if CSV reader can read a file [#167](https://github.com/PHPOffice/PhpSpreadsheet/issues/167)
|
||||||
|
- Use proper € symbol for currency format [#379](https://github.com/PHPOffice/PhpSpreadsheet/pull/379)
|
||||||
|
- Read printing area correctly when skipping some sheets [#371](https://github.com/PHPOffice/PhpSpreadsheet/issues/371)
|
||||||
|
- Avoid incorrectly overwriting calculated value type [#394](https://github.com/PHPOffice/PhpSpreadsheet/issues/394)
|
||||||
|
- Select correct cell when calling freezePane [#389](https://github.com/PHPOffice/PhpSpreadsheet/issues/389)
|
||||||
|
- `setStrikethrough()` did not set the font [#403](https://github.com/PHPOffice/PhpSpreadsheet/issues/403)
|
||||||
|
|
||||||
|
## [1.1.0] - 2018-01-28
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Support for PHP 7.2
|
||||||
|
- Support cell comments in HTML writer and reader [#308](https://github.com/PHPOffice/PhpSpreadsheet/issues/308)
|
||||||
|
- Option to stop at a conditional styling, if it matches (only XLSX format) [#292](https://github.com/PHPOffice/PhpSpreadsheet/pull/292)
|
||||||
|
- Support for line width for data series when rendering Xlsx [#329](https://github.com/PHPOffice/PhpSpreadsheet/pull/329)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Better auto-detection of CSV separators [#305](https://github.com/PHPOffice/PhpSpreadsheet/issues/305)
|
||||||
|
- Support for shape style ending with `;` [#304](https://github.com/PHPOffice/PhpSpreadsheet/issues/304)
|
||||||
|
- Freeze Panes takes wrong coordinates for XLSX [#322](https://github.com/PHPOffice/PhpSpreadsheet/issues/322)
|
||||||
|
- `COLUMNS` and `ROWS` functions crashed in some cases [#336](https://github.com/PHPOffice/PhpSpreadsheet/issues/336)
|
||||||
|
- Support XML file without styles [#331](https://github.com/PHPOffice/PhpSpreadsheet/pull/331)
|
||||||
|
- Cell coordinates which are already a range cause an exception [#319](https://github.com/PHPOffice/PhpSpreadsheet/issues/319)
|
||||||
|
|
||||||
|
## [1.0.0] - 2017-12-25
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Support to write merged cells in ODS format [#287](https://github.com/PHPOffice/PhpSpreadsheet/issues/287)
|
||||||
|
- Able to set the `topLeftCell` in freeze panes [#261](https://github.com/PHPOffice/PhpSpreadsheet/pull/261)
|
||||||
|
- Support `DateTimeImmutable` as cell value
|
||||||
|
- Support migration of prefixed classes
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Can read very small HTML files [#194](https://github.com/PHPOffice/PhpSpreadsheet/issues/194)
|
||||||
|
- Written DataValidation was corrupted [#290](https://github.com/PHPOffice/PhpSpreadsheet/issues/290)
|
||||||
|
- Date format compatible with both LibreOffice and Excel [#298](https://github.com/PHPOffice/PhpSpreadsheet/issues/298)
|
||||||
|
|
||||||
|
### BREAKING CHANGE
|
||||||
|
|
||||||
|
- Constant `TYPE_DOUGHTNUTCHART` is now `TYPE_DOUGHNUTCHART`.
|
||||||
|
|
||||||
|
## [1.0.0-beta2] - 2017-11-26
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Support for chart fill color - @CrazyBite [#158](https://github.com/PHPOffice/PhpSpreadsheet/pull/158)
|
||||||
|
- Support for read Hyperlink for xml - @GreatHumorist [#223](https://github.com/PHPOffice/PhpSpreadsheet/pull/223)
|
||||||
|
- Support for cell value validation according to data validation rules - @SailorMax [#257](https://github.com/PHPOffice/PhpSpreadsheet/pull/257)
|
||||||
|
- Support for custom implementation, or configuration, of PDF libraries - @SailorMax [#266](https://github.com/PHPOffice/PhpSpreadsheet/pull/266)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Merge data-validations to reduce written worksheet size - @billblume [#131](https://github.com/PHPOffice/PhpSpreadSheet/issues/131)
|
||||||
|
- Throws exception if a XML file is invalid - @GreatHumorist [#222](https://github.com/PHPOffice/PhpSpreadsheet/pull/222)
|
||||||
|
- Upgrade to mPDF 7.0+ [#144](https://github.com/PHPOffice/PhpSpreadsheet/issues/144)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Control characters in cell values are automatically escaped [#212](https://github.com/PHPOffice/PhpSpreadsheet/issues/212)
|
||||||
|
- Prevent color changing when copy/pasting xls files written by PhpSpreadsheet to another file - @al-lala [#218](https://github.com/PHPOffice/PhpSpreadsheet/issues/218)
|
||||||
|
- Add cell reference automatic when there is no cell reference('r' attribute) in Xlsx file. - @GreatHumorist [#225](https://github.com/PHPOffice/PhpSpreadsheet/pull/225) Refer to [#201](https://github.com/PHPOffice/PhpSpreadsheet/issues/201)
|
||||||
|
- `Reader\Xlsx::getFromZipArchive()` function return false if the zip entry could not be located. - @anton-harvey [#268](https://github.com/PHPOffice/PhpSpreadsheet/pull/268)
|
||||||
|
|
||||||
|
### BREAKING CHANGE
|
||||||
|
|
||||||
|
- Extracted coordinate method to dedicate class [migration guide](./docs/topics/migration-from-PHPExcel.md).
|
||||||
|
- Column indexes are based on 1, see the [migration guide](./docs/topics/migration-from-PHPExcel.md).
|
||||||
|
- Standardization of array keys used for style, see the [migration guide](./docs/topics/migration-from-PHPExcel.md).
|
||||||
|
- Easier usage of PDF writers, and other custom readers and writers, see the [migration guide](./docs/topics/migration-from-PHPExcel.md).
|
||||||
|
- Easier usage of chart renderers, see the [migration guide](./docs/topics/migration-from-PHPExcel.md).
|
||||||
|
- Rename a few more classes to keep them in their related namespaces:
|
||||||
|
- `CalcEngine` => `Calculation\Engine`
|
||||||
|
- `PhpSpreadsheet\Calculation` => `PhpSpreadsheet\Calculation\Calculation`
|
||||||
|
- `PhpSpreadsheet\Cell` => `PhpSpreadsheet\Cell\Cell`
|
||||||
|
- `PhpSpreadsheet\Chart` => `PhpSpreadsheet\Chart\Chart`
|
||||||
|
- `PhpSpreadsheet\RichText` => `PhpSpreadsheet\RichText\RichText`
|
||||||
|
- `PhpSpreadsheet\Style` => `PhpSpreadsheet\Style\Style`
|
||||||
|
- `PhpSpreadsheet\Worksheet` => `PhpSpreadsheet\Worksheet\Worksheet`
|
||||||
|
|
||||||
|
## [1.0.0-beta] - 2017-08-17
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Initial implementation of SUMIFS() function
|
||||||
|
- Additional codepages
|
||||||
|
- MemoryDrawing not working in HTML writer [#808](https://github.com/PHPOffice/PHPExcel/issues/808)
|
||||||
|
- CSV Reader can auto-detect the separator used in file [#141](https://github.com/PHPOffice/PhpSpreadsheet/pull/141)
|
||||||
|
- HTML Reader supports some basic inline styles [#180](https://github.com/PHPOffice/PhpSpreadsheet/pull/180)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Start following [SemVer](https://semver.org) properly.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix to getCell() method when cell reference includes a worksheet reference - @MarkBaker
|
||||||
|
- Ignore inlineStr type if formula element exists - @ncrypthic [#570](https://github.com/PHPOffice/PHPExcel/issues/570)
|
||||||
|
- Excel 2007 Reader freezes because of conditional formatting - @rentalhost [#575](https://github.com/PHPOffice/PHPExcel/issues/575)
|
||||||
|
- Readers will now parse files containing worksheet titles over 31 characters [#176](https://github.com/PHPOffice/PhpSpreadsheet/pull/176)
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
- Whitespace after toRichTextObject() - @MarkBaker [#554](https://github.com/PHPOffice/PHPExcel/issues/554)
|
||||||
|
- Optimize vlookup() sort - @umpirsky [#548](https://github.com/PHPOffice/PHPExcel/issues/548)
|
||||||
|
- c:max and c:min elements shall NOT be inside c:orientation elements - @vitalyrepin [#869](https://github.com/PHPOffice/PHPExcel/pull/869)
|
||||||
|
- Implement actual timezone adjustment into PHPExcel_Shared_Date::PHPToExcel - @sim642 [#489](https://github.com/PHPOffice/PHPExcel/pull/489)
|
||||||
|
|
||||||
|
### BREAKING CHANGE
|
||||||
|
|
||||||
|
- Introduction of namespaces for all classes, eg: `PHPExcel_Calculation_Functions` becomes `PhpOffice\PhpSpreadsheet\Calculation\Functions`
|
||||||
|
- Some classes were renamed for clarity and/or consistency:
|
||||||
|
|
||||||
|
For a comprehensive list of all class changes, and a semi-automated migration path, read the [migration guide](./docs/topics/migration-from-PHPExcel.md).
|
||||||
|
|
||||||
|
- Dropped `PHPExcel_Calculation_Functions::VERSION()`. Composer or git should be used to know the version.
|
||||||
|
- Dropped `PHPExcel_Settings::setPdfRenderer()` and `PHPExcel_Settings::setPdfRenderer()`. Composer should be used to autoload PDF libs.
|
||||||
|
- Dropped support for HHVM
|
||||||
|
|
||||||
|
## Previous versions of PHPExcel
|
||||||
|
|
||||||
|
The changelog for the project when it was called PHPExcel is [still available](./CHANGELOG.PHPExcel.md).
|
||||||
11
htdocs/includes/phpoffice/phpspreadsheet/CONTRIBUTING.md
Normal file
11
htdocs/includes/phpoffice/phpspreadsheet/CONTRIBUTING.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Want to contribute?
|
||||||
|
|
||||||
|
If you would like to contribute, here are some notes and guidelines:
|
||||||
|
|
||||||
|
- All new development happens on feature/fix branches, and are then merged to the `master` branch once stable; so the `master` branch is always the most up-to-date, working code
|
||||||
|
- Tagged releases are made from the `master` branch
|
||||||
|
- If you are going to be submitting a pull request, please fork from `master`, and submit your pull request back as a fix/feature branch referencing the GitHub issue number
|
||||||
|
- Code style might be automatically fixed by `composer fix`
|
||||||
|
- All code changes must be validated by `composer check`
|
||||||
|
- [Helpful article about forking](https://help.github.com/articles/fork-a-repo/ "Forking a GitHub repository")
|
||||||
|
- [Helpful article about pull requests](https://help.github.com/articles/using-pull-requests/ "Pull Requests")
|
||||||
21
htdocs/includes/phpoffice/phpspreadsheet/LICENSE
Normal file
21
htdocs/includes/phpoffice/phpspreadsheet/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 PhpSpreadsheet Authors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
86
htdocs/includes/phpoffice/phpspreadsheet/composer.json
Normal file
86
htdocs/includes/phpoffice/phpspreadsheet/composer.json
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"name": "phpoffice/phpspreadsheet",
|
||||||
|
"description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
|
||||||
|
"keywords": ["PHP", "OpenXML", "Excel", "xlsx", "xls", "ods", "gnumeric", "spreadsheet"],
|
||||||
|
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
|
||||||
|
"type": "library",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Maarten Balliauw",
|
||||||
|
"homepage": "https://blog.maartenballiauw.be"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mark Baker",
|
||||||
|
"homepage": "https://markbakeruk.net"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Franck Lefevre",
|
||||||
|
"homepage": "https://rootslabs.net"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Erik Tilt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Adrien Crivelli"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"check": [
|
||||||
|
"php-cs-fixer fix --ansi --dry-run --diff",
|
||||||
|
"phpcs --report-width=200 samples/ src/ tests/ --ignore=samples/Header.php --standard=PSR2 -n",
|
||||||
|
"phpunit --color=always"
|
||||||
|
],
|
||||||
|
"fix": [
|
||||||
|
"php-cs-fixer fix --ansi"
|
||||||
|
],
|
||||||
|
"versions": [
|
||||||
|
"phpcs --report-width=200 samples/ src/ tests/ --ignore=samples/Header.php --standard=PHPCompatibility --runtime-set testVersion 7.1- -n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1",
|
||||||
|
"ext-ctype": "*",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"ext-fileinfo": "*",
|
||||||
|
"ext-libxml": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"ext-SimpleXML": "*",
|
||||||
|
"ext-xml": "*",
|
||||||
|
"ext-xmlreader": "*",
|
||||||
|
"ext-xmlwriter": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"ext-zlib": "*",
|
||||||
|
"markbaker/complex": "^1.4",
|
||||||
|
"markbaker/matrix": "^1.2",
|
||||||
|
"psr/simple-cache": "^1.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"dompdf/dompdf": "^0.8.3",
|
||||||
|
"friendsofphp/php-cs-fixer": "^2.16",
|
||||||
|
"jpgraph/jpgraph": "^4.0",
|
||||||
|
"mpdf/mpdf": "^8.0",
|
||||||
|
"phpcompatibility/php-compatibility": "^9.3",
|
||||||
|
"phpunit/phpunit": "^7.5",
|
||||||
|
"squizlabs/php_codesniffer": "^3.5",
|
||||||
|
"tecnickcom/tcpdf": "^6.3"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
|
||||||
|
"dompdf/dompdf": "Option for rendering PDF with PDF Writer",
|
||||||
|
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer",
|
||||||
|
"jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"PhpOffice\\PhpSpreadsheetTests\\": "tests/PhpSpreadsheetTests"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3503
htdocs/includes/phpoffice/phpspreadsheet/composer.lock
generated
Normal file
3503
htdocs/includes/phpoffice/phpspreadsheet/composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
7
htdocs/includes/phpoffice/phpspreadsheet/mkdocs.yml
Normal file
7
htdocs/includes/phpoffice/phpspreadsheet/mkdocs.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
site_name: PhpSpreadsheet Documentation
|
||||||
|
repo_url: https://github.com/PHPOffice/phpspreadsheet
|
||||||
|
edit_uri: edit/master/docs/
|
||||||
|
|
||||||
|
theme: readthedocs
|
||||||
|
extra_css:
|
||||||
|
- extra/extra.css
|
||||||
23
htdocs/includes/phpoffice/phpspreadsheet/phpunit.xml.dist
Normal file
23
htdocs/includes/phpoffice/phpspreadsheet/phpunit.xml.dist
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/7.5/phpunit.xsd"
|
||||||
|
bootstrap="./tests/bootstrap.php"
|
||||||
|
backupGlobals="true"
|
||||||
|
colors="true">
|
||||||
|
<php>
|
||||||
|
<ini name="memory_limit" value="2048M"/>
|
||||||
|
</php>
|
||||||
|
<testsuite name="PhpSpreadsheet Unit Test Suite">
|
||||||
|
<directory suffix="Test.php">./tests/PhpSpreadsheetTests</directory>
|
||||||
|
</testsuite>
|
||||||
|
<filter>
|
||||||
|
<whitelist>
|
||||||
|
<directory suffix=".php">./src</directory>
|
||||||
|
<exclude>
|
||||||
|
<directory>./src/PhpSpreadsheet/Shared/JAMA</directory>
|
||||||
|
<directory>./src/PhpSpreadsheet/Writer/PDF</directory>
|
||||||
|
</exclude>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
||||||
22
htdocs/includes/phpoffice/phpspreadsheet/src/Bootstrap.php
Normal file
22
htdocs/includes/phpoffice/phpspreadsheet/src/Bootstrap.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap for PhpSpreadsheet classes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This sucks, but we have to try to find the composer autoloader
|
||||||
|
|
||||||
|
$paths = [
|
||||||
|
__DIR__ . '/../vendor/autoload.php', // In case PhpSpreadsheet is cloned directly
|
||||||
|
__DIR__ . '/../../../autoload.php', // In case PhpSpreadsheet is a composer dependency.
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($paths as $path) {
|
||||||
|
if (file_exists($path)) {
|
||||||
|
require_once $path;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \Exception('Composer autoloader could not be found. Install dependencies with `composer install` and try again.');
|
||||||
@ -25,7 +25,7 @@ class Calculation
|
|||||||
// Function (allow for the old @ symbol that could be used to prefix a function, but we'll ignore it)
|
// Function (allow for the old @ symbol that could be used to prefix a function, but we'll ignore it)
|
||||||
const CALCULATION_REGEXP_FUNCTION = '@?(?:_xlfn\.)?([A-Z][A-Z0-9\.]*)[\s]*\(';
|
const CALCULATION_REGEXP_FUNCTION = '@?(?:_xlfn\.)?([A-Z][A-Z0-9\.]*)[\s]*\(';
|
||||||
// Cell reference (cell or range of cells, with or without a sheet reference)
|
// Cell reference (cell or range of cells, with or without a sheet reference)
|
||||||
const CALCULATION_REGEXP_CELLREF = '((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?\$?([a-z]{1,3})\$?(\d{1,7})';
|
const CALCULATION_REGEXP_CELLREF = '((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?\$?\b([a-z]{1,3})\$?(\d{1,7})(?![\w.])';
|
||||||
// Named Range of cells
|
// Named Range of cells
|
||||||
const CALCULATION_REGEXP_NAMEDRANGE = '((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?([_A-Z][_A-Z0-9\.]*)';
|
const CALCULATION_REGEXP_NAMEDRANGE = '((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?([_A-Z][_A-Z0-9\.]*)';
|
||||||
// Error
|
// Error
|
||||||
@ -66,6 +66,15 @@ class Calculation
|
|||||||
*/
|
*/
|
||||||
private $calculationCacheEnabled = true;
|
private $calculationCacheEnabled = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to generate unique store keys.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $branchStoreKeyCounter = 0;
|
||||||
|
|
||||||
|
private $branchPruningEnabled = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of operators that can be used within formulae
|
* List of operators that can be used within formulae
|
||||||
* The true/false value indicates whether it is a binary operator or a unary operator.
|
* The true/false value indicates whether it is a binary operator or a unary operator.
|
||||||
@ -254,6 +263,11 @@ class Calculation
|
|||||||
'functionCall' => [Logical::class, 'logicalAnd'],
|
'functionCall' => [Logical::class, 'logicalAnd'],
|
||||||
'argumentCount' => '1+',
|
'argumentCount' => '1+',
|
||||||
],
|
],
|
||||||
|
'ARABIC' => [
|
||||||
|
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||||
|
'functionCall' => [MathTrig::class, 'ARABIC'],
|
||||||
|
'argumentCount' => '1',
|
||||||
|
],
|
||||||
'AREAS' => [
|
'AREAS' => [
|
||||||
'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE,
|
'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE,
|
||||||
'functionCall' => [Functions::class, 'DUMMY'],
|
'functionCall' => [Functions::class, 'DUMMY'],
|
||||||
@ -319,6 +333,11 @@ class Calculation
|
|||||||
'functionCall' => [Functions::class, 'DUMMY'],
|
'functionCall' => [Functions::class, 'DUMMY'],
|
||||||
'argumentCount' => '1',
|
'argumentCount' => '1',
|
||||||
],
|
],
|
||||||
|
'BASE' => [
|
||||||
|
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||||
|
'functionCall' => [MathTrig::class, 'BASE'],
|
||||||
|
'argumentCount' => '2,3',
|
||||||
|
],
|
||||||
'BESSELI' => [
|
'BESSELI' => [
|
||||||
'category' => Category::CATEGORY_ENGINEERING,
|
'category' => Category::CATEGORY_ENGINEERING,
|
||||||
'functionCall' => [Engineering::class, 'BESSELI'],
|
'functionCall' => [Engineering::class, 'BESSELI'],
|
||||||
@ -527,7 +546,7 @@ class Calculation
|
|||||||
],
|
],
|
||||||
'COUNTIFS' => [
|
'COUNTIFS' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Functions::class, 'DUMMY'],
|
'functionCall' => [Statistical::class, 'COUNTIFS'],
|
||||||
'argumentCount' => '2+',
|
'argumentCount' => '2+',
|
||||||
],
|
],
|
||||||
'COUPDAYBS' => [
|
'COUPDAYBS' => [
|
||||||
@ -895,6 +914,16 @@ class Calculation
|
|||||||
'functionCall' => [MathTrig::class, 'FLOOR'],
|
'functionCall' => [MathTrig::class, 'FLOOR'],
|
||||||
'argumentCount' => '2',
|
'argumentCount' => '2',
|
||||||
],
|
],
|
||||||
|
'FLOOR.MATH' => [
|
||||||
|
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||||
|
'functionCall' => [MathTrig::class, 'FLOORMATH'],
|
||||||
|
'argumentCount' => '3',
|
||||||
|
],
|
||||||
|
'FLOOR.PRECISE' => [
|
||||||
|
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||||
|
'functionCall' => [MathTrig::class, 'FLOORPRECISE'],
|
||||||
|
'argumentCount' => '2',
|
||||||
|
],
|
||||||
'FORECAST' => [
|
'FORECAST' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'FORECAST'],
|
'functionCall' => [Statistical::class, 'FORECAST'],
|
||||||
@ -1018,6 +1047,16 @@ class Calculation
|
|||||||
'functionCall' => [Logical::class, 'IFERROR'],
|
'functionCall' => [Logical::class, 'IFERROR'],
|
||||||
'argumentCount' => '2',
|
'argumentCount' => '2',
|
||||||
],
|
],
|
||||||
|
'IFNA' => [
|
||||||
|
'category' => Category::CATEGORY_LOGICAL,
|
||||||
|
'functionCall' => [Logical::class, 'IFNA'],
|
||||||
|
'argumentCount' => '2',
|
||||||
|
],
|
||||||
|
'IFS' => [
|
||||||
|
'category' => Category::CATEGORY_LOGICAL,
|
||||||
|
'functionCall' => [Functions::class, 'DUMMY'],
|
||||||
|
'argumentCount' => '2+',
|
||||||
|
],
|
||||||
'IMABS' => [
|
'IMABS' => [
|
||||||
'category' => Category::CATEGORY_ENGINEERING,
|
'category' => Category::CATEGORY_ENGINEERING,
|
||||||
'functionCall' => [Engineering::class, 'IMABS'],
|
'functionCall' => [Engineering::class, 'IMABS'],
|
||||||
@ -1356,10 +1395,10 @@ class Calculation
|
|||||||
'functionCall' => [Statistical::class, 'MAXA'],
|
'functionCall' => [Statistical::class, 'MAXA'],
|
||||||
'argumentCount' => '1+',
|
'argumentCount' => '1+',
|
||||||
],
|
],
|
||||||
'MAXIF' => [
|
'MAXIFS' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'MAXIF'],
|
'functionCall' => [Statistical::class, 'MAXIFS'],
|
||||||
'argumentCount' => '2+',
|
'argumentCount' => '3+',
|
||||||
],
|
],
|
||||||
'MDETERM' => [
|
'MDETERM' => [
|
||||||
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
'category' => Category::CATEGORY_MATH_AND_TRIG,
|
||||||
@ -1401,10 +1440,10 @@ class Calculation
|
|||||||
'functionCall' => [Statistical::class, 'MINA'],
|
'functionCall' => [Statistical::class, 'MINA'],
|
||||||
'argumentCount' => '1+',
|
'argumentCount' => '1+',
|
||||||
],
|
],
|
||||||
'MINIF' => [
|
'MINIFS' => [
|
||||||
'category' => Category::CATEGORY_STATISTICAL,
|
'category' => Category::CATEGORY_STATISTICAL,
|
||||||
'functionCall' => [Statistical::class, 'MINIF'],
|
'functionCall' => [Statistical::class, 'MINIFS'],
|
||||||
'argumentCount' => '2+',
|
'argumentCount' => '3+',
|
||||||
],
|
],
|
||||||
'MINUTE' => [
|
'MINUTE' => [
|
||||||
'category' => Category::CATEGORY_DATE_AND_TIME,
|
'category' => Category::CATEGORY_DATE_AND_TIME,
|
||||||
@ -1474,7 +1513,12 @@ class Calculation
|
|||||||
'NETWORKDAYS' => [
|
'NETWORKDAYS' => [
|
||||||
'category' => Category::CATEGORY_DATE_AND_TIME,
|
'category' => Category::CATEGORY_DATE_AND_TIME,
|
||||||
'functionCall' => [DateTime::class, 'NETWORKDAYS'],
|
'functionCall' => [DateTime::class, 'NETWORKDAYS'],
|
||||||
'argumentCount' => '2+',
|
'argumentCount' => '2-3',
|
||||||
|
],
|
||||||
|
'NETWORKDAYS.INTL' => [
|
||||||
|
'category' => Category::CATEGORY_DATE_AND_TIME,
|
||||||
|
'functionCall' => [Functions::class, 'DUMMY'],
|
||||||
|
'argumentCount' => '2-4',
|
||||||
],
|
],
|
||||||
'NOMINAL' => [
|
'NOMINAL' => [
|
||||||
'category' => Category::CATEGORY_FINANCIAL,
|
'category' => Category::CATEGORY_FINANCIAL,
|
||||||
@ -2143,7 +2187,12 @@ class Calculation
|
|||||||
'WORKDAY' => [
|
'WORKDAY' => [
|
||||||
'category' => Category::CATEGORY_DATE_AND_TIME,
|
'category' => Category::CATEGORY_DATE_AND_TIME,
|
||||||
'functionCall' => [DateTime::class, 'WORKDAY'],
|
'functionCall' => [DateTime::class, 'WORKDAY'],
|
||||||
'argumentCount' => '2+',
|
'argumentCount' => '2-3',
|
||||||
|
],
|
||||||
|
'WORKDAY.INTL' => [
|
||||||
|
'category' => Category::CATEGORY_DATE_AND_TIME,
|
||||||
|
'functionCall' => [Functions::class, 'DUMMY'],
|
||||||
|
'argumentCount' => '2-4',
|
||||||
],
|
],
|
||||||
'XIRR' => [
|
'XIRR' => [
|
||||||
'category' => Category::CATEGORY_FINANCIAL,
|
'category' => Category::CATEGORY_FINANCIAL,
|
||||||
@ -2196,7 +2245,7 @@ class Calculation
|
|||||||
private static $controlFunctions = [
|
private static $controlFunctions = [
|
||||||
'MKMATRIX' => [
|
'MKMATRIX' => [
|
||||||
'argumentCount' => '*',
|
'argumentCount' => '*',
|
||||||
'functionCall' => 'self::mkMatrix',
|
'functionCall' => [__CLASS__, 'mkMatrix'],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -2251,6 +2300,7 @@ class Calculation
|
|||||||
public function flushInstance()
|
public function flushInstance()
|
||||||
{
|
{
|
||||||
$this->clearCalculationCache();
|
$this->clearCalculationCache();
|
||||||
|
$this->clearBranchStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2394,6 +2444,32 @@ class Calculation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/disable calculation cache.
|
||||||
|
*
|
||||||
|
* @param bool $pValue
|
||||||
|
* @param mixed $enabled
|
||||||
|
*/
|
||||||
|
public function setBranchPruningEnabled($enabled)
|
||||||
|
{
|
||||||
|
$this->branchPruningEnabled = $enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enableBranchPruning()
|
||||||
|
{
|
||||||
|
$this->setBranchPruningEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disableBranchPruning()
|
||||||
|
{
|
||||||
|
$this->setBranchPruningEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clearBranchStore()
|
||||||
|
{
|
||||||
|
$this->branchStoreKeyCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the currently defined locale code.
|
* Get the currently defined locale code.
|
||||||
*
|
*
|
||||||
@ -2416,7 +2492,7 @@ class Calculation
|
|||||||
// Identify our locale and language
|
// Identify our locale and language
|
||||||
$language = $locale = strtolower($locale);
|
$language = $locale = strtolower($locale);
|
||||||
if (strpos($locale, '_') !== false) {
|
if (strpos($locale, '_') !== false) {
|
||||||
list($language) = explode('_', $locale);
|
[$language] = explode('_', $locale);
|
||||||
}
|
}
|
||||||
if (count(self::$validLocaleLanguages) == 1) {
|
if (count(self::$validLocaleLanguages) == 1) {
|
||||||
self::loadLocales();
|
self::loadLocales();
|
||||||
@ -2441,9 +2517,9 @@ class Calculation
|
|||||||
// Retrieve the list of locale or language specific function names
|
// Retrieve the list of locale or language specific function names
|
||||||
$localeFunctions = file($functionNamesFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
$localeFunctions = file($functionNamesFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
foreach ($localeFunctions as $localeFunction) {
|
foreach ($localeFunctions as $localeFunction) {
|
||||||
list($localeFunction) = explode('##', $localeFunction); // Strip out comments
|
[$localeFunction] = explode('##', $localeFunction); // Strip out comments
|
||||||
if (strpos($localeFunction, '=') !== false) {
|
if (strpos($localeFunction, '=') !== false) {
|
||||||
list($fName, $lfName) = explode('=', $localeFunction);
|
[$fName, $lfName] = explode('=', $localeFunction);
|
||||||
$fName = trim($fName);
|
$fName = trim($fName);
|
||||||
$lfName = trim($lfName);
|
$lfName = trim($lfName);
|
||||||
if ((isset(self::$phpSpreadsheetFunctions[$fName])) && ($lfName != '') && ($fName != $lfName)) {
|
if ((isset(self::$phpSpreadsheetFunctions[$fName])) && ($lfName != '') && ($fName != $lfName)) {
|
||||||
@ -2466,9 +2542,9 @@ class Calculation
|
|||||||
if (file_exists($configFile)) {
|
if (file_exists($configFile)) {
|
||||||
$localeSettings = file($configFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
$localeSettings = file($configFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
foreach ($localeSettings as $localeSetting) {
|
foreach ($localeSettings as $localeSetting) {
|
||||||
list($localeSetting) = explode('##', $localeSetting); // Strip out comments
|
[$localeSetting] = explode('##', $localeSetting); // Strip out comments
|
||||||
if (strpos($localeSetting, '=') !== false) {
|
if (strpos($localeSetting, '=') !== false) {
|
||||||
list($settingName, $settingValue) = explode('=', $localeSetting);
|
[$settingName, $settingValue] = explode('=', $localeSetting);
|
||||||
$settingName = strtoupper(trim($settingName));
|
$settingName = strtoupper(trim($settingName));
|
||||||
switch ($settingName) {
|
switch ($settingName) {
|
||||||
case 'ARGUMENTSEPARATOR':
|
case 'ARGUMENTSEPARATOR':
|
||||||
@ -2772,7 +2848,7 @@ class Calculation
|
|||||||
}
|
}
|
||||||
self::$returnArrayAsType = $returnArrayAsType;
|
self::$returnArrayAsType = $returnArrayAsType;
|
||||||
|
|
||||||
if ($result === null) {
|
if ($result === null && $pCell->getWorksheet()->getSheetView()->getShowZeros()) {
|
||||||
return 0;
|
return 0;
|
||||||
} elseif ((is_float($result)) && ((is_nan($result)) || (is_infinite($result)))) {
|
} elseif ((is_float($result)) && ((is_nan($result)) || (is_infinite($result)))) {
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
@ -2823,13 +2899,13 @@ class Calculation
|
|||||||
$this->debugLog->clearLog();
|
$this->debugLog->clearLog();
|
||||||
$this->cyclicReferenceStack->clear();
|
$this->cyclicReferenceStack->clear();
|
||||||
|
|
||||||
|
$resetCache = $this->getCalculationCacheEnabled();
|
||||||
if ($this->spreadsheet !== null && $cellID === null && $pCell === null) {
|
if ($this->spreadsheet !== null && $cellID === null && $pCell === null) {
|
||||||
$cellID = 'A1';
|
$cellID = 'A1';
|
||||||
$pCell = $this->spreadsheet->getActiveSheet()->getCell($cellID);
|
$pCell = $this->spreadsheet->getActiveSheet()->getCell($cellID);
|
||||||
} else {
|
} else {
|
||||||
// Disable calculation cacheing because it only applies to cell calculations, not straight formulae
|
// Disable calculation cacheing because it only applies to cell calculations, not straight formulae
|
||||||
// But don't actually flush any cache
|
// But don't actually flush any cache
|
||||||
$resetCache = $this->getCalculationCacheEnabled();
|
|
||||||
$this->calculationCacheEnabled = false;
|
$this->calculationCacheEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2862,6 +2938,7 @@ class Calculation
|
|||||||
if (($this->calculationCacheEnabled) && (isset($this->calculationCache[$cellReference]))) {
|
if (($this->calculationCacheEnabled) && (isset($this->calculationCache[$cellReference]))) {
|
||||||
$this->debugLog->writeDebugLog('Retrieving value for cell ', $cellReference, ' from cache');
|
$this->debugLog->writeDebugLog('Retrieving value for cell ', $cellReference, ' from cache');
|
||||||
// Return the cached result
|
// Return the cached result
|
||||||
|
|
||||||
$cellValue = $this->calculationCache[$cellReference];
|
$cellValue = $this->calculationCache[$cellReference];
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -2977,17 +3054,17 @@ class Calculation
|
|||||||
// Examine each of the two operands, and turn them into an array if they aren't one already
|
// Examine each of the two operands, and turn them into an array if they aren't one already
|
||||||
// Note that this function should only be called if one or both of the operand is already an array
|
// Note that this function should only be called if one or both of the operand is already an array
|
||||||
if (!is_array($operand1)) {
|
if (!is_array($operand1)) {
|
||||||
list($matrixRows, $matrixColumns) = self::getMatrixDimensions($operand2);
|
[$matrixRows, $matrixColumns] = self::getMatrixDimensions($operand2);
|
||||||
$operand1 = array_fill(0, $matrixRows, array_fill(0, $matrixColumns, $operand1));
|
$operand1 = array_fill(0, $matrixRows, array_fill(0, $matrixColumns, $operand1));
|
||||||
$resize = 0;
|
$resize = 0;
|
||||||
} elseif (!is_array($operand2)) {
|
} elseif (!is_array($operand2)) {
|
||||||
list($matrixRows, $matrixColumns) = self::getMatrixDimensions($operand1);
|
[$matrixRows, $matrixColumns] = self::getMatrixDimensions($operand1);
|
||||||
$operand2 = array_fill(0, $matrixRows, array_fill(0, $matrixColumns, $operand2));
|
$operand2 = array_fill(0, $matrixRows, array_fill(0, $matrixColumns, $operand2));
|
||||||
$resize = 0;
|
$resize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($matrix1Rows, $matrix1Columns) = self::getMatrixDimensions($operand1);
|
[$matrix1Rows, $matrix1Columns] = self::getMatrixDimensions($operand1);
|
||||||
list($matrix2Rows, $matrix2Columns) = self::getMatrixDimensions($operand2);
|
[$matrix2Rows, $matrix2Columns] = self::getMatrixDimensions($operand2);
|
||||||
if (($matrix1Rows == $matrix2Columns) && ($matrix2Rows == $matrix1Columns)) {
|
if (($matrix1Rows == $matrix2Columns) && ($matrix2Rows == $matrix1Columns)) {
|
||||||
$resize = 1;
|
$resize = 1;
|
||||||
}
|
}
|
||||||
@ -3197,7 +3274,7 @@ class Calculation
|
|||||||
/**
|
/**
|
||||||
* @param string $formula
|
* @param string $formula
|
||||||
*
|
*
|
||||||
* @return string
|
* @return false|string False indicates an error
|
||||||
*/
|
*/
|
||||||
private function convertMatrixReferences($formula)
|
private function convertMatrixReferences($formula)
|
||||||
{
|
{
|
||||||
@ -3321,9 +3398,53 @@ class Calculation
|
|||||||
// - is a negation or + is a positive operator rather than an operation
|
// - is a negation or + is a positive operator rather than an operation
|
||||||
$expectingOperand = false; // We use this test in syntax-checking the expression to determine whether an operand
|
$expectingOperand = false; // We use this test in syntax-checking the expression to determine whether an operand
|
||||||
// should be null in a function call
|
// should be null in a function call
|
||||||
|
|
||||||
|
// IF branch pruning
|
||||||
|
// currently pending storeKey (last item of the storeKeysStack
|
||||||
|
$pendingStoreKey = null;
|
||||||
|
// stores a list of storeKeys (string[])
|
||||||
|
$pendingStoreKeysStack = [];
|
||||||
|
$expectingConditionMap = []; // ['storeKey' => true, ...]
|
||||||
|
$expectingThenMap = []; // ['storeKey' => true, ...]
|
||||||
|
$expectingElseMap = []; // ['storeKey' => true, ...]
|
||||||
|
$parenthesisDepthMap = []; // ['storeKey' => 4, ...]
|
||||||
|
|
||||||
// The guts of the lexical parser
|
// The guts of the lexical parser
|
||||||
// Loop through the formula extracting each operator and operand in turn
|
// Loop through the formula extracting each operator and operand in turn
|
||||||
while (true) {
|
while (true) {
|
||||||
|
// Branch pruning: we adapt the output item to the context (it will
|
||||||
|
// be used to limit its computation)
|
||||||
|
$currentCondition = null;
|
||||||
|
$currentOnlyIf = null;
|
||||||
|
$currentOnlyIfNot = null;
|
||||||
|
$previousStoreKey = null;
|
||||||
|
$pendingStoreKey = end($pendingStoreKeysStack);
|
||||||
|
|
||||||
|
if ($this->branchPruningEnabled) {
|
||||||
|
// this is a condition ?
|
||||||
|
if (isset($expectingConditionMap[$pendingStoreKey]) && $expectingConditionMap[$pendingStoreKey]) {
|
||||||
|
$currentCondition = $pendingStoreKey;
|
||||||
|
$stackDepth = count($pendingStoreKeysStack);
|
||||||
|
if ($stackDepth > 1) { // nested if
|
||||||
|
$previousStoreKey = $pendingStoreKeysStack[$stackDepth - 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isset($expectingThenMap[$pendingStoreKey]) && $expectingThenMap[$pendingStoreKey]) {
|
||||||
|
$currentOnlyIf = $pendingStoreKey;
|
||||||
|
} elseif (isset($previousStoreKey)) {
|
||||||
|
if (isset($expectingThenMap[$previousStoreKey]) && $expectingThenMap[$previousStoreKey]) {
|
||||||
|
$currentOnlyIf = $previousStoreKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isset($expectingElseMap[$pendingStoreKey]) && $expectingElseMap[$pendingStoreKey]) {
|
||||||
|
$currentOnlyIfNot = $pendingStoreKey;
|
||||||
|
} elseif (isset($previousStoreKey)) {
|
||||||
|
if (isset($expectingElseMap[$previousStoreKey]) && $expectingElseMap[$previousStoreKey]) {
|
||||||
|
$currentOnlyIfNot = $previousStoreKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$opCharacter = $formula[$index]; // Get the first character of the value at the current index position
|
$opCharacter = $formula[$index]; // Get the first character of the value at the current index position
|
||||||
if ((isset(self::$comparisonOperators[$opCharacter])) && (strlen($formula) > $index) && (isset(self::$comparisonOperators[$formula[$index + 1]]))) {
|
if ((isset(self::$comparisonOperators[$opCharacter])) && (strlen($formula) > $index) && (isset(self::$comparisonOperators[$formula[$index + 1]]))) {
|
||||||
$opCharacter .= $formula[++$index];
|
$opCharacter .= $formula[++$index];
|
||||||
@ -3333,10 +3454,12 @@ class Calculation
|
|||||||
$isOperandOrFunction = preg_match($regexpMatchString, substr($formula, $index), $match);
|
$isOperandOrFunction = preg_match($regexpMatchString, substr($formula, $index), $match);
|
||||||
|
|
||||||
if ($opCharacter == '-' && !$expectingOperator) { // Is it a negation instead of a minus?
|
if ($opCharacter == '-' && !$expectingOperator) { // Is it a negation instead of a minus?
|
||||||
$stack->push('Unary Operator', '~'); // Put a negation on the stack
|
// Put a negation on the stack
|
||||||
|
$stack->push('Unary Operator', '~', null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
|
||||||
++$index; // and drop the negation symbol
|
++$index; // and drop the negation symbol
|
||||||
} elseif ($opCharacter == '%' && $expectingOperator) {
|
} elseif ($opCharacter == '%' && $expectingOperator) {
|
||||||
$stack->push('Unary Operator', '%'); // Put a percentage on the stack
|
// Put a percentage on the stack
|
||||||
|
$stack->push('Unary Operator', '%', null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
|
||||||
++$index;
|
++$index;
|
||||||
} elseif ($opCharacter == '+' && !$expectingOperator) { // Positive (unary plus rather than binary operator plus) can be discarded?
|
} elseif ($opCharacter == '+' && !$expectingOperator) { // Positive (unary plus rather than binary operator plus) can be discarded?
|
||||||
++$index; // Drop the redundant plus symbol
|
++$index; // Drop the redundant plus symbol
|
||||||
@ -3349,7 +3472,10 @@ class Calculation
|
|||||||
@(self::$operatorAssociativity[$opCharacter] ? self::$operatorPrecedence[$opCharacter] < self::$operatorPrecedence[$o2['value']] : self::$operatorPrecedence[$opCharacter] <= self::$operatorPrecedence[$o2['value']])) {
|
@(self::$operatorAssociativity[$opCharacter] ? self::$operatorPrecedence[$opCharacter] < self::$operatorPrecedence[$o2['value']] : self::$operatorPrecedence[$opCharacter] <= self::$operatorPrecedence[$o2['value']])) {
|
||||||
$output[] = $stack->pop(); // Swap operands and higher precedence operators from the stack to the output
|
$output[] = $stack->pop(); // Swap operands and higher precedence operators from the stack to the output
|
||||||
}
|
}
|
||||||
$stack->push('Binary Operator', $opCharacter); // Finally put our current operator onto the stack
|
|
||||||
|
// Finally put our current operator onto the stack
|
||||||
|
$stack->push('Binary Operator', $opCharacter, null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
|
||||||
|
|
||||||
++$index;
|
++$index;
|
||||||
$expectingOperator = false;
|
$expectingOperator = false;
|
||||||
} elseif ($opCharacter == ')' && $expectingOperator) { // Are we expecting to close a parenthesis?
|
} elseif ($opCharacter == ')' && $expectingOperator) { // Are we expecting to close a parenthesis?
|
||||||
@ -3361,7 +3487,29 @@ class Calculation
|
|||||||
$output[] = $o2;
|
$output[] = $o2;
|
||||||
}
|
}
|
||||||
$d = $stack->last(2);
|
$d = $stack->last(2);
|
||||||
if (preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/i', $d['value'], $matches)) { // Did this parenthesis just close a function?
|
|
||||||
|
// Branch pruning we decrease the depth whether is it a function
|
||||||
|
// call or a parenthesis
|
||||||
|
if (!empty($pendingStoreKey)) {
|
||||||
|
$parenthesisDepthMap[$pendingStoreKey] -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($d) && preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/i', $d['value'], $matches)) { // Did this parenthesis just close a function?
|
||||||
|
if (!empty($pendingStoreKey) && $parenthesisDepthMap[$pendingStoreKey] == -1) {
|
||||||
|
// we are closing an IF(
|
||||||
|
if ($d['value'] != 'IF(') {
|
||||||
|
return $this->raiseFormulaError('Parser bug we should be in an "IF("');
|
||||||
|
}
|
||||||
|
if ($expectingConditionMap[$pendingStoreKey]) {
|
||||||
|
return $this->raiseFormulaError('We should not be expecting a condition');
|
||||||
|
}
|
||||||
|
$expectingThenMap[$pendingStoreKey] = false;
|
||||||
|
$expectingElseMap[$pendingStoreKey] = false;
|
||||||
|
$parenthesisDepthMap[$pendingStoreKey] -= 1;
|
||||||
|
array_pop($pendingStoreKeysStack);
|
||||||
|
unset($pendingStoreKey);
|
||||||
|
}
|
||||||
|
|
||||||
$functionName = $matches[1]; // Get the function name
|
$functionName = $matches[1]; // Get the function name
|
||||||
$d = $stack->pop();
|
$d = $stack->pop();
|
||||||
$argumentCount = $d['value']; // See how many arguments there were (argument count is the next value stored on the stack)
|
$argumentCount = $d['value']; // See how many arguments there were (argument count is the next value stored on the stack)
|
||||||
@ -3422,6 +3570,20 @@ class Calculation
|
|||||||
}
|
}
|
||||||
++$index;
|
++$index;
|
||||||
} elseif ($opCharacter == ',') { // Is this the separator for function arguments?
|
} elseif ($opCharacter == ',') { // Is this the separator for function arguments?
|
||||||
|
if (!empty($pendingStoreKey) &&
|
||||||
|
$parenthesisDepthMap[$pendingStoreKey] == 0
|
||||||
|
) {
|
||||||
|
// We must go to the IF next argument
|
||||||
|
if ($expectingConditionMap[$pendingStoreKey]) {
|
||||||
|
$expectingConditionMap[$pendingStoreKey] = false;
|
||||||
|
$expectingThenMap[$pendingStoreKey] = true;
|
||||||
|
} elseif ($expectingThenMap[$pendingStoreKey]) {
|
||||||
|
$expectingThenMap[$pendingStoreKey] = false;
|
||||||
|
$expectingElseMap[$pendingStoreKey] = true;
|
||||||
|
} elseif ($expectingElseMap[$pendingStoreKey]) {
|
||||||
|
return $this->raiseFormulaError('Reaching fourth argument of an IF');
|
||||||
|
}
|
||||||
|
}
|
||||||
while (($o2 = $stack->pop()) && $o2['value'] != '(') { // Pop off the stack back to the last (
|
while (($o2 = $stack->pop()) && $o2['value'] != '(') { // Pop off the stack back to the last (
|
||||||
if ($o2 === null) {
|
if ($o2 === null) {
|
||||||
return $this->raiseFormulaError('Formula Error: Unexpected ,');
|
return $this->raiseFormulaError('Formula Error: Unexpected ,');
|
||||||
@ -3439,13 +3601,19 @@ class Calculation
|
|||||||
return $this->raiseFormulaError('Formula Error: Unexpected ,');
|
return $this->raiseFormulaError('Formula Error: Unexpected ,');
|
||||||
}
|
}
|
||||||
$d = $stack->pop();
|
$d = $stack->pop();
|
||||||
$stack->push($d['type'], ++$d['value'], $d['reference']); // increment the argument count
|
$itemStoreKey = $d['storeKey'] ?? null;
|
||||||
$stack->push('Brace', '('); // put the ( back on, we'll need to pop back to it again
|
$itemOnlyIf = $d['onlyIf'] ?? null;
|
||||||
|
$itemOnlyIfNot = $d['onlyIfNot'] ?? null;
|
||||||
|
$stack->push($d['type'], ++$d['value'], $d['reference'], $itemStoreKey, $itemOnlyIf, $itemOnlyIfNot); // increment the argument count
|
||||||
|
$stack->push('Brace', '(', null, $itemStoreKey, $itemOnlyIf, $itemOnlyIfNot); // put the ( back on, we'll need to pop back to it again
|
||||||
$expectingOperator = false;
|
$expectingOperator = false;
|
||||||
$expectingOperand = true;
|
$expectingOperand = true;
|
||||||
++$index;
|
++$index;
|
||||||
} elseif ($opCharacter == '(' && !$expectingOperator) {
|
} elseif ($opCharacter == '(' && !$expectingOperator) {
|
||||||
$stack->push('Brace', '(');
|
if (!empty($pendingStoreKey)) { // Branch pruning: we go deeper
|
||||||
|
$parenthesisDepthMap[$pendingStoreKey] += 1;
|
||||||
|
}
|
||||||
|
$stack->push('Brace', '(', null, $currentCondition, $currentOnlyIf, $currentOnlyIf);
|
||||||
++$index;
|
++$index;
|
||||||
} elseif ($isOperandOrFunction && !$expectingOperator) { // do we now have a function/variable/number?
|
} elseif ($isOperandOrFunction && !$expectingOperator) { // do we now have a function/variable/number?
|
||||||
$expectingOperator = true;
|
$expectingOperator = true;
|
||||||
@ -3456,13 +3624,28 @@ class Calculation
|
|||||||
if (preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/i', $val, $matches)) {
|
if (preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/i', $val, $matches)) {
|
||||||
$val = preg_replace('/\s/u', '', $val);
|
$val = preg_replace('/\s/u', '', $val);
|
||||||
if (isset(self::$phpSpreadsheetFunctions[strtoupper($matches[1])]) || isset(self::$controlFunctions[strtoupper($matches[1])])) { // it's a function
|
if (isset(self::$phpSpreadsheetFunctions[strtoupper($matches[1])]) || isset(self::$controlFunctions[strtoupper($matches[1])])) { // it's a function
|
||||||
$stack->push('Function', strtoupper($val));
|
$valToUpper = strtoupper($val);
|
||||||
|
// here $matches[1] will contain values like "IF"
|
||||||
|
// and $val "IF("
|
||||||
|
if ($this->branchPruningEnabled && ($valToUpper == 'IF(')) { // we handle a new if
|
||||||
|
$pendingStoreKey = $this->getUnusedBranchStoreKey();
|
||||||
|
$pendingStoreKeysStack[] = $pendingStoreKey;
|
||||||
|
$expectingConditionMap[$pendingStoreKey] = true;
|
||||||
|
$parenthesisDepthMap[$pendingStoreKey] = 0;
|
||||||
|
} else { // this is not a if but we good deeper
|
||||||
|
if (!empty($pendingStoreKey) && array_key_exists($pendingStoreKey, $parenthesisDepthMap)) {
|
||||||
|
$parenthesisDepthMap[$pendingStoreKey] += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$stack->push('Function', $valToUpper, null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
|
||||||
|
// tests if the function is closed right after opening
|
||||||
$ax = preg_match('/^\s*(\s*\))/ui', substr($formula, $index + $length), $amatch);
|
$ax = preg_match('/^\s*(\s*\))/ui', substr($formula, $index + $length), $amatch);
|
||||||
if ($ax) {
|
if ($ax) {
|
||||||
$stack->push('Operand Count for Function ' . strtoupper($val) . ')', 0);
|
$stack->push('Operand Count for Function ' . $valToUpper . ')', 0, null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
|
||||||
$expectingOperator = true;
|
$expectingOperator = true;
|
||||||
} else {
|
} else {
|
||||||
$stack->push('Operand Count for Function ' . strtoupper($val) . ')', 1);
|
$stack->push('Operand Count for Function ' . $valToUpper . ')', 1, null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
|
||||||
$expectingOperator = false;
|
$expectingOperator = false;
|
||||||
}
|
}
|
||||||
$stack->push('Brace', '(');
|
$stack->push('Brace', '(');
|
||||||
@ -3475,7 +3658,7 @@ class Calculation
|
|||||||
|
|
||||||
// If the last entry on the stack was a : operator, then we have a cell range reference
|
// If the last entry on the stack was a : operator, then we have a cell range reference
|
||||||
$testPrevOp = $stack->last(1);
|
$testPrevOp = $stack->last(1);
|
||||||
if ($testPrevOp['value'] == ':') {
|
if ($testPrevOp !== null && $testPrevOp['value'] == ':') {
|
||||||
// If we have a worksheet reference, then we're playing with a 3D reference
|
// If we have a worksheet reference, then we're playing with a 3D reference
|
||||||
if ($matches[2] == '') {
|
if ($matches[2] == '') {
|
||||||
// Otherwise, we 'inherit' the worksheet reference from the start cell reference
|
// Otherwise, we 'inherit' the worksheet reference from the start cell reference
|
||||||
@ -3490,32 +3673,39 @@ class Calculation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$output[] = ['type' => 'Cell Reference', 'value' => $val, 'reference' => $val];
|
$outputItem = $stack->getStackItem('Cell Reference', $val, $val, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
|
||||||
|
|
||||||
|
$output[] = $outputItem;
|
||||||
} else { // it's a variable, constant, string, number or boolean
|
} else { // it's a variable, constant, string, number or boolean
|
||||||
// If the last entry on the stack was a : operator, then we may have a row or column range reference
|
// If the last entry on the stack was a : operator, then we may have a row or column range reference
|
||||||
$testPrevOp = $stack->last(1);
|
$testPrevOp = $stack->last(1);
|
||||||
if ($testPrevOp['value'] == ':') {
|
if ($testPrevOp !== null && $testPrevOp['value'] === ':') {
|
||||||
$startRowColRef = $output[count($output) - 1]['value'];
|
$startRowColRef = $output[count($output) - 1]['value'];
|
||||||
list($rangeWS1, $startRowColRef) = Worksheet::extractSheetTitle($startRowColRef, true);
|
[$rangeWS1, $startRowColRef] = Worksheet::extractSheetTitle($startRowColRef, true);
|
||||||
|
$rangeSheetRef = $rangeWS1;
|
||||||
if ($rangeWS1 != '') {
|
if ($rangeWS1 != '') {
|
||||||
$rangeWS1 .= '!';
|
$rangeWS1 .= '!';
|
||||||
}
|
}
|
||||||
list($rangeWS2, $val) = Worksheet::extractSheetTitle($val, true);
|
[$rangeWS2, $val] = Worksheet::extractSheetTitle($val, true);
|
||||||
if ($rangeWS2 != '') {
|
if ($rangeWS2 != '') {
|
||||||
$rangeWS2 .= '!';
|
$rangeWS2 .= '!';
|
||||||
} else {
|
} else {
|
||||||
$rangeWS2 = $rangeWS1;
|
$rangeWS2 = $rangeWS1;
|
||||||
}
|
}
|
||||||
|
$refSheet = $pCellParent;
|
||||||
|
if ($pCellParent !== null && $rangeSheetRef !== $pCellParent->getTitle()) {
|
||||||
|
$refSheet = $pCellParent->getParent()->getSheetByName($rangeSheetRef);
|
||||||
|
}
|
||||||
if ((is_int($startRowColRef)) && (ctype_digit($val)) &&
|
if ((is_int($startRowColRef)) && (ctype_digit($val)) &&
|
||||||
($startRowColRef <= 1048576) && ($val <= 1048576)) {
|
($startRowColRef <= 1048576) && ($val <= 1048576)) {
|
||||||
// Row range
|
// Row range
|
||||||
$endRowColRef = ($pCellParent !== null) ? $pCellParent->getHighestColumn() : 'XFD'; // Max 16,384 columns for Excel2007
|
$endRowColRef = ($refSheet !== null) ? $refSheet->getHighestColumn() : 'XFD'; // Max 16,384 columns for Excel2007
|
||||||
$output[count($output) - 1]['value'] = $rangeWS1 . 'A' . $startRowColRef;
|
$output[count($output) - 1]['value'] = $rangeWS1 . 'A' . $startRowColRef;
|
||||||
$val = $rangeWS2 . $endRowColRef . $val;
|
$val = $rangeWS2 . $endRowColRef . $val;
|
||||||
} elseif ((ctype_alpha($startRowColRef)) && (ctype_alpha($val)) &&
|
} elseif ((ctype_alpha($startRowColRef)) && (ctype_alpha($val)) &&
|
||||||
(strlen($startRowColRef) <= 3) && (strlen($val) <= 3)) {
|
(strlen($startRowColRef) <= 3) && (strlen($val) <= 3)) {
|
||||||
// Column range
|
// Column range
|
||||||
$endRowColRef = ($pCellParent !== null) ? $pCellParent->getHighestRow() : 1048576; // Max 1,048,576 rows for Excel2007
|
$endRowColRef = ($refSheet !== null) ? $refSheet->getHighestRow() : 1048576; // Max 1,048,576 rows for Excel2007
|
||||||
$output[count($output) - 1]['value'] = $rangeWS1 . strtoupper($startRowColRef) . '1';
|
$output[count($output) - 1]['value'] = $rangeWS1 . strtoupper($startRowColRef) . '1';
|
||||||
$val = $rangeWS2 . $val . $endRowColRef;
|
$val = $rangeWS2 . $val . $endRowColRef;
|
||||||
}
|
}
|
||||||
@ -3537,7 +3727,7 @@ class Calculation
|
|||||||
} elseif (($localeConstant = array_search(trim(strtoupper($val)), self::$localeBoolean)) !== false) {
|
} elseif (($localeConstant = array_search(trim(strtoupper($val)), self::$localeBoolean)) !== false) {
|
||||||
$val = self::$excelConstants[$localeConstant];
|
$val = self::$excelConstants[$localeConstant];
|
||||||
}
|
}
|
||||||
$details = ['type' => 'Value', 'value' => $val, 'reference' => null];
|
$details = $stack->getStackItem('Value', $val, null, $currentCondition, $currentOnlyIf, $currentOnlyIfNot);
|
||||||
if ($localeConstant) {
|
if ($localeConstant) {
|
||||||
$details['localeValue'] = $localeConstant;
|
$details['localeValue'] = $localeConstant;
|
||||||
}
|
}
|
||||||
@ -3557,7 +3747,7 @@ class Calculation
|
|||||||
} elseif (isset(self::$operators[$opCharacter]) && !$expectingOperator) {
|
} elseif (isset(self::$operators[$opCharacter]) && !$expectingOperator) {
|
||||||
return $this->raiseFormulaError("Formula Error: Unexpected operator '$opCharacter'");
|
return $this->raiseFormulaError("Formula Error: Unexpected operator '$opCharacter'");
|
||||||
} else { // I don't even want to know what you did to get here
|
} else { // I don't even want to know what you did to get here
|
||||||
return $this->raiseFormulaError('Formula Error: An unexpected error occured');
|
return $this->raiseFormulaError('Formula Error: An unexpected error occurred');
|
||||||
}
|
}
|
||||||
// Test for end of formula string
|
// Test for end of formula string
|
||||||
if ($index == strlen($formula)) {
|
if ($index == strlen($formula)) {
|
||||||
@ -3640,9 +3830,85 @@ class Calculation
|
|||||||
$pCellParent = ($pCell !== null) ? $pCell->getParent() : null;
|
$pCellParent = ($pCell !== null) ? $pCell->getParent() : null;
|
||||||
$stack = new Stack();
|
$stack = new Stack();
|
||||||
|
|
||||||
|
// Stores branches that have been pruned
|
||||||
|
$fakedForBranchPruning = [];
|
||||||
|
// help us to know when pruning ['branchTestId' => true/false]
|
||||||
|
$branchStore = [];
|
||||||
|
|
||||||
// Loop through each token in turn
|
// Loop through each token in turn
|
||||||
foreach ($tokens as $tokenData) {
|
foreach ($tokens as $tokenData) {
|
||||||
$token = $tokenData['value'];
|
$token = $tokenData['value'];
|
||||||
|
|
||||||
|
// Branch pruning: skip useless resolutions
|
||||||
|
$storeKey = $tokenData['storeKey'] ?? null;
|
||||||
|
if ($this->branchPruningEnabled && isset($tokenData['onlyIf'])) {
|
||||||
|
$onlyIfStoreKey = $tokenData['onlyIf'];
|
||||||
|
$storeValue = $branchStore[$onlyIfStoreKey] ?? null;
|
||||||
|
$storeValueAsBool = ($storeValue === null) ?
|
||||||
|
true : (bool) Functions::flattenSingleValue($storeValue);
|
||||||
|
if (is_array($storeValue)) {
|
||||||
|
$wrappedItem = end($storeValue);
|
||||||
|
$storeValue = end($wrappedItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($storeValue)
|
||||||
|
&& (
|
||||||
|
!$storeValueAsBool
|
||||||
|
|| Functions::isError($storeValue)
|
||||||
|
|| ($storeValue === 'Pruned branch')
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// If branching value is not true, we don't need to compute
|
||||||
|
if (!isset($fakedForBranchPruning['onlyIf-' . $onlyIfStoreKey])) {
|
||||||
|
$stack->push('Value', 'Pruned branch (only if ' . $onlyIfStoreKey . ') ' . $token);
|
||||||
|
$fakedForBranchPruning['onlyIf-' . $onlyIfStoreKey] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
// We are processing an if condition
|
||||||
|
// We cascade the pruning to the depending branches
|
||||||
|
$branchStore[$storeKey] = 'Pruned branch';
|
||||||
|
$fakedForBranchPruning['onlyIfNot-' . $storeKey] = true;
|
||||||
|
$fakedForBranchPruning['onlyIf-' . $storeKey] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->branchPruningEnabled && isset($tokenData['onlyIfNot'])) {
|
||||||
|
$onlyIfNotStoreKey = $tokenData['onlyIfNot'];
|
||||||
|
$storeValue = $branchStore[$onlyIfNotStoreKey] ?? null;
|
||||||
|
$storeValueAsBool = ($storeValue === null) ?
|
||||||
|
true : (bool) Functions::flattenSingleValue($storeValue);
|
||||||
|
if (is_array($storeValue)) {
|
||||||
|
$wrappedItem = end($storeValue);
|
||||||
|
$storeValue = end($wrappedItem);
|
||||||
|
}
|
||||||
|
if (isset($storeValue)
|
||||||
|
&& (
|
||||||
|
$storeValueAsBool
|
||||||
|
|| Functions::isError($storeValue)
|
||||||
|
|| ($storeValue === 'Pruned branch'))
|
||||||
|
) {
|
||||||
|
// If branching value is true, we don't need to compute
|
||||||
|
if (!isset($fakedForBranchPruning['onlyIfNot-' . $onlyIfNotStoreKey])) {
|
||||||
|
$stack->push('Value', 'Pruned branch (only if not ' . $onlyIfNotStoreKey . ') ' . $token);
|
||||||
|
$fakedForBranchPruning['onlyIfNot-' . $onlyIfNotStoreKey] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
// We are processing an if condition
|
||||||
|
// We cascade the pruning to the depending branches
|
||||||
|
$branchStore[$storeKey] = 'Pruned branch';
|
||||||
|
$fakedForBranchPruning['onlyIfNot-' . $storeKey] = true;
|
||||||
|
$fakedForBranchPruning['onlyIf-' . $storeKey] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if the token is a binary operator, pop the top two values off the stack, do the operation, and push the result back on the stack
|
// if the token is a binary operator, pop the top two values off the stack, do the operation, and push the result back on the stack
|
||||||
if (isset(self::$binaryOperators[$token])) {
|
if (isset(self::$binaryOperators[$token])) {
|
||||||
// We must have two operands, error if we don't
|
// We must have two operands, error if we don't
|
||||||
@ -3672,18 +3938,21 @@ class Calculation
|
|||||||
case '<=': // Less than or Equal to
|
case '<=': // Less than or Equal to
|
||||||
case '=': // Equality
|
case '=': // Equality
|
||||||
case '<>': // Inequality
|
case '<>': // Inequality
|
||||||
$this->executeBinaryComparisonOperation($cellID, $operand1, $operand2, $token, $stack);
|
$result = $this->executeBinaryComparisonOperation($cellID, $operand1, $operand2, $token, $stack);
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
$branchStore[$storeKey] = $result;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
// Binary Operators
|
// Binary Operators
|
||||||
case ':': // Range
|
case ':': // Range
|
||||||
if (strpos($operand1Data['reference'], '!') !== false) {
|
if (strpos($operand1Data['reference'], '!') !== false) {
|
||||||
list($sheet1, $operand1Data['reference']) = Worksheet::extractSheetTitle($operand1Data['reference'], true);
|
[$sheet1, $operand1Data['reference']] = Worksheet::extractSheetTitle($operand1Data['reference'], true);
|
||||||
} else {
|
} else {
|
||||||
$sheet1 = ($pCellParent !== null) ? $pCellWorksheet->getTitle() : '';
|
$sheet1 = ($pCellParent !== null) ? $pCellWorksheet->getTitle() : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
list($sheet2, $operand2Data['reference']) = Worksheet::extractSheetTitle($operand2Data['reference'], true);
|
[$sheet2, $operand2Data['reference']] = Worksheet::extractSheetTitle($operand2Data['reference'], true);
|
||||||
if (empty($sheet2)) {
|
if (empty($sheet2)) {
|
||||||
$sheet2 = $sheet1;
|
$sheet2 = $sheet1;
|
||||||
}
|
}
|
||||||
@ -3728,23 +3997,38 @@ class Calculation
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case '+': // Addition
|
case '+': // Addition
|
||||||
$this->executeNumericBinaryOperation($operand1, $operand2, $token, 'plusEquals', $stack);
|
$result = $this->executeNumericBinaryOperation($operand1, $operand2, $token, 'plusEquals', $stack);
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
$branchStore[$storeKey] = $result;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case '-': // Subtraction
|
case '-': // Subtraction
|
||||||
$this->executeNumericBinaryOperation($operand1, $operand2, $token, 'minusEquals', $stack);
|
$result = $this->executeNumericBinaryOperation($operand1, $operand2, $token, 'minusEquals', $stack);
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
$branchStore[$storeKey] = $result;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case '*': // Multiplication
|
case '*': // Multiplication
|
||||||
$this->executeNumericBinaryOperation($operand1, $operand2, $token, 'arrayTimesEquals', $stack);
|
$result = $this->executeNumericBinaryOperation($operand1, $operand2, $token, 'arrayTimesEquals', $stack);
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
$branchStore[$storeKey] = $result;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case '/': // Division
|
case '/': // Division
|
||||||
$this->executeNumericBinaryOperation($operand1, $operand2, $token, 'arrayRightDivide', $stack);
|
$result = $this->executeNumericBinaryOperation($operand1, $operand2, $token, 'arrayRightDivide', $stack);
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
$branchStore[$storeKey] = $result;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case '^': // Exponential
|
case '^': // Exponential
|
||||||
$this->executeNumericBinaryOperation($operand1, $operand2, $token, 'power', $stack);
|
$result = $this->executeNumericBinaryOperation($operand1, $operand2, $token, 'power', $stack);
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
$branchStore[$storeKey] = $result;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case '&': // Concatenation
|
case '&': // Concatenation
|
||||||
@ -3777,6 +4061,10 @@ class Calculation
|
|||||||
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($result));
|
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($result));
|
||||||
$stack->push('Value', $result);
|
$stack->push('Value', $result);
|
||||||
|
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
$branchStore[$storeKey] = $result;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case '|': // Intersect
|
case '|': // Intersect
|
||||||
$rowIntersect = array_intersect_key($operand1, $operand2);
|
$rowIntersect = array_intersect_key($operand1, $operand2);
|
||||||
@ -3821,6 +4109,9 @@ class Calculation
|
|||||||
}
|
}
|
||||||
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($result));
|
$this->debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($result));
|
||||||
$stack->push('Value', $result);
|
$stack->push('Value', $result);
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
$branchStore[$storeKey] = $result;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->executeNumericBinaryOperation($multiplier, $arg, '*', 'arrayTimesEquals', $stack);
|
$this->executeNumericBinaryOperation($multiplier, $arg, '*', 'arrayTimesEquals', $stack);
|
||||||
}
|
}
|
||||||
@ -3894,9 +4185,16 @@ class Calculation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$stack->push('Value', $cellValue, $cellRef);
|
$stack->push('Value', $cellValue, $cellRef);
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
$branchStore[$storeKey] = $cellValue;
|
||||||
|
}
|
||||||
|
|
||||||
// if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on
|
// if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on
|
||||||
} elseif (preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/i', $token, $matches)) {
|
} elseif (preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/i', $token, $matches)) {
|
||||||
|
if ($pCellParent) {
|
||||||
|
$pCell->attach($pCellParent);
|
||||||
|
}
|
||||||
|
|
||||||
$functionName = $matches[1];
|
$functionName = $matches[1];
|
||||||
$argCount = $stack->pop();
|
$argCount = $stack->pop();
|
||||||
$argCount = $argCount['value'];
|
$argCount = $argCount['value'];
|
||||||
@ -3939,6 +4237,7 @@ class Calculation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse the order of the arguments
|
// Reverse the order of the arguments
|
||||||
krsort($args);
|
krsort($args);
|
||||||
|
|
||||||
@ -3963,22 +4262,32 @@ class Calculation
|
|||||||
}
|
}
|
||||||
unset($arg);
|
unset($arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = call_user_func_array($functionCall, $args);
|
$result = call_user_func_array($functionCall, $args);
|
||||||
|
|
||||||
if ($functionName != 'MKMATRIX') {
|
if ($functionName != 'MKMATRIX') {
|
||||||
$this->debugLog->writeDebugLog('Evaluation Result for ', self::localeFunc($functionName), '() function call is ', $this->showTypeDetails($result));
|
$this->debugLog->writeDebugLog('Evaluation Result for ', self::localeFunc($functionName), '() function call is ', $this->showTypeDetails($result));
|
||||||
}
|
}
|
||||||
$stack->push('Value', self::wrapResult($result));
|
$stack->push('Value', self::wrapResult($result));
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
$branchStore[$storeKey] = $result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if the token is a number, boolean, string or an Excel error, push it onto the stack
|
// if the token is a number, boolean, string or an Excel error, push it onto the stack
|
||||||
if (isset(self::$excelConstants[strtoupper($token)])) {
|
if (isset(self::$excelConstants[strtoupper($token)])) {
|
||||||
$excelConstant = strtoupper($token);
|
$excelConstant = strtoupper($token);
|
||||||
$stack->push('Constant Value', self::$excelConstants[$excelConstant]);
|
$stack->push('Constant Value', self::$excelConstants[$excelConstant]);
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
$branchStore[$storeKey] = self::$excelConstants[$excelConstant];
|
||||||
|
}
|
||||||
$this->debugLog->writeDebugLog('Evaluating Constant ', $excelConstant, ' as ', $this->showTypeDetails(self::$excelConstants[$excelConstant]));
|
$this->debugLog->writeDebugLog('Evaluating Constant ', $excelConstant, ' as ', $this->showTypeDetails(self::$excelConstants[$excelConstant]));
|
||||||
} elseif ((is_numeric($token)) || ($token === null) || (is_bool($token)) || ($token == '') || ($token[0] == '"') || ($token[0] == '#')) {
|
} elseif ((is_numeric($token)) || ($token === null) || (is_bool($token)) || ($token == '') || ($token[0] == '"') || ($token[0] == '#')) {
|
||||||
$stack->push('Value', $token);
|
$stack->push('Value', $token);
|
||||||
// if the token is a named range, push the named range name onto the stack
|
if (isset($storeKey)) {
|
||||||
|
$branchStore[$storeKey] = $token;
|
||||||
|
}
|
||||||
|
// if the token is a named range, push the named range name onto the stack
|
||||||
} elseif (preg_match('/^' . self::CALCULATION_REGEXP_NAMEDRANGE . '$/i', $token, $matches)) {
|
} elseif (preg_match('/^' . self::CALCULATION_REGEXP_NAMEDRANGE . '$/i', $token, $matches)) {
|
||||||
$namedRange = $matches[6];
|
$namedRange = $matches[6];
|
||||||
$this->debugLog->writeDebugLog('Evaluating Named Range ', $namedRange);
|
$this->debugLog->writeDebugLog('Evaluating Named Range ', $namedRange);
|
||||||
@ -3987,6 +4296,9 @@ class Calculation
|
|||||||
$pCell->attach($pCellParent);
|
$pCell->attach($pCellParent);
|
||||||
$this->debugLog->writeDebugLog('Evaluation Result for named range ', $namedRange, ' is ', $this->showTypeDetails($cellValue));
|
$this->debugLog->writeDebugLog('Evaluation Result for named range ', $namedRange, ' is ', $this->showTypeDetails($cellValue));
|
||||||
$stack->push('Named Range', $cellValue, $namedRange);
|
$stack->push('Named Range', $cellValue, $namedRange);
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
$branchStore[$storeKey] = $cellValue;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return $this->raiseFormulaError("undefined variable '$token'");
|
return $this->raiseFormulaError("undefined variable '$token'");
|
||||||
}
|
}
|
||||||
@ -4048,7 +4360,7 @@ class Calculation
|
|||||||
* @param Stack $stack
|
* @param Stack $stack
|
||||||
* @param bool $recursingArrays
|
* @param bool $recursingArrays
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
private function executeBinaryComparisonOperation($cellID, $operand1, $operand2, $operation, Stack &$stack, $recursingArrays = false)
|
private function executeBinaryComparisonOperation($cellID, $operand1, $operand2, $operation, Stack &$stack, $recursingArrays = false)
|
||||||
{
|
{
|
||||||
@ -4085,7 +4397,7 @@ class Calculation
|
|||||||
// And push the result onto the stack
|
// And push the result onto the stack
|
||||||
$stack->push('Array', $result);
|
$stack->push('Array', $result);
|
||||||
|
|
||||||
return true;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple validate the two operands if they are string values
|
// Simple validate the two operands if they are string values
|
||||||
@ -4175,7 +4487,7 @@ class Calculation
|
|||||||
// And push the result onto the stack
|
// And push the result onto the stack
|
||||||
$stack->push('Value', $result);
|
$stack->push('Value', $result);
|
||||||
|
|
||||||
return true;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -4201,7 +4513,7 @@ class Calculation
|
|||||||
* @param string $matrixFunction
|
* @param string $matrixFunction
|
||||||
* @param mixed $stack
|
* @param mixed $stack
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool|mixed
|
||||||
*/
|
*/
|
||||||
private function executeNumericBinaryOperation($operand1, $operand2, $operation, $matrixFunction, &$stack)
|
private function executeNumericBinaryOperation($operand1, $operand2, $operation, $matrixFunction, &$stack)
|
||||||
{
|
{
|
||||||
@ -4279,7 +4591,7 @@ class Calculation
|
|||||||
// And push the result onto the stack
|
// And push the result onto the stack
|
||||||
$stack->push('Value', $result);
|
$stack->push('Value', $result);
|
||||||
|
|
||||||
return true;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// trigger an error, but nicely, if need be
|
// trigger an error, but nicely, if need be
|
||||||
@ -4312,7 +4624,7 @@ class Calculation
|
|||||||
if ($pSheet !== null) {
|
if ($pSheet !== null) {
|
||||||
$pSheetName = $pSheet->getTitle();
|
$pSheetName = $pSheet->getTitle();
|
||||||
if (strpos($pRange, '!') !== false) {
|
if (strpos($pRange, '!') !== false) {
|
||||||
list($pSheetName, $pRange) = Worksheet::extractSheetTitle($pRange, true);
|
[$pSheetName, $pRange] = Worksheet::extractSheetTitle($pRange, true);
|
||||||
$pSheet = $this->spreadsheet->getSheetByName($pSheetName);
|
$pSheet = $this->spreadsheet->getSheetByName($pSheetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4365,7 +4677,7 @@ class Calculation
|
|||||||
if ($pSheet !== null) {
|
if ($pSheet !== null) {
|
||||||
$pSheetName = $pSheet->getTitle();
|
$pSheetName = $pSheet->getTitle();
|
||||||
if (strpos($pRange, '!') !== false) {
|
if (strpos($pRange, '!') !== false) {
|
||||||
list($pSheetName, $pRange) = Worksheet::extractSheetTitle($pRange, true);
|
[$pSheetName, $pRange] = Worksheet::extractSheetTitle($pRange, true);
|
||||||
$pSheet = $this->spreadsheet->getSheetByName($pSheetName);
|
$pSheet = $this->spreadsheet->getSheetByName($pSheetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4389,7 +4701,7 @@ class Calculation
|
|||||||
$aReferences = Coordinate::extractAllCellReferencesInRange($pRange);
|
$aReferences = Coordinate::extractAllCellReferencesInRange($pRange);
|
||||||
if (!isset($aReferences[1])) {
|
if (!isset($aReferences[1])) {
|
||||||
// Single cell (or single column or row) in range
|
// Single cell (or single column or row) in range
|
||||||
list($currentCol, $currentRow) = Coordinate::coordinateFromString($aReferences[0]);
|
[$currentCol, $currentRow] = Coordinate::coordinateFromString($aReferences[0]);
|
||||||
if ($pSheet->cellExists($aReferences[0])) {
|
if ($pSheet->cellExists($aReferences[0])) {
|
||||||
$returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
|
$returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
|
||||||
} else {
|
} else {
|
||||||
@ -4399,7 +4711,7 @@ class Calculation
|
|||||||
// Extract cell data for all cells in the range
|
// Extract cell data for all cells in the range
|
||||||
foreach ($aReferences as $reference) {
|
foreach ($aReferences as $reference) {
|
||||||
// Extract range
|
// Extract range
|
||||||
list($currentCol, $currentRow) = Coordinate::coordinateFromString($reference);
|
[$currentCol, $currentRow] = Coordinate::coordinateFromString($reference);
|
||||||
if ($pSheet->cellExists($reference)) {
|
if ($pSheet->cellExists($reference)) {
|
||||||
$returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog);
|
$returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog);
|
||||||
} else {
|
} else {
|
||||||
@ -4483,4 +4795,26 @@ class Calculation
|
|||||||
|
|
||||||
return $args;
|
return $args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getUnusedBranchStoreKey()
|
||||||
|
{
|
||||||
|
$storeKeyValue = 'storeKey-' . $this->branchStoreKeyCounter;
|
||||||
|
++$this->branchStoreKeyCounter;
|
||||||
|
|
||||||
|
return $storeKeyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getTokensAsString($tokens)
|
||||||
|
{
|
||||||
|
$tokensStr = array_map(function ($token) {
|
||||||
|
$value = $token['value'] ?? 'no value';
|
||||||
|
while (is_array($value)) {
|
||||||
|
$value = array_pop($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}, $tokens);
|
||||||
|
|
||||||
|
return '[ ' . implode(' | ', $tokensStr) . ' ]';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -147,7 +147,7 @@ class Database
|
|||||||
* the column label in which you specify a condition for the
|
* the column label in which you specify a condition for the
|
||||||
* column.
|
* column.
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string
|
||||||
*/
|
*/
|
||||||
public static function DAVERAGE($database, $field, $criteria)
|
public static function DAVERAGE($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
@ -452,7 +452,7 @@ class Database
|
|||||||
* the column label in which you specify a condition for the
|
* the column label in which you specify a condition for the
|
||||||
* column.
|
* column.
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string
|
||||||
*/
|
*/
|
||||||
public static function DSTDEV($database, $field, $criteria)
|
public static function DSTDEV($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
@ -493,7 +493,7 @@ class Database
|
|||||||
* the column label in which you specify a condition for the
|
* the column label in which you specify a condition for the
|
||||||
* column.
|
* column.
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string
|
||||||
*/
|
*/
|
||||||
public static function DSTDEVP($database, $field, $criteria)
|
public static function DSTDEVP($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class DateTime
|
|||||||
*/
|
*/
|
||||||
public static function isLeapYear($year)
|
public static function isLeapYear($year)
|
||||||
{
|
{
|
||||||
return (($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0);
|
return (($year % 4) === 0) && (($year % 100) !== 0) || (($year % 400) === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -156,11 +156,11 @@ class DateTime
|
|||||||
$retValue = (float) Date::PHPToExcel(time());
|
$retValue = (float) Date::PHPToExcel(time());
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Functions::RETURNDATE_PHP_NUMERIC:
|
case Functions::RETURNDATE_UNIX_TIMESTAMP:
|
||||||
$retValue = (int) time();
|
$retValue = (int) time();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Functions::RETURNDATE_PHP_OBJECT:
|
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
|
||||||
$retValue = new \DateTime();
|
$retValue = new \DateTime();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -200,11 +200,11 @@ class DateTime
|
|||||||
$retValue = (float) $excelDateTime;
|
$retValue = (float) $excelDateTime;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Functions::RETURNDATE_PHP_NUMERIC:
|
case Functions::RETURNDATE_UNIX_TIMESTAMP:
|
||||||
$retValue = (int) Date::excelToTimestamp($excelDateTime);
|
$retValue = (int) Date::excelToTimestamp($excelDateTime);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Functions::RETURNDATE_PHP_OBJECT:
|
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
|
||||||
$retValue = Date::excelToDateTimeObject($excelDateTime);
|
$retValue = Date::excelToDateTimeObject($excelDateTime);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -325,9 +325,9 @@ class DateTime
|
|||||||
switch (Functions::getReturnDateType()) {
|
switch (Functions::getReturnDateType()) {
|
||||||
case Functions::RETURNDATE_EXCEL:
|
case Functions::RETURNDATE_EXCEL:
|
||||||
return (float) $excelDateValue;
|
return (float) $excelDateValue;
|
||||||
case Functions::RETURNDATE_PHP_NUMERIC:
|
case Functions::RETURNDATE_UNIX_TIMESTAMP:
|
||||||
return (int) Date::excelToTimestamp($excelDateValue);
|
return (int) Date::excelToTimestamp($excelDateValue);
|
||||||
case Functions::RETURNDATE_PHP_OBJECT:
|
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
|
||||||
return Date::excelToDateTimeObject($excelDateValue);
|
return Date::excelToDateTimeObject($excelDateValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -420,9 +420,9 @@ class DateTime
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (float) Date::formattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second);
|
return (float) Date::formattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second);
|
||||||
case Functions::RETURNDATE_PHP_NUMERIC:
|
case Functions::RETURNDATE_UNIX_TIMESTAMP:
|
||||||
return (int) Date::excelToTimestamp(Date::formattedPHPToExcel(1970, 1, 1, $hour, $minute, $second)); // -2147468400; // -2147472000 + 3600
|
return (int) Date::excelToTimestamp(Date::formattedPHPToExcel(1970, 1, 1, $hour, $minute, $second)); // -2147468400; // -2147472000 + 3600
|
||||||
case Functions::RETURNDATE_PHP_OBJECT:
|
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
|
||||||
$dayAdjust = 0;
|
$dayAdjust = 0;
|
||||||
if ($hour < 0) {
|
if ($hour < 0) {
|
||||||
$dayAdjust = floor($hour / 24);
|
$dayAdjust = floor($hour / 24);
|
||||||
@ -472,7 +472,6 @@ class DateTime
|
|||||||
*/
|
*/
|
||||||
public static function DATEVALUE($dateValue = 1)
|
public static function DATEVALUE($dateValue = 1)
|
||||||
{
|
{
|
||||||
$dateValueOrig = $dateValue;
|
|
||||||
$dateValue = trim(Functions::flattenSingleValue($dateValue), '"');
|
$dateValue = trim(Functions::flattenSingleValue($dateValue), '"');
|
||||||
// Strip any ordinals because they're allowed in Excel (English only)
|
// Strip any ordinals because they're allowed in Excel (English only)
|
||||||
$dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue);
|
$dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue);
|
||||||
@ -492,7 +491,7 @@ class DateTime
|
|||||||
$yearFound = true;
|
$yearFound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((count($t1) == 1) && (strpos($t, ':') != false)) {
|
if ((count($t1) == 1) && (strpos($t, ':') !== false)) {
|
||||||
// We've been fed a time value without any date
|
// We've been fed a time value without any date
|
||||||
return 0.0;
|
return 0.0;
|
||||||
} elseif (count($t1) == 2) {
|
} elseif (count($t1) == 2) {
|
||||||
@ -569,9 +568,9 @@ class DateTime
|
|||||||
switch (Functions::getReturnDateType()) {
|
switch (Functions::getReturnDateType()) {
|
||||||
case Functions::RETURNDATE_EXCEL:
|
case Functions::RETURNDATE_EXCEL:
|
||||||
return (float) $excelDateValue;
|
return (float) $excelDateValue;
|
||||||
case Functions::RETURNDATE_PHP_NUMERIC:
|
case Functions::RETURNDATE_UNIX_TIMESTAMP:
|
||||||
return (int) Date::excelToTimestamp($excelDateValue);
|
return (int) Date::excelToTimestamp($excelDateValue);
|
||||||
case Functions::RETURNDATE_PHP_OBJECT:
|
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
|
||||||
return new \DateTime($PHPDateArray['year'] . '-' . $PHPDateArray['month'] . '-' . $PHPDateArray['day'] . ' 00:00:00');
|
return new \DateTime($PHPDateArray['year'] . '-' . $PHPDateArray['month'] . '-' . $PHPDateArray['day'] . ' 00:00:00');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -631,9 +630,9 @@ class DateTime
|
|||||||
switch (Functions::getReturnDateType()) {
|
switch (Functions::getReturnDateType()) {
|
||||||
case Functions::RETURNDATE_EXCEL:
|
case Functions::RETURNDATE_EXCEL:
|
||||||
return (float) $excelDateValue;
|
return (float) $excelDateValue;
|
||||||
case Functions::RETURNDATE_PHP_NUMERIC:
|
case Functions::RETURNDATE_UNIX_TIMESTAMP:
|
||||||
return (int) $phpDateValue = Date::excelToTimestamp($excelDateValue + 25569) - 3600;
|
return (int) $phpDateValue = Date::excelToTimestamp($excelDateValue + 25569) - 3600;
|
||||||
case Functions::RETURNDATE_PHP_OBJECT:
|
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
|
||||||
return new \DateTime('1900-01-01 ' . $PHPDateArray['hour'] . ':' . $PHPDateArray['minute'] . ':' . $PHPDateArray['second']);
|
return new \DateTime('1900-01-01 ' . $PHPDateArray['hour'] . ':' . $PHPDateArray['minute'] . ':' . $PHPDateArray['second']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -683,7 +682,6 @@ class DateTime
|
|||||||
$endMonths = $PHPEndDateObject->format('n');
|
$endMonths = $PHPEndDateObject->format('n');
|
||||||
$endYears = $PHPEndDateObject->format('Y');
|
$endYears = $PHPEndDateObject->format('Y');
|
||||||
|
|
||||||
$retVal = Functions::NAN();
|
|
||||||
switch ($unit) {
|
switch ($unit) {
|
||||||
case 'D':
|
case 'D':
|
||||||
$retVal = (int) $difference;
|
$retVal = (int) $difference;
|
||||||
@ -880,6 +878,8 @@ class DateTime
|
|||||||
*
|
*
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* YEARFRAC(startDate,endDate[,method])
|
* YEARFRAC(startDate,endDate[,method])
|
||||||
|
* See https://lists.oasis-open.org/archives/office-formula/200806/msg00039.html
|
||||||
|
* for description of algorithm used in Excel
|
||||||
*
|
*
|
||||||
* @category Date/Time Functions
|
* @category Date/Time Functions
|
||||||
*
|
*
|
||||||
@ -894,7 +894,7 @@ class DateTime
|
|||||||
* 3 Actual/365
|
* 3 Actual/365
|
||||||
* 4 European 30/360
|
* 4 European 30/360
|
||||||
*
|
*
|
||||||
* @return float fraction of the year
|
* @return float|string fraction of the year, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0)
|
public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0)
|
||||||
{
|
{
|
||||||
@ -908,6 +908,11 @@ class DateTime
|
|||||||
if (is_string($endDate = self::getDateValue($endDate))) {
|
if (is_string($endDate = self::getDateValue($endDate))) {
|
||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
}
|
}
|
||||||
|
if ($startDate > $endDate) {
|
||||||
|
$temp = $startDate;
|
||||||
|
$startDate = $endDate;
|
||||||
|
$endDate = $temp;
|
||||||
|
}
|
||||||
|
|
||||||
if (((is_numeric($method)) && (!is_string($method))) || ($method == '')) {
|
if (((is_numeric($method)) && (!is_string($method))) || ($method == '')) {
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
@ -918,46 +923,43 @@ class DateTime
|
|||||||
$startYear = self::YEAR($startDate);
|
$startYear = self::YEAR($startDate);
|
||||||
$endYear = self::YEAR($endDate);
|
$endYear = self::YEAR($endDate);
|
||||||
$years = $endYear - $startYear + 1;
|
$years = $endYear - $startYear + 1;
|
||||||
$leapDays = 0;
|
$startMonth = self::MONTHOFYEAR($startDate);
|
||||||
|
$startDay = self::DAYOFMONTH($startDate);
|
||||||
|
$endMonth = self::MONTHOFYEAR($endDate);
|
||||||
|
$endDay = self::DAYOFMONTH($endDate);
|
||||||
|
$startMonthDay = 100 * $startMonth + $startDay;
|
||||||
|
$endMonthDay = 100 * $endMonth + $endDay;
|
||||||
if ($years == 1) {
|
if ($years == 1) {
|
||||||
if (self::isLeapYear($endYear)) {
|
if (self::isLeapYear($endYear)) {
|
||||||
$startMonth = self::MONTHOFYEAR($startDate);
|
$tmpCalcAnnualBasis = 366;
|
||||||
$endMonth = self::MONTHOFYEAR($endDate);
|
} else {
|
||||||
$endDay = self::DAYOFMONTH($endDate);
|
$tmpCalcAnnualBasis = 365;
|
||||||
if (($startMonth < 3) ||
|
}
|
||||||
(($endMonth * 100 + $endDay) >= (2 * 100 + 29))) {
|
} elseif ($years == 2 && $startMonthDay >= $endMonthDay) {
|
||||||
$leapDays += 1;
|
if (self::isLeapYear($startYear)) {
|
||||||
|
if ($startMonthDay <= 229) {
|
||||||
|
$tmpCalcAnnualBasis = 366;
|
||||||
|
} else {
|
||||||
|
$tmpCalcAnnualBasis = 365;
|
||||||
}
|
}
|
||||||
|
} elseif (self::isLeapYear($endYear)) {
|
||||||
|
if ($endMonthDay >= 229) {
|
||||||
|
$tmpCalcAnnualBasis = 366;
|
||||||
|
} else {
|
||||||
|
$tmpCalcAnnualBasis = 365;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$tmpCalcAnnualBasis = 365;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
$tmpCalcAnnualBasis = 0;
|
||||||
for ($year = $startYear; $year <= $endYear; ++$year) {
|
for ($year = $startYear; $year <= $endYear; ++$year) {
|
||||||
if ($year == $startYear) {
|
$tmpCalcAnnualBasis += self::isLeapYear($year) ? 366 : 365;
|
||||||
$startMonth = self::MONTHOFYEAR($startDate);
|
|
||||||
$startDay = self::DAYOFMONTH($startDate);
|
|
||||||
if ($startMonth < 3) {
|
|
||||||
$leapDays += (self::isLeapYear($year)) ? 1 : 0;
|
|
||||||
}
|
|
||||||
} elseif ($year == $endYear) {
|
|
||||||
$endMonth = self::MONTHOFYEAR($endDate);
|
|
||||||
$endDay = self::DAYOFMONTH($endDate);
|
|
||||||
if (($endMonth * 100 + $endDay) >= (2 * 100 + 29)) {
|
|
||||||
$leapDays += (self::isLeapYear($year)) ? 1 : 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$leapDays += (self::isLeapYear($year)) ? 1 : 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ($years == 2) {
|
$tmpCalcAnnualBasis /= $years;
|
||||||
if (($leapDays == 0) && (self::isLeapYear($startYear)) && ($days > 365)) {
|
|
||||||
$leapDays = 1;
|
|
||||||
} elseif ($days < 366) {
|
|
||||||
$years = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$leapDays /= $years;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $days / (365 + $leapDays);
|
return $days / $tmpCalcAnnualBasis;
|
||||||
case 2:
|
case 2:
|
||||||
return self::DATEDIF($startDate, $endDate) / 360;
|
return self::DATEDIF($startDate, $endDate) / 360;
|
||||||
case 3:
|
case 3:
|
||||||
@ -1154,9 +1156,9 @@ class DateTime
|
|||||||
switch (Functions::getReturnDateType()) {
|
switch (Functions::getReturnDateType()) {
|
||||||
case Functions::RETURNDATE_EXCEL:
|
case Functions::RETURNDATE_EXCEL:
|
||||||
return (float) $endDate;
|
return (float) $endDate;
|
||||||
case Functions::RETURNDATE_PHP_NUMERIC:
|
case Functions::RETURNDATE_UNIX_TIMESTAMP:
|
||||||
return (int) Date::excelToTimestamp($endDate);
|
return (int) Date::excelToTimestamp($endDate);
|
||||||
case Functions::RETURNDATE_PHP_OBJECT:
|
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
|
||||||
return Date::excelToDateTimeObject($endDate);
|
return Date::excelToDateTimeObject($endDate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1239,7 +1241,7 @@ class DateTime
|
|||||||
|
|
||||||
// Execute function
|
// Execute function
|
||||||
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
|
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
|
||||||
$DoW = $PHPDateObject->format('w');
|
$DoW = (int) $PHPDateObject->format('w');
|
||||||
|
|
||||||
$firstDay = 1;
|
$firstDay = 1;
|
||||||
switch ($style) {
|
switch ($style) {
|
||||||
@ -1248,13 +1250,13 @@ class DateTime
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if ($DoW == 0) {
|
if ($DoW === 0) {
|
||||||
$DoW = 7;
|
$DoW = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if ($DoW == 0) {
|
if ($DoW === 0) {
|
||||||
$DoW = 7;
|
$DoW = 7;
|
||||||
}
|
}
|
||||||
$firstDay = 0;
|
$firstDay = 0;
|
||||||
@ -1272,9 +1274,39 @@ class DateTime
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int) $DoW;
|
return $DoW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const STARTWEEK_SUNDAY = 1;
|
||||||
|
const STARTWEEK_MONDAY = 2;
|
||||||
|
const STARTWEEK_MONDAY_ALT = 11;
|
||||||
|
const STARTWEEK_TUESDAY = 12;
|
||||||
|
const STARTWEEK_WEDNESDAY = 13;
|
||||||
|
const STARTWEEK_THURSDAY = 14;
|
||||||
|
const STARTWEEK_FRIDAY = 15;
|
||||||
|
const STARTWEEK_SATURDAY = 16;
|
||||||
|
const STARTWEEK_SUNDAY_ALT = 17;
|
||||||
|
const DOW_SUNDAY = 1;
|
||||||
|
const DOW_MONDAY = 2;
|
||||||
|
const DOW_TUESDAY = 3;
|
||||||
|
const DOW_WEDNESDAY = 4;
|
||||||
|
const DOW_THURSDAY = 5;
|
||||||
|
const DOW_FRIDAY = 6;
|
||||||
|
const DOW_SATURDAY = 7;
|
||||||
|
const STARTWEEK_MONDAY_ISO = 21;
|
||||||
|
const METHODARR = [
|
||||||
|
self::STARTWEEK_SUNDAY => self::DOW_SUNDAY,
|
||||||
|
self::DOW_MONDAY,
|
||||||
|
self::STARTWEEK_MONDAY_ALT => self::DOW_MONDAY,
|
||||||
|
self::DOW_TUESDAY,
|
||||||
|
self::DOW_WEDNESDAY,
|
||||||
|
self::DOW_THURSDAY,
|
||||||
|
self::DOW_FRIDAY,
|
||||||
|
self::DOW_SATURDAY,
|
||||||
|
self::DOW_SUNDAY,
|
||||||
|
self::STARTWEEK_MONDAY_ISO => self::STARTWEEK_MONDAY_ISO,
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WEEKNUM.
|
* WEEKNUM.
|
||||||
*
|
*
|
||||||
@ -1293,41 +1325,51 @@ class DateTime
|
|||||||
* @param int $method Week begins on Sunday or Monday
|
* @param int $method Week begins on Sunday or Monday
|
||||||
* 1 or omitted Week begins on Sunday.
|
* 1 or omitted Week begins on Sunday.
|
||||||
* 2 Week begins on Monday.
|
* 2 Week begins on Monday.
|
||||||
|
* 11 Week begins on Monday.
|
||||||
|
* 12 Week begins on Tuesday.
|
||||||
|
* 13 Week begins on Wednesday.
|
||||||
|
* 14 Week begins on Thursday.
|
||||||
|
* 15 Week begins on Friday.
|
||||||
|
* 16 Week begins on Saturday.
|
||||||
|
* 17 Week begins on Sunday.
|
||||||
|
* 21 ISO (Jan. 4 is week 1, begins on Monday).
|
||||||
*
|
*
|
||||||
* @return int|string Week Number
|
* @return int|string Week Number
|
||||||
*/
|
*/
|
||||||
public static function WEEKNUM($dateValue = 1, $method = 1)
|
public static function WEEKNUM($dateValue = 1, $method = self::STARTWEEK_SUNDAY)
|
||||||
{
|
{
|
||||||
$dateValue = Functions::flattenSingleValue($dateValue);
|
$dateValue = Functions::flattenSingleValue($dateValue);
|
||||||
$method = Functions::flattenSingleValue($method);
|
$method = Functions::flattenSingleValue($method);
|
||||||
|
|
||||||
if (!is_numeric($method)) {
|
if (!is_numeric($method)) {
|
||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
} elseif (($method < 1) || ($method > 2)) {
|
|
||||||
return Functions::NAN();
|
|
||||||
}
|
}
|
||||||
$method = floor($method);
|
$method = (int) $method;
|
||||||
|
if (!array_key_exists($method, self::METHODARR)) {
|
||||||
|
return Functions::NaN();
|
||||||
|
}
|
||||||
|
$method = self::METHODARR[$method];
|
||||||
|
|
||||||
if ($dateValue === null) {
|
$dateValue = self::getDateValue($dateValue);
|
||||||
$dateValue = 1;
|
if (is_string($dateValue)) {
|
||||||
} elseif (is_string($dateValue = self::getDateValue($dateValue))) {
|
|
||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
} elseif ($dateValue < 0.0) {
|
}
|
||||||
|
if ($dateValue < 0.0) {
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute function
|
// Execute function
|
||||||
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
|
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
|
||||||
|
if ($method == self::STARTWEEK_MONDAY_ISO) {
|
||||||
|
return (int) $PHPDateObject->format('W');
|
||||||
|
}
|
||||||
$dayOfYear = $PHPDateObject->format('z');
|
$dayOfYear = $PHPDateObject->format('z');
|
||||||
$PHPDateObject->modify('-' . $dayOfYear . ' days');
|
$PHPDateObject->modify('-' . $dayOfYear . ' days');
|
||||||
$firstDayOfFirstWeek = $PHPDateObject->format('w');
|
$firstDayOfFirstWeek = $PHPDateObject->format('w');
|
||||||
$daysInFirstWeek = (6 - $firstDayOfFirstWeek + $method) % 7;
|
$daysInFirstWeek = (6 - $firstDayOfFirstWeek + $method) % 7;
|
||||||
$interval = $dayOfYear - $daysInFirstWeek;
|
$daysInFirstWeek += 7 * !$daysInFirstWeek;
|
||||||
$weekOfYear = floor($interval / 7) + 1;
|
$endFirstWeek = $daysInFirstWeek - 1;
|
||||||
|
$weekOfYear = floor(($dayOfYear - $endFirstWeek + 13) / 7);
|
||||||
if ($daysInFirstWeek) {
|
|
||||||
++$weekOfYear;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int) $weekOfYear;
|
return (int) $weekOfYear;
|
||||||
}
|
}
|
||||||
@ -1591,9 +1633,9 @@ class DateTime
|
|||||||
switch (Functions::getReturnDateType()) {
|
switch (Functions::getReturnDateType()) {
|
||||||
case Functions::RETURNDATE_EXCEL:
|
case Functions::RETURNDATE_EXCEL:
|
||||||
return (float) Date::PHPToExcel($PHPDateObject);
|
return (float) Date::PHPToExcel($PHPDateObject);
|
||||||
case Functions::RETURNDATE_PHP_NUMERIC:
|
case Functions::RETURNDATE_UNIX_TIMESTAMP:
|
||||||
return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject));
|
return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject));
|
||||||
case Functions::RETURNDATE_PHP_OBJECT:
|
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
|
||||||
return $PHPDateObject;
|
return $PHPDateObject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1640,9 +1682,9 @@ class DateTime
|
|||||||
switch (Functions::getReturnDateType()) {
|
switch (Functions::getReturnDateType()) {
|
||||||
case Functions::RETURNDATE_EXCEL:
|
case Functions::RETURNDATE_EXCEL:
|
||||||
return (float) Date::PHPToExcel($PHPDateObject);
|
return (float) Date::PHPToExcel($PHPDateObject);
|
||||||
case Functions::RETURNDATE_PHP_NUMERIC:
|
case Functions::RETURNDATE_UNIX_TIMESTAMP:
|
||||||
return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject));
|
return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject));
|
||||||
case Functions::RETURNDATE_PHP_OBJECT:
|
case Functions::RETURNDATE_PHP_DATETIME_OBJECT:
|
||||||
return $PHPDateObject;
|
return $PHPDateObject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -785,7 +785,7 @@ class Engineering
|
|||||||
* If $ord is nonnumeric, BESSELI returns the #VALUE! error value.
|
* If $ord is nonnumeric, BESSELI returns the #VALUE! error value.
|
||||||
* If $ord < 0, BESSELI returns the #NUM! error value.
|
* If $ord < 0, BESSELI returns the #NUM! error value.
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function BESSELI($x, $ord)
|
public static function BESSELI($x, $ord)
|
||||||
{
|
{
|
||||||
@ -839,7 +839,7 @@ class Engineering
|
|||||||
* If $ord is nonnumeric, BESSELJ returns the #VALUE! error value.
|
* If $ord is nonnumeric, BESSELJ returns the #VALUE! error value.
|
||||||
* If $ord < 0, BESSELJ returns the #NUM! error value.
|
* If $ord < 0, BESSELJ returns the #NUM! error value.
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function BESSELJ($x, $ord)
|
public static function BESSELJ($x, $ord)
|
||||||
{
|
{
|
||||||
@ -932,7 +932,7 @@ class Engineering
|
|||||||
* If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
|
* If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
|
||||||
* If $ord < 0, BESSELK returns the #NUM! error value.
|
* If $ord < 0, BESSELK returns the #NUM! error value.
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function BESSELK($x, $ord)
|
public static function BESSELK($x, $ord)
|
||||||
{
|
{
|
||||||
@ -1021,7 +1021,7 @@ class Engineering
|
|||||||
* If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
|
* If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
|
||||||
* If $ord < 0, BESSELK returns the #NUM! error value.
|
* If $ord < 0, BESSELK returns the #NUM! error value.
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function BESSELY($x, $ord)
|
public static function BESSELY($x, $ord)
|
||||||
{
|
{
|
||||||
@ -2713,7 +2713,7 @@ class Engineering
|
|||||||
* @param string $fromUOM the units for value
|
* @param string $fromUOM the units for value
|
||||||
* @param string $toUOM the units for the result
|
* @param string $toUOM the units for the result
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string
|
||||||
*/
|
*/
|
||||||
public static function CONVERTUOM($value, $fromUOM, $toUOM)
|
public static function CONVERTUOM($value, $fromUOM, $toUOM)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -71,7 +71,7 @@ class Financial
|
|||||||
* 3 365
|
* 3 365
|
||||||
* 4 European 360
|
* 4 European 360
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
private static function daysPerYear($year, $basis = 0)
|
private static function daysPerYear($year, $basis = 0)
|
||||||
{
|
{
|
||||||
@ -144,7 +144,7 @@ class Financial
|
|||||||
* 3 Actual/365
|
* 3 Actual/365
|
||||||
* 4 European 30/360
|
* 4 European 30/360
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function ACCRINT($issue, $firstinterest, $settlement, $rate, $par = 1000, $frequency = 1, $basis = 0)
|
public static function ACCRINT($issue, $firstinterest, $settlement, $rate, $par = 1000, $frequency = 1, $basis = 0)
|
||||||
{
|
{
|
||||||
@ -197,7 +197,7 @@ class Financial
|
|||||||
* 3 Actual/365
|
* 3 Actual/365
|
||||||
* 4 European 30/360
|
* 4 European 30/360
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function ACCRINTM($issue, $settlement, $rate, $par = 1000, $basis = 0)
|
public static function ACCRINTM($issue, $settlement, $rate, $par = 1000, $basis = 0)
|
||||||
{
|
{
|
||||||
@ -417,7 +417,7 @@ class Financial
|
|||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($settlement > $maturity) ||
|
if (($settlement >= $maturity) ||
|
||||||
(!self::isValidFrequency($frequency)) ||
|
(!self::isValidFrequency($frequency)) ||
|
||||||
(($basis < 0) || ($basis > 4))) {
|
(($basis < 0) || ($basis > 4))) {
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
@ -476,7 +476,7 @@ class Financial
|
|||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($settlement > $maturity) ||
|
if (($settlement >= $maturity) ||
|
||||||
(!self::isValidFrequency($frequency)) ||
|
(!self::isValidFrequency($frequency)) ||
|
||||||
(($basis < 0) || ($basis > 4))) {
|
(($basis < 0) || ($basis > 4))) {
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
@ -550,7 +550,7 @@ class Financial
|
|||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($settlement > $maturity) ||
|
if (($settlement >= $maturity) ||
|
||||||
(!self::isValidFrequency($frequency)) ||
|
(!self::isValidFrequency($frequency)) ||
|
||||||
(($basis < 0) || ($basis > 4))) {
|
(($basis < 0) || ($basis > 4))) {
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
@ -610,7 +610,7 @@ class Financial
|
|||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($settlement > $maturity) ||
|
if (($settlement >= $maturity) ||
|
||||||
(!self::isValidFrequency($frequency)) ||
|
(!self::isValidFrequency($frequency)) ||
|
||||||
(($basis < 0) || ($basis > 4))) {
|
(($basis < 0) || ($basis > 4))) {
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
@ -667,26 +667,22 @@ class Financial
|
|||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($settlement > $maturity) ||
|
if (($settlement >= $maturity) ||
|
||||||
(!self::isValidFrequency($frequency)) ||
|
(!self::isValidFrequency($frequency)) ||
|
||||||
(($basis < 0) || ($basis > 4))) {
|
(($basis < 0) || ($basis > 4))) {
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
}
|
}
|
||||||
|
|
||||||
$settlement = self::couponFirstPeriodDate($settlement, $maturity, $frequency, true);
|
$daysPerYear = self::daysPerYear(DateTime::YEAR($settlement), $basis);
|
||||||
$daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis) * 365;
|
$daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis) * $daysPerYear;
|
||||||
|
|
||||||
switch ($frequency) {
|
switch ($frequency) {
|
||||||
case 1: // annual payments
|
case 1: // annual payments
|
||||||
return ceil($daysBetweenSettlementAndMaturity / 360);
|
|
||||||
case 2: // half-yearly
|
case 2: // half-yearly
|
||||||
return ceil($daysBetweenSettlementAndMaturity / 180);
|
|
||||||
case 4: // quarterly
|
case 4: // quarterly
|
||||||
return ceil($daysBetweenSettlementAndMaturity / 90);
|
|
||||||
case 6: // bimonthly
|
case 6: // bimonthly
|
||||||
return ceil($daysBetweenSettlementAndMaturity / 60);
|
|
||||||
case 12: // monthly
|
case 12: // monthly
|
||||||
return ceil($daysBetweenSettlementAndMaturity / 30);
|
return ceil($daysBetweenSettlementAndMaturity / $daysPerYear * $frequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
@ -740,7 +736,7 @@ class Financial
|
|||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($settlement > $maturity) ||
|
if (($settlement >= $maturity) ||
|
||||||
(!self::isValidFrequency($frequency)) ||
|
(!self::isValidFrequency($frequency)) ||
|
||||||
(($basis < 0) || ($basis > 4))) {
|
(($basis < 0) || ($basis > 4))) {
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
@ -1428,7 +1424,7 @@ class Financial
|
|||||||
* @param float $finance_rate The interest rate you pay on the money used in the cash flows
|
* @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
|
* @param float $reinvestment_rate The interest rate you receive on the cash flows as you reinvest them
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function MIRR($values, $finance_rate, $reinvestment_rate)
|
public static function MIRR($values, $finance_rate, $reinvestment_rate)
|
||||||
{
|
{
|
||||||
@ -1470,7 +1466,7 @@ class Financial
|
|||||||
* @param float $effect_rate Effective interest rate
|
* @param float $effect_rate Effective interest rate
|
||||||
* @param int $npery Number of compounding payments per year
|
* @param int $npery Number of compounding payments per year
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function NOMINAL($effect_rate = 0, $npery = 0)
|
public static function NOMINAL($effect_rate = 0, $npery = 0)
|
||||||
{
|
{
|
||||||
@ -1497,7 +1493,7 @@ class Financial
|
|||||||
* @param float $fv Future Value
|
* @param float $fv Future Value
|
||||||
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
|
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function NPER($rate = 0, $pmt = 0, $pv = 0, $fv = 0, $type = 0)
|
public static function NPER($rate = 0, $pmt = 0, $pv = 0, $fv = 0, $type = 0)
|
||||||
{
|
{
|
||||||
@ -1565,7 +1561,7 @@ class Financial
|
|||||||
* @param float $pv Present Value
|
* @param float $pv Present Value
|
||||||
* @param float $fv Future Value
|
* @param float $fv Future Value
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function PDURATION($rate = 0, $pv = 0, $fv = 0)
|
public static function PDURATION($rate = 0, $pv = 0, $fv = 0)
|
||||||
{
|
{
|
||||||
@ -1594,7 +1590,7 @@ class Financial
|
|||||||
* @param float $fv Future Value
|
* @param float $fv Future Value
|
||||||
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
|
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function PMT($rate = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0)
|
public static function PMT($rate = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0)
|
||||||
{
|
{
|
||||||
@ -1629,7 +1625,7 @@ class Financial
|
|||||||
* @param float $fv Future Value
|
* @param float $fv Future Value
|
||||||
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
|
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function PPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0)
|
public static function PPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0)
|
||||||
{
|
{
|
||||||
@ -1713,7 +1709,7 @@ class Financial
|
|||||||
* 3 Actual/365
|
* 3 Actual/365
|
||||||
* 4 European 30/360
|
* 4 European 30/360
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function PRICEDISC($settlement, $maturity, $discount, $redemption, $basis = 0)
|
public static function PRICEDISC($settlement, $maturity, $discount, $redemption, $basis = 0)
|
||||||
{
|
{
|
||||||
@ -1759,7 +1755,7 @@ class Financial
|
|||||||
* 3 Actual/365
|
* 3 Actual/365
|
||||||
* 4 European 30/360
|
* 4 European 30/360
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function PRICEMAT($settlement, $maturity, $issue, $rate, $yield, $basis = 0)
|
public static function PRICEMAT($settlement, $maturity, $issue, $rate, $yield, $basis = 0)
|
||||||
{
|
{
|
||||||
@ -1817,7 +1813,7 @@ class Financial
|
|||||||
* @param float $fv Future Value
|
* @param float $fv Future Value
|
||||||
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
|
* @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function PV($rate = 0, $nper = 0, $pmt = 0, $fv = 0, $type = 0)
|
public static function PV($rate = 0, $nper = 0, $pmt = 0, $fv = 0, $type = 0)
|
||||||
{
|
{
|
||||||
@ -1933,7 +1929,7 @@ class Financial
|
|||||||
* 3 Actual/365
|
* 3 Actual/365
|
||||||
* 4 European 30/360
|
* 4 European 30/360
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function RECEIVED($settlement, $maturity, $investment, $discount, $basis = 0)
|
public static function RECEIVED($settlement, $maturity, $investment, $discount, $basis = 0)
|
||||||
{
|
{
|
||||||
@ -1969,7 +1965,7 @@ class Financial
|
|||||||
* @param float $pv Present Value
|
* @param float $pv Present Value
|
||||||
* @param float $fv Future Value
|
* @param float $fv Future Value
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function RRI($nper = 0, $pv = 0, $fv = 0)
|
public static function RRI($nper = 0, $pv = 0, $fv = 0)
|
||||||
{
|
{
|
||||||
@ -1996,7 +1992,7 @@ class Financial
|
|||||||
* @param mixed $salvage Value at the end of the depreciation
|
* @param mixed $salvage Value at the end of the depreciation
|
||||||
* @param mixed $life Number of periods over which the asset is depreciated
|
* @param mixed $life Number of periods over which the asset is depreciated
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function SLN($cost, $salvage, $life)
|
public static function SLN($cost, $salvage, $life)
|
||||||
{
|
{
|
||||||
@ -2026,7 +2022,7 @@ class Financial
|
|||||||
* @param mixed $life Number of periods over which the asset is depreciated
|
* @param mixed $life Number of periods over which the asset is depreciated
|
||||||
* @param mixed $period Period
|
* @param mixed $period Period
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function SYD($cost, $salvage, $life, $period)
|
public static function SYD($cost, $salvage, $life, $period)
|
||||||
{
|
{
|
||||||
@ -2058,7 +2054,7 @@ class Financial
|
|||||||
* The maturity date is the date when the Treasury bill expires.
|
* The maturity date is the date when the Treasury bill expires.
|
||||||
* @param int $discount The Treasury bill's discount rate
|
* @param int $discount The Treasury bill's discount rate
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function TBILLEQ($settlement, $maturity, $discount)
|
public static function TBILLEQ($settlement, $maturity, $discount)
|
||||||
{
|
{
|
||||||
@ -2097,7 +2093,7 @@ class Financial
|
|||||||
* The maturity date is the date when the Treasury bill expires.
|
* The maturity date is the date when the Treasury bill expires.
|
||||||
* @param int $discount The Treasury bill's discount rate
|
* @param int $discount The Treasury bill's discount rate
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function TBILLPRICE($settlement, $maturity, $discount)
|
public static function TBILLPRICE($settlement, $maturity, $discount)
|
||||||
{
|
{
|
||||||
@ -2152,7 +2148,7 @@ class Financial
|
|||||||
* The maturity date is the date when the Treasury bill expires.
|
* The maturity date is the date when the Treasury bill expires.
|
||||||
* @param int $price The Treasury bill's price per $100 face value
|
* @param int $price The Treasury bill's price per $100 face value
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|mixed|string
|
||||||
*/
|
*/
|
||||||
public static function TBILLYIELD($settlement, $maturity, $price)
|
public static function TBILLYIELD($settlement, $maturity, $price)
|
||||||
{
|
{
|
||||||
@ -2187,6 +2183,23 @@ class Financial
|
|||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XIRR.
|
||||||
|
*
|
||||||
|
* Returns the internal rate of return for a schedule of cash flows that is not necessarily periodic.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* =XIRR(values,dates,guess)
|
||||||
|
*
|
||||||
|
* @param float[] $values A series of cash flow payments
|
||||||
|
* The series of values must contain at least one positive value & one negative value
|
||||||
|
* @param mixed[] $dates A series of payment dates
|
||||||
|
* The first payment date indicates the beginning of the schedule of payments
|
||||||
|
* All other dates must be later than this date, but they may occur in any order
|
||||||
|
* @param float $guess An optional guess at the expected answer
|
||||||
|
*
|
||||||
|
* @return float|mixed|string
|
||||||
|
*/
|
||||||
public static function XIRR($values, $dates, $guess = 0.1)
|
public static function XIRR($values, $dates, $guess = 0.1)
|
||||||
{
|
{
|
||||||
if ((!is_array($values)) && (!is_array($dates))) {
|
if ((!is_array($values)) && (!is_array($dates))) {
|
||||||
@ -2199,11 +2212,28 @@ class Financial
|
|||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$datesCount = count($dates);
|
||||||
|
for ($i = 0; $i < $datesCount; ++$i) {
|
||||||
|
$dates[$i] = DateTime::getDateValue($dates[$i]);
|
||||||
|
if (!is_numeric($dates[$i])) {
|
||||||
|
return Functions::VALUE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (min($dates) != $dates[0]) {
|
||||||
|
return Functions::NAN();
|
||||||
|
}
|
||||||
|
|
||||||
// create an initial range, with a root somewhere between 0 and guess
|
// create an initial range, with a root somewhere between 0 and guess
|
||||||
$x1 = 0.0;
|
$x1 = 0.0;
|
||||||
$x2 = $guess;
|
$x2 = $guess;
|
||||||
$f1 = self::XNPV($x1, $values, $dates);
|
$f1 = self::XNPV($x1, $values, $dates);
|
||||||
|
if (!is_numeric($f1)) {
|
||||||
|
return $f1;
|
||||||
|
}
|
||||||
$f2 = self::XNPV($x2, $values, $dates);
|
$f2 = self::XNPV($x2, $values, $dates);
|
||||||
|
if (!is_numeric($f2)) {
|
||||||
|
return $f2;
|
||||||
|
}
|
||||||
for ($i = 0; $i < self::FINANCIAL_MAX_ITERATIONS; ++$i) {
|
for ($i = 0; $i < self::FINANCIAL_MAX_ITERATIONS; ++$i) {
|
||||||
if (($f1 * $f2) < 0.0) {
|
if (($f1 * $f2) < 0.0) {
|
||||||
break;
|
break;
|
||||||
@ -2214,7 +2244,7 @@ class Financial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (($f1 * $f2) > 0.0) {
|
if (($f1 * $f2) > 0.0) {
|
||||||
return Functions::VALUE();
|
return Functions::NAN();
|
||||||
}
|
}
|
||||||
|
|
||||||
$f = self::XNPV($x1, $values, $dates);
|
$f = self::XNPV($x1, $values, $dates);
|
||||||
@ -2251,15 +2281,15 @@ class Financial
|
|||||||
* =XNPV(rate,values,dates)
|
* =XNPV(rate,values,dates)
|
||||||
*
|
*
|
||||||
* @param float $rate the discount rate to apply to the cash flows
|
* @param float $rate the discount rate to apply to the cash flows
|
||||||
* @param array of float $values A series of cash flows that corresponds to a schedule of payments in dates.
|
* @param float[] $values A series of cash flows that corresponds to a schedule of payments in dates.
|
||||||
* The first payment is optional and corresponds to a cost or payment that occurs at the beginning of the investment.
|
* The first payment is optional and corresponds to a cost or payment that occurs at the beginning of the investment.
|
||||||
* If the first value is a cost or payment, it must be a negative value. All succeeding payments are discounted based on a 365-day year.
|
* If the first value is a cost or payment, it must be a negative value. All succeeding payments are discounted based on a 365-day year.
|
||||||
* The series of values must contain at least one positive value and one negative value.
|
* The series of values must contain at least one positive value and one negative value.
|
||||||
* @param array of mixed $dates A schedule of payment dates that corresponds to the cash flow payments.
|
* @param mixed[] $dates A schedule of payment dates that corresponds to the cash flow payments.
|
||||||
* The first payment date indicates the beginning of the schedule of payments.
|
* The first payment date indicates the beginning of the schedule of payments.
|
||||||
* All other dates must be later than this date, but they may occur in any order.
|
* All other dates must be later than this date, but they may occur in any order.
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|mixed|string
|
||||||
*/
|
*/
|
||||||
public static function XNPV($rate, $values, $dates)
|
public static function XNPV($rate, $values, $dates)
|
||||||
{
|
{
|
||||||
@ -2277,7 +2307,7 @@ class Financial
|
|||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
}
|
}
|
||||||
if ((min($values) > 0) || (max($values) < 0)) {
|
if ((min($values) > 0) || (max($values) < 0)) {
|
||||||
return Functions::VALUE();
|
return Functions::NAN();
|
||||||
}
|
}
|
||||||
|
|
||||||
$xnpv = 0.0;
|
$xnpv = 0.0;
|
||||||
@ -2309,7 +2339,7 @@ class Financial
|
|||||||
* 3 Actual/365
|
* 3 Actual/365
|
||||||
* 4 European 30/360
|
* 4 European 30/360
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function YIELDDISC($settlement, $maturity, $price, $redemption, $basis = 0)
|
public static function YIELDDISC($settlement, $maturity, $price, $redemption, $basis = 0)
|
||||||
{
|
{
|
||||||
@ -2360,7 +2390,7 @@ class Financial
|
|||||||
* 3 Actual/365
|
* 3 Actual/365
|
||||||
* 4 European 30/360
|
* 4 European 30/360
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function YIELDMAT($settlement, $maturity, $issue, $rate, $price, $basis = 0)
|
public static function YIELDMAT($settlement, $maturity, $issue, $rate, $price, $basis = 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -17,8 +17,11 @@ class Functions
|
|||||||
const COMPATIBILITY_EXCEL = 'Excel';
|
const COMPATIBILITY_EXCEL = 'Excel';
|
||||||
const COMPATIBILITY_GNUMERIC = 'Gnumeric';
|
const COMPATIBILITY_GNUMERIC = 'Gnumeric';
|
||||||
const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc';
|
const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc';
|
||||||
|
|
||||||
const RETURNDATE_PHP_NUMERIC = 'P';
|
const RETURNDATE_PHP_NUMERIC = 'P';
|
||||||
|
const RETURNDATE_UNIX_TIMESTAMP = 'P';
|
||||||
const RETURNDATE_PHP_OBJECT = 'O';
|
const RETURNDATE_PHP_OBJECT = 'O';
|
||||||
|
const RETURNDATE_PHP_DATETIME_OBJECT = 'O';
|
||||||
const RETURNDATE_EXCEL = 'E';
|
const RETURNDATE_EXCEL = 'E';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,16 +104,16 @@ class Functions
|
|||||||
*
|
*
|
||||||
* @param string $returnDateType Return Date Format
|
* @param string $returnDateType Return Date Format
|
||||||
* Permitted values are:
|
* Permitted values are:
|
||||||
* Functions::RETURNDATE_PHP_NUMERIC 'P'
|
* Functions::RETURNDATE_UNIX_TIMESTAMP 'P'
|
||||||
* Functions::RETURNDATE_PHP_OBJECT 'O'
|
* Functions::RETURNDATE_PHP_DATETIME_OBJECT 'O'
|
||||||
* Functions::RETURNDATE_EXCEL 'E'
|
* Functions::RETURNDATE_EXCEL 'E'
|
||||||
*
|
*
|
||||||
* @return bool Success or failure
|
* @return bool Success or failure
|
||||||
*/
|
*/
|
||||||
public static function setReturnDateType($returnDateType)
|
public static function setReturnDateType($returnDateType)
|
||||||
{
|
{
|
||||||
if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) ||
|
if (($returnDateType == self::RETURNDATE_UNIX_TIMESTAMP) ||
|
||||||
($returnDateType == self::RETURNDATE_PHP_OBJECT) ||
|
($returnDateType == self::RETURNDATE_PHP_DATETIME_OBJECT) ||
|
||||||
($returnDateType == self::RETURNDATE_EXCEL)
|
($returnDateType == self::RETURNDATE_EXCEL)
|
||||||
) {
|
) {
|
||||||
self::$returnDateType = $returnDateType;
|
self::$returnDateType = $returnDateType;
|
||||||
@ -128,8 +131,8 @@ class Functions
|
|||||||
*
|
*
|
||||||
* @return string Return Date Format
|
* @return string Return Date Format
|
||||||
* Possible Return values are:
|
* Possible Return values are:
|
||||||
* Functions::RETURNDATE_PHP_NUMERIC 'P'
|
* Functions::RETURNDATE_UNIX_TIMESTAMP 'P'
|
||||||
* Functions::RETURNDATE_PHP_OBJECT 'O'
|
* Functions::RETURNDATE_PHP_DATETIME_OBJECT 'O'
|
||||||
* Functions::RETURNDATE_EXCEL 'E'
|
* Functions::RETURNDATE_EXCEL 'E'
|
||||||
*/
|
*/
|
||||||
public static function getReturnDateType()
|
public static function getReturnDateType()
|
||||||
@ -267,25 +270,29 @@ class Functions
|
|||||||
public static function ifCondition($condition)
|
public static function ifCondition($condition)
|
||||||
{
|
{
|
||||||
$condition = self::flattenSingleValue($condition);
|
$condition = self::flattenSingleValue($condition);
|
||||||
if (!isset($condition[0]) && !is_numeric($condition)) {
|
|
||||||
|
if ($condition === '') {
|
||||||
$condition = '=""';
|
$condition = '=""';
|
||||||
}
|
}
|
||||||
if (!in_array($condition[0], ['>', '<', '='])) {
|
|
||||||
|
if (!is_string($condition) || !in_array($condition[0], ['>', '<', '='])) {
|
||||||
if (!is_numeric($condition)) {
|
if (!is_numeric($condition)) {
|
||||||
$condition = Calculation::wrapResult(strtoupper($condition));
|
$condition = Calculation::wrapResult(strtoupper($condition));
|
||||||
}
|
}
|
||||||
|
|
||||||
return '=' . $condition;
|
return str_replace('""""', '""', '=' . $condition);
|
||||||
}
|
}
|
||||||
preg_match('/(=|<[>=]?|>=?)(.*)/', $condition, $matches);
|
preg_match('/(=|<[>=]?|>=?)(.*)/', $condition, $matches);
|
||||||
list(, $operator, $operand) = $matches;
|
[, $operator, $operand] = $matches;
|
||||||
|
|
||||||
if (!is_numeric($operand)) {
|
if (is_numeric(trim($operand, '"'))) {
|
||||||
|
$operand = trim($operand, '"');
|
||||||
|
} elseif (!is_numeric($operand)) {
|
||||||
$operand = str_replace('"', '""', $operand);
|
$operand = str_replace('"', '""', $operand);
|
||||||
$operand = Calculation::wrapResult(strtoupper($operand));
|
$operand = Calculation::wrapResult(strtoupper($operand));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $operator . $operand;
|
return str_replace('""""', '""', $operator . $operand);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -639,7 +646,7 @@ class Functions
|
|||||||
public static function flattenSingleValue($value = '')
|
public static function flattenSingleValue($value = '')
|
||||||
{
|
{
|
||||||
while (is_array($value)) {
|
while (is_array($value)) {
|
||||||
$value = array_pop($value);
|
$value = array_shift($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
|
|||||||
@ -266,6 +266,10 @@ class Logical
|
|||||||
*/
|
*/
|
||||||
public static function statementIf($condition = true, $returnIfTrue = 0, $returnIfFalse = false)
|
public static function statementIf($condition = true, $returnIfTrue = 0, $returnIfFalse = false)
|
||||||
{
|
{
|
||||||
|
if (Functions::isError($condition)) {
|
||||||
|
return $condition;
|
||||||
|
}
|
||||||
|
|
||||||
$condition = ($condition === null) ? true : (bool) Functions::flattenSingleValue($condition);
|
$condition = ($condition === null) ? true : (bool) Functions::flattenSingleValue($condition);
|
||||||
$returnIfTrue = ($returnIfTrue === null) ? 0 : Functions::flattenSingleValue($returnIfTrue);
|
$returnIfTrue = ($returnIfTrue === null) ? 0 : Functions::flattenSingleValue($returnIfTrue);
|
||||||
$returnIfFalse = ($returnIfFalse === null) ? false : Functions::flattenSingleValue($returnIfFalse);
|
$returnIfFalse = ($returnIfFalse === null) ? false : Functions::flattenSingleValue($returnIfFalse);
|
||||||
@ -347,4 +351,25 @@ class Logical
|
|||||||
|
|
||||||
return self::statementIf(Functions::isError($testValue), $errorpart, $testValue);
|
return self::statementIf(Functions::isError($testValue), $errorpart, $testValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IFNA.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* =IFNA(testValue,napart)
|
||||||
|
*
|
||||||
|
* @category Logical Functions
|
||||||
|
*
|
||||||
|
* @param mixed $testValue Value to check, is also the value returned when not an NA
|
||||||
|
* @param mixed $napart Value to return when testValue is an NA condition
|
||||||
|
*
|
||||||
|
* @return mixed The value of errorpart or testValue determined by error condition
|
||||||
|
*/
|
||||||
|
public static function IFNA($testValue = '', $napart = '')
|
||||||
|
{
|
||||||
|
$testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue);
|
||||||
|
$napart = ($napart === null) ? '' : Functions::flattenSingleValue($napart);
|
||||||
|
|
||||||
|
return self::statementIf(Functions::isNa($testValue), $napart, $testValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -98,9 +98,9 @@ class LookupRef
|
|||||||
return (int) Coordinate::columnIndexFromString($columnKey);
|
return (int) Coordinate::columnIndexFromString($columnKey);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
list($sheet, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
|
[$sheet, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
|
||||||
if (strpos($cellAddress, ':') !== false) {
|
if (strpos($cellAddress, ':') !== false) {
|
||||||
list($startAddress, $endAddress) = explode(':', $cellAddress);
|
[$startAddress, $endAddress] = explode(':', $cellAddress);
|
||||||
$startAddress = preg_replace('/[^a-z]/i', '', $startAddress);
|
$startAddress = preg_replace('/[^a-z]/i', '', $startAddress);
|
||||||
$endAddress = preg_replace('/[^a-z]/i', '', $endAddress);
|
$endAddress = preg_replace('/[^a-z]/i', '', $endAddress);
|
||||||
$returnValue = [];
|
$returnValue = [];
|
||||||
@ -138,7 +138,7 @@ class LookupRef
|
|||||||
|
|
||||||
reset($cellAddress);
|
reset($cellAddress);
|
||||||
$isMatrix = (is_numeric(key($cellAddress)));
|
$isMatrix = (is_numeric(key($cellAddress)));
|
||||||
list($columns, $rows) = Calculation::getMatrixDimensions($cellAddress);
|
[$columns, $rows] = Calculation::getMatrixDimensions($cellAddress);
|
||||||
|
|
||||||
if ($isMatrix) {
|
if ($isMatrix) {
|
||||||
return $rows;
|
return $rows;
|
||||||
@ -175,9 +175,9 @@ class LookupRef
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
list($sheet, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
|
[$sheet, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
|
||||||
if (strpos($cellAddress, ':') !== false) {
|
if (strpos($cellAddress, ':') !== false) {
|
||||||
list($startAddress, $endAddress) = explode(':', $cellAddress);
|
[$startAddress, $endAddress] = explode(':', $cellAddress);
|
||||||
$startAddress = preg_replace('/\D/', '', $startAddress);
|
$startAddress = preg_replace('/\D/', '', $startAddress);
|
||||||
$endAddress = preg_replace('/\D/', '', $endAddress);
|
$endAddress = preg_replace('/\D/', '', $endAddress);
|
||||||
$returnValue = [];
|
$returnValue = [];
|
||||||
@ -187,7 +187,7 @@ class LookupRef
|
|||||||
|
|
||||||
return $returnValue;
|
return $returnValue;
|
||||||
}
|
}
|
||||||
list($cellAddress) = explode(':', $cellAddress);
|
[$cellAddress] = explode(':', $cellAddress);
|
||||||
|
|
||||||
return (int) preg_replace('/\D/', '', $cellAddress);
|
return (int) preg_replace('/\D/', '', $cellAddress);
|
||||||
}
|
}
|
||||||
@ -215,7 +215,7 @@ class LookupRef
|
|||||||
|
|
||||||
reset($cellAddress);
|
reset($cellAddress);
|
||||||
$isMatrix = (is_numeric(key($cellAddress)));
|
$isMatrix = (is_numeric(key($cellAddress)));
|
||||||
list($columns, $rows) = Calculation::getMatrixDimensions($cellAddress);
|
[$columns, $rows] = Calculation::getMatrixDimensions($cellAddress);
|
||||||
|
|
||||||
if ($isMatrix) {
|
if ($isMatrix) {
|
||||||
return $columns;
|
return $columns;
|
||||||
@ -285,7 +285,7 @@ class LookupRef
|
|||||||
$cellAddress1 = $cellAddress;
|
$cellAddress1 = $cellAddress;
|
||||||
$cellAddress2 = null;
|
$cellAddress2 = null;
|
||||||
if (strpos($cellAddress, ':') !== false) {
|
if (strpos($cellAddress, ':') !== false) {
|
||||||
list($cellAddress1, $cellAddress2) = explode(':', $cellAddress);
|
[$cellAddress1, $cellAddress2] = explode(':', $cellAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellAddress1, $matches)) ||
|
if ((!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellAddress1, $matches)) ||
|
||||||
@ -295,7 +295,7 @@ class LookupRef
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (strpos($cellAddress, '!') !== false) {
|
if (strpos($cellAddress, '!') !== false) {
|
||||||
list($sheetName, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
|
[$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
|
||||||
$sheetName = trim($sheetName, "'");
|
$sheetName = trim($sheetName, "'");
|
||||||
$pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName);
|
$pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName);
|
||||||
} else {
|
} else {
|
||||||
@ -306,7 +306,7 @@ class LookupRef
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (strpos($cellAddress, '!') !== false) {
|
if (strpos($cellAddress, '!') !== false) {
|
||||||
list($sheetName, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
|
[$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
|
||||||
$sheetName = trim($sheetName, "'");
|
$sheetName = trim($sheetName, "'");
|
||||||
$pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName);
|
$pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName);
|
||||||
} else {
|
} else {
|
||||||
@ -359,16 +359,16 @@ class LookupRef
|
|||||||
|
|
||||||
$sheetName = null;
|
$sheetName = null;
|
||||||
if (strpos($cellAddress, '!')) {
|
if (strpos($cellAddress, '!')) {
|
||||||
list($sheetName, $cellAddress) = Worksheet::extractSheetTitle($cellAddress, true);
|
[$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
|
||||||
$sheetName = trim($sheetName, "'");
|
$sheetName = trim($sheetName, "'");
|
||||||
}
|
}
|
||||||
if (strpos($cellAddress, ':')) {
|
if (strpos($cellAddress, ':')) {
|
||||||
list($startCell, $endCell) = explode(':', $cellAddress);
|
[$startCell, $endCell] = explode(':', $cellAddress);
|
||||||
} else {
|
} else {
|
||||||
$startCell = $endCell = $cellAddress;
|
$startCell = $endCell = $cellAddress;
|
||||||
}
|
}
|
||||||
list($startCellColumn, $startCellRow) = Coordinate::coordinateFromString($startCell);
|
[$startCellColumn, $startCellRow] = Coordinate::coordinateFromString($startCell);
|
||||||
list($endCellColumn, $endCellRow) = Coordinate::coordinateFromString($endCell);
|
[$endCellColumn, $endCellRow] = Coordinate::coordinateFromString($endCell);
|
||||||
|
|
||||||
$startCellRow += $rows;
|
$startCellRow += $rows;
|
||||||
$startCellColumn = Coordinate::columnIndexFromString($startCellColumn) - 1;
|
$startCellColumn = Coordinate::columnIndexFromString($startCellColumn) - 1;
|
||||||
@ -464,9 +464,10 @@ class LookupRef
|
|||||||
*
|
*
|
||||||
* @param mixed $lookupValue The value that you want to match in lookup_array
|
* @param mixed $lookupValue The value that you want to match in lookup_array
|
||||||
* @param mixed $lookupArray The range of cells being searched
|
* @param mixed $lookupArray The range of cells being searched
|
||||||
* @param mixed $matchType The number -1, 0, or 1. -1 means above, 0 means exact match, 1 means below. If match_type is 1 or -1, the list has to be ordered.
|
* @param mixed $matchType The number -1, 0, or 1. -1 means above, 0 means exact match, 1 means below.
|
||||||
|
* If match_type is 1 or -1, the list has to be ordered.
|
||||||
*
|
*
|
||||||
* @return int The relative position of the found item
|
* @return int|string The relative position of the found item
|
||||||
*/
|
*/
|
||||||
public static function MATCH($lookupValue, $lookupArray, $matchType = 1)
|
public static function MATCH($lookupValue, $lookupArray, $matchType = 1)
|
||||||
{
|
{
|
||||||
@ -474,9 +475,10 @@ class LookupRef
|
|||||||
$lookupValue = Functions::flattenSingleValue($lookupValue);
|
$lookupValue = Functions::flattenSingleValue($lookupValue);
|
||||||
$matchType = ($matchType === null) ? 1 : (int) Functions::flattenSingleValue($matchType);
|
$matchType = ($matchType === null) ? 1 : (int) Functions::flattenSingleValue($matchType);
|
||||||
|
|
||||||
$initialLookupValue = $lookupValue;
|
// MATCH is not case sensitive, so we convert lookup value to be lower cased in case it's string type.
|
||||||
// MATCH is not case sensitive
|
if (is_string($lookupValue)) {
|
||||||
$lookupValue = StringHelper::strToLower($lookupValue);
|
$lookupValue = StringHelper::strToLower($lookupValue);
|
||||||
|
}
|
||||||
|
|
||||||
// Lookup_value type has to be number, text, or logical values
|
// Lookup_value type has to be number, text, or logical values
|
||||||
if ((!is_numeric($lookupValue)) && (!is_string($lookupValue)) && (!is_bool($lookupValue))) {
|
if ((!is_numeric($lookupValue)) && (!is_string($lookupValue)) && (!is_bool($lookupValue))) {
|
||||||
@ -522,16 +524,54 @@ class LookupRef
|
|||||||
// find the match
|
// find the match
|
||||||
// **
|
// **
|
||||||
|
|
||||||
if ($matchType == 0 || $matchType == 1) {
|
if ($matchType === 0 || $matchType === 1) {
|
||||||
foreach ($lookupArray as $i => $lookupArrayValue) {
|
foreach ($lookupArray as $i => $lookupArrayValue) {
|
||||||
$onlyNumeric = is_numeric($lookupArrayValue) && is_numeric($lookupValue);
|
$typeMatch = gettype($lookupValue) === gettype($lookupArrayValue);
|
||||||
$onlyNumericExactMatch = $onlyNumeric && $lookupArrayValue == $lookupValue;
|
$exactTypeMatch = $typeMatch && $lookupArrayValue === $lookupValue;
|
||||||
$nonOnlyNumericExactMatch = !$onlyNumeric && $lookupArrayValue === $lookupValue;
|
$nonOnlyNumericExactMatch = !$typeMatch && $lookupArrayValue === $lookupValue;
|
||||||
$exactMatch = $onlyNumericExactMatch || $nonOnlyNumericExactMatch;
|
$exactMatch = $exactTypeMatch || $nonOnlyNumericExactMatch;
|
||||||
if (($matchType == 0) && $exactMatch) {
|
|
||||||
// exact match
|
if ($matchType === 0) {
|
||||||
return $i + 1;
|
if ($typeMatch && is_string($lookupValue) && (bool) preg_match('/([\?\*])/', $lookupValue)) {
|
||||||
} elseif (($matchType == 1) && ($lookupArrayValue <= $lookupValue)) {
|
$splitString = $lookupValue;
|
||||||
|
$chars = array_map(function ($i) use ($splitString) {
|
||||||
|
return mb_substr($splitString, $i, 1);
|
||||||
|
}, range(0, mb_strlen($splitString) - 1));
|
||||||
|
|
||||||
|
$length = count($chars);
|
||||||
|
$pattern = '/^';
|
||||||
|
for ($j = 0; $j < $length; ++$j) {
|
||||||
|
if ($chars[$j] === '~') {
|
||||||
|
if (isset($chars[$j + 1])) {
|
||||||
|
if ($chars[$j + 1] === '*') {
|
||||||
|
$pattern .= preg_quote($chars[$j + 1], '/');
|
||||||
|
++$j;
|
||||||
|
} elseif ($chars[$j + 1] === '?') {
|
||||||
|
$pattern .= preg_quote($chars[$j + 1], '/');
|
||||||
|
++$j;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$pattern .= preg_quote($chars[$j], '/');
|
||||||
|
}
|
||||||
|
} elseif ($chars[$j] === '*') {
|
||||||
|
$pattern .= '.*';
|
||||||
|
} elseif ($chars[$j] === '?') {
|
||||||
|
$pattern .= '.{1}';
|
||||||
|
} else {
|
||||||
|
$pattern .= preg_quote($chars[$j], '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$pattern .= '$/';
|
||||||
|
if ((bool) preg_match($pattern, $lookupArrayValue)) {
|
||||||
|
// exact match
|
||||||
|
return $i + 1;
|
||||||
|
}
|
||||||
|
} elseif ($exactMatch) {
|
||||||
|
// exact match
|
||||||
|
return $i + 1;
|
||||||
|
}
|
||||||
|
} elseif (($matchType === 1) && $typeMatch && ($lookupArrayValue <= $lookupValue)) {
|
||||||
$i = array_search($i, $keySet);
|
$i = array_search($i, $keySet);
|
||||||
|
|
||||||
// The current value is the (first) match
|
// The current value is the (first) match
|
||||||
@ -539,26 +579,26 @@ class LookupRef
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// matchType = -1
|
|
||||||
|
|
||||||
// "Special" case: since the array it's supposed to be ordered in descending order, the
|
|
||||||
// Excel algorithm gives up immediately if the first element is smaller than the searched value
|
|
||||||
if ($lookupArray[0] < $lookupValue) {
|
|
||||||
return Functions::NA();
|
|
||||||
}
|
|
||||||
|
|
||||||
$maxValueKey = null;
|
$maxValueKey = null;
|
||||||
|
|
||||||
// The basic algorithm is:
|
// The basic algorithm is:
|
||||||
// Iterate and keep the highest match until the next element is smaller than the searched value.
|
// Iterate and keep the highest match until the next element is smaller than the searched value.
|
||||||
// Return immediately if perfect match is found
|
// Return immediately if perfect match is found
|
||||||
foreach ($lookupArray as $i => $lookupArrayValue) {
|
foreach ($lookupArray as $i => $lookupArrayValue) {
|
||||||
if ($lookupArrayValue == $lookupValue) {
|
$typeMatch = gettype($lookupValue) === gettype($lookupArrayValue);
|
||||||
|
$exactTypeMatch = $typeMatch && $lookupArrayValue === $lookupValue;
|
||||||
|
$nonOnlyNumericExactMatch = !$typeMatch && $lookupArrayValue === $lookupValue;
|
||||||
|
$exactMatch = $exactTypeMatch || $nonOnlyNumericExactMatch;
|
||||||
|
|
||||||
|
if ($exactMatch) {
|
||||||
// Another "special" case. If a perfect match is found,
|
// Another "special" case. If a perfect match is found,
|
||||||
// the algorithm gives up immediately
|
// the algorithm gives up immediately
|
||||||
return $i + 1;
|
return $i + 1;
|
||||||
} elseif ($lookupArrayValue >= $lookupValue) {
|
} elseif ($typeMatch & $lookupArrayValue >= $lookupValue) {
|
||||||
$maxValueKey = $i + 1;
|
$maxValueKey = $i + 1;
|
||||||
|
} elseif ($typeMatch & $lookupArrayValue < $lookupValue) {
|
||||||
|
//Excel algorithm gives up immediately if the first element is smaller than the searched value
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,8 +834,10 @@ class LookupRef
|
|||||||
$lookupLower = StringHelper::strToLower($lookup_value);
|
$lookupLower = StringHelper::strToLower($lookup_value);
|
||||||
$rowDataLower = StringHelper::strToLower($rowData);
|
$rowDataLower = StringHelper::strToLower($rowData);
|
||||||
|
|
||||||
if (($bothNumeric && $rowData > $lookup_value) ||
|
if ($not_exact_match && (
|
||||||
($bothNotNumeric && $rowDataLower > $lookupLower)) {
|
($bothNumeric && $rowData > $lookup_value) ||
|
||||||
|
($bothNotNumeric && $rowDataLower > $lookupLower)
|
||||||
|
)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,6 +38,88 @@ class MathTrig
|
|||||||
return ($num - ($num % $n)) / $n;
|
return ($num - ($num % $n)) / $n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ARABIC.
|
||||||
|
*
|
||||||
|
* Converts a Roman numeral to an Arabic numeral.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* ARABIC(text)
|
||||||
|
*
|
||||||
|
* @category Mathematical and Trigonometric Functions
|
||||||
|
*
|
||||||
|
* @param string $roman
|
||||||
|
*
|
||||||
|
* @return int|string the arabic numberal contrived from the roman numeral
|
||||||
|
*/
|
||||||
|
public static function ARABIC($roman)
|
||||||
|
{
|
||||||
|
// An empty string should return 0
|
||||||
|
$roman = substr(trim(strtoupper((string) Functions::flattenSingleValue($roman))), 0, 255);
|
||||||
|
if ($roman === '') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the roman numeral to an arabic number
|
||||||
|
$negativeNumber = $roman[0] === '-';
|
||||||
|
if ($negativeNumber) {
|
||||||
|
$roman = substr($roman, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$arabic = self::calculateArabic(str_split($roman));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return Functions::VALUE(); // Invalid character detected
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($negativeNumber) {
|
||||||
|
$arabic *= -1; // The number should be negative
|
||||||
|
}
|
||||||
|
|
||||||
|
return $arabic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively calculate the arabic value of a roman numeral.
|
||||||
|
*
|
||||||
|
* @param array $roman
|
||||||
|
* @param int $sum
|
||||||
|
* @param int $subtract
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected static function calculateArabic(array $roman, &$sum = 0, $subtract = 0)
|
||||||
|
{
|
||||||
|
$lookup = [
|
||||||
|
'M' => 1000,
|
||||||
|
'D' => 500,
|
||||||
|
'C' => 100,
|
||||||
|
'L' => 50,
|
||||||
|
'X' => 10,
|
||||||
|
'V' => 5,
|
||||||
|
'I' => 1,
|
||||||
|
];
|
||||||
|
|
||||||
|
$numeral = array_shift($roman);
|
||||||
|
if (!isset($lookup[$numeral])) {
|
||||||
|
throw new \Exception('Invalid character detected');
|
||||||
|
}
|
||||||
|
|
||||||
|
$arabic = $lookup[$numeral];
|
||||||
|
if (count($roman) > 0 && isset($lookup[$roman[0]]) && $arabic < $lookup[$roman[0]]) {
|
||||||
|
$subtract += $arabic;
|
||||||
|
} else {
|
||||||
|
$sum += ($arabic - $subtract);
|
||||||
|
$subtract = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($roman) > 0) {
|
||||||
|
self::calculateArabic($roman, $sum, $subtract);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ATAN2.
|
* ATAN2.
|
||||||
*
|
*
|
||||||
@ -59,7 +141,7 @@ class MathTrig
|
|||||||
* @param float $xCoordinate the x-coordinate of the point
|
* @param float $xCoordinate the x-coordinate of the point
|
||||||
* @param float $yCoordinate the y-coordinate of the point
|
* @param float $yCoordinate the y-coordinate of the point
|
||||||
*
|
*
|
||||||
* @return float the inverse tangent of the specified x- and y-coordinates
|
* @return float|string the inverse tangent of the specified x- and y-coordinates, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function ATAN2($xCoordinate = null, $yCoordinate = null)
|
public static function ATAN2($xCoordinate = null, $yCoordinate = null)
|
||||||
{
|
{
|
||||||
@ -84,6 +166,49 @@ class MathTrig
|
|||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BASE.
|
||||||
|
*
|
||||||
|
* Converts a number into a text representation with the given radix (base).
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* BASE(Number, Radix [Min_length])
|
||||||
|
*
|
||||||
|
* @category Mathematical and Trigonometric Functions
|
||||||
|
*
|
||||||
|
* @param float $number
|
||||||
|
* @param float $radix
|
||||||
|
* @param int $minLength
|
||||||
|
*
|
||||||
|
* @return string the text representation with the given radix (base)
|
||||||
|
*/
|
||||||
|
public static function BASE($number, $radix, $minLength = null)
|
||||||
|
{
|
||||||
|
$number = Functions::flattenSingleValue($number);
|
||||||
|
$radix = Functions::flattenSingleValue($radix);
|
||||||
|
$minLength = Functions::flattenSingleValue($minLength);
|
||||||
|
|
||||||
|
if (is_numeric($number) && is_numeric($radix) && ($minLength === null || is_numeric($minLength))) {
|
||||||
|
// Truncate to an integer
|
||||||
|
$number = (int) $number;
|
||||||
|
$radix = (int) $radix;
|
||||||
|
$minLength = (int) $minLength;
|
||||||
|
|
||||||
|
if ($number < 0 || $number >= 2 ** 53 || $radix < 2 || $radix > 36) {
|
||||||
|
return Functions::NAN(); // Numeric range constraints
|
||||||
|
}
|
||||||
|
|
||||||
|
$outcome = strtoupper((string) base_convert($number, 10, $radix));
|
||||||
|
if ($minLength !== null) {
|
||||||
|
$outcome = str_pad($outcome, $minLength, '0', STR_PAD_LEFT); // String padding
|
||||||
|
}
|
||||||
|
|
||||||
|
return $outcome;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Functions::VALUE();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CEILING.
|
* CEILING.
|
||||||
*
|
*
|
||||||
@ -100,7 +225,7 @@ class MathTrig
|
|||||||
* @param float $number the number you want to round
|
* @param float $number the number you want to round
|
||||||
* @param float $significance the multiple to which you want to round
|
* @param float $significance the multiple to which you want to round
|
||||||
*
|
*
|
||||||
* @return float Rounded Number
|
* @return float|string Rounded Number, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function CEILING($number, $significance = null)
|
public static function CEILING($number, $significance = null)
|
||||||
{
|
{
|
||||||
@ -139,7 +264,7 @@ class MathTrig
|
|||||||
* @param int $numObjs Number of different objects
|
* @param int $numObjs Number of different objects
|
||||||
* @param int $numInSet Number of objects in each combination
|
* @param int $numInSet Number of objects in each combination
|
||||||
*
|
*
|
||||||
* @return int Number of combinations
|
* @return int|string Number of combinations, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function COMBIN($numObjs, $numInSet)
|
public static function COMBIN($numObjs, $numInSet)
|
||||||
{
|
{
|
||||||
@ -175,7 +300,7 @@ class MathTrig
|
|||||||
*
|
*
|
||||||
* @param float $number Number to round
|
* @param float $number Number to round
|
||||||
*
|
*
|
||||||
* @return int Rounded Number
|
* @return int|string Rounded Number, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function EVEN($number)
|
public static function EVEN($number)
|
||||||
{
|
{
|
||||||
@ -209,7 +334,7 @@ class MathTrig
|
|||||||
*
|
*
|
||||||
* @param float $factVal Factorial Value
|
* @param float $factVal Factorial Value
|
||||||
*
|
*
|
||||||
* @return int Factorial
|
* @return int|string Factorial, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function FACT($factVal)
|
public static function FACT($factVal)
|
||||||
{
|
{
|
||||||
@ -220,10 +345,9 @@ class MathTrig
|
|||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
}
|
}
|
||||||
$factLoop = floor($factVal);
|
$factLoop = floor($factVal);
|
||||||
if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
|
if ((Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) &&
|
||||||
if ($factVal > $factLoop) {
|
($factVal > $factLoop)) {
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$factorial = 1;
|
$factorial = 1;
|
||||||
@ -249,7 +373,7 @@ class MathTrig
|
|||||||
*
|
*
|
||||||
* @param float $factVal Factorial Value
|
* @param float $factVal Factorial Value
|
||||||
*
|
*
|
||||||
* @return int Double Factorial
|
* @return int|string Double Factorial, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function FACTDOUBLE($factVal)
|
public static function FACTDOUBLE($factVal)
|
||||||
{
|
{
|
||||||
@ -285,7 +409,7 @@ class MathTrig
|
|||||||
* @param float $number Number to round
|
* @param float $number Number to round
|
||||||
* @param float $significance Significance
|
* @param float $significance Significance
|
||||||
*
|
*
|
||||||
* @return float Rounded Number
|
* @return float|string Rounded Number, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function FLOOR($number, $significance = null)
|
public static function FLOOR($number, $significance = null)
|
||||||
{
|
{
|
||||||
@ -302,7 +426,9 @@ class MathTrig
|
|||||||
return Functions::DIV0();
|
return Functions::DIV0();
|
||||||
} elseif ($number == 0.0) {
|
} elseif ($number == 0.0) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
} elseif (self::SIGN($number) == self::SIGN($significance)) {
|
} elseif (self::SIGN($significance) == 1) {
|
||||||
|
return floor($number / $significance) * $significance;
|
||||||
|
} elseif (self::SIGN($number) == -1 && self::SIGN($significance) == -1) {
|
||||||
return floor($number / $significance) * $significance;
|
return floor($number / $significance) * $significance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,6 +438,80 @@ class MathTrig
|
|||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FLOOR.MATH.
|
||||||
|
*
|
||||||
|
* Round a number down to the nearest integer or to the nearest multiple of significance.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* FLOOR.MATH(number[,significance[,mode]])
|
||||||
|
*
|
||||||
|
* @category Mathematical and Trigonometric Functions
|
||||||
|
*
|
||||||
|
* @param float $number Number to round
|
||||||
|
* @param float $significance Significance
|
||||||
|
* @param int $mode direction to round negative numbers
|
||||||
|
*
|
||||||
|
* @return float|string Rounded Number, or a string containing an error
|
||||||
|
*/
|
||||||
|
public static function FLOORMATH($number, $significance = null, $mode = 0)
|
||||||
|
{
|
||||||
|
$number = Functions::flattenSingleValue($number);
|
||||||
|
$significance = Functions::flattenSingleValue($significance);
|
||||||
|
$mode = Functions::flattenSingleValue($mode);
|
||||||
|
|
||||||
|
if (is_numeric($number) && $significance === null) {
|
||||||
|
$significance = $number / abs($number);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_numeric($number) && is_numeric($significance) && is_numeric($mode)) {
|
||||||
|
if ($significance == 0.0) {
|
||||||
|
return Functions::DIV0();
|
||||||
|
} elseif ($number == 0.0) {
|
||||||
|
return 0.0;
|
||||||
|
} elseif (self::SIGN($significance) == -1 || (self::SIGN($number) == -1 && !empty($mode))) {
|
||||||
|
return ceil($number / $significance) * $significance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return floor($number / $significance) * $significance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Functions::VALUE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FLOOR.PRECISE.
|
||||||
|
*
|
||||||
|
* Rounds number down, toward zero, to the nearest multiple of significance.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* FLOOR.PRECISE(number[,significance])
|
||||||
|
*
|
||||||
|
* @category Mathematical and Trigonometric Functions
|
||||||
|
*
|
||||||
|
* @param float $number Number to round
|
||||||
|
* @param float $significance Significance
|
||||||
|
*
|
||||||
|
* @return float|string Rounded Number, or a string containing an error
|
||||||
|
*/
|
||||||
|
public static function FLOORPRECISE($number, $significance = 1)
|
||||||
|
{
|
||||||
|
$number = Functions::flattenSingleValue($number);
|
||||||
|
$significance = Functions::flattenSingleValue($significance);
|
||||||
|
|
||||||
|
if ((is_numeric($number)) && (is_numeric($significance))) {
|
||||||
|
if ($significance == 0.0) {
|
||||||
|
return Functions::DIV0();
|
||||||
|
} elseif ($number == 0.0) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return floor($number / abs($significance)) * abs($significance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Functions::VALUE();
|
||||||
|
}
|
||||||
|
|
||||||
private static function evaluateGCD($a, $b)
|
private static function evaluateGCD($a, $b)
|
||||||
{
|
{
|
||||||
return $b ? self::evaluateGCD($b, $a % $b) : $a;
|
return $b ? self::evaluateGCD($b, $a % $b) : $a;
|
||||||
@ -331,7 +531,7 @@ class MathTrig
|
|||||||
*
|
*
|
||||||
* @param mixed ...$args Data values
|
* @param mixed ...$args Data values
|
||||||
*
|
*
|
||||||
* @return int Greatest Common Divisor
|
* @return int|mixed|string Greatest Common Divisor, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function GCD(...$args)
|
public static function GCD(...$args)
|
||||||
{
|
{
|
||||||
@ -365,7 +565,7 @@ class MathTrig
|
|||||||
*
|
*
|
||||||
* @param float $number Number to cast to an integer
|
* @param float $number Number to cast to an integer
|
||||||
*
|
*
|
||||||
* @return int Integer value
|
* @return int|string Integer value, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function INT($number)
|
public static function INT($number)
|
||||||
{
|
{
|
||||||
@ -398,7 +598,7 @@ class MathTrig
|
|||||||
*
|
*
|
||||||
* @param mixed ...$args Data values
|
* @param mixed ...$args Data values
|
||||||
*
|
*
|
||||||
* @return int Lowest Common Multiplier
|
* @return int|string Lowest Common Multiplier, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function LCM(...$args)
|
public static function LCM(...$args)
|
||||||
{
|
{
|
||||||
@ -450,7 +650,7 @@ class MathTrig
|
|||||||
* @param float $number The positive real number for which you want the logarithm
|
* @param float $number The positive real number for which you want the logarithm
|
||||||
* @param float $base The base of the logarithm. If base is omitted, it is assumed to be 10.
|
* @param float $base The base of the logarithm. If base is omitted, it is assumed to be 10.
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string The result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function logBase($number = null, $base = 10)
|
public static function logBase($number = null, $base = 10)
|
||||||
{
|
{
|
||||||
@ -479,7 +679,7 @@ class MathTrig
|
|||||||
*
|
*
|
||||||
* @param array $matrixValues A matrix of values
|
* @param array $matrixValues A matrix of values
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string The result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function MDETERM($matrixValues)
|
public static function MDETERM($matrixValues)
|
||||||
{
|
{
|
||||||
@ -531,7 +731,7 @@ class MathTrig
|
|||||||
*
|
*
|
||||||
* @param array $matrixValues A matrix of values
|
* @param array $matrixValues A matrix of values
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array|string The result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function MINVERSE($matrixValues)
|
public static function MINVERSE($matrixValues)
|
||||||
{
|
{
|
||||||
@ -581,7 +781,7 @@ class MathTrig
|
|||||||
* @param array $matrixData1 A matrix of values
|
* @param array $matrixData1 A matrix of values
|
||||||
* @param array $matrixData2 A matrix of values
|
* @param array $matrixData2 A matrix of values
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array|string The result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function MMULT($matrixData1, $matrixData2)
|
public static function MMULT($matrixData1, $matrixData2)
|
||||||
{
|
{
|
||||||
@ -643,7 +843,7 @@ class MathTrig
|
|||||||
* @param int $a Dividend
|
* @param int $a Dividend
|
||||||
* @param int $b Divisor
|
* @param int $b Divisor
|
||||||
*
|
*
|
||||||
* @return int Remainder
|
* @return int|string Remainder, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function MOD($a = 1, $b = 1)
|
public static function MOD($a = 1, $b = 1)
|
||||||
{
|
{
|
||||||
@ -669,7 +869,7 @@ class MathTrig
|
|||||||
* @param float $number Number to round
|
* @param float $number Number to round
|
||||||
* @param int $multiple Multiple to which you want to round $number
|
* @param int $multiple Multiple to which you want to round $number
|
||||||
*
|
*
|
||||||
* @return float Rounded Number
|
* @return float|string Rounded Number, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function MROUND($number, $multiple)
|
public static function MROUND($number, $multiple)
|
||||||
{
|
{
|
||||||
@ -699,7 +899,7 @@ class MathTrig
|
|||||||
*
|
*
|
||||||
* @param array of mixed Data Series
|
* @param array of mixed Data Series
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string The result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function MULTINOMIAL(...$args)
|
public static function MULTINOMIAL(...$args)
|
||||||
{
|
{
|
||||||
@ -736,7 +936,7 @@ class MathTrig
|
|||||||
*
|
*
|
||||||
* @param float $number Number to round
|
* @param float $number Number to round
|
||||||
*
|
*
|
||||||
* @return int Rounded Number
|
* @return int|string Rounded Number, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function ODD($number)
|
public static function ODD($number)
|
||||||
{
|
{
|
||||||
@ -771,7 +971,7 @@ class MathTrig
|
|||||||
* @param float $x
|
* @param float $x
|
||||||
* @param float $y
|
* @param float $y
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string The result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function POWER($x = 0, $y = 2)
|
public static function POWER($x = 0, $y = 2)
|
||||||
{
|
{
|
||||||
@ -930,7 +1130,7 @@ class MathTrig
|
|||||||
* @param float $number Number to round
|
* @param float $number Number to round
|
||||||
* @param int $digits Number of digits to which you want to round $number
|
* @param int $digits Number of digits to which you want to round $number
|
||||||
*
|
*
|
||||||
* @return float Rounded Number
|
* @return float|string Rounded Number, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function ROUNDUP($number, $digits)
|
public static function ROUNDUP($number, $digits)
|
||||||
{
|
{
|
||||||
@ -938,12 +1138,11 @@ class MathTrig
|
|||||||
$digits = Functions::flattenSingleValue($digits);
|
$digits = Functions::flattenSingleValue($digits);
|
||||||
|
|
||||||
if ((is_numeric($number)) && (is_numeric($digits))) {
|
if ((is_numeric($number)) && (is_numeric($digits))) {
|
||||||
$significance = pow(10, (int) $digits);
|
|
||||||
if ($number < 0.0) {
|
if ($number < 0.0) {
|
||||||
return floor($number * $significance) / $significance;
|
return round($number - 0.5 * pow(0.1, $digits), $digits, PHP_ROUND_HALF_DOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ceil($number * $significance) / $significance;
|
return round($number + 0.5 * pow(0.1, $digits), $digits, PHP_ROUND_HALF_DOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
@ -957,7 +1156,7 @@ class MathTrig
|
|||||||
* @param float $number Number to round
|
* @param float $number Number to round
|
||||||
* @param int $digits Number of digits to which you want to round $number
|
* @param int $digits Number of digits to which you want to round $number
|
||||||
*
|
*
|
||||||
* @return float Rounded Number
|
* @return float|string Rounded Number, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function ROUNDDOWN($number, $digits)
|
public static function ROUNDDOWN($number, $digits)
|
||||||
{
|
{
|
||||||
@ -965,12 +1164,11 @@ class MathTrig
|
|||||||
$digits = Functions::flattenSingleValue($digits);
|
$digits = Functions::flattenSingleValue($digits);
|
||||||
|
|
||||||
if ((is_numeric($number)) && (is_numeric($digits))) {
|
if ((is_numeric($number)) && (is_numeric($digits))) {
|
||||||
$significance = pow(10, (int) $digits);
|
|
||||||
if ($number < 0.0) {
|
if ($number < 0.0) {
|
||||||
return ceil($number * $significance) / $significance;
|
return round($number + 0.5 * pow(0.1, $digits), $digits, PHP_ROUND_HALF_UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
return floor($number * $significance) / $significance;
|
return round($number - 0.5 * pow(0.1, $digits), $digits, PHP_ROUND_HALF_UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Functions::VALUE();
|
return Functions::VALUE();
|
||||||
@ -986,7 +1184,7 @@ class MathTrig
|
|||||||
* @param float $m Step by which to increase $n for each term in the series
|
* @param float $m Step by which to increase $n for each term in the series
|
||||||
* @param array of mixed Data Series
|
* @param array of mixed Data Series
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string The result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function SERIESSUM(...$args)
|
public static function SERIESSUM(...$args)
|
||||||
{
|
{
|
||||||
@ -1025,7 +1223,7 @@ class MathTrig
|
|||||||
*
|
*
|
||||||
* @param float $number Number to round
|
* @param float $number Number to round
|
||||||
*
|
*
|
||||||
* @return int sign value
|
* @return int|string sign value, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function SIGN($number)
|
public static function SIGN($number)
|
||||||
{
|
{
|
||||||
@ -1052,7 +1250,7 @@ class MathTrig
|
|||||||
*
|
*
|
||||||
* @param float $number Number
|
* @param float $number Number
|
||||||
*
|
*
|
||||||
* @return float Square Root of Number * Pi
|
* @return float|string Square Root of Number * Pi, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function SQRTPI($number)
|
public static function SQRTPI($number)
|
||||||
{
|
{
|
||||||
@ -1074,7 +1272,7 @@ class MathTrig
|
|||||||
return array_filter(
|
return array_filter(
|
||||||
$args,
|
$args,
|
||||||
function ($index) use ($cellReference) {
|
function ($index) use ($cellReference) {
|
||||||
list(, $row, $column) = explode('.', $index);
|
[, $row, $column] = explode('.', $index);
|
||||||
|
|
||||||
return $cellReference->getWorksheet()->getRowDimension($row)->getVisible() &&
|
return $cellReference->getWorksheet()->getRowDimension($row)->getVisible() &&
|
||||||
$cellReference->getWorksheet()->getColumnDimension($column)->getVisible();
|
$cellReference->getWorksheet()->getColumnDimension($column)->getVisible();
|
||||||
@ -1088,7 +1286,7 @@ class MathTrig
|
|||||||
return array_filter(
|
return array_filter(
|
||||||
$args,
|
$args,
|
||||||
function ($index) use ($cellReference) {
|
function ($index) use ($cellReference) {
|
||||||
list(, $row, $column) = explode('.', $index);
|
[, $row, $column] = explode('.', $index);
|
||||||
if ($cellReference->getWorksheet()->cellExists($column . $row)) {
|
if ($cellReference->getWorksheet()->cellExists($column . $row)) {
|
||||||
//take this cell out if it contains the SUBTOTAL or AGGREGATE functions in a formula
|
//take this cell out if it contains the SUBTOTAL or AGGREGATE functions in a formula
|
||||||
$isFormula = $cellReference->getWorksheet()->getCell($column . $row)->isFormula();
|
$isFormula = $cellReference->getWorksheet()->getCell($column . $row)->isFormula();
|
||||||
@ -1116,7 +1314,7 @@ class MathTrig
|
|||||||
* in hidden rows or columns
|
* in hidden rows or columns
|
||||||
* @param array of mixed Data Series
|
* @param array of mixed Data Series
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string
|
||||||
*/
|
*/
|
||||||
public static function SUBTOTAL(...$args)
|
public static function SUBTOTAL(...$args)
|
||||||
{
|
{
|
||||||
@ -1306,7 +1504,7 @@ class MathTrig
|
|||||||
*
|
*
|
||||||
* @param mixed ...$args Data values
|
* @param mixed ...$args Data values
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float|string The result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function SUMPRODUCT(...$args)
|
public static function SUMPRODUCT(...$args)
|
||||||
{
|
{
|
||||||
@ -1451,7 +1649,7 @@ class MathTrig
|
|||||||
* @param float $value
|
* @param float $value
|
||||||
* @param int $digits
|
* @param int $digits
|
||||||
*
|
*
|
||||||
* @return float Truncated value
|
* @return float|string Truncated value, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function TRUNC($value = 0, $digits = 0)
|
public static function TRUNC($value = 0, $digits = 0)
|
||||||
{
|
{
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -52,7 +52,7 @@ class TextData
|
|||||||
return ($stringValue) ? Calculation::getTRUE() : Calculation::getFALSE();
|
return ($stringValue) ? Calculation::getTRUE() : Calculation::getFALSE();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self::$invalidChars == null) {
|
if (self::$invalidChars === null) {
|
||||||
self::$invalidChars = range(chr(0), chr(31));
|
self::$invalidChars = range(chr(0), chr(31));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +84,15 @@ class TextData
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function convertBooleanValue($value)
|
||||||
|
{
|
||||||
|
if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
|
||||||
|
return (int) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($value) ? Calculation::getTRUE() : Calculation::getFALSE();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ASCIICODE.
|
* ASCIICODE.
|
||||||
*
|
*
|
||||||
@ -98,11 +107,7 @@ class TextData
|
|||||||
}
|
}
|
||||||
$characters = Functions::flattenSingleValue($characters);
|
$characters = Functions::flattenSingleValue($characters);
|
||||||
if (is_bool($characters)) {
|
if (is_bool($characters)) {
|
||||||
if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
|
$characters = self::convertBooleanValue($characters);
|
||||||
$characters = (int) $characters;
|
|
||||||
} else {
|
|
||||||
$characters = ($characters) ? Calculation::getTRUE() : Calculation::getFALSE();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$character = $characters;
|
$character = $characters;
|
||||||
@ -126,11 +131,7 @@ class TextData
|
|||||||
$aArgs = Functions::flattenArray($args);
|
$aArgs = Functions::flattenArray($args);
|
||||||
foreach ($aArgs as $arg) {
|
foreach ($aArgs as $arg) {
|
||||||
if (is_bool($arg)) {
|
if (is_bool($arg)) {
|
||||||
if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
|
$arg = self::convertBooleanValue($arg);
|
||||||
$arg = (int) $arg;
|
|
||||||
} else {
|
|
||||||
$arg = ($arg) ? Calculation::getTRUE() : Calculation::getFALSE();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$returnValue .= $arg;
|
$returnValue .= $arg;
|
||||||
}
|
}
|
||||||
@ -197,7 +198,7 @@ class TextData
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (($offset > 0) && (StringHelper::countCharacters($haystack) > $offset)) {
|
if (($offset > 0) && (StringHelper::countCharacters($haystack) > $offset)) {
|
||||||
if (StringHelper::countCharacters($needle) == 0) {
|
if (StringHelper::countCharacters($needle) === 0) {
|
||||||
return $offset;
|
return $offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +233,7 @@ class TextData
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (($offset > 0) && (StringHelper::countCharacters($haystack) > $offset)) {
|
if (($offset > 0) && (StringHelper::countCharacters($haystack) > $offset)) {
|
||||||
if (StringHelper::countCharacters($needle) == 0) {
|
if (StringHelper::countCharacters($needle) === 0) {
|
||||||
return $offset;
|
return $offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,14 +266,19 @@ class TextData
|
|||||||
if (!is_numeric($value) || !is_numeric($decimals)) {
|
if (!is_numeric($value) || !is_numeric($decimals)) {
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
}
|
}
|
||||||
$decimals = floor($decimals);
|
$decimals = (int) floor($decimals);
|
||||||
|
|
||||||
$valueResult = round($value, $decimals);
|
$valueResult = round($value, $decimals);
|
||||||
if ($decimals < 0) {
|
if ($decimals < 0) {
|
||||||
$decimals = 0;
|
$decimals = 0;
|
||||||
}
|
}
|
||||||
if (!$no_commas) {
|
if (!$no_commas) {
|
||||||
$valueResult = number_format($valueResult, $decimals);
|
$valueResult = number_format(
|
||||||
|
$valueResult,
|
||||||
|
$decimals,
|
||||||
|
StringHelper::getDecimalSeparator(),
|
||||||
|
StringHelper::getThousandsSeparator()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (string) $valueResult;
|
return (string) $valueResult;
|
||||||
@ -659,11 +665,7 @@ class TextData
|
|||||||
if ($ignoreEmpty && trim($arg) == '') {
|
if ($ignoreEmpty && trim($arg) == '') {
|
||||||
unset($aArgs[$key]);
|
unset($aArgs[$key]);
|
||||||
} elseif (is_bool($arg)) {
|
} elseif (is_bool($arg)) {
|
||||||
if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
|
$arg = self::convertBooleanValue($arg);
|
||||||
$arg = (int) $arg;
|
|
||||||
} else {
|
|
||||||
$arg = ($arg) ? Calculation::getTRUE() : Calculation::getFALSE();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,14 +36,24 @@ class Stack
|
|||||||
* @param mixed $type
|
* @param mixed $type
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
* @param mixed $reference
|
* @param mixed $reference
|
||||||
|
* @param null|string $storeKey will store the result under this alias
|
||||||
|
* @param null|string $onlyIf will only run computation if the matching
|
||||||
|
* store key is true
|
||||||
|
* @param null|string $onlyIfNot will only run computation if the matching
|
||||||
|
* store key is false
|
||||||
*/
|
*/
|
||||||
public function push($type, $value, $reference = null)
|
public function push(
|
||||||
{
|
$type,
|
||||||
$this->stack[$this->count++] = [
|
$value,
|
||||||
'type' => $type,
|
$reference = null,
|
||||||
'value' => $value,
|
$storeKey = null,
|
||||||
'reference' => $reference,
|
$onlyIf = null,
|
||||||
];
|
$onlyIfNot = null
|
||||||
|
) {
|
||||||
|
$stackItem = $this->getStackItem($type, $value, $reference, $storeKey, $onlyIf, $onlyIfNot);
|
||||||
|
|
||||||
|
$this->stack[$this->count++] = $stackItem;
|
||||||
|
|
||||||
if ($type == 'Function') {
|
if ($type == 'Function') {
|
||||||
$localeFunction = Calculation::localeFunc($value);
|
$localeFunction = Calculation::localeFunc($value);
|
||||||
if ($localeFunction != $value) {
|
if ($localeFunction != $value) {
|
||||||
@ -52,6 +62,35 @@ class Stack
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getStackItem(
|
||||||
|
$type,
|
||||||
|
$value,
|
||||||
|
$reference = null,
|
||||||
|
$storeKey = null,
|
||||||
|
$onlyIf = null,
|
||||||
|
$onlyIfNot = null
|
||||||
|
) {
|
||||||
|
$stackItem = [
|
||||||
|
'type' => $type,
|
||||||
|
'value' => $value,
|
||||||
|
'reference' => $reference,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isset($storeKey)) {
|
||||||
|
$stackItem['storeKey'] = $storeKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($onlyIf)) {
|
||||||
|
$stackItem['onlyIf'] = $onlyIf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($onlyIfNot)) {
|
||||||
|
$stackItem['onlyIfNot'] = $onlyIfNot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $stackItem;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pop the last entry from the stack.
|
* Pop the last entry from the stack.
|
||||||
*
|
*
|
||||||
@ -90,4 +129,21 @@ class Stack
|
|||||||
$this->stack = [];
|
$this->stack = [];
|
||||||
$this->count = 0;
|
$this->count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
$str = 'Stack: ';
|
||||||
|
foreach ($this->stack as $index => $item) {
|
||||||
|
if ($index > $this->count - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$value = $item['value'] ?? 'no value';
|
||||||
|
while (is_array($value)) {
|
||||||
|
$value = array_pop($value);
|
||||||
|
}
|
||||||
|
$str .= $value . ' |> ';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ ADDRESS
|
|||||||
AMORDEGRC
|
AMORDEGRC
|
||||||
AMORLINC
|
AMORLINC
|
||||||
AND
|
AND
|
||||||
|
ARABIC
|
||||||
AREAS
|
AREAS
|
||||||
ASC
|
ASC
|
||||||
ASIN
|
ASIN
|
||||||
@ -22,6 +23,7 @@ AVERAGEA
|
|||||||
AVERAGEIF
|
AVERAGEIF
|
||||||
AVERAGEIFS
|
AVERAGEIFS
|
||||||
BAHTTEXT
|
BAHTTEXT
|
||||||
|
BASE
|
||||||
BESSELI
|
BESSELI
|
||||||
BESSELJ
|
BESSELJ
|
||||||
BESSELK
|
BESSELK
|
||||||
@ -137,6 +139,8 @@ FISHER
|
|||||||
FISHERINV
|
FISHERINV
|
||||||
FIXED
|
FIXED
|
||||||
FLOOR
|
FLOOR
|
||||||
|
FLOOR.MATH
|
||||||
|
FLOOR.PRECISE
|
||||||
FORECAST
|
FORECAST
|
||||||
FREQUENCY
|
FREQUENCY
|
||||||
FTEST
|
FTEST
|
||||||
@ -224,6 +228,7 @@ LOWER
|
|||||||
MATCH
|
MATCH
|
||||||
MAX
|
MAX
|
||||||
MAXA
|
MAXA
|
||||||
|
MAXIFS
|
||||||
MDETERM
|
MDETERM
|
||||||
MDURATION
|
MDURATION
|
||||||
MEDIAN
|
MEDIAN
|
||||||
@ -231,6 +236,7 @@ MID
|
|||||||
MIDB
|
MIDB
|
||||||
MIN
|
MIN
|
||||||
MINA
|
MINA
|
||||||
|
MINIFS
|
||||||
MINUTE
|
MINUTE
|
||||||
MINVERSE
|
MINVERSE
|
||||||
MIRR
|
MIRR
|
||||||
|
|||||||
@ -118,7 +118,7 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder
|
|||||||
// Check for time without seconds e.g. '9:45', '09:45'
|
// Check for time without seconds e.g. '9:45', '09:45'
|
||||||
if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d$/', $value)) {
|
if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d$/', $value)) {
|
||||||
// Convert value to number
|
// Convert value to number
|
||||||
list($h, $m) = explode(':', $value);
|
[$h, $m] = explode(':', $value);
|
||||||
$days = $h / 24 + $m / 1440;
|
$days = $h / 24 + $m / 1440;
|
||||||
$cell->setValueExplicit($days, DataType::TYPE_NUMERIC);
|
$cell->setValueExplicit($days, DataType::TYPE_NUMERIC);
|
||||||
// Set style
|
// Set style
|
||||||
@ -131,7 +131,7 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder
|
|||||||
// Check for time with seconds '9:45:59', '09:45:59'
|
// Check for time with seconds '9:45:59', '09:45:59'
|
||||||
if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d:[0-5]\d$/', $value)) {
|
if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d:[0-5]\d$/', $value)) {
|
||||||
// Convert value to number
|
// Convert value to number
|
||||||
list($h, $m, $s) = explode(':', $value);
|
[$h, $m, $s] = explode(':', $value);
|
||||||
$days = $h / 24 + $m / 1440 + $s / 86400;
|
$days = $h / 24 + $m / 1440 + $s / 86400;
|
||||||
// Convert value to number
|
// Convert value to number
|
||||||
$cell->setValueExplicit($days, DataType::TYPE_NUMERIC);
|
$cell->setValueExplicit($days, DataType::TYPE_NUMERIC);
|
||||||
|
|||||||
@ -67,7 +67,7 @@ class Cell
|
|||||||
/**
|
/**
|
||||||
* Update the cell into the cell collection.
|
* Update the cell into the cell collection.
|
||||||
*
|
*
|
||||||
* @return self
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function updateInCollection()
|
public function updateInCollection()
|
||||||
{
|
{
|
||||||
@ -177,7 +177,7 @@ class Cell
|
|||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*
|
*
|
||||||
* @return Cell
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setValue($pValue)
|
public function setValue($pValue)
|
||||||
{
|
{
|
||||||
@ -217,7 +217,10 @@ class Cell
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case DataType::TYPE_NUMERIC:
|
case DataType::TYPE_NUMERIC:
|
||||||
$this->value = (float) $pValue;
|
if (is_string($pValue) && !is_numeric($pValue)) {
|
||||||
|
throw new Exception('Invalid numeric value for datatype Numeric');
|
||||||
|
}
|
||||||
|
$this->value = 0 + $pValue;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DataType::TYPE_FORMULA:
|
case DataType::TYPE_FORMULA:
|
||||||
@ -263,7 +266,7 @@ class Cell
|
|||||||
// We don't yet handle array returns
|
// We don't yet handle array returns
|
||||||
if (is_array($result)) {
|
if (is_array($result)) {
|
||||||
while (is_array($result)) {
|
while (is_array($result)) {
|
||||||
$result = array_pop($result);
|
$result = array_shift($result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception $ex) {
|
} catch (Exception $ex) {
|
||||||
@ -511,7 +514,7 @@ class Cell
|
|||||||
{
|
{
|
||||||
if ($mergeRange = $this->getMergeRange()) {
|
if ($mergeRange = $this->getMergeRange()) {
|
||||||
$mergeRange = Coordinate::splitRange($mergeRange);
|
$mergeRange = Coordinate::splitRange($mergeRange);
|
||||||
list($startCell) = $mergeRange[0];
|
[$startCell] = $mergeRange[0];
|
||||||
if ($this->getCoordinate() === $startCell) {
|
if ($this->getCoordinate() === $startCell) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -569,7 +572,7 @@ class Cell
|
|||||||
*/
|
*/
|
||||||
public function isInRange($pRange)
|
public function isInRange($pRange)
|
||||||
{
|
{
|
||||||
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($pRange);
|
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($pRange);
|
||||||
|
|
||||||
// Translate properties
|
// Translate properties
|
||||||
$myColumn = Coordinate::columnIndexFromString($this->getColumn());
|
$myColumn = Coordinate::columnIndexFromString($this->getColumn());
|
||||||
@ -669,7 +672,7 @@ class Cell
|
|||||||
*
|
*
|
||||||
* @param mixed $pAttributes
|
* @param mixed $pAttributes
|
||||||
*
|
*
|
||||||
* @return Cell
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setFormulaAttributes($pAttributes)
|
public function setFormulaAttributes($pAttributes)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -71,7 +71,7 @@ abstract class Coordinate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Split out any worksheet name from the reference
|
// Split out any worksheet name from the reference
|
||||||
list($worksheet, $pCoordinateString) = Worksheet::extractSheetTitle($pCoordinateString, true);
|
[$worksheet, $pCoordinateString] = Worksheet::extractSheetTitle($pCoordinateString, true);
|
||||||
if ($worksheet > '') {
|
if ($worksheet > '') {
|
||||||
$worksheet .= '!';
|
$worksheet .= '!';
|
||||||
}
|
}
|
||||||
@ -102,13 +102,13 @@ abstract class Coordinate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Split out any worksheet name from the coordinate
|
// Split out any worksheet name from the coordinate
|
||||||
list($worksheet, $pCoordinateString) = Worksheet::extractSheetTitle($pCoordinateString, true);
|
[$worksheet, $pCoordinateString] = Worksheet::extractSheetTitle($pCoordinateString, true);
|
||||||
if ($worksheet > '') {
|
if ($worksheet > '') {
|
||||||
$worksheet .= '!';
|
$worksheet .= '!';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create absolute coordinate
|
// Create absolute coordinate
|
||||||
list($column, $row) = self::coordinateFromString($pCoordinateString);
|
[$column, $row] = self::coordinateFromString($pCoordinateString);
|
||||||
$column = ltrim($column, '$');
|
$column = ltrim($column, '$');
|
||||||
$row = ltrim($row, '$');
|
$row = ltrim($row, '$');
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ abstract class Coordinate
|
|||||||
if (strpos($pRange, ':') === false) {
|
if (strpos($pRange, ':') === false) {
|
||||||
$rangeA = $rangeB = $pRange;
|
$rangeA = $rangeB = $pRange;
|
||||||
} else {
|
} else {
|
||||||
list($rangeA, $rangeB) = explode(':', $pRange);
|
[$rangeA, $rangeB] = explode(':', $pRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate range outer borders
|
// Calculate range outer borders
|
||||||
@ -211,7 +211,7 @@ abstract class Coordinate
|
|||||||
public static function rangeDimension($pRange)
|
public static function rangeDimension($pRange)
|
||||||
{
|
{
|
||||||
// Calculate range outer borders
|
// Calculate range outer borders
|
||||||
list($rangeStart, $rangeEnd) = self::rangeBoundaries($pRange);
|
[$rangeStart, $rangeEnd] = self::rangeBoundaries($pRange);
|
||||||
|
|
||||||
return [($rangeEnd[0] - $rangeStart[0] + 1), ($rangeEnd[1] - $rangeStart[1] + 1)];
|
return [($rangeEnd[0] - $rangeStart[0] + 1), ($rangeEnd[1] - $rangeStart[1] + 1)];
|
||||||
}
|
}
|
||||||
@ -238,7 +238,7 @@ abstract class Coordinate
|
|||||||
if (strpos($pRange, ':') === false) {
|
if (strpos($pRange, ':') === false) {
|
||||||
$rangeA = $rangeB = $pRange;
|
$rangeA = $rangeB = $pRange;
|
||||||
} else {
|
} else {
|
||||||
list($rangeA, $rangeB) = explode(':', $pRange);
|
[$rangeA, $rangeB] = explode(':', $pRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [self::coordinateFromString($rangeA), self::coordinateFromString($rangeB)];
|
return [self::coordinateFromString($rangeA), self::coordinateFromString($rangeB)];
|
||||||
@ -376,9 +376,9 @@ abstract class Coordinate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Range...
|
// Range...
|
||||||
list($rangeStart, $rangeEnd) = $range;
|
[$rangeStart, $rangeEnd] = $range;
|
||||||
list($startColumn, $startRow) = self::coordinateFromString($rangeStart);
|
[$startColumn, $startRow] = self::coordinateFromString($rangeStart);
|
||||||
list($endColumn, $endRow) = self::coordinateFromString($rangeEnd);
|
[$endColumn, $endRow] = self::coordinateFromString($rangeEnd);
|
||||||
$startColumnIndex = self::columnIndexFromString($startColumn);
|
$startColumnIndex = self::columnIndexFromString($startColumn);
|
||||||
$endColumnIndex = self::columnIndexFromString($endColumn);
|
$endColumnIndex = self::columnIndexFromString($endColumn);
|
||||||
++$endColumnIndex;
|
++$endColumnIndex;
|
||||||
@ -432,7 +432,7 @@ abstract class Coordinate
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($column, $row) = self::coordinateFromString($coord);
|
[$column, $row] = self::coordinateFromString($coord);
|
||||||
$row = (int) (ltrim($row, '$'));
|
$row = (int) (ltrim($row, '$'));
|
||||||
$hashCode = $column . '-' . (is_object($value) ? $value->getHashCode() : $value);
|
$hashCode = $column . '-' . (is_object($value) ? $value->getHashCode() : $value);
|
||||||
|
|
||||||
|
|||||||
@ -142,7 +142,7 @@ class DataValidation
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return DataValidation
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setFormula1($value)
|
public function setFormula1($value)
|
||||||
{
|
{
|
||||||
@ -166,7 +166,7 @@ class DataValidation
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return DataValidation
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setFormula2($value)
|
public function setFormula2($value)
|
||||||
{
|
{
|
||||||
@ -190,7 +190,7 @@ class DataValidation
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return DataValidation
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setType($value)
|
public function setType($value)
|
||||||
{
|
{
|
||||||
@ -214,7 +214,7 @@ class DataValidation
|
|||||||
*
|
*
|
||||||
* @param string $value see self::STYLE_*
|
* @param string $value see self::STYLE_*
|
||||||
*
|
*
|
||||||
* @return DataValidation
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setErrorStyle($value)
|
public function setErrorStyle($value)
|
||||||
{
|
{
|
||||||
@ -238,7 +238,7 @@ class DataValidation
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return DataValidation
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setOperator($value)
|
public function setOperator($value)
|
||||||
{
|
{
|
||||||
@ -262,7 +262,7 @@ class DataValidation
|
|||||||
*
|
*
|
||||||
* @param bool $value
|
* @param bool $value
|
||||||
*
|
*
|
||||||
* @return DataValidation
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setAllowBlank($value)
|
public function setAllowBlank($value)
|
||||||
{
|
{
|
||||||
@ -286,7 +286,7 @@ class DataValidation
|
|||||||
*
|
*
|
||||||
* @param bool $value
|
* @param bool $value
|
||||||
*
|
*
|
||||||
* @return DataValidation
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShowDropDown($value)
|
public function setShowDropDown($value)
|
||||||
{
|
{
|
||||||
@ -310,7 +310,7 @@ class DataValidation
|
|||||||
*
|
*
|
||||||
* @param bool $value
|
* @param bool $value
|
||||||
*
|
*
|
||||||
* @return DataValidation
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShowInputMessage($value)
|
public function setShowInputMessage($value)
|
||||||
{
|
{
|
||||||
@ -334,7 +334,7 @@ class DataValidation
|
|||||||
*
|
*
|
||||||
* @param bool $value
|
* @param bool $value
|
||||||
*
|
*
|
||||||
* @return DataValidation
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShowErrorMessage($value)
|
public function setShowErrorMessage($value)
|
||||||
{
|
{
|
||||||
@ -358,7 +358,7 @@ class DataValidation
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return DataValidation
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setErrorTitle($value)
|
public function setErrorTitle($value)
|
||||||
{
|
{
|
||||||
@ -382,7 +382,7 @@ class DataValidation
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return DataValidation
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setError($value)
|
public function setError($value)
|
||||||
{
|
{
|
||||||
@ -406,7 +406,7 @@ class DataValidation
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return DataValidation
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setPromptTitle($value)
|
public function setPromptTitle($value)
|
||||||
{
|
{
|
||||||
@ -430,7 +430,7 @@ class DataValidation
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return DataValidation
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setPrompt($value)
|
public function setPrompt($value)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -51,16 +51,16 @@ class DefaultValueBinder implements IValueBinder
|
|||||||
// Match the value against a few data types
|
// Match the value against a few data types
|
||||||
if ($pValue === null) {
|
if ($pValue === null) {
|
||||||
return DataType::TYPE_NULL;
|
return DataType::TYPE_NULL;
|
||||||
|
} elseif (is_float($pValue) || is_int($pValue)) {
|
||||||
|
return DataType::TYPE_NUMERIC;
|
||||||
|
} elseif (is_bool($pValue)) {
|
||||||
|
return DataType::TYPE_BOOL;
|
||||||
} elseif ($pValue === '') {
|
} elseif ($pValue === '') {
|
||||||
return DataType::TYPE_STRING;
|
return DataType::TYPE_STRING;
|
||||||
} elseif ($pValue instanceof RichText) {
|
} elseif ($pValue instanceof RichText) {
|
||||||
return DataType::TYPE_INLINE;
|
return DataType::TYPE_INLINE;
|
||||||
} elseif ($pValue[0] === '=' && strlen($pValue) > 1) {
|
} elseif (is_string($pValue) && $pValue[0] === '=' && strlen($pValue) > 1) {
|
||||||
return DataType::TYPE_FORMULA;
|
return DataType::TYPE_FORMULA;
|
||||||
} elseif (is_bool($pValue)) {
|
|
||||||
return DataType::TYPE_BOOL;
|
|
||||||
} elseif (is_float($pValue) || is_int($pValue)) {
|
|
||||||
return DataType::TYPE_NUMERIC;
|
|
||||||
} elseif (preg_match('/^[\+\-]?(\d+\\.?\d*|\d*\\.?\d+)([Ee][\-\+]?[0-2]?\d{1,3})?$/', $pValue)) {
|
} elseif (preg_match('/^[\+\-]?(\d+\\.?\d*|\d*\\.?\d+)([Ee][\-\+]?[0-2]?\d{1,3})?$/', $pValue)) {
|
||||||
$tValue = ltrim($pValue, '+-');
|
$tValue = ltrim($pValue, '+-');
|
||||||
if (is_string($pValue) && $tValue[0] === '0' && strlen($tValue) > 1 && $tValue[1] !== '.') {
|
if (is_string($pValue) && $tValue[0] === '0' && strlen($tValue) > 1 && $tValue[1] !== '.') {
|
||||||
|
|||||||
@ -46,7 +46,7 @@ class Hyperlink
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return Hyperlink
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setUrl($value)
|
public function setUrl($value)
|
||||||
{
|
{
|
||||||
@ -70,7 +70,7 @@ class Hyperlink
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return Hyperlink
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setTooltip($value)
|
public function setTooltip($value)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -354,7 +354,7 @@ class Axis extends Properties
|
|||||||
*
|
*
|
||||||
* @param int $shadow_presets
|
* @param int $shadow_presets
|
||||||
*
|
*
|
||||||
* @return Axis
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setShadowPresetsProperties($shadow_presets)
|
private function setShadowPresetsProperties($shadow_presets)
|
||||||
{
|
{
|
||||||
@ -370,7 +370,7 @@ class Axis extends Properties
|
|||||||
* @param array $properties_map
|
* @param array $properties_map
|
||||||
* @param mixed &$reference
|
* @param mixed &$reference
|
||||||
*
|
*
|
||||||
* @return Axis
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setShadowProperiesMapValues(array $properties_map, &$reference = null)
|
private function setShadowProperiesMapValues(array $properties_map, &$reference = null)
|
||||||
{
|
{
|
||||||
@ -402,7 +402,7 @@ class Axis extends Properties
|
|||||||
* @param int $alpha
|
* @param int $alpha
|
||||||
* @param string $type
|
* @param string $type
|
||||||
*
|
*
|
||||||
* @return Axis
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setShadowColor($color, $alpha, $type)
|
private function setShadowColor($color, $alpha, $type)
|
||||||
{
|
{
|
||||||
@ -416,7 +416,7 @@ class Axis extends Properties
|
|||||||
*
|
*
|
||||||
* @param float $blur
|
* @param float $blur
|
||||||
*
|
*
|
||||||
* @return Axis
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setShadowBlur($blur)
|
private function setShadowBlur($blur)
|
||||||
{
|
{
|
||||||
@ -432,7 +432,7 @@ class Axis extends Properties
|
|||||||
*
|
*
|
||||||
* @param int $angle
|
* @param int $angle
|
||||||
*
|
*
|
||||||
* @return Axis
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setShadowAngle($angle)
|
private function setShadowAngle($angle)
|
||||||
{
|
{
|
||||||
@ -448,7 +448,7 @@ class Axis extends Properties
|
|||||||
*
|
*
|
||||||
* @param float $distance
|
* @param float $distance
|
||||||
*
|
*
|
||||||
* @return Axis
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setShadowDistance($distance)
|
private function setShadowDistance($distance)
|
||||||
{
|
{
|
||||||
@ -506,7 +506,7 @@ class Axis extends Properties
|
|||||||
*
|
*
|
||||||
* @param float $size
|
* @param float $size
|
||||||
*
|
*
|
||||||
* @return Axis
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setGlowSize($size)
|
private function setGlowSize($size)
|
||||||
{
|
{
|
||||||
@ -524,7 +524,7 @@ class Axis extends Properties
|
|||||||
* @param int $alpha
|
* @param int $alpha
|
||||||
* @param string $type
|
* @param string $type
|
||||||
*
|
*
|
||||||
* @return Axis
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setGlowColor($color, $alpha, $type)
|
private function setGlowColor($color, $alpha, $type)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -156,7 +156,7 @@ class Chart
|
|||||||
* @param null|GridLines $majorGridlines
|
* @param null|GridLines $majorGridlines
|
||||||
* @param null|GridLines $minorGridlines
|
* @param null|GridLines $minorGridlines
|
||||||
*/
|
*/
|
||||||
public function __construct($name, Title $title = null, Legend $legend = null, PlotArea $plotArea = null, $plotVisibleOnly = true, $displayBlanksAs = '0', Title $xAxisLabel = null, Title $yAxisLabel = null, Axis $xAxis = null, Axis $yAxis = null, GridLines $majorGridlines = null, GridLines $minorGridlines = null)
|
public function __construct($name, Title $title = null, Legend $legend = null, PlotArea $plotArea = null, $plotVisibleOnly = true, $displayBlanksAs = 'gap', Title $xAxisLabel = null, Title $yAxisLabel = null, Axis $xAxis = null, Axis $yAxis = null, GridLines $majorGridlines = null, GridLines $minorGridlines = null)
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->title = $title;
|
$this->title = $title;
|
||||||
@ -197,7 +197,7 @@ class Chart
|
|||||||
*
|
*
|
||||||
* @param Worksheet $pValue
|
* @param Worksheet $pValue
|
||||||
*
|
*
|
||||||
* @return Chart
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setWorksheet(Worksheet $pValue = null)
|
public function setWorksheet(Worksheet $pValue = null)
|
||||||
{
|
{
|
||||||
@ -221,7 +221,7 @@ class Chart
|
|||||||
*
|
*
|
||||||
* @param Title $title
|
* @param Title $title
|
||||||
*
|
*
|
||||||
* @return Chart
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setTitle(Title $title)
|
public function setTitle(Title $title)
|
||||||
{
|
{
|
||||||
@ -245,7 +245,7 @@ class Chart
|
|||||||
*
|
*
|
||||||
* @param Legend $legend
|
* @param Legend $legend
|
||||||
*
|
*
|
||||||
* @return Chart
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setLegend(Legend $legend)
|
public function setLegend(Legend $legend)
|
||||||
{
|
{
|
||||||
@ -269,7 +269,7 @@ class Chart
|
|||||||
*
|
*
|
||||||
* @param Title $label
|
* @param Title $label
|
||||||
*
|
*
|
||||||
* @return Chart
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setXAxisLabel(Title $label)
|
public function setXAxisLabel(Title $label)
|
||||||
{
|
{
|
||||||
@ -293,7 +293,7 @@ class Chart
|
|||||||
*
|
*
|
||||||
* @param Title $label
|
* @param Title $label
|
||||||
*
|
*
|
||||||
* @return Chart
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setYAxisLabel(Title $label)
|
public function setYAxisLabel(Title $label)
|
||||||
{
|
{
|
||||||
@ -327,7 +327,7 @@ class Chart
|
|||||||
*
|
*
|
||||||
* @param bool $plotVisibleOnly
|
* @param bool $plotVisibleOnly
|
||||||
*
|
*
|
||||||
* @return Chart
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setPlotVisibleOnly($plotVisibleOnly)
|
public function setPlotVisibleOnly($plotVisibleOnly)
|
||||||
{
|
{
|
||||||
@ -351,7 +351,7 @@ class Chart
|
|||||||
*
|
*
|
||||||
* @param string $displayBlanksAs
|
* @param string $displayBlanksAs
|
||||||
*
|
*
|
||||||
* @return Chart
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setDisplayBlanksAs($displayBlanksAs)
|
public function setDisplayBlanksAs($displayBlanksAs)
|
||||||
{
|
{
|
||||||
@ -423,7 +423,7 @@ class Chart
|
|||||||
* @param int $xOffset
|
* @param int $xOffset
|
||||||
* @param int $yOffset
|
* @param int $yOffset
|
||||||
*
|
*
|
||||||
* @return Chart
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setTopLeftPosition($cell, $xOffset = null, $yOffset = null)
|
public function setTopLeftPosition($cell, $xOffset = null, $yOffset = null)
|
||||||
{
|
{
|
||||||
@ -467,7 +467,7 @@ class Chart
|
|||||||
*
|
*
|
||||||
* @param string $cell
|
* @param string $cell
|
||||||
*
|
*
|
||||||
* @return Chart
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setTopLeftCell($cell)
|
public function setTopLeftCell($cell)
|
||||||
{
|
{
|
||||||
@ -482,7 +482,7 @@ class Chart
|
|||||||
* @param int $xOffset
|
* @param int $xOffset
|
||||||
* @param int $yOffset
|
* @param int $yOffset
|
||||||
*
|
*
|
||||||
* @return Chart
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setTopLeftOffset($xOffset, $yOffset)
|
public function setTopLeftOffset($xOffset, $yOffset)
|
||||||
{
|
{
|
||||||
@ -541,7 +541,7 @@ class Chart
|
|||||||
* @param int $xOffset
|
* @param int $xOffset
|
||||||
* @param int $yOffset
|
* @param int $yOffset
|
||||||
*
|
*
|
||||||
* @return Chart
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setBottomRightPosition($cell, $xOffset = null, $yOffset = null)
|
public function setBottomRightPosition($cell, $xOffset = null, $yOffset = null)
|
||||||
{
|
{
|
||||||
@ -593,7 +593,7 @@ class Chart
|
|||||||
* @param int $xOffset
|
* @param int $xOffset
|
||||||
* @param int $yOffset
|
* @param int $yOffset
|
||||||
*
|
*
|
||||||
* @return Chart
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setBottomRightOffset($xOffset, $yOffset)
|
public function setBottomRightOffset($xOffset, $yOffset)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -157,7 +157,7 @@ class DataSeries
|
|||||||
*
|
*
|
||||||
* @param string $plotType
|
* @param string $plotType
|
||||||
*
|
*
|
||||||
* @return DataSeries
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setPlotType($plotType)
|
public function setPlotType($plotType)
|
||||||
{
|
{
|
||||||
@ -181,7 +181,7 @@ class DataSeries
|
|||||||
*
|
*
|
||||||
* @param string $groupingType
|
* @param string $groupingType
|
||||||
*
|
*
|
||||||
* @return DataSeries
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setPlotGrouping($groupingType)
|
public function setPlotGrouping($groupingType)
|
||||||
{
|
{
|
||||||
@ -205,7 +205,7 @@ class DataSeries
|
|||||||
*
|
*
|
||||||
* @param string $plotDirection
|
* @param string $plotDirection
|
||||||
*
|
*
|
||||||
* @return DataSeries
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setPlotDirection($plotDirection)
|
public function setPlotDirection($plotDirection)
|
||||||
{
|
{
|
||||||
@ -297,7 +297,7 @@ class DataSeries
|
|||||||
*
|
*
|
||||||
* @param null|string $plotStyle
|
* @param null|string $plotStyle
|
||||||
*
|
*
|
||||||
* @return DataSeries
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setPlotStyle($plotStyle)
|
public function setPlotStyle($plotStyle)
|
||||||
{
|
{
|
||||||
@ -360,7 +360,7 @@ class DataSeries
|
|||||||
*
|
*
|
||||||
* @param bool $smoothLine
|
* @param bool $smoothLine
|
||||||
*
|
*
|
||||||
* @return DataSeries
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setSmoothLine($smoothLine)
|
public function setSmoothLine($smoothLine)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -117,7 +117,7 @@ class DataSeriesValues
|
|||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*
|
*
|
||||||
* @return DataSeriesValues
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setDataType($dataType)
|
public function setDataType($dataType)
|
||||||
{
|
{
|
||||||
@ -144,7 +144,7 @@ class DataSeriesValues
|
|||||||
*
|
*
|
||||||
* @param string $dataSource
|
* @param string $dataSource
|
||||||
*
|
*
|
||||||
* @return DataSeriesValues
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setDataSource($dataSource)
|
public function setDataSource($dataSource)
|
||||||
{
|
{
|
||||||
@ -168,7 +168,7 @@ class DataSeriesValues
|
|||||||
*
|
*
|
||||||
* @param string $marker
|
* @param string $marker
|
||||||
*
|
*
|
||||||
* @return DataSeriesValues
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setPointMarker($marker)
|
public function setPointMarker($marker)
|
||||||
{
|
{
|
||||||
@ -192,7 +192,7 @@ class DataSeriesValues
|
|||||||
*
|
*
|
||||||
* @param string $formatCode
|
* @param string $formatCode
|
||||||
*
|
*
|
||||||
* @return DataSeriesValues
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setFormatCode($formatCode)
|
public function setFormatCode($formatCode)
|
||||||
{
|
{
|
||||||
@ -275,7 +275,7 @@ class DataSeriesValues
|
|||||||
*
|
*
|
||||||
* @param int $width
|
* @param int $width
|
||||||
*
|
*
|
||||||
* @return DataSeriesValues
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setLineWidth($width)
|
public function setLineWidth($width)
|
||||||
{
|
{
|
||||||
@ -346,7 +346,7 @@ class DataSeriesValues
|
|||||||
*
|
*
|
||||||
* @param array $dataValues
|
* @param array $dataValues
|
||||||
*
|
*
|
||||||
* @return DataSeriesValues
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setDataValues($dataValues)
|
public function setDataValues($dataValues)
|
||||||
{
|
{
|
||||||
@ -370,13 +370,13 @@ class DataSeriesValues
|
|||||||
if ($flatten) {
|
if ($flatten) {
|
||||||
$this->dataValues = Functions::flattenArray($newDataValues);
|
$this->dataValues = Functions::flattenArray($newDataValues);
|
||||||
foreach ($this->dataValues as &$dataValue) {
|
foreach ($this->dataValues as &$dataValue) {
|
||||||
if ((!empty($dataValue)) && ($dataValue[0] == '#')) {
|
if (is_string($dataValue) && !empty($dataValue) && $dataValue[0] == '#') {
|
||||||
$dataValue = 0.0;
|
$dataValue = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unset($dataValue);
|
unset($dataValue);
|
||||||
} else {
|
} else {
|
||||||
list($worksheet, $cellRange) = Worksheet::extractSheetTitle($this->dataSource, true);
|
[$worksheet, $cellRange] = Worksheet::extractSheetTitle($this->dataSource, true);
|
||||||
$dimensions = Coordinate::rangeDimension(str_replace('$', '', $cellRange));
|
$dimensions = Coordinate::rangeDimension(str_replace('$', '', $cellRange));
|
||||||
if (($dimensions[0] == 1) || ($dimensions[1] == 1)) {
|
if (($dimensions[0] == 1) || ($dimensions[1] == 1)) {
|
||||||
$this->dataValues = Functions::flattenArray($newDataValues);
|
$this->dataValues = Functions::flattenArray($newDataValues);
|
||||||
|
|||||||
@ -91,7 +91,7 @@ class GridLines extends Properties
|
|||||||
/**
|
/**
|
||||||
* Change Object State to True.
|
* Change Object State to True.
|
||||||
*
|
*
|
||||||
* @return GridLines
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function activateObject()
|
private function activateObject()
|
||||||
{
|
{
|
||||||
@ -229,7 +229,7 @@ class GridLines extends Properties
|
|||||||
*
|
*
|
||||||
* @param float $size
|
* @param float $size
|
||||||
*
|
*
|
||||||
* @return GridLines
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setGlowSize($size)
|
private function setGlowSize($size)
|
||||||
{
|
{
|
||||||
@ -245,7 +245,7 @@ class GridLines extends Properties
|
|||||||
* @param int $alpha
|
* @param int $alpha
|
||||||
* @param string $type
|
* @param string $type
|
||||||
*
|
*
|
||||||
* @return GridLines
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setGlowColor($color, $alpha, $type)
|
private function setGlowColor($color, $alpha, $type)
|
||||||
{
|
{
|
||||||
@ -305,7 +305,7 @@ class GridLines extends Properties
|
|||||||
*
|
*
|
||||||
* @param int $shadow_presets
|
* @param int $shadow_presets
|
||||||
*
|
*
|
||||||
* @return GridLines
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setShadowPresetsProperties($shadow_presets)
|
private function setShadowPresetsProperties($shadow_presets)
|
||||||
{
|
{
|
||||||
@ -321,7 +321,7 @@ class GridLines extends Properties
|
|||||||
* @param array $properties_map
|
* @param array $properties_map
|
||||||
* @param mixed &$reference
|
* @param mixed &$reference
|
||||||
*
|
*
|
||||||
* @return GridLines
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setShadowProperiesMapValues(array $properties_map, &$reference = null)
|
private function setShadowProperiesMapValues(array $properties_map, &$reference = null)
|
||||||
{
|
{
|
||||||
@ -353,7 +353,7 @@ class GridLines extends Properties
|
|||||||
* @param int $alpha
|
* @param int $alpha
|
||||||
* @param string $type
|
* @param string $type
|
||||||
*
|
*
|
||||||
* @return GridLines
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setShadowColor($color, $alpha, $type)
|
private function setShadowColor($color, $alpha, $type)
|
||||||
{
|
{
|
||||||
@ -375,7 +375,7 @@ class GridLines extends Properties
|
|||||||
*
|
*
|
||||||
* @param float $blur
|
* @param float $blur
|
||||||
*
|
*
|
||||||
* @return GridLines
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setShadowBlur($blur)
|
private function setShadowBlur($blur)
|
||||||
{
|
{
|
||||||
@ -391,7 +391,7 @@ class GridLines extends Properties
|
|||||||
*
|
*
|
||||||
* @param int $angle
|
* @param int $angle
|
||||||
*
|
*
|
||||||
* @return GridLines
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setShadowAngle($angle)
|
private function setShadowAngle($angle)
|
||||||
{
|
{
|
||||||
@ -407,7 +407,7 @@ class GridLines extends Properties
|
|||||||
*
|
*
|
||||||
* @param float $distance
|
* @param float $distance
|
||||||
*
|
*
|
||||||
* @return GridLines
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setShadowDistance($distance)
|
private function setShadowDistance($distance)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -153,7 +153,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setLayoutTarget($value)
|
public function setLayoutTarget($value)
|
||||||
{
|
{
|
||||||
@ -177,7 +177,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setXMode($value)
|
public function setXMode($value)
|
||||||
{
|
{
|
||||||
@ -201,7 +201,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setYMode($value)
|
public function setYMode($value)
|
||||||
{
|
{
|
||||||
@ -225,7 +225,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param float $value
|
* @param float $value
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setXPosition($value)
|
public function setXPosition($value)
|
||||||
{
|
{
|
||||||
@ -249,7 +249,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param float $value
|
* @param float $value
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setYPosition($value)
|
public function setYPosition($value)
|
||||||
{
|
{
|
||||||
@ -273,7 +273,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param float $value
|
* @param float $value
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setWidth($value)
|
public function setWidth($value)
|
||||||
{
|
{
|
||||||
@ -297,7 +297,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param float $value
|
* @param float $value
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setHeight($value)
|
public function setHeight($value)
|
||||||
{
|
{
|
||||||
@ -322,7 +322,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param bool $value Show legend key
|
* @param bool $value Show legend key
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShowLegendKey($value)
|
public function setShowLegendKey($value)
|
||||||
{
|
{
|
||||||
@ -347,7 +347,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param bool $value Show val
|
* @param bool $value Show val
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShowVal($value)
|
public function setShowVal($value)
|
||||||
{
|
{
|
||||||
@ -372,7 +372,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param bool $value Show cat name
|
* @param bool $value Show cat name
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShowCatName($value)
|
public function setShowCatName($value)
|
||||||
{
|
{
|
||||||
@ -397,7 +397,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param bool $value Show series name
|
* @param bool $value Show series name
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShowSerName($value)
|
public function setShowSerName($value)
|
||||||
{
|
{
|
||||||
@ -422,7 +422,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param bool $value Show percentage
|
* @param bool $value Show percentage
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShowPercent($value)
|
public function setShowPercent($value)
|
||||||
{
|
{
|
||||||
@ -447,7 +447,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param bool $value Show bubble size
|
* @param bool $value Show bubble size
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShowBubbleSize($value)
|
public function setShowBubbleSize($value)
|
||||||
{
|
{
|
||||||
@ -472,7 +472,7 @@ class Layout
|
|||||||
*
|
*
|
||||||
* @param bool $value Show leader lines
|
* @param bool $value Show leader lines
|
||||||
*
|
*
|
||||||
* @return Layout
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShowLeaderLines($value)
|
public function setShowLeaderLines($value)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -94,7 +94,7 @@ class PlotArea
|
|||||||
*
|
*
|
||||||
* @param DataSeries[] $plotSeries
|
* @param DataSeries[] $plotSeries
|
||||||
*
|
*
|
||||||
* @return PlotArea
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setPlotSeries(array $plotSeries)
|
public function setPlotSeries(array $plotSeries)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -442,7 +442,7 @@ class JpGraph implements IRenderer
|
|||||||
$seriesPlot->link->SetColor(self::$colourSet[self::$plotColour]);
|
$seriesPlot->link->SetColor(self::$colourSet[self::$plotColour]);
|
||||||
} elseif ($scatterStyle == 'smoothMarker') {
|
} elseif ($scatterStyle == 'smoothMarker') {
|
||||||
$spline = new \Spline($dataValuesY, $dataValuesX);
|
$spline = new \Spline($dataValuesY, $dataValuesX);
|
||||||
list($splineDataY, $splineDataX) = $spline->Get(count($dataValuesX) * self::$width / 20);
|
[$splineDataY, $splineDataX] = $spline->Get(count($dataValuesX) * self::$width / 20);
|
||||||
$lplot = new \LinePlot($splineDataX, $splineDataY);
|
$lplot = new \LinePlot($splineDataX, $splineDataY);
|
||||||
$lplot->SetColor(self::$colourSet[self::$plotColour]);
|
$lplot->SetColor(self::$colourSet[self::$plotColour]);
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,7 @@ class Title
|
|||||||
*
|
*
|
||||||
* @param string $caption
|
* @param string $caption
|
||||||
*
|
*
|
||||||
* @return Title
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setCaption($caption)
|
public function setCaption($caption)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -16,8 +16,6 @@ abstract class CellsFactory
|
|||||||
* */
|
* */
|
||||||
public static function getInstance(Worksheet $parent)
|
public static function getInstance(Worksheet $parent)
|
||||||
{
|
{
|
||||||
$instance = new Cells($parent, Settings::getCache());
|
return new Cells($parent, Settings::getCache());
|
||||||
|
|
||||||
return $instance;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -96,7 +96,7 @@ class Comment implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string $author
|
* @param string $author
|
||||||
*
|
*
|
||||||
* @return Comment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setAuthor($author)
|
public function setAuthor($author)
|
||||||
{
|
{
|
||||||
@ -120,7 +120,7 @@ class Comment implements IComparable
|
|||||||
*
|
*
|
||||||
* @param RichText $pValue
|
* @param RichText $pValue
|
||||||
*
|
*
|
||||||
* @return Comment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setText(RichText $pValue)
|
public function setText(RichText $pValue)
|
||||||
{
|
{
|
||||||
@ -144,7 +144,7 @@ class Comment implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string $width
|
* @param string $width
|
||||||
*
|
*
|
||||||
* @return Comment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setWidth($width)
|
public function setWidth($width)
|
||||||
{
|
{
|
||||||
@ -168,7 +168,7 @@ class Comment implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return Comment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setHeight($value)
|
public function setHeight($value)
|
||||||
{
|
{
|
||||||
@ -192,7 +192,7 @@ class Comment implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return Comment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setMarginLeft($value)
|
public function setMarginLeft($value)
|
||||||
{
|
{
|
||||||
@ -216,7 +216,7 @@ class Comment implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return Comment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setMarginTop($value)
|
public function setMarginTop($value)
|
||||||
{
|
{
|
||||||
@ -240,7 +240,7 @@ class Comment implements IComparable
|
|||||||
*
|
*
|
||||||
* @param bool $value
|
* @param bool $value
|
||||||
*
|
*
|
||||||
* @return Comment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setVisible($value)
|
public function setVisible($value)
|
||||||
{
|
{
|
||||||
@ -264,7 +264,7 @@ class Comment implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string $alignment see Style\Alignment::HORIZONTAL_*
|
* @param string $alignment see Style\Alignment::HORIZONTAL_*
|
||||||
*
|
*
|
||||||
* @return Comment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setAlignment($alignment)
|
public function setAlignment($alignment)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -122,7 +122,7 @@ class Properties
|
|||||||
*
|
*
|
||||||
* @param string $creator
|
* @param string $creator
|
||||||
*
|
*
|
||||||
* @return Properties
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setCreator($creator)
|
public function setCreator($creator)
|
||||||
{
|
{
|
||||||
@ -146,7 +146,7 @@ class Properties
|
|||||||
*
|
*
|
||||||
* @param string $pValue
|
* @param string $pValue
|
||||||
*
|
*
|
||||||
* @return Properties
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setLastModifiedBy($pValue)
|
public function setLastModifiedBy($pValue)
|
||||||
{
|
{
|
||||||
@ -170,7 +170,7 @@ class Properties
|
|||||||
*
|
*
|
||||||
* @param int|string $time
|
* @param int|string $time
|
||||||
*
|
*
|
||||||
* @return Properties
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setCreated($time)
|
public function setCreated($time)
|
||||||
{
|
{
|
||||||
@ -204,7 +204,7 @@ class Properties
|
|||||||
*
|
*
|
||||||
* @param int|string $time
|
* @param int|string $time
|
||||||
*
|
*
|
||||||
* @return Properties
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setModified($time)
|
public function setModified($time)
|
||||||
{
|
{
|
||||||
@ -238,7 +238,7 @@ class Properties
|
|||||||
*
|
*
|
||||||
* @param string $title
|
* @param string $title
|
||||||
*
|
*
|
||||||
* @return Properties
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setTitle($title)
|
public function setTitle($title)
|
||||||
{
|
{
|
||||||
@ -262,7 +262,7 @@ class Properties
|
|||||||
*
|
*
|
||||||
* @param string $description
|
* @param string $description
|
||||||
*
|
*
|
||||||
* @return Properties
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setDescription($description)
|
public function setDescription($description)
|
||||||
{
|
{
|
||||||
@ -286,7 +286,7 @@ class Properties
|
|||||||
*
|
*
|
||||||
* @param string $subject
|
* @param string $subject
|
||||||
*
|
*
|
||||||
* @return Properties
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setSubject($subject)
|
public function setSubject($subject)
|
||||||
{
|
{
|
||||||
@ -310,7 +310,7 @@ class Properties
|
|||||||
*
|
*
|
||||||
* @param string $keywords
|
* @param string $keywords
|
||||||
*
|
*
|
||||||
* @return Properties
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setKeywords($keywords)
|
public function setKeywords($keywords)
|
||||||
{
|
{
|
||||||
@ -334,7 +334,7 @@ class Properties
|
|||||||
*
|
*
|
||||||
* @param string $category
|
* @param string $category
|
||||||
*
|
*
|
||||||
* @return Properties
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setCategory($category)
|
public function setCategory($category)
|
||||||
{
|
{
|
||||||
@ -358,7 +358,7 @@ class Properties
|
|||||||
*
|
*
|
||||||
* @param string $company
|
* @param string $company
|
||||||
*
|
*
|
||||||
* @return Properties
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setCompany($company)
|
public function setCompany($company)
|
||||||
{
|
{
|
||||||
@ -382,7 +382,7 @@ class Properties
|
|||||||
*
|
*
|
||||||
* @param string $manager
|
* @param string $manager
|
||||||
*
|
*
|
||||||
* @return Properties
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setManager($manager)
|
public function setManager($manager)
|
||||||
{
|
{
|
||||||
@ -453,7 +453,7 @@ class Properties
|
|||||||
* 'd' : Date/Time
|
* 'd' : Date/Time
|
||||||
* 'b' : Boolean
|
* 'b' : Boolean
|
||||||
*
|
*
|
||||||
* @return Properties
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null)
|
public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -75,7 +75,7 @@ class Security
|
|||||||
*
|
*
|
||||||
* @param bool $pValue
|
* @param bool $pValue
|
||||||
*
|
*
|
||||||
* @return Security
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setLockRevision($pValue)
|
public function setLockRevision($pValue)
|
||||||
{
|
{
|
||||||
@ -99,7 +99,7 @@ class Security
|
|||||||
*
|
*
|
||||||
* @param bool $pValue
|
* @param bool $pValue
|
||||||
*
|
*
|
||||||
* @return Security
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setLockStructure($pValue)
|
public function setLockStructure($pValue)
|
||||||
{
|
{
|
||||||
@ -123,7 +123,7 @@ class Security
|
|||||||
*
|
*
|
||||||
* @param bool $pValue
|
* @param bool $pValue
|
||||||
*
|
*
|
||||||
* @return Security
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setLockWindows($pValue)
|
public function setLockWindows($pValue)
|
||||||
{
|
{
|
||||||
@ -148,7 +148,7 @@ class Security
|
|||||||
* @param string $pValue
|
* @param string $pValue
|
||||||
* @param bool $pAlreadyHashed If the password has already been hashed, set this to true
|
* @param bool $pAlreadyHashed If the password has already been hashed, set this to true
|
||||||
*
|
*
|
||||||
* @return Security
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setRevisionsPassword($pValue, $pAlreadyHashed = false)
|
public function setRevisionsPassword($pValue, $pAlreadyHashed = false)
|
||||||
{
|
{
|
||||||
@ -176,7 +176,7 @@ class Security
|
|||||||
* @param string $pValue
|
* @param string $pValue
|
||||||
* @param bool $pAlreadyHashed If the password has already been hashed, set this to true
|
* @param bool $pAlreadyHashed If the password has already been hashed, set this to true
|
||||||
*
|
*
|
||||||
* @return Security
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setWorkbookPassword($pValue, $pAlreadyHashed = false)
|
public function setWorkbookPassword($pValue, $pAlreadyHashed = false)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Category;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
use ReflectionClass;
|
||||||
|
use ReflectionException;
|
||||||
|
use UnexpectedValueException;
|
||||||
|
|
||||||
|
class DocumentGenerator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param array[] $phpSpreadsheetFunctions
|
||||||
|
*
|
||||||
|
* @throws ReflectionException
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function generateFunctionListByCategory(array $phpSpreadsheetFunctions): string
|
||||||
|
{
|
||||||
|
$result = "# Function list by category\n";
|
||||||
|
foreach (self::getCategories() as $categoryConstant => $category) {
|
||||||
|
$result .= "\n";
|
||||||
|
$result .= "## {$categoryConstant}\n";
|
||||||
|
$result .= "\n";
|
||||||
|
$lengths = [20, 42];
|
||||||
|
$result .= self::tableRow($lengths, ['Excel Function', 'PhpSpreadsheet Function']) . "\n";
|
||||||
|
$result .= self::tableRow($lengths, null) . "\n";
|
||||||
|
foreach ($phpSpreadsheetFunctions as $excelFunction => $functionInfo) {
|
||||||
|
if ($category === $functionInfo['category']) {
|
||||||
|
$phpFunction = self::getPhpSpreadsheetFunctionText($functionInfo['functionCall']);
|
||||||
|
$result .= self::tableRow($lengths, [$excelFunction, $phpFunction]) . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ReflectionException
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function getCategories(): array
|
||||||
|
{
|
||||||
|
return (new ReflectionClass(Category::class))->getConstants();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function tableRow(array $lengths, array $values = null): string
|
||||||
|
{
|
||||||
|
$result = '';
|
||||||
|
foreach (array_map(null, $lengths, $values ?? []) as $i => [$length, $value]) {
|
||||||
|
$pad = $value === null ? '-' : ' ';
|
||||||
|
if ($i > 0) {
|
||||||
|
$result .= '|' . $pad;
|
||||||
|
}
|
||||||
|
$result .= str_pad($value ?? '', $length, $pad);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtrim($result, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getPhpSpreadsheetFunctionText($functionCall): string
|
||||||
|
{
|
||||||
|
if (is_string($functionCall)) {
|
||||||
|
return $functionCall;
|
||||||
|
}
|
||||||
|
if ($functionCall === [Functions::class, 'DUMMY']) {
|
||||||
|
return '**Not yet Implemented**';
|
||||||
|
}
|
||||||
|
if (is_array($functionCall)) {
|
||||||
|
return "\\{$functionCall[0]}::{$functionCall[1]}";
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnexpectedValueException(
|
||||||
|
'$functionCall is of type ' . gettype($functionCall) . '. string or array expected'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array[] $phpSpreadsheetFunctions
|
||||||
|
*
|
||||||
|
* @throws ReflectionException
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function generateFunctionListByName(array $phpSpreadsheetFunctions): string
|
||||||
|
{
|
||||||
|
$categoryConstants = array_flip(self::getCategories());
|
||||||
|
$result = "# Function list by name\n";
|
||||||
|
$lastAlphabet = null;
|
||||||
|
foreach ($phpSpreadsheetFunctions as $excelFunction => $functionInfo) {
|
||||||
|
$lengths = [20, 31, 42];
|
||||||
|
if ($lastAlphabet !== $excelFunction[0]) {
|
||||||
|
$lastAlphabet = $excelFunction[0];
|
||||||
|
$result .= "\n";
|
||||||
|
$result .= "## {$lastAlphabet}\n";
|
||||||
|
$result .= "\n";
|
||||||
|
$result .= self::tableRow($lengths, ['Excel Function', 'Category', 'PhpSpreadsheet Function']) . "\n";
|
||||||
|
$result .= self::tableRow($lengths, null) . "\n";
|
||||||
|
}
|
||||||
|
$category = $categoryConstants[$functionInfo['category']];
|
||||||
|
$phpFunction = self::getPhpSpreadsheetFunctionText($functionInfo['functionCall']);
|
||||||
|
$result .= self::tableRow($lengths, [$excelFunction, $category, $phpFunction]) . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -52,9 +52,8 @@ abstract class IOFactory
|
|||||||
|
|
||||||
// Instantiate writer
|
// Instantiate writer
|
||||||
$className = self::$writers[$writerType];
|
$className = self::$writers[$writerType];
|
||||||
$writer = new $className($spreadsheet);
|
|
||||||
|
|
||||||
return $writer;
|
return new $className($spreadsheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,9 +73,8 @@ abstract class IOFactory
|
|||||||
|
|
||||||
// Instantiate reader
|
// Instantiate reader
|
||||||
$className = self::$readers[$readerType];
|
$className = self::$readers[$readerType];
|
||||||
$reader = new $className();
|
|
||||||
|
|
||||||
return $reader;
|
return new $className();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -82,7 +82,7 @@ class NamedRange
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return NamedRange
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setName($value)
|
public function setName($value)
|
||||||
{
|
{
|
||||||
@ -123,7 +123,7 @@ class NamedRange
|
|||||||
*
|
*
|
||||||
* @param Worksheet $value
|
* @param Worksheet $value
|
||||||
*
|
*
|
||||||
* @return NamedRange
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setWorksheet(Worksheet $value = null)
|
public function setWorksheet(Worksheet $value = null)
|
||||||
{
|
{
|
||||||
@ -149,7 +149,7 @@ class NamedRange
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return NamedRange
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setRange($value)
|
public function setRange($value)
|
||||||
{
|
{
|
||||||
@ -175,7 +175,7 @@ class NamedRange
|
|||||||
*
|
*
|
||||||
* @param bool $value
|
* @param bool $value
|
||||||
*
|
*
|
||||||
* @return NamedRange
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setLocalOnly($value)
|
public function setLocalOnly($value)
|
||||||
{
|
{
|
||||||
@ -200,7 +200,7 @@ class NamedRange
|
|||||||
*
|
*
|
||||||
* @param null|Worksheet $value
|
* @param null|Worksheet $value
|
||||||
*
|
*
|
||||||
* @return NamedRange
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setScope(Worksheet $value = null)
|
public function setScope(Worksheet $value = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -70,7 +70,7 @@ class Csv extends BaseReader
|
|||||||
*
|
*
|
||||||
* @param string $pValue Input encoding, eg: 'UTF-8'
|
* @param string $pValue Input encoding, eg: 'UTF-8'
|
||||||
*
|
*
|
||||||
* @return Csv
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setInputEncoding($pValue)
|
public function setInputEncoding($pValue)
|
||||||
{
|
{
|
||||||
@ -175,9 +175,8 @@ class Csv extends BaseReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($potentialDelimiters as $delimiter) {
|
foreach ($potentialDelimiters as $delimiter) {
|
||||||
$counts[$delimiter][] = isset($countLine[$delimiter])
|
$counts[$delimiter][] = $countLine[$delimiter]
|
||||||
? $countLine[$delimiter]
|
?? 0;
|
||||||
: 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,7 +415,7 @@ class Csv extends BaseReader
|
|||||||
*
|
*
|
||||||
* @param string $delimiter Delimiter, eg: ','
|
* @param string $delimiter Delimiter, eg: ','
|
||||||
*
|
*
|
||||||
* @return CSV
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setDelimiter($delimiter)
|
public function setDelimiter($delimiter)
|
||||||
{
|
{
|
||||||
@ -440,7 +439,7 @@ class Csv extends BaseReader
|
|||||||
*
|
*
|
||||||
* @param string $enclosure Enclosure, defaults to "
|
* @param string $enclosure Enclosure, defaults to "
|
||||||
*
|
*
|
||||||
* @return CSV
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setEnclosure($enclosure)
|
public function setEnclosure($enclosure)
|
||||||
{
|
{
|
||||||
@ -467,7 +466,7 @@ class Csv extends BaseReader
|
|||||||
*
|
*
|
||||||
* @param int $pValue Sheet index
|
* @param int $pValue Sheet index
|
||||||
*
|
*
|
||||||
* @return CSV
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setSheetIndex($pValue)
|
public function setSheetIndex($pValue)
|
||||||
{
|
{
|
||||||
@ -481,7 +480,7 @@ class Csv extends BaseReader
|
|||||||
*
|
*
|
||||||
* @param bool $contiguous
|
* @param bool $contiguous
|
||||||
*
|
*
|
||||||
* @return Csv
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setContiguous($contiguous)
|
public function setContiguous($contiguous)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -267,7 +267,7 @@ class Gnumeric extends BaseReader
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case 'user-defined':
|
case 'user-defined':
|
||||||
list(, $attrName) = explode(':', $attributes['name']);
|
[, $attrName] = explode(':', $attributes['name']);
|
||||||
switch ($attrName) {
|
switch ($attrName) {
|
||||||
case 'publisher':
|
case 'publisher':
|
||||||
$docProps->setCompany(trim($propertyValue));
|
$docProps->setCompany(trim($propertyValue));
|
||||||
@ -879,7 +879,7 @@ class Gnumeric extends BaseReader
|
|||||||
|
|
||||||
private static function parseGnumericColour($gnmColour)
|
private static function parseGnumericColour($gnmColour)
|
||||||
{
|
{
|
||||||
list($gnmR, $gnmG, $gnmB) = explode(':', $gnmColour);
|
[$gnmR, $gnmG, $gnmB] = explode(':', $gnmColour);
|
||||||
$gnmR = substr(str_pad($gnmR, 4, '0', STR_PAD_RIGHT), 0, 2);
|
$gnmR = substr(str_pad($gnmR, 4, '0', STR_PAD_RIGHT), 0, 2);
|
||||||
$gnmG = substr(str_pad($gnmG, 4, '0', STR_PAD_RIGHT), 0, 2);
|
$gnmG = substr(str_pad($gnmG, 4, '0', STR_PAD_RIGHT), 0, 2);
|
||||||
$gnmB = substr(str_pad($gnmB, 4, '0', STR_PAD_RIGHT), 0, 2);
|
$gnmB = substr(str_pad($gnmB, 4, '0', STR_PAD_RIGHT), 0, 2);
|
||||||
|
|||||||
@ -223,7 +223,7 @@ class Html extends BaseReader
|
|||||||
*
|
*
|
||||||
* @param string $pValue Input encoding, eg: 'ANSI'
|
* @param string $pValue Input encoding, eg: 'ANSI'
|
||||||
*
|
*
|
||||||
* @return Html
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setInputEncoding($pValue)
|
public function setInputEncoding($pValue)
|
||||||
{
|
{
|
||||||
@ -374,8 +374,9 @@ class Html extends BaseReader
|
|||||||
// no break
|
// no break
|
||||||
case 'br':
|
case 'br':
|
||||||
if ($this->tableLevel > 0) {
|
if ($this->tableLevel > 0) {
|
||||||
// If we're inside a table, replace with a \n
|
// If we're inside a table, replace with a \n and set the cell to wrap
|
||||||
$cellContent .= "\n";
|
$cellContent .= "\n";
|
||||||
|
$sheet->getStyle($column . $row)->getAlignment()->setWrapText(true);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise flush our existing content and move the row cursor on
|
// Otherwise flush our existing content and move the row cursor on
|
||||||
$this->flushCell($sheet, $column, $row, $cellContent);
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
||||||
@ -489,22 +490,22 @@ class Html extends BaseReader
|
|||||||
case 'td':
|
case 'td':
|
||||||
$this->processDomElement($child, $sheet, $row, $column, $cellContent);
|
$this->processDomElement($child, $sheet, $row, $column, $cellContent);
|
||||||
|
|
||||||
// apply inline style
|
|
||||||
$this->applyInlineStyle($sheet, $row, $column, $attributeArray);
|
|
||||||
|
|
||||||
while (isset($this->rowspan[$column . $row])) {
|
while (isset($this->rowspan[$column . $row])) {
|
||||||
++$column;
|
++$column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply inline style
|
||||||
|
$this->applyInlineStyle($sheet, $row, $column, $attributeArray);
|
||||||
|
|
||||||
$this->flushCell($sheet, $column, $row, $cellContent);
|
$this->flushCell($sheet, $column, $row, $cellContent);
|
||||||
|
|
||||||
if (isset($attributeArray['rowspan'], $attributeArray['colspan'])) {
|
if (isset($attributeArray['rowspan'], $attributeArray['colspan'])) {
|
||||||
//create merging rowspan and colspan
|
//create merging rowspan and colspan
|
||||||
$columnTo = $column;
|
$columnTo = $column;
|
||||||
for ($i = 0; $i < $attributeArray['colspan'] - 1; ++$i) {
|
for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) {
|
||||||
++$columnTo;
|
++$columnTo;
|
||||||
}
|
}
|
||||||
$range = $column . $row . ':' . $columnTo . ($row + $attributeArray['rowspan'] - 1);
|
$range = $column . $row . ':' . $columnTo . ($row + (int) $attributeArray['rowspan'] - 1);
|
||||||
foreach (Coordinate::extractAllCellReferencesInRange($range) as $value) {
|
foreach (Coordinate::extractAllCellReferencesInRange($range) as $value) {
|
||||||
$this->rowspan[$value] = true;
|
$this->rowspan[$value] = true;
|
||||||
}
|
}
|
||||||
@ -512,7 +513,7 @@ class Html extends BaseReader
|
|||||||
$column = $columnTo;
|
$column = $columnTo;
|
||||||
} elseif (isset($attributeArray['rowspan'])) {
|
} elseif (isset($attributeArray['rowspan'])) {
|
||||||
//create merging rowspan
|
//create merging rowspan
|
||||||
$range = $column . $row . ':' . $column . ($row + $attributeArray['rowspan'] - 1);
|
$range = $column . $row . ':' . $column . ($row + (int) $attributeArray['rowspan'] - 1);
|
||||||
foreach (Coordinate::extractAllCellReferencesInRange($range) as $value) {
|
foreach (Coordinate::extractAllCellReferencesInRange($range) as $value) {
|
||||||
$this->rowspan[$value] = true;
|
$this->rowspan[$value] = true;
|
||||||
}
|
}
|
||||||
@ -520,7 +521,7 @@ class Html extends BaseReader
|
|||||||
} elseif (isset($attributeArray['colspan'])) {
|
} elseif (isset($attributeArray['colspan'])) {
|
||||||
//create merging colspan
|
//create merging colspan
|
||||||
$columnTo = $column;
|
$columnTo = $column;
|
||||||
for ($i = 0; $i < $attributeArray['colspan'] - 1; ++$i) {
|
for ($i = 0; $i < (int) $attributeArray['colspan'] - 1; ++$i) {
|
||||||
++$columnTo;
|
++$columnTo;
|
||||||
}
|
}
|
||||||
$sheet->mergeCells($column . $row . ':' . $columnTo . $row);
|
$sheet->mergeCells($column . $row . ':' . $columnTo . $row);
|
||||||
@ -591,28 +592,63 @@ class Html extends BaseReader
|
|||||||
throw new Exception($pFilename . ' is an Invalid HTML file.');
|
throw new Exception($pFilename . ' is an Invalid HTML file.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new sheet
|
// Create a new DOM object
|
||||||
while ($spreadsheet->getSheetCount() <= $this->sheetIndex) {
|
|
||||||
$spreadsheet->createSheet();
|
|
||||||
}
|
|
||||||
$spreadsheet->setActiveSheetIndex($this->sheetIndex);
|
|
||||||
|
|
||||||
// Create a new DOM object
|
|
||||||
$dom = new DOMDocument();
|
$dom = new DOMDocument();
|
||||||
// Reload the HTML file into the DOM object
|
// Reload the HTML file into the DOM object
|
||||||
$loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scanFile($pFilename), 'HTML-ENTITIES', 'UTF-8'));
|
$loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scanFile($pFilename), 'HTML-ENTITIES', 'UTF-8'));
|
||||||
if ($loaded === false) {
|
if ($loaded === false) {
|
||||||
throw new Exception('Failed to load ' . $pFilename . ' as a DOM Document');
|
throw new Exception('Failed to load ' . $pFilename . ' as a DOM Document');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Discard white space
|
return $this->loadDocument($dom, $spreadsheet);
|
||||||
$dom->preserveWhiteSpace = false;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spreadsheet from content.
|
||||||
|
*
|
||||||
|
* @param string $content
|
||||||
|
* @param null|Spreadsheet $spreadsheet
|
||||||
|
*
|
||||||
|
* @return Spreadsheet
|
||||||
|
*/
|
||||||
|
public function loadFromString($content, ?Spreadsheet $spreadsheet = null): Spreadsheet
|
||||||
|
{
|
||||||
|
// Create a new DOM object
|
||||||
|
$dom = new DOMDocument();
|
||||||
|
// Reload the HTML file into the DOM object
|
||||||
|
$loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanner->scan($content), 'HTML-ENTITIES', 'UTF-8'));
|
||||||
|
if ($loaded === false) {
|
||||||
|
throw new Exception('Failed to load content as a DOM Document');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->loadDocument($dom, $spreadsheet ?? new Spreadsheet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads PhpSpreadsheet from DOMDocument into PhpSpreadsheet instance.
|
||||||
|
*
|
||||||
|
* @param DOMDocument $document
|
||||||
|
* @param Spreadsheet $spreadsheet
|
||||||
|
*
|
||||||
|
* @throws \PhpOffice\PhpSpreadsheet\Exception
|
||||||
|
*
|
||||||
|
* @return Spreadsheet
|
||||||
|
*/
|
||||||
|
private function loadDocument(DOMDocument $document, Spreadsheet $spreadsheet): Spreadsheet
|
||||||
|
{
|
||||||
|
while ($spreadsheet->getSheetCount() <= $this->sheetIndex) {
|
||||||
|
$spreadsheet->createSheet();
|
||||||
|
}
|
||||||
|
$spreadsheet->setActiveSheetIndex($this->sheetIndex);
|
||||||
|
|
||||||
|
// Discard white space
|
||||||
|
$document->preserveWhiteSpace = false;
|
||||||
|
|
||||||
$row = 0;
|
$row = 0;
|
||||||
$column = 'A';
|
$column = 'A';
|
||||||
$content = '';
|
$content = '';
|
||||||
$this->rowspan = [];
|
$this->rowspan = [];
|
||||||
$this->processDomElement($dom, $spreadsheet->getActiveSheet(), $row, $column, $content);
|
$this->processDomElement($document, $spreadsheet->getActiveSheet(), $row, $column, $content);
|
||||||
|
|
||||||
// Return
|
// Return
|
||||||
return $spreadsheet;
|
return $spreadsheet;
|
||||||
@ -633,7 +669,7 @@ class Html extends BaseReader
|
|||||||
*
|
*
|
||||||
* @param int $pValue Sheet index
|
* @param int $pValue Sheet index
|
||||||
*
|
*
|
||||||
* @return HTML
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setSheetIndex($pValue)
|
public function setSheetIndex($pValue)
|
||||||
{
|
{
|
||||||
@ -919,7 +955,7 @@ class Html extends BaseReader
|
|||||||
*/
|
*/
|
||||||
private function setBorderStyle(Style $cellStyle, $styleValue, $type)
|
private function setBorderStyle(Style $cellStyle, $styleValue, $type)
|
||||||
{
|
{
|
||||||
list(, $borderStyle, $color) = explode(' ', $styleValue);
|
[, $borderStyle, $color] = explode(' ', $styleValue);
|
||||||
|
|
||||||
$cellStyle->applyFromArray([
|
$cellStyle->applyFromArray([
|
||||||
'borders' => [
|
'borders' => [
|
||||||
|
|||||||
@ -490,7 +490,7 @@ class Ods extends BaseReader
|
|||||||
|
|
||||||
$dateObj = new DateTime($value, $GMT);
|
$dateObj = new DateTime($value, $GMT);
|
||||||
$dateObj->setTimeZone($timezoneObj);
|
$dateObj->setTimeZone($timezoneObj);
|
||||||
list($year, $month, $day, $hour, $minute, $second) = explode(
|
[$year, $month, $day, $hour, $minute, $second] = explode(
|
||||||
' ',
|
' ',
|
||||||
$dateObj->format('Y m d H i s')
|
$dateObj->format('Y m d H i s')
|
||||||
);
|
);
|
||||||
|
|||||||
@ -19,12 +19,11 @@ class Properties
|
|||||||
$docProps = $this->spreadsheet->getProperties();
|
$docProps = $this->spreadsheet->getProperties();
|
||||||
$officeProperty = $xml->children($namespacesMeta['office']);
|
$officeProperty = $xml->children($namespacesMeta['office']);
|
||||||
foreach ($officeProperty as $officePropertyData) {
|
foreach ($officeProperty as $officePropertyData) {
|
||||||
/** @var \SimpleXMLElement $officePropertyData */
|
// @var \SimpleXMLElement $officePropertyData
|
||||||
$officePropertiesDC = (object) [];
|
|
||||||
if (isset($namespacesMeta['dc'])) {
|
if (isset($namespacesMeta['dc'])) {
|
||||||
$officePropertiesDC = $officePropertyData->children($namespacesMeta['dc']);
|
$officePropertiesDC = $officePropertyData->children($namespacesMeta['dc']);
|
||||||
|
$this->setCoreProperties($docProps, $officePropertiesDC);
|
||||||
}
|
}
|
||||||
$this->setCoreProperties($docProps, $officePropertiesDC);
|
|
||||||
|
|
||||||
$officePropertyMeta = (object) [];
|
$officePropertyMeta = (object) [];
|
||||||
if (isset($namespacesMeta['dc'])) {
|
if (isset($namespacesMeta['dc'])) {
|
||||||
|
|||||||
@ -83,7 +83,7 @@ class Slk extends BaseReader
|
|||||||
*
|
*
|
||||||
* @param string $pValue Input encoding, eg: 'ANSI'
|
* @param string $pValue Input encoding, eg: 'ANSI'
|
||||||
*
|
*
|
||||||
* @return Slk
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setInputEncoding($pValue)
|
public function setInputEncoding($pValue)
|
||||||
{
|
{
|
||||||
@ -384,7 +384,7 @@ class Slk extends BaseReader
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case 'W':
|
case 'W':
|
||||||
list($startCol, $endCol, $columnWidth) = explode(' ', substr($rowDatum, 1));
|
[$startCol, $endCol, $columnWidth] = explode(' ', substr($rowDatum, 1));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
@ -485,7 +485,7 @@ class Slk extends BaseReader
|
|||||||
*
|
*
|
||||||
* @param int $pValue Sheet index
|
* @param int $pValue Sheet index
|
||||||
*
|
*
|
||||||
* @return Slk
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setSheetIndex($pValue)
|
public function setSheetIndex($pValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1089,8 +1089,8 @@ class Xls extends BaseReader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// calculate the width and height of the shape
|
// calculate the width and height of the shape
|
||||||
list($startColumn, $startRow) = Coordinate::coordinateFromString($spContainer->getStartCoordinates());
|
[$startColumn, $startRow] = Coordinate::coordinateFromString($spContainer->getStartCoordinates());
|
||||||
list($endColumn, $endRow) = Coordinate::coordinateFromString($spContainer->getEndCoordinates());
|
[$endColumn, $endRow] = Coordinate::coordinateFromString($spContainer->getEndCoordinates());
|
||||||
|
|
||||||
$startOffsetX = $spContainer->getStartOffsetX();
|
$startOffsetX = $spContainer->getStartOffsetX();
|
||||||
$startOffsetY = $spContainer->getStartOffsetY();
|
$startOffsetY = $spContainer->getStartOffsetY();
|
||||||
@ -1175,7 +1175,7 @@ class Xls extends BaseReader
|
|||||||
// treat SHAREDFMLA records
|
// treat SHAREDFMLA records
|
||||||
if ($this->version == self::XLS_BIFF8) {
|
if ($this->version == self::XLS_BIFF8) {
|
||||||
foreach ($this->sharedFormulaParts as $cell => $baseCell) {
|
foreach ($this->sharedFormulaParts as $cell => $baseCell) {
|
||||||
list($column, $row) = Coordinate::coordinateFromString($cell);
|
[$column, $row] = Coordinate::coordinateFromString($cell);
|
||||||
if (($this->getReadFilter() !== null) && $this->getReadFilter()->readCell($column, $row, $this->phpSheet->getTitle())) {
|
if (($this->getReadFilter() !== null) && $this->getReadFilter()->readCell($column, $row, $this->phpSheet->getTitle())) {
|
||||||
$formula = $this->getFormulaFromStructure($this->sharedFormulas[$baseCell], $cell);
|
$formula = $this->getFormulaFromStructure($this->sharedFormulas[$baseCell], $cell);
|
||||||
$this->phpSheet->getCell($cell)->setValueExplicit('=' . $formula, DataType::TYPE_FORMULA);
|
$this->phpSheet->getCell($cell)->setValueExplicit('=' . $formula, DataType::TYPE_FORMULA);
|
||||||
@ -1251,8 +1251,8 @@ class Xls extends BaseReader
|
|||||||
|
|
||||||
$coordinateStrings = explode(':', $extractedRange);
|
$coordinateStrings = explode(':', $extractedRange);
|
||||||
if (count($coordinateStrings) == 2) {
|
if (count($coordinateStrings) == 2) {
|
||||||
list($firstColumn, $firstRow) = Coordinate::coordinateFromString($coordinateStrings[0]);
|
[$firstColumn, $firstRow] = Coordinate::coordinateFromString($coordinateStrings[0]);
|
||||||
list($lastColumn, $lastRow) = Coordinate::coordinateFromString($coordinateStrings[1]);
|
[$lastColumn, $lastRow] = Coordinate::coordinateFromString($coordinateStrings[1]);
|
||||||
|
|
||||||
if ($firstColumn == 'A' and $lastColumn == 'IV') {
|
if ($firstColumn == 'A' and $lastColumn == 'IV') {
|
||||||
// then we have repeating rows
|
// then we have repeating rows
|
||||||
@ -3825,7 +3825,7 @@ class Xls extends BaseReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->readDataOnly && !$emptyCell) {
|
if (!$this->readDataOnly && !$emptyCell && isset($this->mapCellXfIndex[$xfIndex])) {
|
||||||
// add style information
|
// add style information
|
||||||
$cell->setXfIndex($this->mapCellXfIndex[$xfIndex]);
|
$cell->setXfIndex($this->mapCellXfIndex[$xfIndex]);
|
||||||
}
|
}
|
||||||
@ -5279,12 +5279,10 @@ class Xls extends BaseReader
|
|||||||
$nextIdentifier = self::getUInt2d($this->data, $this->pos);
|
$nextIdentifier = self::getUInt2d($this->data, $this->pos);
|
||||||
} while ($nextIdentifier == self::XLS_TYPE_CONTINUE);
|
} while ($nextIdentifier == self::XLS_TYPE_CONTINUE);
|
||||||
|
|
||||||
$splicedData = [
|
return [
|
||||||
'recordData' => $data,
|
'recordData' => $data,
|
||||||
'spliceOffsets' => $spliceOffsets,
|
'spliceOffsets' => $spliceOffsets,
|
||||||
];
|
];
|
||||||
|
|
||||||
return $splicedData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -5355,12 +5353,12 @@ class Xls extends BaseReader
|
|||||||
$formulaStrings = [];
|
$formulaStrings = [];
|
||||||
foreach ($tokens as $token) {
|
foreach ($tokens as $token) {
|
||||||
// initialize spaces
|
// initialize spaces
|
||||||
$space0 = isset($space0) ? $space0 : ''; // spaces before next token, not tParen
|
$space0 = $space0 ?? ''; // spaces before next token, not tParen
|
||||||
$space1 = isset($space1) ? $space1 : ''; // carriage returns before next token, not tParen
|
$space1 = $space1 ?? ''; // carriage returns before next token, not tParen
|
||||||
$space2 = isset($space2) ? $space2 : ''; // spaces before opening parenthesis
|
$space2 = $space2 ?? ''; // spaces before opening parenthesis
|
||||||
$space3 = isset($space3) ? $space3 : ''; // carriage returns before opening parenthesis
|
$space3 = $space3 ?? ''; // carriage returns before opening parenthesis
|
||||||
$space4 = isset($space4) ? $space4 : ''; // spaces before closing parenthesis
|
$space4 = $space4 ?? ''; // spaces before closing parenthesis
|
||||||
$space5 = isset($space5) ? $space5 : ''; // carriage returns before closing parenthesis
|
$space5 = $space5 ?? ''; // carriage returns before closing parenthesis
|
||||||
|
|
||||||
switch ($token['name']) {
|
switch ($token['name']) {
|
||||||
case 'tAdd': // addition
|
case 'tAdd': // addition
|
||||||
@ -7145,7 +7143,7 @@ class Xls extends BaseReader
|
|||||||
*/
|
*/
|
||||||
private function readBIFF8CellAddressB($cellAddressStructure, $baseCell = 'A1')
|
private function readBIFF8CellAddressB($cellAddressStructure, $baseCell = 'A1')
|
||||||
{
|
{
|
||||||
list($baseCol, $baseRow) = Coordinate::coordinateFromString($baseCell);
|
[$baseCol, $baseRow] = Coordinate::coordinateFromString($baseCell);
|
||||||
$baseCol = Coordinate::columnIndexFromString($baseCol) - 1;
|
$baseCol = Coordinate::columnIndexFromString($baseCol) - 1;
|
||||||
|
|
||||||
// offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
|
// offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
|
||||||
@ -7328,7 +7326,7 @@ class Xls extends BaseReader
|
|||||||
*/
|
*/
|
||||||
private function readBIFF8CellRangeAddressB($subData, $baseCell = 'A1')
|
private function readBIFF8CellRangeAddressB($subData, $baseCell = 'A1')
|
||||||
{
|
{
|
||||||
list($baseCol, $baseRow) = Coordinate::coordinateFromString($baseCell);
|
[$baseCol, $baseRow] = Coordinate::coordinateFromString($baseCell);
|
||||||
$baseCol = Coordinate::columnIndexFromString($baseCol) - 1;
|
$baseCol = Coordinate::columnIndexFromString($baseCol) - 1;
|
||||||
|
|
||||||
// TODO: if cell range is just a single cell, should this funciton
|
// TODO: if cell range is just a single cell, should this funciton
|
||||||
|
|||||||
@ -77,34 +77,17 @@ class Xlsx extends BaseReader
|
|||||||
{
|
{
|
||||||
File::assertFile($pFilename);
|
File::assertFile($pFilename);
|
||||||
|
|
||||||
$xl = false;
|
$result = false;
|
||||||
// Load file
|
|
||||||
$zip = new ZipArchive();
|
$zip = new ZipArchive();
|
||||||
if ($zip->open($pFilename) === true) {
|
|
||||||
// check if it is an OOXML archive
|
|
||||||
$rels = simplexml_load_string(
|
|
||||||
$this->securityScanner->scan(
|
|
||||||
$this->getFromZipArchive($zip, '_rels/.rels')
|
|
||||||
),
|
|
||||||
'SimpleXMLElement',
|
|
||||||
Settings::getLibXmlLoaderOptions()
|
|
||||||
);
|
|
||||||
if ($rels !== false) {
|
|
||||||
foreach ($rels->Relationship as $rel) {
|
|
||||||
switch ($rel['Type']) {
|
|
||||||
case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
|
|
||||||
if (basename($rel['Target']) == 'workbook.xml') {
|
|
||||||
$xl = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
if ($zip->open($pFilename) === true) {
|
||||||
}
|
$workbookBasename = $this->getWorkbookBaseName($zip);
|
||||||
}
|
$result = !empty($workbookBasename);
|
||||||
}
|
|
||||||
$zip->close();
|
$zip->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $xl;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -357,8 +340,9 @@ class Xlsx extends BaseReader
|
|||||||
|
|
||||||
// Read the theme first, because we need the colour scheme when reading the styles
|
// Read the theme first, because we need the colour scheme when reading the styles
|
||||||
//~ http://schemas.openxmlformats.org/package/2006/relationships"
|
//~ http://schemas.openxmlformats.org/package/2006/relationships"
|
||||||
|
$workbookBasename = $this->getWorkbookBaseName($zip);
|
||||||
$wbRels = simplexml_load_string(
|
$wbRels = simplexml_load_string(
|
||||||
$this->securityScanner->scan($this->getFromZipArchive($zip, 'xl/_rels/workbook.xml.rels')),
|
$this->securityScanner->scan($this->getFromZipArchive($zip, "xl/_rels/${workbookBasename}.rels")),
|
||||||
'SimpleXMLElement',
|
'SimpleXMLElement',
|
||||||
Settings::getLibXmlLoaderOptions()
|
Settings::getLibXmlLoaderOptions()
|
||||||
);
|
);
|
||||||
@ -445,18 +429,20 @@ class Xlsx extends BaseReader
|
|||||||
|
|
||||||
$sharedStrings = [];
|
$sharedStrings = [];
|
||||||
$xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings']"));
|
$xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings']"));
|
||||||
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
if ($xpath) {
|
||||||
$xmlStrings = simplexml_load_string(
|
//~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
||||||
$this->securityScanner->scan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
|
$xmlStrings = simplexml_load_string(
|
||||||
'SimpleXMLElement',
|
$this->securityScanner->scan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
|
||||||
Settings::getLibXmlLoaderOptions()
|
'SimpleXMLElement',
|
||||||
);
|
Settings::getLibXmlLoaderOptions()
|
||||||
if (isset($xmlStrings, $xmlStrings->si)) {
|
);
|
||||||
foreach ($xmlStrings->si as $val) {
|
if (isset($xmlStrings, $xmlStrings->si)) {
|
||||||
if (isset($val->t)) {
|
foreach ($xmlStrings->si as $val) {
|
||||||
$sharedStrings[] = StringHelper::controlCharacterOOXML2PHP((string) $val->t);
|
if (isset($val->t)) {
|
||||||
} elseif (isset($val->r)) {
|
$sharedStrings[] = StringHelper::controlCharacterOOXML2PHP((string) $val->t);
|
||||||
$sharedStrings[] = $this->parseRichText($val);
|
} elseif (isset($val->r)) {
|
||||||
|
$sharedStrings[] = $this->parseRichText($val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -743,15 +729,6 @@ class Xlsx extends BaseReader
|
|||||||
|
|
||||||
// read empty cells or the cells are not empty
|
// read empty cells or the cells are not empty
|
||||||
if ($this->readEmptyCells || ($value !== null && $value !== '')) {
|
if ($this->readEmptyCells || ($value !== null && $value !== '')) {
|
||||||
// Check for numeric values
|
|
||||||
if (is_numeric($value) && $cellDataType != 's') {
|
|
||||||
if ($value == (int) $value) {
|
|
||||||
$value = (int) $value;
|
|
||||||
} elseif ($value == (float) $value) {
|
|
||||||
$value = (float) $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rich text?
|
// Rich text?
|
||||||
if ($value instanceof RichText && $this->readDataOnly) {
|
if ($value instanceof RichText && $this->readDataOnly) {
|
||||||
$value = $value->getPlainText();
|
$value = $value->getPlainText();
|
||||||
@ -1352,7 +1329,7 @@ class Xlsx extends BaseReader
|
|||||||
$rangeSets = preg_split("/('?(?:.*?)'?(?:![A-Z0-9]+:[A-Z0-9]+)),?/", $extractedRange, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
|
$rangeSets = preg_split("/('?(?:.*?)'?(?:![A-Z0-9]+:[A-Z0-9]+)),?/", $extractedRange, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
|
||||||
$newRangeSets = [];
|
$newRangeSets = [];
|
||||||
foreach ($rangeSets as $rangeSet) {
|
foreach ($rangeSets as $rangeSet) {
|
||||||
list($sheetName, $rangeSet) = Worksheet::extractSheetTitle($rangeSet, true);
|
[$sheetName, $rangeSet] = Worksheet::extractSheetTitle($rangeSet, true);
|
||||||
if (strpos($rangeSet, ':') === false) {
|
if (strpos($rangeSet, ':') === false) {
|
||||||
$rangeSet = $rangeSet . ':' . $rangeSet;
|
$rangeSet = $rangeSet . ':' . $rangeSet;
|
||||||
}
|
}
|
||||||
@ -1426,7 +1403,7 @@ class Xlsx extends BaseReader
|
|||||||
$locatedSheet = $excel->getSheetByName($extractedSheetName);
|
$locatedSheet = $excel->getSheetByName($extractedSheetName);
|
||||||
|
|
||||||
// Modify range
|
// Modify range
|
||||||
list($worksheetName, $extractedRange) = Worksheet::extractSheetTitle($extractedRange, true);
|
[$worksheetName, $extractedRange] = Worksheet::extractSheetTitle($extractedRange, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($locatedSheet !== null) {
|
if ($locatedSheet !== null) {
|
||||||
@ -1437,7 +1414,7 @@ class Xlsx extends BaseReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!$this->readDataOnly) || (!empty($this->loadSheetsOnly))) {
|
if ((!$this->readDataOnly || !empty($this->loadSheetsOnly)) && isset($xmlWorkbook->bookViews->workbookView)) {
|
||||||
$workbookView = $xmlWorkbook->bookViews->workbookView;
|
$workbookView = $xmlWorkbook->bookViews->workbookView;
|
||||||
|
|
||||||
// active sheet index
|
// active sheet index
|
||||||
@ -1643,8 +1620,6 @@ class Xlsx extends BaseReader
|
|||||||
$docStyle->getFill()->setFillType($patternType);
|
$docStyle->getFill()->setFillType($patternType);
|
||||||
if ($style->fill->patternFill->fgColor) {
|
if ($style->fill->patternFill->fgColor) {
|
||||||
$docStyle->getFill()->getStartColor()->setARGB(self::readColor($style->fill->patternFill->fgColor, true));
|
$docStyle->getFill()->getStartColor()->setARGB(self::readColor($style->fill->patternFill->fgColor, true));
|
||||||
} else {
|
|
||||||
$docStyle->getFill()->getStartColor()->setARGB('FF000000');
|
|
||||||
}
|
}
|
||||||
if ($style->fill->patternFill->bgColor) {
|
if ($style->fill->patternFill->bgColor) {
|
||||||
$docStyle->getFill()->getEndColor()->setARGB(self::readColor($style->fill->patternFill->bgColor, true));
|
$docStyle->getFill()->getEndColor()->setARGB(self::readColor($style->fill->patternFill->bgColor, true));
|
||||||
@ -1841,7 +1816,7 @@ class Xlsx extends BaseReader
|
|||||||
|
|
||||||
private static function getArrayItem($array, $key = 0)
|
private static function getArrayItem($array, $key = 0)
|
||||||
{
|
{
|
||||||
return isset($array[$key]) ? $array[$key] : null;
|
return $array[$key] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function dirAdd($base, $add)
|
private static function dirAdd($base, $add)
|
||||||
@ -1851,7 +1826,7 @@ class Xlsx extends BaseReader
|
|||||||
|
|
||||||
private static function toCSSArray($style)
|
private static function toCSSArray($style)
|
||||||
{
|
{
|
||||||
$style = trim(str_replace(["\r", "\n"], '', $style), ';');
|
$style = self::stripWhiteSpaceFromStyleString($style);
|
||||||
|
|
||||||
$temp = explode(';', $style);
|
$temp = explode(';', $style);
|
||||||
$style = [];
|
$style = [];
|
||||||
@ -1880,6 +1855,11 @@ class Xlsx extends BaseReader
|
|||||||
return $style;
|
return $style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function stripWhiteSpaceFromStyleString($string)
|
||||||
|
{
|
||||||
|
return trim(str_replace(["\r", "\n", ' '], '', $string), ';');
|
||||||
|
}
|
||||||
|
|
||||||
private static function boolean($value)
|
private static function boolean($value)
|
||||||
{
|
{
|
||||||
if (is_object($value)) {
|
if (is_object($value)) {
|
||||||
@ -2026,4 +2006,38 @@ class Xlsx extends BaseReader
|
|||||||
|
|
||||||
return (bool) $xsdBoolean;
|
return (bool) $xsdBoolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ZipArchive $zip Opened zip archive
|
||||||
|
*
|
||||||
|
* @return string basename of the used excel workbook
|
||||||
|
*/
|
||||||
|
private function getWorkbookBaseName(ZipArchive $zip)
|
||||||
|
{
|
||||||
|
$workbookBasename = '';
|
||||||
|
|
||||||
|
// check if it is an OOXML archive
|
||||||
|
$rels = simplexml_load_string(
|
||||||
|
$this->securityScanner->scan(
|
||||||
|
$this->getFromZipArchive($zip, '_rels/.rels')
|
||||||
|
),
|
||||||
|
'SimpleXMLElement',
|
||||||
|
Settings::getLibXmlLoaderOptions()
|
||||||
|
);
|
||||||
|
if ($rels !== false) {
|
||||||
|
foreach ($rels->Relationship as $rel) {
|
||||||
|
switch ($rel['Type']) {
|
||||||
|
case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument':
|
||||||
|
$basename = basename($rel['Target']);
|
||||||
|
if (preg_match('/workbook.*\.xml/', $basename)) {
|
||||||
|
$workbookBasename = $basename;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $workbookBasename;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,8 @@ class AutoFilter
|
|||||||
|
|
||||||
public function load()
|
public function load()
|
||||||
{
|
{
|
||||||
$autoFilterRange = (string) $this->worksheetXml->autoFilter['ref'];
|
// Remove all "$" in the auto filter range
|
||||||
|
$autoFilterRange = preg_replace('/\$/', '', $this->worksheetXml->autoFilter['ref']);
|
||||||
if (strpos($autoFilterRange, ':') !== false) {
|
if (strpos($autoFilterRange, ':') !== false) {
|
||||||
$this->readAutoFilter($autoFilterRange, $this->worksheetXml);
|
$this->readAutoFilter($autoFilterRange, $this->worksheetXml);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,8 @@ class ConditionalStyles
|
|||||||
if (((string) $cfRule['type'] == Conditional::CONDITION_NONE
|
if (((string) $cfRule['type'] == Conditional::CONDITION_NONE
|
||||||
|| (string) $cfRule['type'] == Conditional::CONDITION_CELLIS
|
|| (string) $cfRule['type'] == Conditional::CONDITION_CELLIS
|
||||||
|| (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSTEXT
|
|| (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSTEXT
|
||||||
|
|| (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSBLANKS
|
||||||
|
|| (string) $cfRule['type'] == Conditional::CONDITION_NOTCONTAINSBLANKS
|
||||||
|| (string) $cfRule['type'] == Conditional::CONDITION_EXPRESSION)
|
|| (string) $cfRule['type'] == Conditional::CONDITION_EXPRESSION)
|
||||||
&& isset($this->dxfs[(int) ($cfRule['dxfId'])])) {
|
&& isset($this->dxfs[(int) ($cfRule['dxfId'])])) {
|
||||||
$conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;
|
$conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule;
|
||||||
|
|||||||
@ -86,6 +86,6 @@ class Properties
|
|||||||
|
|
||||||
private static function getArrayItem(array $array, $key = 0)
|
private static function getArrayItem(array $array, $key = 0)
|
||||||
{
|
{
|
||||||
return isset($array[$key]) ? $array[$key] : null;
|
return $array[$key] ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,7 @@ class SheetViews extends BaseParserClass
|
|||||||
$this->gridLines();
|
$this->gridLines();
|
||||||
$this->headers();
|
$this->headers();
|
||||||
$this->direction();
|
$this->direction();
|
||||||
|
$this->showZeros();
|
||||||
|
|
||||||
if (isset($this->sheetViewXml->pane)) {
|
if (isset($this->sheetViewXml->pane)) {
|
||||||
$this->pane();
|
$this->pane();
|
||||||
@ -92,6 +93,15 @@ class SheetViews extends BaseParserClass
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function showZeros()
|
||||||
|
{
|
||||||
|
if (isset($this->sheetViewXml['showZeros'])) {
|
||||||
|
$this->worksheet->getSheetView()->setShowZeros(
|
||||||
|
self::boolean((string) $this->sheetViewXml['showZeros'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function pane()
|
private function pane()
|
||||||
{
|
{
|
||||||
$xSplit = 0;
|
$xSplit = 0;
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use PhpOffice\PhpSpreadsheet\Style\Borders;
|
|||||||
use PhpOffice\PhpSpreadsheet\Style\Color;
|
use PhpOffice\PhpSpreadsheet\Style\Color;
|
||||||
use PhpOffice\PhpSpreadsheet\Style\Fill;
|
use PhpOffice\PhpSpreadsheet\Style\Fill;
|
||||||
use PhpOffice\PhpSpreadsheet\Style\Font;
|
use PhpOffice\PhpSpreadsheet\Style\Font;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
||||||
use PhpOffice\PhpSpreadsheet\Style\Protection;
|
use PhpOffice\PhpSpreadsheet\Style\Protection;
|
||||||
use PhpOffice\PhpSpreadsheet\Style\Style;
|
use PhpOffice\PhpSpreadsheet\Style\Style;
|
||||||
|
|
||||||
@ -71,6 +72,17 @@ class Styles extends BaseParserClass
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function readNumberFormat(NumberFormat $numfmtStyle, \SimpleXMLElement $numfmtStyleXml)
|
||||||
|
{
|
||||||
|
if ($numfmtStyleXml->count() === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$numfmt = $numfmtStyleXml->attributes();
|
||||||
|
if ($numfmt->count() > 0 && isset($numfmt['formatCode'])) {
|
||||||
|
$numfmtStyle->setFormatCode((string) $numfmt['formatCode']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static function readFillStyle(Fill $fillStyle, \SimpleXMLElement $fillStyleXml)
|
private static function readFillStyle(Fill $fillStyle, \SimpleXMLElement $fillStyleXml)
|
||||||
{
|
{
|
||||||
if ($fillStyleXml->gradientFill) {
|
if ($fillStyleXml->gradientFill) {
|
||||||
@ -149,7 +161,11 @@ class Styles extends BaseParserClass
|
|||||||
|
|
||||||
private function readStyle(Style $docStyle, $style)
|
private function readStyle(Style $docStyle, $style)
|
||||||
{
|
{
|
||||||
$docStyle->getNumberFormat()->setFormatCode($style->numFmt);
|
if ($style->numFmt instanceof \SimpleXMLElement) {
|
||||||
|
self::readNumberFormat($docStyle->getNumberFormat(), $style->numFmt);
|
||||||
|
} else {
|
||||||
|
$docStyle->getNumberFormat()->setFormatCode($style->numFmt);
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($style->font)) {
|
if (isset($style->font)) {
|
||||||
self::readFontStyle($docStyle->getFont(), $style->font);
|
self::readFontStyle($docStyle->getFont(), $style->font);
|
||||||
@ -163,7 +179,7 @@ class Styles extends BaseParserClass
|
|||||||
self::readBorderStyle($docStyle->getBorders(), $style->border);
|
self::readBorderStyle($docStyle->getBorders(), $style->border);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($style->alignment)) {
|
if (isset($style->alignment->alignment)) {
|
||||||
self::readAlignmentStyle($docStyle->getAlignment(), $style->alignment);
|
self::readAlignmentStyle($docStyle->getAlignment(), $style->alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,6 +276,6 @@ class Styles extends BaseParserClass
|
|||||||
|
|
||||||
private static function getArrayItem($array, $key = 0)
|
private static function getArrayItem($array, $key = 0)
|
||||||
{
|
{
|
||||||
return isset($array[$key]) ? $array[$key] : null;
|
return $array[$key] ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -285,9 +285,8 @@ class Xml extends BaseReader
|
|||||||
{
|
{
|
||||||
$pixels = ($widthUnits / 256) * 7;
|
$pixels = ($widthUnits / 256) * 7;
|
||||||
$offsetWidthUnits = $widthUnits % 256;
|
$offsetWidthUnits = $widthUnits % 256;
|
||||||
$pixels += round($offsetWidthUnits / (256 / 7));
|
|
||||||
|
|
||||||
return $pixels;
|
return $pixels + round($offsetWidthUnits / (256 / 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function hex2str($hex)
|
protected static function hex2str($hex)
|
||||||
|
|||||||
@ -82,11 +82,8 @@ class ReferenceHelper
|
|||||||
*/
|
*/
|
||||||
public static function cellSort($a, $b)
|
public static function cellSort($a, $b)
|
||||||
{
|
{
|
||||||
// TODO Scrutinizer doesn't like sscanf($a, '%[A-Z]%d', $ac, $ar), and we can't use short list() syntax
|
[$ac, $ar] = sscanf($a, '%[A-Z]%d');
|
||||||
// [$ac, $ar] = sscanf($a, '%[A-Z]%d') while retaining PHP 5.6 support.
|
[$bc, $br] = sscanf($b, '%[A-Z]%d');
|
||||||
// Switch when we drop support for 5.6
|
|
||||||
list($ac, $ar) = sscanf($a, '%[A-Z]%d');
|
|
||||||
list($bc, $br) = sscanf($b, '%[A-Z]%d');
|
|
||||||
|
|
||||||
if ($ar === $br) {
|
if ($ar === $br) {
|
||||||
return strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc);
|
return strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc);
|
||||||
@ -106,11 +103,8 @@ class ReferenceHelper
|
|||||||
*/
|
*/
|
||||||
public static function cellReverseSort($a, $b)
|
public static function cellReverseSort($a, $b)
|
||||||
{
|
{
|
||||||
// TODO Scrutinizer doesn't like sscanf($a, '%[A-Z]%d', $ac, $ar), and we can't use short list() syntax
|
[$ac, $ar] = sscanf($a, '%[A-Z]%d');
|
||||||
// [$ac, $ar] = sscanf($a, '%[A-Z]%d') while retaining PHP 5.6 support.
|
[$bc, $br] = sscanf($b, '%[A-Z]%d');
|
||||||
// Switch when we drop support for 5.6
|
|
||||||
list($ac, $ar) = sscanf($a, '%[A-Z]%d');
|
|
||||||
list($bc, $br) = sscanf($b, '%[A-Z]%d');
|
|
||||||
|
|
||||||
if ($ar === $br) {
|
if ($ar === $br) {
|
||||||
return 1 - strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc);
|
return 1 - strcasecmp(strlen($ac) . $ac, strlen($bc) . $bc);
|
||||||
@ -132,7 +126,7 @@ class ReferenceHelper
|
|||||||
*/
|
*/
|
||||||
private static function cellAddressInDeleteRange($cellAddress, $beforeRow, $pNumRows, $beforeColumnIndex, $pNumCols)
|
private static function cellAddressInDeleteRange($cellAddress, $beforeRow, $pNumRows, $beforeColumnIndex, $pNumCols)
|
||||||
{
|
{
|
||||||
list($cellColumn, $cellRow) = Coordinate::coordinateFromString($cellAddress);
|
[$cellColumn, $cellRow] = Coordinate::coordinateFromString($cellAddress);
|
||||||
$cellColumnIndex = Coordinate::columnIndexFromString($cellColumn);
|
$cellColumnIndex = Coordinate::columnIndexFromString($cellColumn);
|
||||||
// Is cell within the range of rows/columns if we're deleting
|
// Is cell within the range of rows/columns if we're deleting
|
||||||
if ($pNumRows < 0 &&
|
if ($pNumRows < 0 &&
|
||||||
@ -319,7 +313,7 @@ class ReferenceHelper
|
|||||||
if (!empty($aColumnDimensions)) {
|
if (!empty($aColumnDimensions)) {
|
||||||
foreach ($aColumnDimensions as $objColumnDimension) {
|
foreach ($aColumnDimensions as $objColumnDimension) {
|
||||||
$newReference = $this->updateCellReference($objColumnDimension->getColumnIndex() . '1', $pBefore, $pNumCols, $pNumRows);
|
$newReference = $this->updateCellReference($objColumnDimension->getColumnIndex() . '1', $pBefore, $pNumCols, $pNumRows);
|
||||||
list($newReference) = Coordinate::coordinateFromString($newReference);
|
[$newReference] = Coordinate::coordinateFromString($newReference);
|
||||||
if ($objColumnDimension->getColumnIndex() != $newReference) {
|
if ($objColumnDimension->getColumnIndex() != $newReference) {
|
||||||
$objColumnDimension->setColumnIndex($newReference);
|
$objColumnDimension->setColumnIndex($newReference);
|
||||||
}
|
}
|
||||||
@ -344,7 +338,7 @@ class ReferenceHelper
|
|||||||
if (!empty($aRowDimensions)) {
|
if (!empty($aRowDimensions)) {
|
||||||
foreach ($aRowDimensions as $objRowDimension) {
|
foreach ($aRowDimensions as $objRowDimension) {
|
||||||
$newReference = $this->updateCellReference('A' . $objRowDimension->getRowIndex(), $pBefore, $pNumCols, $pNumRows);
|
$newReference = $this->updateCellReference('A' . $objRowDimension->getRowIndex(), $pBefore, $pNumCols, $pNumRows);
|
||||||
list(, $newReference) = Coordinate::coordinateFromString($newReference);
|
[, $newReference] = Coordinate::coordinateFromString($newReference);
|
||||||
if ($objRowDimension->getRowIndex() != $newReference) {
|
if ($objRowDimension->getRowIndex() != $newReference) {
|
||||||
$objRowDimension->setRowIndex($newReference);
|
$objRowDimension->setRowIndex($newReference);
|
||||||
}
|
}
|
||||||
@ -378,7 +372,7 @@ class ReferenceHelper
|
|||||||
$allCoordinates = $pSheet->getCoordinates();
|
$allCoordinates = $pSheet->getCoordinates();
|
||||||
|
|
||||||
// Get coordinate of $pBefore
|
// Get coordinate of $pBefore
|
||||||
list($beforeColumn, $beforeRow) = Coordinate::coordinateFromString($pBefore);
|
[$beforeColumn, $beforeRow] = Coordinate::coordinateFromString($pBefore);
|
||||||
$beforeColumnIndex = Coordinate::columnIndexFromString($beforeColumn);
|
$beforeColumnIndex = Coordinate::columnIndexFromString($beforeColumn);
|
||||||
|
|
||||||
// Clear cells if we are removing columns or rows
|
// Clear cells if we are removing columns or rows
|
||||||
@ -539,7 +533,7 @@ class ReferenceHelper
|
|||||||
$row = 0;
|
$row = 0;
|
||||||
sscanf($pBefore, '%[A-Z]%d', $column, $row);
|
sscanf($pBefore, '%[A-Z]%d', $column, $row);
|
||||||
$columnIndex = Coordinate::columnIndexFromString($column);
|
$columnIndex = Coordinate::columnIndexFromString($column);
|
||||||
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($autoFilterRange);
|
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($autoFilterRange);
|
||||||
if ($columnIndex <= $rangeEnd[0]) {
|
if ($columnIndex <= $rangeEnd[0]) {
|
||||||
if ($pNumCols < 0) {
|
if ($pNumCols < 0) {
|
||||||
// If we're actually deleting any columns that fall within the autofilter range,
|
// If we're actually deleting any columns that fall within the autofilter range,
|
||||||
@ -707,7 +701,7 @@ class ReferenceHelper
|
|||||||
if (($match[2] == '') || (trim($match[2], "'") == $sheetName)) {
|
if (($match[2] == '') || (trim($match[2], "'") == $sheetName)) {
|
||||||
$toString = ($match[2] > '') ? $match[2] . '!' : '';
|
$toString = ($match[2] > '') ? $match[2] . '!' : '';
|
||||||
$toString .= $modified3 . ':' . $modified4;
|
$toString .= $modified3 . ':' . $modified4;
|
||||||
list($column, $row) = Coordinate::coordinateFromString($match[3]);
|
[$column, $row] = Coordinate::coordinateFromString($match[3]);
|
||||||
// Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more
|
// Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more
|
||||||
$column = Coordinate::columnIndexFromString(trim($column, '$')) + 100000;
|
$column = Coordinate::columnIndexFromString(trim($column, '$')) + 100000;
|
||||||
$row = trim($row, '$') + 10000000;
|
$row = trim($row, '$') + 10000000;
|
||||||
@ -733,7 +727,7 @@ class ReferenceHelper
|
|||||||
if (($match[2] == '') || (trim($match[2], "'") == $sheetName)) {
|
if (($match[2] == '') || (trim($match[2], "'") == $sheetName)) {
|
||||||
$toString = ($match[2] > '') ? $match[2] . '!' : '';
|
$toString = ($match[2] > '') ? $match[2] . '!' : '';
|
||||||
$toString .= $modified3;
|
$toString .= $modified3;
|
||||||
list($column, $row) = Coordinate::coordinateFromString($match[3]);
|
[$column, $row] = Coordinate::coordinateFromString($match[3]);
|
||||||
// Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more
|
// Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more
|
||||||
$column = Coordinate::columnIndexFromString(trim($column, '$')) + 100000;
|
$column = Coordinate::columnIndexFromString(trim($column, '$')) + 100000;
|
||||||
$row = trim($row, '$') + 10000000;
|
$row = trim($row, '$') + 10000000;
|
||||||
@ -881,10 +875,10 @@ class ReferenceHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get coordinate of $pBefore
|
// Get coordinate of $pBefore
|
||||||
list($beforeColumn, $beforeRow) = Coordinate::coordinateFromString($pBefore);
|
[$beforeColumn, $beforeRow] = Coordinate::coordinateFromString($pBefore);
|
||||||
|
|
||||||
// Get coordinate of $pCellReference
|
// Get coordinate of $pCellReference
|
||||||
list($newColumn, $newRow) = Coordinate::coordinateFromString($pCellReference);
|
[$newColumn, $newRow] = Coordinate::coordinateFromString($pCellReference);
|
||||||
|
|
||||||
// Verify which parts should be updated
|
// Verify which parts should be updated
|
||||||
$updateColumn = (($newColumn[0] != '$') && ($beforeColumn[0] != '$') && (Coordinate::columnIndexFromString($newColumn) >= Coordinate::columnIndexFromString($beforeColumn)));
|
$updateColumn = (($newColumn[0] != '$') && ($beforeColumn[0] != '$') && (Coordinate::columnIndexFromString($newColumn) >= Coordinate::columnIndexFromString($beforeColumn)));
|
||||||
|
|||||||
@ -47,7 +47,7 @@ class RichText implements IComparable
|
|||||||
*
|
*
|
||||||
* @param ITextElement $pText Rich text element
|
* @param ITextElement $pText Rich text element
|
||||||
*
|
*
|
||||||
* @return RichText
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function addText(ITextElement $pText)
|
public function addText(ITextElement $pText)
|
||||||
{
|
{
|
||||||
@ -133,7 +133,7 @@ class RichText implements IComparable
|
|||||||
*
|
*
|
||||||
* @param ITextElement[] $textElements Array of elements
|
* @param ITextElement[] $textElements Array of elements
|
||||||
*
|
*
|
||||||
* @return RichText
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setRichTextElements(array $textElements)
|
public function setRichTextElements(array $textElements)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -40,7 +40,7 @@ class Run extends TextElement implements ITextElement
|
|||||||
*
|
*
|
||||||
* @param Font $pFont Font
|
* @param Font $pFont Font
|
||||||
*
|
*
|
||||||
* @return ITextElement
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setFont(Font $pFont = null)
|
public function setFont(Font $pFont = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -37,7 +37,7 @@ class TextElement implements ITextElement
|
|||||||
*
|
*
|
||||||
* @param $text string Text
|
* @param $text string Text
|
||||||
*
|
*
|
||||||
* @return ITextElement
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setText($text)
|
public function setText($text)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -30,7 +30,6 @@ class Settings
|
|||||||
* 7.2 < 7.2.1
|
* 7.2 < 7.2.1
|
||||||
* 7.1 < 7.1.13
|
* 7.1 < 7.1.13
|
||||||
* 7.0 < 7.0.27
|
* 7.0 < 7.0.27
|
||||||
* 5.6 ANY
|
|
||||||
* then you may need to disable this check to prevent unwanted behaviour in other threads
|
* then you may need to disable this check to prevent unwanted behaviour in other threads
|
||||||
* SECURITY WARNING: Changing this flag is not recommended.
|
* SECURITY WARNING: Changing this flag is not recommended.
|
||||||
*
|
*
|
||||||
@ -122,7 +121,6 @@ class Settings
|
|||||||
* 7.2 < 7.2.1
|
* 7.2 < 7.2.1
|
||||||
* 7.1 < 7.1.13
|
* 7.1 < 7.1.13
|
||||||
* 7.0 < 7.0.27
|
* 7.0 < 7.0.27
|
||||||
* 5.6 ANY
|
|
||||||
* then you may need to disable this check to prevent unwanted behaviour in other threads
|
* then you may need to disable this check to prevent unwanted behaviour in other threads
|
||||||
* SECURITY WARNING: Changing this flag to false is not recommended.
|
* SECURITY WARNING: Changing this flag to false is not recommended.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -298,9 +298,7 @@ class Font
|
|||||||
$upperLeftCornerX = $textBox[6];
|
$upperLeftCornerX = $textBox[6];
|
||||||
|
|
||||||
// Consider the rotation when calculating the width
|
// Consider the rotation when calculating the width
|
||||||
$textWidth = max($lowerRightCornerX - $upperLeftCornerX, $upperRightCornerX - $lowerLeftCornerX);
|
return max($lowerRightCornerX - $upperLeftCornerX, $upperRightCornerX - $lowerLeftCornerX);
|
||||||
|
|
||||||
return $textWidth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -174,7 +174,7 @@ class Matrix
|
|||||||
switch ($match) {
|
switch ($match) {
|
||||||
//A($i0...; $j0...)
|
//A($i0...; $j0...)
|
||||||
case 'integer,integer':
|
case 'integer,integer':
|
||||||
list($i0, $j0) = $args;
|
[$i0, $j0] = $args;
|
||||||
if ($i0 >= 0) {
|
if ($i0 >= 0) {
|
||||||
$m = $this->m - $i0;
|
$m = $this->m - $i0;
|
||||||
} else {
|
} else {
|
||||||
@ -197,7 +197,7 @@ class Matrix
|
|||||||
break;
|
break;
|
||||||
//A($i0...$iF; $j0...$jF)
|
//A($i0...$iF; $j0...$jF)
|
||||||
case 'integer,integer,integer,integer':
|
case 'integer,integer,integer,integer':
|
||||||
list($i0, $iF, $j0, $jF) = $args;
|
[$i0, $iF, $j0, $jF] = $args;
|
||||||
if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) {
|
if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) {
|
||||||
$m = $iF - $i0;
|
$m = $iF - $i0;
|
||||||
} else {
|
} else {
|
||||||
@ -220,7 +220,7 @@ class Matrix
|
|||||||
break;
|
break;
|
||||||
//$R = array of row indices; $C = array of column indices
|
//$R = array of row indices; $C = array of column indices
|
||||||
case 'array,array':
|
case 'array,array':
|
||||||
list($RL, $CL) = $args;
|
[$RL, $CL] = $args;
|
||||||
if (count($RL) > 0) {
|
if (count($RL) > 0) {
|
||||||
$m = count($RL);
|
$m = count($RL);
|
||||||
} else {
|
} else {
|
||||||
@ -243,7 +243,7 @@ class Matrix
|
|||||||
break;
|
break;
|
||||||
//A($i0...$iF); $CL = array of column indices
|
//A($i0...$iF); $CL = array of column indices
|
||||||
case 'integer,integer,array':
|
case 'integer,integer,array':
|
||||||
list($i0, $iF, $CL) = $args;
|
[$i0, $iF, $CL] = $args;
|
||||||
if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) {
|
if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) {
|
||||||
$m = $iF - $i0;
|
$m = $iF - $i0;
|
||||||
} else {
|
} else {
|
||||||
@ -266,7 +266,7 @@ class Matrix
|
|||||||
break;
|
break;
|
||||||
//$RL = array of row indices
|
//$RL = array of row indices
|
||||||
case 'array,integer,integer':
|
case 'array,integer,integer':
|
||||||
list($RL, $j0, $jF) = $args;
|
[$RL, $j0, $jF] = $args;
|
||||||
if (count($RL) > 0) {
|
if (count($RL) > 0) {
|
||||||
$m = count($RL);
|
$m = count($RL);
|
||||||
} else {
|
} else {
|
||||||
@ -524,7 +524,7 @@ class Matrix
|
|||||||
*
|
*
|
||||||
* @param mixed $B Matrix/Array
|
* @param mixed $B Matrix/Array
|
||||||
*
|
*
|
||||||
* @return Matrix Sum
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function plusEquals(...$args)
|
public function plusEquals(...$args)
|
||||||
{
|
{
|
||||||
@ -628,7 +628,7 @@ class Matrix
|
|||||||
*
|
*
|
||||||
* @param mixed $B Matrix/Array
|
* @param mixed $B Matrix/Array
|
||||||
*
|
*
|
||||||
* @return Matrix Sum
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function minusEquals(...$args)
|
public function minusEquals(...$args)
|
||||||
{
|
{
|
||||||
@ -734,7 +734,7 @@ class Matrix
|
|||||||
*
|
*
|
||||||
* @param mixed $B Matrix/Array
|
* @param mixed $B Matrix/Array
|
||||||
*
|
*
|
||||||
* @return Matrix Matrix Aij
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function arrayTimesEquals(...$args)
|
public function arrayTimesEquals(...$args)
|
||||||
{
|
{
|
||||||
@ -1091,7 +1091,7 @@ class Matrix
|
|||||||
*
|
*
|
||||||
* @param mixed $B Matrix/Array
|
* @param mixed $B Matrix/Array
|
||||||
*
|
*
|
||||||
* @return Matrix Sum
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function power(...$args)
|
public function power(...$args)
|
||||||
{
|
{
|
||||||
@ -1150,7 +1150,7 @@ class Matrix
|
|||||||
*
|
*
|
||||||
* @param mixed $B Matrix/Array
|
* @param mixed $B Matrix/Array
|
||||||
*
|
*
|
||||||
* @return Matrix Sum
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function concat(...$args)
|
public function concat(...$args)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -60,7 +60,7 @@ class QRDecomposition
|
|||||||
{
|
{
|
||||||
if ($A instanceof Matrix) {
|
if ($A instanceof Matrix) {
|
||||||
// Initialize.
|
// Initialize.
|
||||||
$this->QR = $A->getArrayCopy();
|
$this->QR = $A->getArray();
|
||||||
$this->m = $A->getRowDimension();
|
$this->m = $A->getRowDimension();
|
||||||
$this->n = $A->getColumnDimension();
|
$this->n = $A->getColumnDimension();
|
||||||
// Main loop.
|
// Main loop.
|
||||||
|
|||||||
@ -253,7 +253,7 @@ class OLE
|
|||||||
*/
|
*/
|
||||||
private static function _readInt1($fh)
|
private static function _readInt1($fh)
|
||||||
{
|
{
|
||||||
list(, $tmp) = unpack('c', fread($fh, 1));
|
[, $tmp] = unpack('c', fread($fh, 1));
|
||||||
|
|
||||||
return $tmp;
|
return $tmp;
|
||||||
}
|
}
|
||||||
@ -267,7 +267,7 @@ class OLE
|
|||||||
*/
|
*/
|
||||||
private static function _readInt2($fh)
|
private static function _readInt2($fh)
|
||||||
{
|
{
|
||||||
list(, $tmp) = unpack('v', fread($fh, 2));
|
[, $tmp] = unpack('v', fread($fh, 2));
|
||||||
|
|
||||||
return $tmp;
|
return $tmp;
|
||||||
}
|
}
|
||||||
@ -281,7 +281,7 @@ class OLE
|
|||||||
*/
|
*/
|
||||||
private static function _readInt4($fh)
|
private static function _readInt4($fh)
|
||||||
{
|
{
|
||||||
list(, $tmp) = unpack('V', fread($fh, 4));
|
[, $tmp] = unpack('V', fread($fh, 4));
|
||||||
|
|
||||||
return $tmp;
|
return $tmp;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -118,7 +118,7 @@ class Root extends PPS
|
|||||||
$aList = [];
|
$aList = [];
|
||||||
PPS::_savePpsSetPnt($aList, [$this]);
|
PPS::_savePpsSetPnt($aList, [$this]);
|
||||||
// calculate values for header
|
// calculate values for header
|
||||||
list($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList); //, $rhInfo);
|
[$iSBDcnt, $iBBcnt, $iPPScnt] = $this->_calcSize($aList); //, $rhInfo);
|
||||||
// Save Header
|
// Save Header
|
||||||
$this->_saveHeader($iSBDcnt, $iBBcnt, $iPPScnt);
|
$this->_saveHeader($iSBDcnt, $iBBcnt, $iPPScnt);
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ class Root extends PPS
|
|||||||
public function _calcSize(&$raList)
|
public function _calcSize(&$raList)
|
||||||
{
|
{
|
||||||
// Calculate Basic Setting
|
// Calculate Basic Setting
|
||||||
list($iSBDcnt, $iBBcnt, $iPPScnt) = [0, 0, 0];
|
[$iSBDcnt, $iBBcnt, $iPPScnt] = [0, 0, 0];
|
||||||
$iSmallLen = 0;
|
$iSmallLen = 0;
|
||||||
$iSBcnt = 0;
|
$iSBcnt = 0;
|
||||||
$iCount = count($raList);
|
$iCount = count($raList);
|
||||||
|
|||||||
@ -430,9 +430,7 @@ class StringHelper
|
|||||||
// characters
|
// characters
|
||||||
$chars = self::convertEncoding($value, 'UTF-16LE', 'UTF-8');
|
$chars = self::convertEncoding($value, 'UTF-16LE', 'UTF-8');
|
||||||
|
|
||||||
$data = pack('vC', $ln, 0x0001) . $chars;
|
return pack('vC', $ln, 0x0001) . $chars;
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -211,7 +211,7 @@ class Xls
|
|||||||
*/
|
*/
|
||||||
public static function oneAnchor2twoAnchor($sheet, $coordinates, $offsetX, $offsetY, $width, $height)
|
public static function oneAnchor2twoAnchor($sheet, $coordinates, $offsetX, $offsetY, $width, $height)
|
||||||
{
|
{
|
||||||
list($column, $row) = Coordinate::coordinateFromString($coordinates);
|
[$column, $row] = Coordinate::coordinateFromString($coordinates);
|
||||||
$col_start = Coordinate::columnIndexFromString($column);
|
$col_start = Coordinate::columnIndexFromString($column);
|
||||||
$row_start = $row - 1;
|
$row_start = $row - 1;
|
||||||
|
|
||||||
@ -269,7 +269,7 @@ class Xls
|
|||||||
$startCoordinates = Coordinate::stringFromColumnIndex($col_start) . ($row_start + 1);
|
$startCoordinates = Coordinate::stringFromColumnIndex($col_start) . ($row_start + 1);
|
||||||
$endCoordinates = Coordinate::stringFromColumnIndex($col_end) . ($row_end + 1);
|
$endCoordinates = Coordinate::stringFromColumnIndex($col_end) . ($row_end + 1);
|
||||||
|
|
||||||
$twoAnchor = [
|
return [
|
||||||
'startCoordinates' => $startCoordinates,
|
'startCoordinates' => $startCoordinates,
|
||||||
'startOffsetX' => $x1,
|
'startOffsetX' => $x1,
|
||||||
'startOffsetY' => $y1,
|
'startOffsetY' => $y1,
|
||||||
@ -277,7 +277,5 @@ class Xls
|
|||||||
'endOffsetX' => $x2,
|
'endOffsetX' => $x2,
|
||||||
'endOffsetY' => $y2,
|
'endOffsetY' => $y2,
|
||||||
];
|
];
|
||||||
|
|
||||||
return $twoAnchor;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -721,7 +721,7 @@ class Spreadsheet
|
|||||||
{
|
{
|
||||||
$worksheetCount = count($this->workSheetCollection);
|
$worksheetCount = count($this->workSheetCollection);
|
||||||
for ($i = 0; $i < $worksheetCount; ++$i) {
|
for ($i = 0; $i < $worksheetCount; ++$i) {
|
||||||
if ($this->workSheetCollection[$i]->getTitle() === $pName) {
|
if ($this->workSheetCollection[$i]->getTitle() === trim($pName, "'")) {
|
||||||
return $this->workSheetCollection[$i];
|
return $this->workSheetCollection[$i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -955,7 +955,7 @@ class Spreadsheet
|
|||||||
* @param string $namedRange
|
* @param string $namedRange
|
||||||
* @param null|Worksheet $pSheet scope: use null for global scope
|
* @param null|Worksheet $pSheet scope: use null for global scope
|
||||||
*
|
*
|
||||||
* @return Spreadsheet
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function removeNamedRange($namedRange, Worksheet $pSheet = null)
|
public function removeNamedRange($namedRange, Worksheet $pSheet = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -140,7 +140,7 @@ class Alignment extends Supervisor
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Alignment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function applyFromArray(array $pStyles)
|
public function applyFromArray(array $pStyles)
|
||||||
{
|
{
|
||||||
@ -193,7 +193,7 @@ class Alignment extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param string $pValue see self::HORIZONTAL_*
|
* @param string $pValue see self::HORIZONTAL_*
|
||||||
*
|
*
|
||||||
* @return Alignment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setHorizontal($pValue)
|
public function setHorizontal($pValue)
|
||||||
{
|
{
|
||||||
@ -230,7 +230,7 @@ class Alignment extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param string $pValue see self::VERTICAL_*
|
* @param string $pValue see self::VERTICAL_*
|
||||||
*
|
*
|
||||||
* @return Alignment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setVertical($pValue)
|
public function setVertical($pValue)
|
||||||
{
|
{
|
||||||
@ -269,7 +269,7 @@ class Alignment extends Supervisor
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Alignment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setTextRotation($pValue)
|
public function setTextRotation($pValue)
|
||||||
{
|
{
|
||||||
@ -312,7 +312,7 @@ class Alignment extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param bool $pValue
|
* @param bool $pValue
|
||||||
*
|
*
|
||||||
* @return Alignment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setWrapText($pValue)
|
public function setWrapText($pValue)
|
||||||
{
|
{
|
||||||
@ -348,7 +348,7 @@ class Alignment extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param bool $pValue
|
* @param bool $pValue
|
||||||
*
|
*
|
||||||
* @return Alignment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShrinkToFit($pValue)
|
public function setShrinkToFit($pValue)
|
||||||
{
|
{
|
||||||
@ -384,7 +384,7 @@ class Alignment extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param int $pValue
|
* @param int $pValue
|
||||||
*
|
*
|
||||||
* @return Alignment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setIndent($pValue)
|
public function setIndent($pValue)
|
||||||
{
|
{
|
||||||
@ -424,7 +424,7 @@ class Alignment extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param int $pValue
|
* @param int $pValue
|
||||||
*
|
*
|
||||||
* @return Alignment
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setReadOrder($pValue)
|
public function setReadOrder($pValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -127,7 +127,7 @@ class Border extends Supervisor
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Border
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function applyFromArray(array $pStyles)
|
public function applyFromArray(array $pStyles)
|
||||||
{
|
{
|
||||||
@ -166,7 +166,7 @@ class Border extends Supervisor
|
|||||||
* When passing a boolean, FALSE equates Border::BORDER_NONE
|
* When passing a boolean, FALSE equates Border::BORDER_NONE
|
||||||
* and TRUE to Border::BORDER_MEDIUM
|
* and TRUE to Border::BORDER_MEDIUM
|
||||||
*
|
*
|
||||||
* @return Border
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setBorderStyle($pValue)
|
public function setBorderStyle($pValue)
|
||||||
{
|
{
|
||||||
@ -202,7 +202,7 @@ class Border extends Supervisor
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Border
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setColor(Color $pValue)
|
public function setColor(Color $pValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -197,7 +197,7 @@ class Borders extends Supervisor
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Borders
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function applyFromArray(array $pStyles)
|
public function applyFromArray(array $pStyles)
|
||||||
{
|
{
|
||||||
@ -382,7 +382,7 @@ class Borders extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param int $pValue see self::DIAGONAL_*
|
* @param int $pValue see self::DIAGONAL_*
|
||||||
*
|
*
|
||||||
* @return Borders
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setDiagonalDirection($pValue)
|
public function setDiagonalDirection($pValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -6,6 +6,17 @@ use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
|
|||||||
|
|
||||||
class Color extends Supervisor
|
class Color extends Supervisor
|
||||||
{
|
{
|
||||||
|
const NAMED_COLORS = [
|
||||||
|
'Black',
|
||||||
|
'White',
|
||||||
|
'Red',
|
||||||
|
'Green',
|
||||||
|
'Blue',
|
||||||
|
'Yellow',
|
||||||
|
'Magenta',
|
||||||
|
'Cyan',
|
||||||
|
];
|
||||||
|
|
||||||
// Colors
|
// Colors
|
||||||
const COLOR_BLACK = 'FF000000';
|
const COLOR_BLACK = 'FF000000';
|
||||||
const COLOR_WHITE = 'FFFFFFFF';
|
const COLOR_WHITE = 'FFFFFFFF';
|
||||||
@ -95,7 +106,7 @@ class Color extends Supervisor
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Color
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function applyFromArray(array $pStyles)
|
public function applyFromArray(array $pStyles)
|
||||||
{
|
{
|
||||||
@ -132,7 +143,7 @@ class Color extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param string $pValue see self::COLOR_*
|
* @param string $pValue see self::COLOR_*
|
||||||
*
|
*
|
||||||
* @return Color
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setARGB($pValue)
|
public function setARGB($pValue)
|
||||||
{
|
{
|
||||||
@ -168,7 +179,7 @@ class Color extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param string $pValue RGB value
|
* @param string $pValue RGB value
|
||||||
*
|
*
|
||||||
* @return Color
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setRGB($pValue)
|
public function setRGB($pValue)
|
||||||
{
|
{
|
||||||
@ -198,11 +209,8 @@ class Color extends Supervisor
|
|||||||
private static function getColourComponent($RGB, $offset, $hex = true)
|
private static function getColourComponent($RGB, $offset, $hex = true)
|
||||||
{
|
{
|
||||||
$colour = substr($RGB, $offset, 2);
|
$colour = substr($RGB, $offset, 2);
|
||||||
if (!$hex) {
|
|
||||||
$colour = hexdec($colour);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $colour;
|
return ($hex) ? $colour : hexdec($colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -257,7 +265,7 @@ class Color extends Supervisor
|
|||||||
*/
|
*/
|
||||||
public static function changeBrightness($hex, $adjustPercentage)
|
public static function changeBrightness($hex, $adjustPercentage)
|
||||||
{
|
{
|
||||||
$rgba = (strlen($hex) == 8);
|
$rgba = (strlen($hex) === 8);
|
||||||
|
|
||||||
$red = self::getRed($hex, false);
|
$red = self::getRed($hex, false);
|
||||||
$green = self::getGreen($hex, false);
|
$green = self::getGreen($hex, false);
|
||||||
@ -289,9 +297,9 @@ class Color extends Supervisor
|
|||||||
}
|
}
|
||||||
|
|
||||||
$rgb = strtoupper(
|
$rgb = strtoupper(
|
||||||
str_pad(dechex($red), 2, '0', 0) .
|
str_pad(dechex((int) $red), 2, '0', 0) .
|
||||||
str_pad(dechex($green), 2, '0', 0) .
|
str_pad(dechex((int) $green), 2, '0', 0) .
|
||||||
str_pad(dechex($blue), 2, '0', 0)
|
str_pad(dechex((int) $blue), 2, '0', 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
return (($rgba) ? 'FF' : '') . $rgb;
|
return (($rgba) ? 'FF' : '') . $rgb;
|
||||||
@ -304,7 +312,7 @@ class Color extends Supervisor
|
|||||||
* @param bool $background Flag to indicate whether default background or foreground colour
|
* @param bool $background Flag to indicate whether default background or foreground colour
|
||||||
* should be returned if the indexed colour doesn't exist
|
* should be returned if the indexed colour doesn't exist
|
||||||
*
|
*
|
||||||
* @return Color
|
* @return self
|
||||||
*/
|
*/
|
||||||
public static function indexedColor($pIndex, $background = false)
|
public static function indexedColor($pIndex, $background = false)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -12,6 +12,7 @@ class Conditional implements IComparable
|
|||||||
const CONDITION_CONTAINSTEXT = 'containsText';
|
const CONDITION_CONTAINSTEXT = 'containsText';
|
||||||
const CONDITION_EXPRESSION = 'expression';
|
const CONDITION_EXPRESSION = 'expression';
|
||||||
const CONDITION_CONTAINSBLANKS = 'containsBlanks';
|
const CONDITION_CONTAINSBLANKS = 'containsBlanks';
|
||||||
|
const CONDITION_NOTCONTAINSBLANKS = 'notContainsBlanks';
|
||||||
|
|
||||||
// Operator types
|
// Operator types
|
||||||
const OPERATOR_NONE = '';
|
const OPERATOR_NONE = '';
|
||||||
@ -93,7 +94,7 @@ class Conditional implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string $pValue Condition type, see self::CONDITION_*
|
* @param string $pValue Condition type, see self::CONDITION_*
|
||||||
*
|
*
|
||||||
* @return Conditional
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setConditionType($pValue)
|
public function setConditionType($pValue)
|
||||||
{
|
{
|
||||||
@ -117,7 +118,7 @@ class Conditional implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string $pValue Conditional operator type, see self::OPERATOR_*
|
* @param string $pValue Conditional operator type, see self::OPERATOR_*
|
||||||
*
|
*
|
||||||
* @return Conditional
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setOperatorType($pValue)
|
public function setOperatorType($pValue)
|
||||||
{
|
{
|
||||||
@ -141,7 +142,7 @@ class Conditional implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*
|
*
|
||||||
* @return Conditional
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setText($value)
|
public function setText($value)
|
||||||
{
|
{
|
||||||
@ -165,7 +166,7 @@ class Conditional implements IComparable
|
|||||||
*
|
*
|
||||||
* @param bool $value
|
* @param bool $value
|
||||||
*
|
*
|
||||||
* @return Conditional
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setStopIfTrue($value)
|
public function setStopIfTrue($value)
|
||||||
{
|
{
|
||||||
@ -189,7 +190,7 @@ class Conditional implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string[] $pValue Condition
|
* @param string[] $pValue Condition
|
||||||
*
|
*
|
||||||
* @return Conditional
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setConditions($pValue)
|
public function setConditions($pValue)
|
||||||
{
|
{
|
||||||
@ -206,7 +207,7 @@ class Conditional implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string $pValue Condition
|
* @param string $pValue Condition
|
||||||
*
|
*
|
||||||
* @return Conditional
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function addCondition($pValue)
|
public function addCondition($pValue)
|
||||||
{
|
{
|
||||||
@ -230,7 +231,7 @@ class Conditional implements IComparable
|
|||||||
*
|
*
|
||||||
* @param Style $pValue
|
* @param Style $pValue
|
||||||
*
|
*
|
||||||
* @return Conditional
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setStyle(Style $pValue = null)
|
public function setStyle(Style $pValue = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -141,7 +141,7 @@ class Fill extends Supervisor
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Fill
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function applyFromArray(array $pStyles)
|
public function applyFromArray(array $pStyles)
|
||||||
{
|
{
|
||||||
@ -188,7 +188,7 @@ class Fill extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param string $pValue Fill type, see self::FILL_*
|
* @param string $pValue Fill type, see self::FILL_*
|
||||||
*
|
*
|
||||||
* @return Fill
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setFillType($pValue)
|
public function setFillType($pValue)
|
||||||
{
|
{
|
||||||
@ -221,7 +221,7 @@ class Fill extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param float $pValue
|
* @param float $pValue
|
||||||
*
|
*
|
||||||
* @return Fill
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setRotation($pValue)
|
public function setRotation($pValue)
|
||||||
{
|
{
|
||||||
@ -252,7 +252,7 @@ class Fill extends Supervisor
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Fill
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setStartColor(Color $pValue)
|
public function setStartColor(Color $pValue)
|
||||||
{
|
{
|
||||||
@ -286,7 +286,7 @@ class Fill extends Supervisor
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Fill
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setEndColor(Color $pValue)
|
public function setEndColor(Color $pValue)
|
||||||
{
|
{
|
||||||
@ -313,12 +313,13 @@ class Fill extends Supervisor
|
|||||||
if ($this->isSupervisor) {
|
if ($this->isSupervisor) {
|
||||||
return $this->getSharedComponent()->getHashCode();
|
return $this->getSharedComponent()->getHashCode();
|
||||||
}
|
}
|
||||||
|
// Note that we don't care about colours for fill type NONE, but could have duplicate NONEs with
|
||||||
|
// different hashes if we don't explicitly prevent this
|
||||||
return md5(
|
return md5(
|
||||||
$this->getFillType() .
|
$this->getFillType() .
|
||||||
$this->getRotation() .
|
$this->getRotation() .
|
||||||
$this->getStartColor()->getHashCode() .
|
($this->getFillType() !== self::FILL_NONE ? $this->getStartColor()->getHashCode() : '') .
|
||||||
$this->getEndColor()->getHashCode() .
|
($this->getFillType() !== self::FILL_NONE ? $this->getEndColor()->getHashCode() : '') .
|
||||||
__CLASS__
|
__CLASS__
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -161,7 +161,7 @@ class Font extends Supervisor
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Font
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function applyFromArray(array $pStyles)
|
public function applyFromArray(array $pStyles)
|
||||||
{
|
{
|
||||||
@ -219,7 +219,7 @@ class Font extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param string $pValue
|
* @param string $pValue
|
||||||
*
|
*
|
||||||
* @return Font
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setName($pValue)
|
public function setName($pValue)
|
||||||
{
|
{
|
||||||
@ -255,7 +255,7 @@ class Font extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param float $pValue
|
* @param float $pValue
|
||||||
*
|
*
|
||||||
* @return Font
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setSize($pValue)
|
public function setSize($pValue)
|
||||||
{
|
{
|
||||||
@ -291,7 +291,7 @@ class Font extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param bool $pValue
|
* @param bool $pValue
|
||||||
*
|
*
|
||||||
* @return Font
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setBold($pValue)
|
public function setBold($pValue)
|
||||||
{
|
{
|
||||||
@ -327,7 +327,7 @@ class Font extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param bool $pValue
|
* @param bool $pValue
|
||||||
*
|
*
|
||||||
* @return Font
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setItalic($pValue)
|
public function setItalic($pValue)
|
||||||
{
|
{
|
||||||
@ -363,7 +363,7 @@ class Font extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param bool $pValue
|
* @param bool $pValue
|
||||||
*
|
*
|
||||||
* @return Font
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setSuperscript($pValue)
|
public function setSuperscript($pValue)
|
||||||
{
|
{
|
||||||
@ -400,7 +400,7 @@ class Font extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param bool $pValue
|
* @param bool $pValue
|
||||||
*
|
*
|
||||||
* @return Font
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setSubscript($pValue)
|
public function setSubscript($pValue)
|
||||||
{
|
{
|
||||||
@ -439,7 +439,7 @@ class Font extends Supervisor
|
|||||||
* If a boolean is passed, then TRUE equates to UNDERLINE_SINGLE,
|
* If a boolean is passed, then TRUE equates to UNDERLINE_SINGLE,
|
||||||
* false equates to UNDERLINE_NONE
|
* false equates to UNDERLINE_NONE
|
||||||
*
|
*
|
||||||
* @return Font
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setUnderline($pValue)
|
public function setUnderline($pValue)
|
||||||
{
|
{
|
||||||
@ -477,7 +477,7 @@ class Font extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param bool $pValue
|
* @param bool $pValue
|
||||||
*
|
*
|
||||||
* @return Font
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setStrikethrough($pValue)
|
public function setStrikethrough($pValue)
|
||||||
{
|
{
|
||||||
@ -512,7 +512,7 @@ class Font extends Supervisor
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Font
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setColor(Color $pValue)
|
public function setColor(Color $pValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -23,8 +23,8 @@ class NumberFormat extends Supervisor
|
|||||||
const FORMAT_PERCENTAGE_00 = '0.00%';
|
const FORMAT_PERCENTAGE_00 = '0.00%';
|
||||||
|
|
||||||
const FORMAT_DATE_YYYYMMDD2 = 'yyyy-mm-dd';
|
const FORMAT_DATE_YYYYMMDD2 = 'yyyy-mm-dd';
|
||||||
const FORMAT_DATE_YYYYMMDD = 'yy-mm-dd';
|
const FORMAT_DATE_YYYYMMDD = 'yyyy-mm-dd';
|
||||||
const FORMAT_DATE_DDMMYYYY = 'dd/mm/yy';
|
const FORMAT_DATE_DDMMYYYY = 'dd/mm/yyyy';
|
||||||
const FORMAT_DATE_DMYSLASH = 'd/m/yy';
|
const FORMAT_DATE_DMYSLASH = 'd/m/yy';
|
||||||
const FORMAT_DATE_DMYMINUS = 'd-m-yy';
|
const FORMAT_DATE_DMYMINUS = 'd-m-yy';
|
||||||
const FORMAT_DATE_DMMINUS = 'd-m';
|
const FORMAT_DATE_DMMINUS = 'd-m';
|
||||||
@ -43,7 +43,7 @@ class NumberFormat extends Supervisor
|
|||||||
const FORMAT_DATE_TIME6 = 'h:mm:ss';
|
const FORMAT_DATE_TIME6 = 'h:mm:ss';
|
||||||
const FORMAT_DATE_TIME7 = 'i:s.S';
|
const FORMAT_DATE_TIME7 = 'i:s.S';
|
||||||
const FORMAT_DATE_TIME8 = 'h:mm:ss;@';
|
const FORMAT_DATE_TIME8 = 'h:mm:ss;@';
|
||||||
const FORMAT_DATE_YYYYMMDDSLASH = 'yy/mm/dd;@';
|
const FORMAT_DATE_YYYYMMDDSLASH = 'yyyy/mm/dd;@';
|
||||||
|
|
||||||
const FORMAT_CURRENCY_USD_SIMPLE = '"$"#,##0.00_-';
|
const FORMAT_CURRENCY_USD_SIMPLE = '"$"#,##0.00_-';
|
||||||
const FORMAT_CURRENCY_USD = '$#,##0_-';
|
const FORMAT_CURRENCY_USD = '$#,##0_-';
|
||||||
@ -139,7 +139,7 @@ class NumberFormat extends Supervisor
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return NumberFormat
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function applyFromArray(array $pStyles)
|
public function applyFromArray(array $pStyles)
|
||||||
{
|
{
|
||||||
@ -176,7 +176,7 @@ class NumberFormat extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param string $pValue see self::FORMAT_*
|
* @param string $pValue see self::FORMAT_*
|
||||||
*
|
*
|
||||||
* @return NumberFormat
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setFormatCode($pValue)
|
public function setFormatCode($pValue)
|
||||||
{
|
{
|
||||||
@ -213,7 +213,7 @@ class NumberFormat extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param int $pValue
|
* @param int $pValue
|
||||||
*
|
*
|
||||||
* @return NumberFormat
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setBuiltInFormatCode($pValue)
|
public function setBuiltInFormatCode($pValue)
|
||||||
{
|
{
|
||||||
@ -367,7 +367,7 @@ class NumberFormat extends Supervisor
|
|||||||
self::fillBuiltInFormatCodes();
|
self::fillBuiltInFormatCodes();
|
||||||
|
|
||||||
// Lookup format code
|
// Lookup format code
|
||||||
if (isset(self::$flippedBuiltInFormats[$formatCode])) {
|
if (array_key_exists($formatCode, self::$flippedBuiltInFormats)) {
|
||||||
return self::$flippedBuiltInFormats[$formatCode];
|
return self::$flippedBuiltInFormats[$formatCode];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -551,24 +551,32 @@ class NumberFormat extends Supervisor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function complexNumberFormatMask($number, $mask)
|
private static function mergeComplexNumberFormatMasks($numbers, $masks)
|
||||||
{
|
{
|
||||||
$sign = ($number < 0.0);
|
$decimalCount = strlen($numbers[1]);
|
||||||
$number = abs($number);
|
$postDecimalMasks = [];
|
||||||
if (strpos($mask, '.') !== false) {
|
|
||||||
$numbers = explode('.', $number . '.0');
|
|
||||||
$masks = explode('.', $mask . '.0');
|
|
||||||
$result1 = self::complexNumberFormatMask($numbers[0], $masks[0]);
|
|
||||||
$result2 = strrev(self::complexNumberFormatMask(strrev($numbers[1]), strrev($masks[1])));
|
|
||||||
|
|
||||||
return (($sign) ? '-' : '') . $result1 . '.' . $result2;
|
do {
|
||||||
}
|
$tempMask = array_pop($masks);
|
||||||
|
$postDecimalMasks[] = $tempMask;
|
||||||
|
$decimalCount -= strlen($tempMask);
|
||||||
|
} while ($decimalCount > 0);
|
||||||
|
|
||||||
$r = preg_match_all('/0+/', $mask, $result, PREG_OFFSET_CAPTURE);
|
return [
|
||||||
if ($r > 1) {
|
implode('.', $masks),
|
||||||
$result = array_reverse($result[0]);
|
implode('.', array_reverse($postDecimalMasks)),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($result as $block) {
|
private static function processComplexNumberFormatMask($number, $mask)
|
||||||
|
{
|
||||||
|
$result = $number;
|
||||||
|
$maskingBlockCount = preg_match_all('/0+/', $mask, $maskingBlocks, PREG_OFFSET_CAPTURE);
|
||||||
|
|
||||||
|
if ($maskingBlockCount > 1) {
|
||||||
|
$maskingBlocks = array_reverse($maskingBlocks[0]);
|
||||||
|
|
||||||
|
foreach ($maskingBlocks as $block) {
|
||||||
$divisor = 1 . $block[0];
|
$divisor = 1 . $block[0];
|
||||||
$size = strlen($block[0]);
|
$size = strlen($block[0]);
|
||||||
$offset = $block[1];
|
$offset = $block[1];
|
||||||
@ -584,13 +592,134 @@ class NumberFormat extends Supervisor
|
|||||||
$mask = substr_replace($mask, $number, $offset, 0);
|
$mask = substr_replace($mask, $number, $offset, 0);
|
||||||
}
|
}
|
||||||
$result = $mask;
|
$result = $mask;
|
||||||
} else {
|
|
||||||
$result = $number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function complexNumberFormatMask($number, $mask, $splitOnPoint = true)
|
||||||
|
{
|
||||||
|
$sign = ($number < 0.0);
|
||||||
|
$number = abs($number);
|
||||||
|
|
||||||
|
if ($splitOnPoint && strpos($mask, '.') !== false && strpos($number, '.') !== false) {
|
||||||
|
$numbers = explode('.', $number);
|
||||||
|
$masks = explode('.', $mask);
|
||||||
|
if (count($masks) > 2) {
|
||||||
|
$masks = self::mergeComplexNumberFormatMasks($numbers, $masks);
|
||||||
|
}
|
||||||
|
$result1 = self::complexNumberFormatMask($numbers[0], $masks[0], false);
|
||||||
|
$result2 = strrev(self::complexNumberFormatMask(strrev($numbers[1]), strrev($masks[1]), false));
|
||||||
|
|
||||||
|
return (($sign) ? '-' : '') . $result1 . '.' . $result2;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = self::processComplexNumberFormatMask($number, $mask);
|
||||||
|
|
||||||
return (($sign) ? '-' : '') . $result;
|
return (($sign) ? '-' : '') . $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function formatStraightNumericValue($value, $format, array $matches, $useThousands, $number_regex)
|
||||||
|
{
|
||||||
|
$left = $matches[1];
|
||||||
|
$dec = $matches[2];
|
||||||
|
$right = $matches[3];
|
||||||
|
|
||||||
|
// minimun width of formatted number (including dot)
|
||||||
|
$minWidth = strlen($left) + strlen($dec) + strlen($right);
|
||||||
|
if ($useThousands) {
|
||||||
|
$value = number_format(
|
||||||
|
$value,
|
||||||
|
strlen($right),
|
||||||
|
StringHelper::getDecimalSeparator(),
|
||||||
|
StringHelper::getThousandsSeparator()
|
||||||
|
);
|
||||||
|
$value = preg_replace($number_regex, $value, $format);
|
||||||
|
} else {
|
||||||
|
if (preg_match('/[0#]E[+-]0/i', $format)) {
|
||||||
|
// Scientific format
|
||||||
|
$value = sprintf('%5.2E', $value);
|
||||||
|
} elseif (preg_match('/0([^\d\.]+)0/', $format) || substr_count($format, '.') > 1) {
|
||||||
|
if ($value == (int) $value && substr_count($format, '.') === 1) {
|
||||||
|
$value *= 10 ** strlen(explode('.', $format)[1]);
|
||||||
|
}
|
||||||
|
$value = self::complexNumberFormatMask($value, $format);
|
||||||
|
} else {
|
||||||
|
$sprintf_pattern = "%0$minWidth." . strlen($right) . 'f';
|
||||||
|
$value = sprintf($sprintf_pattern, $value);
|
||||||
|
$value = preg_replace($number_regex, $value, $format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function formatAsNumber($value, $format)
|
||||||
|
{
|
||||||
|
if ($format === self::FORMAT_CURRENCY_EUR_SIMPLE) {
|
||||||
|
return 'EUR ' . sprintf('%1.2f', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some non-number strings are quoted, so we'll get rid of the quotes, likewise any positional * symbols
|
||||||
|
$format = str_replace(['"', '*'], '', $format);
|
||||||
|
|
||||||
|
// Find out if we need thousands separator
|
||||||
|
// This is indicated by a comma enclosed by a digit placeholder:
|
||||||
|
// #,# or 0,0
|
||||||
|
$useThousands = preg_match('/(#,#|0,0)/', $format);
|
||||||
|
if ($useThousands) {
|
||||||
|
$format = preg_replace('/0,0/', '00', $format);
|
||||||
|
$format = preg_replace('/#,#/', '##', $format);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale thousands, millions,...
|
||||||
|
// This is indicated by a number of commas after a digit placeholder:
|
||||||
|
// #, or 0.0,,
|
||||||
|
$scale = 1; // same as no scale
|
||||||
|
$matches = [];
|
||||||
|
if (preg_match('/(#|0)(,+)/', $format, $matches)) {
|
||||||
|
$scale = pow(1000, strlen($matches[2]));
|
||||||
|
|
||||||
|
// strip the commas
|
||||||
|
$format = preg_replace('/0,+/', '0', $format);
|
||||||
|
$format = preg_replace('/#,+/', '#', $format);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/#?.*\?\/\?/', $format, $m)) {
|
||||||
|
if ($value != (int) $value) {
|
||||||
|
self::formatAsFraction($value, $format);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handle the number itself
|
||||||
|
|
||||||
|
// scale number
|
||||||
|
$value = $value / $scale;
|
||||||
|
// Strip #
|
||||||
|
$format = preg_replace('/\\#/', '0', $format);
|
||||||
|
// Remove locale code [$-###]
|
||||||
|
$format = preg_replace('/\[\$\-.*\]/', '', $format);
|
||||||
|
|
||||||
|
$n = '/\\[[^\\]]+\\]/';
|
||||||
|
$m = preg_replace($n, '', $format);
|
||||||
|
$number_regex = '/(0+)(\\.?)(0*)/';
|
||||||
|
if (preg_match($number_regex, $m, $matches)) {
|
||||||
|
$value = self::formatStraightNumericValue($value, $format, $matches, $useThousands, $number_regex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/\[\$(.*)\]/u', $format, $m)) {
|
||||||
|
// Currency or Accounting
|
||||||
|
$currencyCode = $m[1];
|
||||||
|
[$currencyCode] = explode('-', $currencyCode);
|
||||||
|
if ($currencyCode == '') {
|
||||||
|
$currencyCode = StringHelper::getCurrencyCode();
|
||||||
|
}
|
||||||
|
$value = preg_replace('/\[\$([^\]]*)\]/u', $currencyCode, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a value in a pre-defined format to a PHP string.
|
* Convert a value in a pre-defined format to a PHP string.
|
||||||
*
|
*
|
||||||
@ -660,7 +789,9 @@ class NumberFormat extends Supervisor
|
|||||||
|
|
||||||
// Save format with color information for later use below
|
// Save format with color information for later use below
|
||||||
$formatColor = $format;
|
$formatColor = $format;
|
||||||
|
// Strip colour information
|
||||||
|
$color_regex = '/\[(' . implode('|', Color::NAMED_COLORS) . ')\]/';
|
||||||
|
$format = preg_replace($color_regex, '', $format);
|
||||||
// Let's begin inspecting the format and converting the value to a formatted string
|
// Let's begin inspecting the format and converting the value to a formatted string
|
||||||
|
|
||||||
// Check for date/time characters (not inside quotes)
|
// Check for date/time characters (not inside quotes)
|
||||||
@ -668,105 +799,19 @@ class NumberFormat extends Supervisor
|
|||||||
// datetime format
|
// datetime format
|
||||||
self::formatAsDate($value, $format);
|
self::formatAsDate($value, $format);
|
||||||
} else {
|
} else {
|
||||||
// Strip color information
|
if (substr($format, 0, 1) === '"' && substr($format, -1, 1) === '"') {
|
||||||
$color_regex = '/^\\[[a-zA-Z]+\\]/';
|
$value = substr($format, 1, -1);
|
||||||
$format = preg_replace($color_regex, '', $format);
|
} elseif (preg_match('/%$/', $format)) {
|
||||||
if (preg_match('/%$/', $format)) {
|
|
||||||
// % number format
|
// % number format
|
||||||
self::formatAsPercentage($value, $format);
|
self::formatAsPercentage($value, $format);
|
||||||
} else {
|
} else {
|
||||||
if ($format === self::FORMAT_CURRENCY_EUR_SIMPLE) {
|
$value = self::formatAsNumber($value, $format);
|
||||||
$value = 'EUR ' . sprintf('%1.2f', $value);
|
|
||||||
} else {
|
|
||||||
// Some non-number strings are quoted, so we'll get rid of the quotes, likewise any positional * symbols
|
|
||||||
$format = str_replace(['"', '*'], '', $format);
|
|
||||||
|
|
||||||
// Find out if we need thousands separator
|
|
||||||
// This is indicated by a comma enclosed by a digit placeholder:
|
|
||||||
// #,# or 0,0
|
|
||||||
$useThousands = preg_match('/(#,#|0,0)/', $format);
|
|
||||||
if ($useThousands) {
|
|
||||||
$format = preg_replace('/0,0/', '00', $format);
|
|
||||||
$format = preg_replace('/#,#/', '##', $format);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scale thousands, millions,...
|
|
||||||
// This is indicated by a number of commas after a digit placeholder:
|
|
||||||
// #, or 0.0,,
|
|
||||||
$scale = 1; // same as no scale
|
|
||||||
$matches = [];
|
|
||||||
if (preg_match('/(#|0)(,+)/', $format, $matches)) {
|
|
||||||
$scale = pow(1000, strlen($matches[2]));
|
|
||||||
|
|
||||||
// strip the commas
|
|
||||||
$format = preg_replace('/0,+/', '0', $format);
|
|
||||||
$format = preg_replace('/#,+/', '#', $format);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preg_match('/#?.*\?\/\?/', $format, $m)) {
|
|
||||||
if ($value != (int) $value) {
|
|
||||||
self::formatAsFraction($value, $format);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Handle the number itself
|
|
||||||
|
|
||||||
// scale number
|
|
||||||
$value = $value / $scale;
|
|
||||||
|
|
||||||
// Strip #
|
|
||||||
$format = preg_replace('/\\#/', '0', $format);
|
|
||||||
|
|
||||||
// Remove locale code [$-###]
|
|
||||||
$format = preg_replace('/\[\$\-.*\]/', '', $format);
|
|
||||||
|
|
||||||
$n = '/\\[[^\\]]+\\]/';
|
|
||||||
$m = preg_replace($n, '', $format);
|
|
||||||
$number_regex = '/(0+)(\\.?)(0*)/';
|
|
||||||
if (preg_match($number_regex, $m, $matches)) {
|
|
||||||
$left = $matches[1];
|
|
||||||
$dec = $matches[2];
|
|
||||||
$right = $matches[3];
|
|
||||||
|
|
||||||
// minimun width of formatted number (including dot)
|
|
||||||
$minWidth = strlen($left) + strlen($dec) + strlen($right);
|
|
||||||
if ($useThousands) {
|
|
||||||
$value = number_format(
|
|
||||||
$value,
|
|
||||||
strlen($right),
|
|
||||||
StringHelper::getDecimalSeparator(),
|
|
||||||
StringHelper::getThousandsSeparator()
|
|
||||||
);
|
|
||||||
$value = preg_replace($number_regex, $value, $format);
|
|
||||||
} else {
|
|
||||||
if (preg_match('/[0#]E[+-]0/i', $format)) {
|
|
||||||
// Scientific format
|
|
||||||
$value = sprintf('%5.2E', $value);
|
|
||||||
} elseif (preg_match('/0([^\d\.]+)0/', $format)) {
|
|
||||||
$value = self::complexNumberFormatMask($value, $format);
|
|
||||||
} else {
|
|
||||||
$sprintf_pattern = "%0$minWidth." . strlen($right) . 'f';
|
|
||||||
$value = sprintf($sprintf_pattern, $value);
|
|
||||||
$value = preg_replace($number_regex, $value, $format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (preg_match('/\[\$(.*)\]/u', $format, $m)) {
|
|
||||||
// Currency or Accounting
|
|
||||||
$currencyCode = $m[1];
|
|
||||||
list($currencyCode) = explode('-', $currencyCode);
|
|
||||||
if ($currencyCode == '') {
|
|
||||||
$currencyCode = StringHelper::getCurrencyCode();
|
|
||||||
}
|
|
||||||
$value = preg_replace('/\[\$([^\]]*)\]/u', $currencyCode, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additional formatting provided by callback function
|
// Additional formatting provided by callback function
|
||||||
if ($callBack !== null) {
|
if ($callBack !== null) {
|
||||||
list($writerInstance, $function) = $callBack;
|
[$writerInstance, $function] = $callBack;
|
||||||
$value = $writerInstance->$function($value, $formatColor);
|
$value = $writerInstance->$function($value, $formatColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -86,7 +86,7 @@ class Protection extends Supervisor
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Protection
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function applyFromArray(array $pStyles)
|
public function applyFromArray(array $pStyles)
|
||||||
{
|
{
|
||||||
@ -123,7 +123,7 @@ class Protection extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param string $pValue see self::PROTECTION_*
|
* @param string $pValue see self::PROTECTION_*
|
||||||
*
|
*
|
||||||
* @return Protection
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setLocked($pValue)
|
public function setLocked($pValue)
|
||||||
{
|
{
|
||||||
@ -156,7 +156,7 @@ class Protection extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param string $pValue see self::PROTECTION_*
|
* @param string $pValue see self::PROTECTION_*
|
||||||
*
|
*
|
||||||
* @return Protection
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setHidden($pValue)
|
public function setHidden($pValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -189,7 +189,7 @@ class Style extends Supervisor
|
|||||||
* @param array $pStyles Array containing style information
|
* @param array $pStyles Array containing style information
|
||||||
* @param bool $pAdvanced advanced mode for setting borders
|
* @param bool $pAdvanced advanced mode for setting borders
|
||||||
*
|
*
|
||||||
* @return Style
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function applyFromArray(array $pStyles, $pAdvanced = true)
|
public function applyFromArray(array $pStyles, $pAdvanced = true)
|
||||||
{
|
{
|
||||||
@ -204,7 +204,7 @@ class Style extends Supervisor
|
|||||||
$rangeA = $pRange;
|
$rangeA = $pRange;
|
||||||
$rangeB = $pRange;
|
$rangeB = $pRange;
|
||||||
} else {
|
} else {
|
||||||
list($rangeA, $rangeB) = explode(':', $pRange);
|
[$rangeA, $rangeB] = explode(':', $pRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate range outer borders
|
// Calculate range outer borders
|
||||||
@ -485,7 +485,7 @@ class Style extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param Font $font
|
* @param Font $font
|
||||||
*
|
*
|
||||||
* @return Style
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setFont(Font $font)
|
public function setFont(Font $font)
|
||||||
{
|
{
|
||||||
@ -539,7 +539,7 @@ class Style extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param Conditional[] $pValue Array of conditional styles
|
* @param Conditional[] $pValue Array of conditional styles
|
||||||
*
|
*
|
||||||
* @return Style
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setConditionalStyles(array $pValue)
|
public function setConditionalStyles(array $pValue)
|
||||||
{
|
{
|
||||||
@ -577,7 +577,7 @@ class Style extends Supervisor
|
|||||||
*
|
*
|
||||||
* @param bool $pValue
|
* @param bool $pValue
|
||||||
*
|
*
|
||||||
* @return Style
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setQuotePrefix($pValue)
|
public function setQuotePrefix($pValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -48,7 +48,7 @@ abstract class Supervisor implements IComparable
|
|||||||
* @param Spreadsheet|Style $parent
|
* @param Spreadsheet|Style $parent
|
||||||
* @param null|string $parentPropertyName
|
* @param null|string $parentPropertyName
|
||||||
*
|
*
|
||||||
* @return Supervisor
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function bindParent($parent, $parentPropertyName = null)
|
public function bindParent($parent, $parentPropertyName = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -59,7 +59,7 @@ class AutoFilter
|
|||||||
*
|
*
|
||||||
* @param Worksheet $pSheet
|
* @param Worksheet $pSheet
|
||||||
*
|
*
|
||||||
* @return AutoFilter
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setParent(Worksheet $pSheet = null)
|
public function setParent(Worksheet $pSheet = null)
|
||||||
{
|
{
|
||||||
@ -85,12 +85,12 @@ class AutoFilter
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return AutoFilter
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setRange($pRange)
|
public function setRange($pRange)
|
||||||
{
|
{
|
||||||
// extract coordinate
|
// extract coordinate
|
||||||
list($worksheet, $pRange) = Worksheet::extractSheetTitle($pRange, true);
|
[$worksheet, $pRange] = Worksheet::extractSheetTitle($pRange, true);
|
||||||
|
|
||||||
if (strpos($pRange, ':') !== false) {
|
if (strpos($pRange, ':') !== false) {
|
||||||
$this->range = $pRange;
|
$this->range = $pRange;
|
||||||
@ -105,7 +105,7 @@ class AutoFilter
|
|||||||
$this->columns = [];
|
$this->columns = [];
|
||||||
} else {
|
} else {
|
||||||
// Discard any column rules that are no longer valid within this range
|
// Discard any column rules that are no longer valid within this range
|
||||||
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($this->range);
|
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range);
|
||||||
foreach ($this->columns as $key => $value) {
|
foreach ($this->columns as $key => $value) {
|
||||||
$colIndex = Coordinate::columnIndexFromString($key);
|
$colIndex = Coordinate::columnIndexFromString($key);
|
||||||
if (($rangeStart[0] > $colIndex) || ($rangeEnd[0] < $colIndex)) {
|
if (($rangeStart[0] > $colIndex) || ($rangeEnd[0] < $colIndex)) {
|
||||||
@ -143,7 +143,7 @@ class AutoFilter
|
|||||||
}
|
}
|
||||||
|
|
||||||
$columnIndex = Coordinate::columnIndexFromString($column);
|
$columnIndex = Coordinate::columnIndexFromString($column);
|
||||||
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($this->range);
|
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range);
|
||||||
if (($rangeStart[0] > $columnIndex) || ($rangeEnd[0] < $columnIndex)) {
|
if (($rangeStart[0] > $columnIndex) || ($rangeEnd[0] < $columnIndex)) {
|
||||||
throw new PhpSpreadsheetException('Column is outside of current autofilter range.');
|
throw new PhpSpreadsheetException('Column is outside of current autofilter range.');
|
||||||
}
|
}
|
||||||
@ -196,7 +196,7 @@ class AutoFilter
|
|||||||
*/
|
*/
|
||||||
public function getColumnByOffset($pColumnOffset)
|
public function getColumnByOffset($pColumnOffset)
|
||||||
{
|
{
|
||||||
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($this->range);
|
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range);
|
||||||
$pColumn = Coordinate::stringFromColumnIndex($rangeStart[0] + $pColumnOffset);
|
$pColumn = Coordinate::stringFromColumnIndex($rangeStart[0] + $pColumnOffset);
|
||||||
|
|
||||||
return $this->getColumn($pColumn);
|
return $this->getColumn($pColumn);
|
||||||
@ -210,7 +210,7 @@ class AutoFilter
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return AutoFilter
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setColumn($pColumn)
|
public function setColumn($pColumn)
|
||||||
{
|
{
|
||||||
@ -241,7 +241,7 @@ class AutoFilter
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return AutoFilter
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function clearColumn($pColumn)
|
public function clearColumn($pColumn)
|
||||||
{
|
{
|
||||||
@ -264,7 +264,7 @@ class AutoFilter
|
|||||||
* @param string $fromColumn Column name (e.g. A)
|
* @param string $fromColumn Column name (e.g. A)
|
||||||
* @param string $toColumn Column name (e.g. B)
|
* @param string $toColumn Column name (e.g. B)
|
||||||
*
|
*
|
||||||
* @return AutoFilter
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function shiftColumn($fromColumn, $toColumn)
|
public function shiftColumn($fromColumn, $toColumn)
|
||||||
{
|
{
|
||||||
@ -357,7 +357,7 @@ class AutoFilter
|
|||||||
{
|
{
|
||||||
$dataSet = $ruleSet['filterRules'];
|
$dataSet = $ruleSet['filterRules'];
|
||||||
$join = $ruleSet['join'];
|
$join = $ruleSet['join'];
|
||||||
$customRuleForBlanks = isset($ruleSet['customRuleForBlanks']) ? $ruleSet['customRuleForBlanks'] : false;
|
$customRuleForBlanks = $ruleSet['customRuleForBlanks'] ?? false;
|
||||||
|
|
||||||
if (!$customRuleForBlanks) {
|
if (!$customRuleForBlanks) {
|
||||||
// Blank cells are always ignored, so return a FALSE
|
// Blank cells are always ignored, so return a FALSE
|
||||||
@ -617,11 +617,11 @@ class AutoFilter
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return AutoFilter
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function showHideRows()
|
public function showHideRows()
|
||||||
{
|
{
|
||||||
list($rangeStart, $rangeEnd) = Coordinate::rangeBoundaries($this->range);
|
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range);
|
||||||
|
|
||||||
// The heading row should always be visible
|
// The heading row should always be visible
|
||||||
$this->workSheet->getRowDimension($rangeStart[1])->setVisible(true);
|
$this->workSheet->getRowDimension($rangeStart[1])->setVisible(true);
|
||||||
|
|||||||
@ -101,7 +101,7 @@ class Column
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get AutoFilter Column Index.
|
* Get AutoFilter column index as string eg: 'A'.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -111,13 +111,13 @@ class Column
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set AutoFilter Column Index.
|
* Set AutoFilter column index as string eg: 'A'.
|
||||||
*
|
*
|
||||||
* @param string $pColumn Column (e.g. A)
|
* @param string $pColumn Column (e.g. A)
|
||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Column
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setColumnIndex($pColumn)
|
public function setColumnIndex($pColumn)
|
||||||
{
|
{
|
||||||
@ -147,7 +147,7 @@ class Column
|
|||||||
*
|
*
|
||||||
* @param AutoFilter $pParent
|
* @param AutoFilter $pParent
|
||||||
*
|
*
|
||||||
* @return Column
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setParent(AutoFilter $pParent = null)
|
public function setParent(AutoFilter $pParent = null)
|
||||||
{
|
{
|
||||||
@ -173,7 +173,7 @@ class Column
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Column
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setFilterType($pFilterType)
|
public function setFilterType($pFilterType)
|
||||||
{
|
{
|
||||||
@ -203,7 +203,7 @@ class Column
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Column
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setJoin($pJoin)
|
public function setJoin($pJoin)
|
||||||
{
|
{
|
||||||
@ -223,7 +223,7 @@ class Column
|
|||||||
*
|
*
|
||||||
* @param string[] $attributes
|
* @param string[] $attributes
|
||||||
*
|
*
|
||||||
* @return Column
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setAttributes(array $attributes)
|
public function setAttributes(array $attributes)
|
||||||
{
|
{
|
||||||
@ -238,7 +238,7 @@ class Column
|
|||||||
* @param string $pName Attribute Name
|
* @param string $pName Attribute Name
|
||||||
* @param string $pValue Attribute Value
|
* @param string $pValue Attribute Value
|
||||||
*
|
*
|
||||||
* @return Column
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setAttribute($pName, $pValue)
|
public function setAttribute($pName, $pValue)
|
||||||
{
|
{
|
||||||
@ -316,7 +316,7 @@ class Column
|
|||||||
*
|
*
|
||||||
* @param Column\Rule $pRule
|
* @param Column\Rule $pRule
|
||||||
*
|
*
|
||||||
* @return Column
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function addRule(Column\Rule $pRule)
|
public function addRule(Column\Rule $pRule)
|
||||||
{
|
{
|
||||||
@ -332,7 +332,7 @@ class Column
|
|||||||
*
|
*
|
||||||
* @param int $pIndex Rule index in the ruleset array
|
* @param int $pIndex Rule index in the ruleset array
|
||||||
*
|
*
|
||||||
* @return Column
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function deleteRule($pIndex)
|
public function deleteRule($pIndex)
|
||||||
{
|
{
|
||||||
@ -350,7 +350,7 @@ class Column
|
|||||||
/**
|
/**
|
||||||
* Delete all AutoFilter Column Rules.
|
* Delete all AutoFilter Column Rules.
|
||||||
*
|
*
|
||||||
* @return Column
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function clearRules()
|
public function clearRules()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -262,7 +262,7 @@ class Rule
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Rule
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setRuleType($pRuleType)
|
public function setRuleType($pRuleType)
|
||||||
{
|
{
|
||||||
@ -292,7 +292,7 @@ class Rule
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Rule
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setValue($pValue)
|
public function setValue($pValue)
|
||||||
{
|
{
|
||||||
@ -336,7 +336,7 @@ class Rule
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Rule
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setOperator($pOperator)
|
public function setOperator($pOperator)
|
||||||
{
|
{
|
||||||
@ -369,7 +369,7 @@ class Rule
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Rule
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setGrouping($pGrouping)
|
public function setGrouping($pGrouping)
|
||||||
{
|
{
|
||||||
@ -393,7 +393,7 @@ class Rule
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return Rule
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setRule($pOperator, $pValue, $pGrouping = null)
|
public function setRule($pOperator, $pValue, $pGrouping = null)
|
||||||
{
|
{
|
||||||
@ -424,7 +424,7 @@ class Rule
|
|||||||
*
|
*
|
||||||
* @param Column $pParent
|
* @param Column $pParent
|
||||||
*
|
*
|
||||||
* @return Rule
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setParent(Column $pParent = null)
|
public function setParent(Column $pParent = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -154,7 +154,7 @@ class BaseDrawing implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string $pValue
|
* @param string $pValue
|
||||||
*
|
*
|
||||||
* @return BaseDrawing
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setName($pValue)
|
public function setName($pValue)
|
||||||
{
|
{
|
||||||
@ -178,7 +178,7 @@ class BaseDrawing implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string $description
|
* @param string $description
|
||||||
*
|
*
|
||||||
* @return BaseDrawing
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setDescription($description)
|
public function setDescription($description)
|
||||||
{
|
{
|
||||||
@ -205,7 +205,7 @@ class BaseDrawing implements IComparable
|
|||||||
*
|
*
|
||||||
* @throws PhpSpreadsheetException
|
* @throws PhpSpreadsheetException
|
||||||
*
|
*
|
||||||
* @return BaseDrawing
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setWorksheet(Worksheet $pValue = null, $pOverrideOld = false)
|
public function setWorksheet(Worksheet $pValue = null, $pOverrideOld = false)
|
||||||
{
|
{
|
||||||
@ -253,7 +253,7 @@ class BaseDrawing implements IComparable
|
|||||||
*
|
*
|
||||||
* @param string $pValue eg: 'A1'
|
* @param string $pValue eg: 'A1'
|
||||||
*
|
*
|
||||||
* @return BaseDrawing
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setCoordinates($pValue)
|
public function setCoordinates($pValue)
|
||||||
{
|
{
|
||||||
@ -277,7 +277,7 @@ class BaseDrawing implements IComparable
|
|||||||
*
|
*
|
||||||
* @param int $pValue
|
* @param int $pValue
|
||||||
*
|
*
|
||||||
* @return BaseDrawing
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setOffsetX($pValue)
|
public function setOffsetX($pValue)
|
||||||
{
|
{
|
||||||
@ -301,7 +301,7 @@ class BaseDrawing implements IComparable
|
|||||||
*
|
*
|
||||||
* @param int $pValue
|
* @param int $pValue
|
||||||
*
|
*
|
||||||
* @return BaseDrawing
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setOffsetY($pValue)
|
public function setOffsetY($pValue)
|
||||||
{
|
{
|
||||||
@ -325,7 +325,7 @@ class BaseDrawing implements IComparable
|
|||||||
*
|
*
|
||||||
* @param int $pValue
|
* @param int $pValue
|
||||||
*
|
*
|
||||||
* @return BaseDrawing
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setWidth($pValue)
|
public function setWidth($pValue)
|
||||||
{
|
{
|
||||||
@ -356,7 +356,7 @@ class BaseDrawing implements IComparable
|
|||||||
*
|
*
|
||||||
* @param int $pValue
|
* @param int $pValue
|
||||||
*
|
*
|
||||||
* @return BaseDrawing
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setHeight($pValue)
|
public function setHeight($pValue)
|
||||||
{
|
{
|
||||||
@ -386,7 +386,7 @@ class BaseDrawing implements IComparable
|
|||||||
* @param int $width
|
* @param int $width
|
||||||
* @param int $height
|
* @param int $height
|
||||||
*
|
*
|
||||||
* @return BaseDrawing
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setWidthAndHeight($width, $height)
|
public function setWidthAndHeight($width, $height)
|
||||||
{
|
{
|
||||||
@ -423,7 +423,7 @@ class BaseDrawing implements IComparable
|
|||||||
*
|
*
|
||||||
* @param bool $pValue
|
* @param bool $pValue
|
||||||
*
|
*
|
||||||
* @return BaseDrawing
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setResizeProportional($pValue)
|
public function setResizeProportional($pValue)
|
||||||
{
|
{
|
||||||
@ -447,7 +447,7 @@ class BaseDrawing implements IComparable
|
|||||||
*
|
*
|
||||||
* @param int $pValue
|
* @param int $pValue
|
||||||
*
|
*
|
||||||
* @return BaseDrawing
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setRotation($pValue)
|
public function setRotation($pValue)
|
||||||
{
|
{
|
||||||
@ -471,7 +471,7 @@ class BaseDrawing implements IComparable
|
|||||||
*
|
*
|
||||||
* @param Drawing\Shadow $pValue
|
* @param Drawing\Shadow $pValue
|
||||||
*
|
*
|
||||||
* @return BaseDrawing
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShadow(Drawing\Shadow $pValue = null)
|
public function setShadow(Drawing\Shadow $pValue = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -40,7 +40,7 @@ class Column
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get column index.
|
* Get column index as string eg: 'A'.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user