Introduce PHPStan

To improve the feedback loop on code quality with a process
that can be run locally by the developers, instead of only
on Scrutinizer.
This commit is contained in:
Adrien Crivelli 2021-03-28 20:35:40 +09:00
parent a2bb825bc5
commit a189d933f2
No known key found for this signature in database
GPG Key ID: 16D79B903B4B5874
34 changed files with 370 additions and 212 deletions

View File

@ -124,6 +124,37 @@ jobs:
- name: Code style with PHP_CodeSniffer - name: Code style with PHP_CodeSniffer
run: ./vendor/bin/phpcs -q --report=checkstyle | cs2pr run: ./vendor/bin/phpcs -q --report=checkstyle | cs2pr
phpstan:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup PHP, with composer and extensions
uses: shivammathur/setup-php@v2
with:
php-version: 7.4
extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib
coverage: none
tools: cs2pr
- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache composer dependencies
uses: actions/cache@v2
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install dependencies
run: composer install --no-progress --prefer-dist --optimize-autoloader
- name: Static analysis with PHPStan
run: ./vendor/bin/phpstan analyse
coverage: coverage:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View File

@ -41,7 +41,8 @@
"check": [ "check": [
"php-cs-fixer fix --ansi --dry-run --diff", "php-cs-fixer fix --ansi --dry-run --diff",
"phpcs", "phpcs",
"phpunit --color=always" "phpunit --color=always",
"phpstan analyse --ansi"
], ],
"fix": [ "fix": [
"php-cs-fixer fix --ansi" "php-cs-fixer fix --ansi"
@ -79,6 +80,7 @@
"jpgraph/jpgraph": "^4.0", "jpgraph/jpgraph": "^4.0",
"mpdf/mpdf": "^8.0", "mpdf/mpdf": "^8.0",
"phpcompatibility/php-compatibility": "^9.3", "phpcompatibility/php-compatibility": "^9.3",
"phpstan/phpstan": "^0.12.82",
"phpunit/phpunit": "^8.5", "phpunit/phpunit": "^8.5",
"squizlabs/php_codesniffer": "^3.5", "squizlabs/php_codesniffer": "^3.5",
"tecnickcom/tcpdf": "^6.3" "tecnickcom/tcpdf": "^6.3"

62
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "6c8f34baf3385a533fade30a9a9ad6f1", "content-hash": "89b62d75519340c289a3a763245f1ca0",
"packages": [ "packages": [
{ {
"name": "ezyang/htmlpurifier", "name": "ezyang/htmlpurifier",
@ -1963,6 +1963,66 @@
}, },
"time": "2021-03-17T13:42:18+00:00" "time": "2021-03-17T13:42:18+00:00"
}, },
{
"name": "phpstan/phpstan",
"version": "0.12.82",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "3920f0fb0aff39263d3a4cb0bca120a67a1a6a11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/3920f0fb0aff39263d3a4cb0bca120a67a1a6a11",
"reference": "3920f0fb0aff39263d3a4cb0bca120a67a1a6a11",
"shasum": ""
},
"require": {
"php": "^7.1|^8.0"
},
"conflict": {
"phpstan/phpstan-shim": "*"
},
"bin": [
"phpstan",
"phpstan.phar"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.12-dev"
}
},
"autoload": {
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPStan - PHP Static Analysis Tool",
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/0.12.82"
},
"funding": [
{
"url": "https://github.com/ondrejmirtes",
"type": "github"
},
{
"url": "https://www.patreon.com/phpstan",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan",
"type": "tidelift"
}
],
"time": "2021-03-19T06:08:17+00:00"
},
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "7.0.14", "version": "7.0.14",

11
phpstan.neon.dist Normal file
View File

@ -0,0 +1,11 @@
parameters:
level: 1
paths:
- src/
- tests/
ignoreErrors:
- '~^Class GdImage not found\.$~'
# Ignore all JpGraph issues
- '~^Constant (MARK_CIRCLE|MARK_CROSS|MARK_DIAMOND|MARK_DTRIANGLE|MARK_FILLEDCIRCLE|MARK_SQUARE|MARK_STAR|MARK_UTRIANGLE|MARK_X|SIDE_RIGHT) not found\.$~'
- '~^Instantiated class (AccBarPlot|AccLinePlot|BarPlot|ContourPlot|Graph|GroupBarPlot|GroupBarPlot|LinePlot|LinePlot|PieGraph|PiePlot|PiePlot3D|PiePlotC|RadarGraph|RadarPlot|ScatterPlot|Spline|StockPlot) not found\.$~'

View File

@ -3154,6 +3154,7 @@ class Calculation
// Return Excel errors "as is" // Return Excel errors "as is"
return $value; return $value;
} }
// Return strings wrapped in quotes // Return strings wrapped in quotes
return self::FORMULA_STRING_QUOTE . $value . self::FORMULA_STRING_QUOTE; return self::FORMULA_STRING_QUOTE . $value . self::FORMULA_STRING_QUOTE;
} elseif ((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) { } elseif ((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
@ -3939,6 +3940,7 @@ class Calculation
} }
// Check the argument count // Check the argument count
$argumentCountError = false; $argumentCountError = false;
$expectedArgumentCountString = null;
if (is_numeric($expectedArgumentCount)) { if (is_numeric($expectedArgumentCount)) {
if ($expectedArgumentCount < 0) { if ($expectedArgumentCount < 0) {
if ($argumentCount > abs($expectedArgumentCount)) { if ($argumentCount > abs($expectedArgumentCount)) {
@ -4645,6 +4647,9 @@ class Calculation
$this->debugLog->writeDebugLog('Evaluating Function ', self::localeFunc($functionName), '() with ', (($argCount == 0) ? 'no' : $argCount), ' argument', (($argCount == 1) ? '' : 's')); $this->debugLog->writeDebugLog('Evaluating Function ', self::localeFunc($functionName), '() with ', (($argCount == 0) ? 'no' : $argCount), ' argument', (($argCount == 1) ? '' : 's'));
} }
if ((isset(self::$phpSpreadsheetFunctions[$functionName])) || (isset(self::$controlFunctions[$functionName]))) { // function if ((isset(self::$phpSpreadsheetFunctions[$functionName])) || (isset(self::$controlFunctions[$functionName]))) { // function
$passByReference = false;
$passCellReference = false;
$functionCall = null;
if (isset(self::$phpSpreadsheetFunctions[$functionName])) { if (isset(self::$phpSpreadsheetFunctions[$functionName])) {
$functionCall = self::$phpSpreadsheetFunctions[$functionName]['functionCall']; $functionCall = self::$phpSpreadsheetFunctions[$functionName]['functionCall'];
$passByReference = isset(self::$phpSpreadsheetFunctions[$functionName]['passByReference']); $passByReference = isset(self::$phpSpreadsheetFunctions[$functionName]['passByReference']);
@ -4945,6 +4950,9 @@ class Calculation
} }
break; break;
default:
throw new Exception('Unsupported binary comparison operation');
} }
// Log the result details // Log the result details
@ -5062,6 +5070,9 @@ class Calculation
$result = $operand1 ** $operand2; $result = $operand1 ** $operand2;
break; break;
default:
throw new Exception('Unsupported numeric binary operation');
} }
} }
} }

View File

@ -651,7 +651,7 @@ class DateTime
* *
* Returns the ISO 8601 week number of the year for a specified date. * Returns the ISO 8601 week number of the year for a specified date.
* *
* @Deprecated 2.0.0 Use the funcIsoWeeknum method in the DateTimeExcel\Isoweeknum class instead * @Deprecated 2.0.0 Use the funcIsoWeeknum method in the DateTimeExcel\IsoWeekNum class instead
* *
* Excel Function: * Excel Function:
* ISOWEEKNUM(dateValue) * ISOWEEKNUM(dateValue)
@ -663,7 +663,7 @@ class DateTime
*/ */
public static function ISOWEEKNUM($dateValue = 1) public static function ISOWEEKNUM($dateValue = 1)
{ {
return DateTimeExcel\IsoweekNum::funcIsoWeekNum($dateValue); return DateTimeExcel\IsoWeekNum::funcIsoWeekNum($dateValue);
} }
/** /**

View File

@ -20,6 +20,8 @@ class Financial
{ {
$pmt = self::PMT($rate, $nper, $pv, $fv, $type); $pmt = self::PMT($rate, $nper, $pv, $fv, $type);
$capital = $pv; $capital = $pv;
$interest = 0;
$principal = 0;
for ($i = 1; $i <= $per; ++$i) { for ($i = 1; $i <= $per; ++$i) {
$interest = ($type && $i == 1) ? 0 : -$capital * $rate; $interest = ($type && $i == 1) ? 0 : -$capital * $rate;
$principal = $pmt - $interest; $principal = $pmt - $interest;

View File

@ -301,6 +301,8 @@ class JpGraph implements IRenderer
$seriesPlots = []; $seriesPlots = [];
if ($grouping == 'percentStacked') { if ($grouping == 'percentStacked') {
$sumValues = $this->percentageSumCalculation($groupID, $seriesCount); $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
} else {
$sumValues = [];
} }
// Loop through each data series in turn // Loop through each data series in turn
@ -376,6 +378,8 @@ class JpGraph implements IRenderer
$seriesPlots = []; $seriesPlots = [];
if ($grouping == 'percentStacked') { if ($grouping == 'percentStacked') {
$sumValues = $this->percentageSumCalculation($groupID, $seriesCount); $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
} else {
$sumValues = [];
} }
// Loop through each data series in turn // Loop through each data series in turn

View File

@ -120,7 +120,7 @@ abstract class IOFactory
$reader = self::createReader($guessedReader); $reader = self::createReader($guessedReader);
// Let's see if we are lucky // Let's see if we are lucky
if (isset($reader) && $reader->canRead($filename)) { if ($reader->canRead($filename)) {
return $reader; return $reader;
} }
} }

View File

@ -801,9 +801,10 @@ class Xls extends BaseReader
} }
// treat MSODRAWINGGROUP records, workbook-level Escher // treat MSODRAWINGGROUP records, workbook-level Escher
$escherWorkbook = null;
if (!$this->readDataOnly && $this->drawingGroupData) { if (!$this->readDataOnly && $this->drawingGroupData) {
$escherWorkbook = new Escher(); $escher = new Escher();
$reader = new Xls\Escher($escherWorkbook); $reader = new Xls\Escher($escher);
$escherWorkbook = $reader->load($this->drawingGroupData); $escherWorkbook = $reader->load($this->drawingGroupData);
} }
@ -1133,6 +1134,7 @@ class Xls extends BaseReader
continue 2; continue 2;
} }
if ($escherWorkbook) {
$BSECollection = $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection(); $BSECollection = $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection();
$BSE = $BSECollection[$BSEindex - 1]; $BSE = $BSECollection[$BSEindex - 1];
$blipType = $BSE->getBlipType(); $blipType = $BSE->getBlipType();
@ -1166,6 +1168,7 @@ class Xls extends BaseReader
$drawing->setWorksheet($this->phpSheet); $drawing->setWorksheet($this->phpSheet);
$drawing->setCoordinates($spContainer->getStartCoordinates()); $drawing->setCoordinates($spContainer->getStartCoordinates());
} }
}
break; break;
default: default:
@ -2742,6 +2745,7 @@ class Xls extends BaseReader
$sheetType = ord($recordData[5]); $sheetType = ord($recordData[5]);
// offset: 6; size: var; sheet name // offset: 6; size: var; sheet name
$rec_name = null;
if ($this->version == self::XLS_BIFF8) { if ($this->version == self::XLS_BIFF8) {
$string = self::readUnicodeStringShort(substr($recordData, 6)); $string = self::readUnicodeStringShort(substr($recordData, 6));
$rec_name = $string['value']; $rec_name = $string['value'];
@ -3018,12 +3022,14 @@ class Xls extends BaseReader
// bit: 3; mask: 0x03; 0 = ordinary; 1 = Rich-Text // bit: 3; mask: 0x03; 0 = ordinary; 1 = Rich-Text
$hasRichText = (($optionFlags & 0x08) != 0); $hasRichText = (($optionFlags & 0x08) != 0);
$formattingRuns = 0;
if ($hasRichText) { if ($hasRichText) {
// number of Rich-Text formatting runs // number of Rich-Text formatting runs
$formattingRuns = self::getUInt2d($recordData, $pos); $formattingRuns = self::getUInt2d($recordData, $pos);
$pos += 2; $pos += 2;
} }
$extendedRunLength = 0;
if ($hasAsian) { if ($hasAsian) {
// size of Asian phonetic setting // size of Asian phonetic setting
$extendedRunLength = self::getInt4d($recordData, $pos); $extendedRunLength = self::getInt4d($recordData, $pos);
@ -3034,6 +3040,7 @@ class Xls extends BaseReader
$len = ($isCompressed) ? $numChars : $numChars * 2; $len = ($isCompressed) ? $numChars : $numChars * 2;
// look up limit position - Check it again to be sure that no error occurs when parsing SST structure // look up limit position - Check it again to be sure that no error occurs when parsing SST structure
$limitpos = null;
foreach ($spliceOffsets as $spliceOffset) { foreach ($spliceOffsets as $spliceOffset) {
// it can happen that the string is empty, therefore we need // it can happen that the string is empty, therefore we need
// <= and not just < // <= and not just <
@ -4385,6 +4392,8 @@ class Xls extends BaseReader
// offset: 4; size: 2; index to first visible colum // offset: 4; size: 2; index to first visible colum
$firstVisibleColumn = self::getUInt2d($recordData, 4); $firstVisibleColumn = self::getUInt2d($recordData, 4);
$zoomscaleInPageBreakPreview = 0;
$zoomscaleInNormalView = 0;
if ($this->version === self::XLS_BIFF8) { if ($this->version === self::XLS_BIFF8) {
// offset: 8; size: 2; not used // offset: 8; size: 2; not used
// offset: 10; size: 2; cached magnification factor in page break preview (in percent); 0 = Default (60%) // offset: 10; size: 2; cached magnification factor in page break preview (in percent); 0 = Default (60%)
@ -7636,6 +7645,8 @@ class Xls extends BaseReader
$size = 9; $size = 9;
break; break;
default:
throw new PhpSpreadsheetException('Unsupported BIFF8 constant');
} }
return [ return [

View File

@ -20,7 +20,7 @@ class Color
if ($color <= 0x07 || $color >= 0x40) { if ($color <= 0x07 || $color >= 0x40) {
// special built-in color // special built-in color
return Color\BuiltIn::lookup($color); return Color\BuiltIn::lookup($color);
} elseif (isset($palette, $palette[$color - 8])) { } elseif (isset($palette[$color - 8])) {
// palette color, color index 0x08 maps to pallete index 0 // palette color, color index 0x08 maps to pallete index 0
return $palette[$color - 8]; return $palette[$color - 8];
} }

View File

@ -430,7 +430,7 @@ class Xlsx extends BaseReader
'SimpleXMLElement', 'SimpleXMLElement',
Settings::getLibXmlLoaderOptions() Settings::getLibXmlLoaderOptions()
); );
if (isset($xmlStrings, $xmlStrings->si)) { if (isset($xmlStrings->si)) {
foreach ($xmlStrings->si as $val) { foreach ($xmlStrings->si as $val) {
if (isset($val->t)) { if (isset($val->t)) {
$sharedStrings[] = StringHelper::controlCharacterOOXML2PHP((string) $val->t); $sharedStrings[] = StringHelper::controlCharacterOOXML2PHP((string) $val->t);
@ -511,10 +511,7 @@ class Xlsx extends BaseReader
$numFmt = NumberFormat::builtInFormatCode((int) $xf['numFmtId']); $numFmt = NumberFormat::builtInFormatCode((int) $xf['numFmtId']);
} }
} }
$quotePrefix = false; $quotePrefix = (bool) ($xf['quotePrefix'] ?? false);
if (isset($xf['quotePrefix'])) {
$quotePrefix = (bool) $xf['quotePrefix'];
}
$style = (object) [ $style = (object) [
'numFmt' => $numFmt ?? NumberFormat::FORMAT_GENERAL, 'numFmt' => $numFmt ?? NumberFormat::FORMAT_GENERAL,
@ -544,6 +541,8 @@ class Xlsx extends BaseReader
} }
} }
$quotePrefix = (bool) ($xf['quotePrefix'] ?? false);
$cellStyle = (object) [ $cellStyle = (object) [
'numFmt' => $numFmt, 'numFmt' => $numFmt,
'font' => $xmlStyles->fonts->font[(int) ($xf['fontId'])], 'font' => $xmlStyles->fonts->font[(int) ($xf['fontId'])],
@ -1081,6 +1080,7 @@ class Xlsx extends BaseReader
} }
if ($xmlSheet->drawing && !$this->readDataOnly) { if ($xmlSheet->drawing && !$this->readDataOnly) {
$unparsedDrawings = []; $unparsedDrawings = [];
$fileDrawing = null;
foreach ($xmlSheet->drawing as $drawing) { foreach ($xmlSheet->drawing as $drawing) {
$drawingRelId = (string) self::getArrayItem($drawing->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id'); $drawingRelId = (string) self::getArrayItem($drawing->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id');
$fileDrawing = $drawings[$drawingRelId]; $fileDrawing = $drawings[$drawingRelId];

View File

@ -61,7 +61,7 @@ class Chart
$XaxisLabel = $YaxisLabel = $legend = $title = null; $XaxisLabel = $YaxisLabel = $legend = $title = null;
$dispBlanksAs = $plotVisOnly = null; $dispBlanksAs = $plotVisOnly = null;
$plotArea = null;
foreach ($chartElementsC as $chartElementKey => $chartElement) { foreach ($chartElementsC as $chartElementKey => $chartElement) {
switch ($chartElementKey) { switch ($chartElementKey) {
case 'chart': case 'chart':

View File

@ -436,6 +436,7 @@ class Xml extends BaseReader
// Create new Worksheet // Create new Worksheet
$spreadsheet->createSheet(); $spreadsheet->createSheet();
$spreadsheet->setActiveSheetIndex($worksheetID); $spreadsheet->setActiveSheetIndex($worksheetID);
$worksheetName = '';
if (isset($worksheet_ss['Name'])) { if (isset($worksheet_ss['Name'])) {
$worksheetName = (string) $worksheet_ss['Name']; $worksheetName = (string) $worksheet_ss['Name'];
// Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in // Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in

View File

@ -171,6 +171,8 @@ class Drawing
// Process the header // Process the header
// Structure: http://www.fastgraph.com/help/bmp_header_format.html // Structure: http://www.fastgraph.com/help/bmp_header_format.html
$width = 0;
$height = 0;
if (substr($header, 0, 4) == '424d') { if (substr($header, 0, 4) == '424d') {
// Cut it in parts of 2 bytes // Cut it in parts of 2 bytes
$header_parts = str_split($header, 2); $header_parts = str_split($header, 2);

View File

@ -244,6 +244,7 @@ class Font
// Try to get the exact text width in pixels // Try to get the exact text width in pixels
$approximate = self::$autoSizeMethod == self::AUTOSIZE_METHOD_APPROX; $approximate = self::$autoSizeMethod == self::AUTOSIZE_METHOD_APPROX;
$columnWidth = 0;
if (!$approximate) { if (!$approximate) {
$columnWidthAdjust = ceil(self::getTextWidthPixelsExact('n', $font, 0) * 1.07); $columnWidthAdjust = ceil(self::getTextWidthPixelsExact('n', $font, 0) * 1.07);

View File

@ -70,6 +70,11 @@ class EigenvalueDecomposition
private $cdivi; private $cdivi;
/**
* @var array
*/
private $A;
/** /**
* Symmetric Householder reduction to tridiagonal form. * Symmetric Householder reduction to tridiagonal form.
*/ */
@ -80,6 +85,7 @@ class EigenvalueDecomposition
// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
// Fortran subroutine in EISPACK. // Fortran subroutine in EISPACK.
$this->d = $this->V[$this->n - 1]; $this->d = $this->V[$this->n - 1];
$j = 0;
// Householder reduction to tridiagonal form. // Householder reduction to tridiagonal form.
for ($i = $this->n - 1; $i > 0; --$i) { for ($i = $this->n - 1; $i > 0; --$i) {
$i_ = $i - 1; $i_ = $i - 1;
@ -781,9 +787,9 @@ class EigenvalueDecomposition
/** /**
* Constructor: Check for symmetry, then construct the eigenvalue decomposition. * Constructor: Check for symmetry, then construct the eigenvalue decomposition.
* *
* @param mixed $Arg A Square matrix * @param Matrix $Arg A Square matrix
*/ */
public function __construct($Arg) public function __construct(Matrix $Arg)
{ {
$this->A = $Arg->getArray(); $this->A = $Arg->getArray();
$this->n = $Arg->getColumnDimension(); $this->n = $Arg->getColumnDimension();
@ -848,6 +854,7 @@ class EigenvalueDecomposition
*/ */
public function getD() public function getD()
{ {
$D = [];
for ($i = 0; $i < $this->n; ++$i) { for ($i = 0; $i < $this->n; ++$i) {
$D[$i] = array_fill(0, $this->n, 0.0); $D[$i] = array_fill(0, $this->n, 0.0);
$D[$i][$i] = $this->d[$i]; $D[$i][$i] = $this->d[$i];

View File

@ -135,6 +135,7 @@ class LUDecomposition
*/ */
public function getL() public function getL()
{ {
$L = [];
for ($i = 0; $i < $this->m; ++$i) { for ($i = 0; $i < $this->m; ++$i) {
for ($j = 0; $j < $this->n; ++$j) { for ($j = 0; $j < $this->n; ++$j) {
if ($i > $j) { if ($i > $j) {
@ -159,6 +160,7 @@ class LUDecomposition
*/ */
public function getU() public function getU()
{ {
$U = [];
for ($i = 0; $i < $this->n; ++$i) { for ($i = 0; $i < $this->n; ++$i) {
for ($j = 0; $j < $this->n; ++$j) { for ($j = 0; $j < $this->n; ++$j) {
if ($i <= $j) { if ($i <= $j) {

View File

@ -476,6 +476,7 @@ class SingularValueDecomposition
*/ */
public function getS() public function getS()
{ {
$S = [];
for ($i = 0; $i < $this->n; ++$i) { for ($i = 0; $i < $this->n; ++$i) {
for ($j = 0; $j < $this->n; ++$j) { for ($j = 0; $j < $this->n; ++$j) {
$S[$i][$j] = 0.0; $S[$i][$j] = 0.0;

View File

@ -21,6 +21,7 @@ namespace PhpOffice\PhpSpreadsheet\Shared;
// +----------------------------------------------------------------------+ // +----------------------------------------------------------------------+
// //
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException; use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
use PhpOffice\PhpSpreadsheet\Shared\OLE\ChainedBlockStream; use PhpOffice\PhpSpreadsheet\Shared\OLE\ChainedBlockStream;
use PhpOffice\PhpSpreadsheet\Shared\OLE\PPS\Root; use PhpOffice\PhpSpreadsheet\Shared\OLE\PPS\Root;
@ -317,7 +318,7 @@ class OLE
break; break;
default: default:
break; throw new Exception('Unsupported PPS type');
} }
fseek($fh, 1, SEEK_CUR); fseek($fh, 1, SEEK_CUR);
$pps->Type = $type; $pps->Type = $type;
@ -496,7 +497,7 @@ class OLE
*/ */
public static function localDateToOLE($date) public static function localDateToOLE($date)
{ {
if (!isset($date)) { if (!$date) {
return "\x00\x00\x00\x00\x00\x00\x00\x00"; return "\x00\x00\x00\x00\x00\x00\x00\x00";
} }

View File

@ -91,6 +91,8 @@ class Trend
case self::TREND_BEST_FIT_NO_POLY: case self::TREND_BEST_FIT_NO_POLY:
// If the request is to determine the best fit regression, then we test each Trend line in turn // If the request is to determine the best fit regression, then we test each Trend line in turn
// Start by generating an instance of each available Trend method // Start by generating an instance of each available Trend method
$bestFit = [];
$bestFitValue = [];
foreach (self::$trendTypes as $trendMethod) { foreach (self::$trendTypes as $trendMethod) {
$className = '\PhpOffice\PhpSpreadsheet\Shared\Trend\\' . $trendType . 'BestFit'; $className = '\PhpOffice\PhpSpreadsheet\Shared\Trend\\' . $trendType . 'BestFit';
$bestFit[$trendMethod] = new $className($yValues, $xValues, $const); $bestFit[$trendMethod] = new $className($yValues, $xValues, $const);

View File

@ -55,7 +55,7 @@ class Spreadsheet
/** /**
* Calculation Engine. * Calculation Engine.
* *
* @var Calculation * @var null|Calculation
*/ */
private $calculationEngine; private $calculationEngine;
@ -505,8 +505,8 @@ class Spreadsheet
*/ */
public function __destruct() public function __destruct()
{ {
$this->calculationEngine = null;
$this->disconnectWorksheets(); $this->disconnectWorksheets();
$this->calculationEngine = null;
} }
/** /**
@ -527,7 +527,7 @@ class Spreadsheet
/** /**
* Return the calculation engine for this worksheet. * Return the calculation engine for this worksheet.
* *
* @return Calculation * @return null|Calculation
*/ */
public function getCalculationEngine() public function getCalculationEngine()
{ {
@ -1343,6 +1343,7 @@ class Spreadsheet
// remove cellXfs without references and create mapping so we can update xfIndex // remove cellXfs without references and create mapping so we can update xfIndex
// for all cells and columns // for all cells and columns
$countNeededCellXfs = 0; $countNeededCellXfs = 0;
$map = [];
foreach ($this->cellXfCollection as $index => $cellXf) { foreach ($this->cellXfCollection as $index => $cellXf) {
if ($countReferencesCellXf[$index] > 0 || $index == 0) { // we must never remove the first cellXf if ($countReferencesCellXf[$index] > 0 || $index == 0) { // we must never remove the first cellXf
++$countNeededCellXfs; ++$countNeededCellXfs;

View File

@ -47,11 +47,8 @@ class Border extends Supervisor
* @param bool $isSupervisor Flag indicating if this is a supervisor or not * @param bool $isSupervisor Flag indicating if this is a supervisor or not
* Leave this value at default unless you understand exactly what * Leave this value at default unless you understand exactly what
* its ramifications are * its ramifications are
* @param bool $isConditional Flag indicating if this is a conditional style or not
* Leave this value at default unless you understand exactly what
* its ramifications are
*/ */
public function __construct($isSupervisor = false, $isConditional = false) public function __construct($isSupervisor = false)
{ {
// Supervisor? // Supervisor?
parent::__construct($isSupervisor); parent::__construct($isSupervisor);

View File

@ -95,21 +95,18 @@ class Borders extends Supervisor
* @param bool $isSupervisor Flag indicating if this is a supervisor or not * @param bool $isSupervisor Flag indicating if this is a supervisor or not
* Leave this value at default unless you understand exactly what * Leave this value at default unless you understand exactly what
* its ramifications are * its ramifications are
* @param bool $isConditional Flag indicating if this is a conditional style or not
* Leave this value at default unless you understand exactly what
* its ramifications are
*/ */
public function __construct($isSupervisor = false, $isConditional = false) public function __construct($isSupervisor = false)
{ {
// Supervisor? // Supervisor?
parent::__construct($isSupervisor); parent::__construct($isSupervisor);
// Initialise values // Initialise values
$this->left = new Border($isSupervisor, $isConditional); $this->left = new Border($isSupervisor);
$this->right = new Border($isSupervisor, $isConditional); $this->right = new Border($isSupervisor);
$this->top = new Border($isSupervisor, $isConditional); $this->top = new Border($isSupervisor);
$this->bottom = new Border($isSupervisor, $isConditional); $this->bottom = new Border($isSupervisor);
$this->diagonal = new Border($isSupervisor, $isConditional); $this->diagonal = new Border($isSupervisor);
$this->diagonalDirection = self::DIAGONAL_NONE; $this->diagonalDirection = self::DIAGONAL_NONE;
// Specially for supervisor // Specially for supervisor

View File

@ -35,6 +35,7 @@ class NumberFormatter
if ($maskingBlockCount > 1) { if ($maskingBlockCount > 1) {
$maskingBlocks = array_reverse($maskingBlocks[0]); $maskingBlocks = array_reverse($maskingBlocks[0]);
$offset = 0;
foreach ($maskingBlocks as $block) { foreach ($maskingBlocks as $block) {
$size = strlen($block[0]); $size = strlen($block[0]);
$divisor = 10 ** $size; $divisor = 10 ** $size;

View File

@ -80,7 +80,7 @@ class Style extends Supervisor
// Initialise values // Initialise values
$this->font = new Font($isSupervisor, $isConditional); $this->font = new Font($isSupervisor, $isConditional);
$this->fill = new Fill($isSupervisor, $isConditional); $this->fill = new Fill($isSupervisor, $isConditional);
$this->borders = new Borders($isSupervisor, $isConditional); $this->borders = new Borders($isSupervisor);
$this->alignment = new Alignment($isSupervisor, $isConditional); $this->alignment = new Alignment($isSupervisor, $isConditional);
$this->numberFormat = new NumberFormat($isSupervisor, $isConditional); $this->numberFormat = new NumberFormat($isSupervisor, $isConditional);
$this->protection = new Protection($isSupervisor, $isConditional); $this->protection = new Protection($isSupervisor, $isConditional);
@ -349,56 +349,11 @@ class Style extends Supervisor
} }
// First loop through columns, rows, or cells to find out which styles are affected by this operation // First loop through columns, rows, or cells to find out which styles are affected by this operation
switch ($selectionType) { $oldXfIndexes = $this->getOldXfIndexes($selectionType, $rangeStart, $rangeEnd, $rangeStart0, $rangeEnd0, $pStyles);
case 'COLUMN':
$oldXfIndexes = [];
for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
$oldXfIndexes[$this->getActiveSheet()->getColumnDimensionByColumn($col)->getXfIndex()] = true;
}
foreach ($this->getActiveSheet()->getColumnIterator($rangeStart0, $rangeEnd0) as $columnIterator) {
$cellIterator = $columnIterator->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(true);
foreach ($cellIterator as $columnCell) {
if ($columnCell !== null) {
$columnCell->getStyle()->applyFromArray($pStyles);
}
}
}
break;
case 'ROW':
$oldXfIndexes = [];
for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
if ($this->getActiveSheet()->getRowDimension($row)->getXfIndex() === null) {
$oldXfIndexes[0] = true; // row without explicit style should be formatted based on default style
} else {
$oldXfIndexes[$this->getActiveSheet()->getRowDimension($row)->getXfIndex()] = true;
}
}
foreach ($this->getActiveSheet()->getRowIterator((int) $rangeStart[1], (int) $rangeEnd[1]) as $rowIterator) {
$cellIterator = $rowIterator->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(true);
foreach ($cellIterator as $rowCell) {
if ($rowCell !== null) {
$rowCell->getStyle()->applyFromArray($pStyles);
}
}
}
break;
case 'CELL':
$oldXfIndexes = [];
for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
$oldXfIndexes[$this->getActiveSheet()->getCellByColumnAndRow($col, $row)->getXfIndex()] = true;
}
}
break;
}
// clone each of the affected styles, apply the style array, and add the new styles to the workbook // clone each of the affected styles, apply the style array, and add the new styles to the workbook
$workbook = $this->getActiveSheet()->getParent(); $workbook = $this->getActiveSheet()->getParent();
$newXfIndexes = [];
foreach ($oldXfIndexes as $oldXfIndex => $dummy) { foreach ($oldXfIndexes as $oldXfIndex => $dummy) {
$style = $workbook->getCellXfByIndex($oldXfIndex); $style = $workbook->getCellXfByIndex($oldXfIndex);
$newStyle = clone $style; $newStyle = clone $style;
@ -472,6 +427,57 @@ class Style extends Supervisor
return $this; return $this;
} }
private function getOldXfIndexes(string $selectionType, array $rangeStart, array $rangeEnd, string $rangeStart0, string $rangeEnd0, array $pStyles): array
{
$oldXfIndexes = [];
switch ($selectionType) {
case 'COLUMN':
for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
$oldXfIndexes[$this->getActiveSheet()->getColumnDimensionByColumn($col)->getXfIndex()] = true;
}
foreach ($this->getActiveSheet()->getColumnIterator($rangeStart0, $rangeEnd0) as $columnIterator) {
$cellIterator = $columnIterator->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(true);
foreach ($cellIterator as $columnCell) {
if ($columnCell !== null) {
$columnCell->getStyle()->applyFromArray($pStyles);
}
}
}
break;
case 'ROW':
for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
if ($this->getActiveSheet()->getRowDimension($row)->getXfIndex() === null) {
$oldXfIndexes[0] = true; // row without explicit style should be formatted based on default style
} else {
$oldXfIndexes[$this->getActiveSheet()->getRowDimension($row)->getXfIndex()] = true;
}
}
foreach ($this->getActiveSheet()->getRowIterator((int) $rangeStart[1], (int) $rangeEnd[1]) as $rowIterator) {
$cellIterator = $rowIterator->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(true);
foreach ($cellIterator as $rowCell) {
if ($rowCell !== null) {
$rowCell->getStyle()->applyFromArray($pStyles);
}
}
}
break;
case 'CELL':
for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
$oldXfIndexes[$this->getActiveSheet()->getCellByColumnAndRow($col, $row)->getXfIndex()] = true;
}
}
break;
}
return $oldXfIndexes;
}
/** /**
* Get Fill. * Get Fill.
* *

View File

@ -779,6 +779,9 @@ class AutoFilter
case AutoFilter\Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER: case AutoFilter\Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER:
$ruleValues = []; $ruleValues = [];
$dataRowCount = $rangeEnd[1] - $rangeStart[1]; $dataRowCount = $rangeEnd[1] - $rangeStart[1];
$toptenRuleType = null;
$ruleValue = null;
$ruleOperator = null;
foreach ($rules as $rule) { foreach ($rules as $rule) {
// We should only ever have one Dynamic Filter Rule anyway // We should only ever have one Dynamic Filter Rule anyway
$toptenRuleType = $rule->getGrouping(); $toptenRuleType = $rule->getGrouping();

View File

@ -420,6 +420,7 @@ class Xls extends BaseWriter
private function processDrawing(BstoreContainer &$bstoreContainer, BaseDrawing $drawing): void private function processDrawing(BstoreContainer &$bstoreContainer, BaseDrawing $drawing): void
{ {
$blipType = null;
$blipData = ''; $blipData = '';
$filename = $drawing->getPath(); $filename = $drawing->getPath();

View File

@ -747,7 +747,7 @@ class Parser
return pack('C', 0xFF); return pack('C', 0xFF);
} }
private function convertDefinedName(string $name): void private function convertDefinedName(string $name): string
{ {
if (strlen($name) > 255) { if (strlen($name) > 255) {
throw new WriterException('Defined Name is too long'); throw new WriterException('Defined Name is too long');
@ -764,7 +764,8 @@ class Parser
$ptgRef = pack('Cvxx', $this->ptg['ptgName'], $nameReference); $ptgRef = pack('Cvxx', $this->ptg['ptgName'], $nameReference);
throw new WriterException('Cannot yet write formulae with defined names to Xls'); throw new WriterException('Cannot yet write formulae with defined names to Xls');
// return $ptgRef;
return $ptgRef;
} }
/** /**
@ -968,6 +969,7 @@ class Parser
*/ */
private function advance() private function advance()
{ {
$token = '';
$i = $this->currentCharacter; $i = $this->currentCharacter;
$formula_length = strlen($this->formula); $formula_length = strlen($this->formula);
// eat up white spaces // eat up white spaces

View File

@ -1344,32 +1344,13 @@ class Worksheet extends BIFFwriter
*/ */
private function writeColinfo($col_array): void private function writeColinfo($col_array): void
{ {
if (isset($col_array[0])) { $colFirst = $col_array[0] ?? null;
$colFirst = $col_array[0]; $colLast = $col_array[1] ?? null;
} $coldx = $col_array[2] ?? 8.43;
if (isset($col_array[1])) { $xfIndex = $col_array[3] ?? 15;
$colLast = $col_array[1]; $grbit = $col_array[4] ?? 0;
} $level = $col_array[5] ?? 0;
if (isset($col_array[2])) {
$coldx = $col_array[2];
} else {
$coldx = 8.43;
}
if (isset($col_array[3])) {
$xfIndex = $col_array[3];
} else {
$xfIndex = 15;
}
if (isset($col_array[4])) {
$grbit = $col_array[4];
} else {
$grbit = 0;
}
if (isset($col_array[5])) {
$level = $col_array[5];
} else {
$level = 0;
}
$record = 0x007D; // Record identifier $record = 0x007D; // Record identifier
$length = 0x000C; // Number of bytes to follow $length = 0x000C; // Number of bytes to follow
@ -1425,13 +1406,6 @@ class Worksheet extends BIFFwriter
$irefAct = 0; // Active cell ref $irefAct = 0; // Active cell ref
$cref = 1; // Number of refs $cref = 1; // Number of refs
if (!isset($rwLast)) {
$rwLast = $rwFirst; // Last row in reference
}
if (!isset($colLast)) {
$colLast = $colFirst; // Last col in reference
}
// Swap last row/col for first row/col as necessary // Swap last row/col for first row/col as necessary
if ($rwFirst > $rwLast) { if ($rwFirst > $rwLast) {
[$rwFirst, $rwLast] = [$rwLast, $rwFirst]; [$rwFirst, $rwLast] = [$rwLast, $rwFirst];
@ -1660,7 +1634,7 @@ class Worksheet extends BIFFwriter
if (!isset($rwTop)) { if (!isset($rwTop)) {
$rwTop = $y; $rwTop = $y;
} }
if (!isset($colLeft)) { if (!$colLeft) {
$colLeft = $x; $colLeft = $x;
} }
} else { } else {
@ -1668,7 +1642,7 @@ class Worksheet extends BIFFwriter
if (!isset($rwTop)) { if (!isset($rwTop)) {
$rwTop = 0; $rwTop = 0;
} }
if (!isset($colLeft)) { if (!$colLeft) {
$colLeft = 0; $colLeft = 0;
} }
@ -1684,7 +1658,7 @@ class Worksheet extends BIFFwriter
// Determine which pane should be active. There is also the undocumented // Determine which pane should be active. There is also the undocumented
// option to override this should it be necessary: may be removed later. // option to override this should it be necessary: may be removed later.
// //
if (!isset($pnnAct)) { if (!$pnnAct) {
if ($x != 0 && $y != 0) { if ($x != 0 && $y != 0) {
$pnnAct = 0; // Bottom right $pnnAct = 0; // Bottom right
} }
@ -2974,9 +2948,9 @@ class Worksheet extends BIFFwriter
private function writeCFRule(Conditional $conditional): void private function writeCFRule(Conditional $conditional): void
{ {
$record = 0x01B1; // Record identifier $record = 0x01B1; // Record identifier
$type = null; // Type of the CF
$operatorType = null; // Comparison operator
// $type : Type of the CF
// $operatorType : Comparison operator
if ($conditional->getConditionType() == Conditional::CONDITION_EXPRESSION) { if ($conditional->getConditionType() == Conditional::CONDITION_EXPRESSION) {
$type = 0x02; $type = 0x02;
$operatorType = 0x00; $operatorType = 0x00;
@ -3141,6 +3115,11 @@ class Worksheet extends BIFFwriter
// Text direction // Text direction
$flags |= (1 == 0 ? 0x80000000 : 0); $flags |= (1 == 0 ? 0x80000000 : 0);
$dataBlockFont = null;
$dataBlockAlign = null;
$dataBlockBorder = null;
$dataBlockFill = null;
// Data Blocks // Data Blocks
if ($bFormatFont == 1) { if ($bFormatFont == 1) {
// Font Name // Font Name
@ -4398,15 +4377,6 @@ class Worksheet extends BIFFwriter
$dataBlockFill = pack('v', $blockFillPatternStyle); $dataBlockFill = pack('v', $blockFillPatternStyle);
$dataBlockFill .= pack('v', $colorIdxFg | ($colorIdxBg << 7)); $dataBlockFill .= pack('v', $colorIdxFg | ($colorIdxBg << 7));
} }
if ($bFormatProt == 1) {
$dataBlockProtection = 0;
if ($conditional->getStyle()->getProtection()->getLocked() == Protection::PROTECTION_PROTECTED) {
$dataBlockProtection = 1;
}
if ($conditional->getStyle()->getProtection()->getHidden() == Protection::PROTECTION_PROTECTED) {
$dataBlockProtection = 1 << 1;
}
}
$data = pack('CCvvVv', $type, $operatorType, $szValue1, $szValue2, $flags, 0x0000); $data = pack('CCvvVv', $type, $operatorType, $szValue1, $szValue2, $flags, 0x0000);
if ($bFormatFont == 1) { // Block Formatting : OK if ($bFormatFont == 1) { // Block Formatting : OK
@ -4422,7 +4392,7 @@ class Worksheet extends BIFFwriter
$data .= $dataBlockFill; $data .= $dataBlockFill;
} }
if ($bFormatProt == 1) { if ($bFormatProt == 1) {
$data .= $dataBlockProtection; $data .= $this->getDataBlockProtection($conditional);
} }
if ($operand1 !== null) { if ($operand1 !== null) {
$data .= $operand1; $data .= $operand1;
@ -4486,4 +4456,17 @@ class Worksheet extends BIFFwriter
$data .= $cellRange; $data .= $cellRange;
$this->append($header . $data); $this->append($header . $data);
} }
private function getDataBlockProtection(Conditional $conditional): int
{
$dataBlockProtection = 0;
if ($conditional->getStyle()->getProtection()->getLocked() == Protection::PROTECTION_PROTECTED) {
$dataBlockProtection = 1;
}
if ($conditional->getStyle()->getProtection()->getHidden() == Protection::PROTECTION_PROTECTED) {
$dataBlockProtection = 1 << 1;
}
return $dataBlockProtection;
}
} }

View File

@ -115,6 +115,21 @@ class Xf
*/ */
private $rightBorderColor; private $rightBorderColor;
/**
* @var int
*/
private $diag;
/**
* @var int
*/
private $diagColor;
/**
* @var Style
*/
private $style;
/** /**
* Constructor. * Constructor.
* *
@ -132,14 +147,14 @@ class Xf
$this->foregroundColor = 0x40; $this->foregroundColor = 0x40;
$this->backgroundColor = 0x41; $this->backgroundColor = 0x41;
$this->_diag = 0; $this->diag = 0;
$this->bottomBorderColor = 0x40; $this->bottomBorderColor = 0x40;
$this->topBorderColor = 0x40; $this->topBorderColor = 0x40;
$this->leftBorderColor = 0x40; $this->leftBorderColor = 0x40;
$this->rightBorderColor = 0x40; $this->rightBorderColor = 0x40;
$this->_diag_color = 0x40; $this->diagColor = 0x40;
$this->_style = $style; $this->style = $style;
} }
/** /**
@ -153,39 +168,39 @@ class Xf
if ($this->isStyleXf) { if ($this->isStyleXf) {
$style = 0xFFF5; $style = 0xFFF5;
} else { } else {
$style = self::mapLocked($this->_style->getProtection()->getLocked()); $style = self::mapLocked($this->style->getProtection()->getLocked());
$style |= self::mapHidden($this->_style->getProtection()->getHidden()) << 1; $style |= self::mapHidden($this->style->getProtection()->getHidden()) << 1;
} }
// Flags to indicate if attributes have been set. // Flags to indicate if attributes have been set.
$atr_num = ($this->numberFormatIndex != 0) ? 1 : 0; $atr_num = ($this->numberFormatIndex != 0) ? 1 : 0;
$atr_fnt = ($this->fontIndex != 0) ? 1 : 0; $atr_fnt = ($this->fontIndex != 0) ? 1 : 0;
$atr_alc = ((int) $this->_style->getAlignment()->getWrapText()) ? 1 : 0; $atr_alc = ((int) $this->style->getAlignment()->getWrapText()) ? 1 : 0;
$atr_bdr = (self::mapBorderStyle($this->_style->getBorders()->getBottom()->getBorderStyle()) || $atr_bdr = (self::mapBorderStyle($this->style->getBorders()->getBottom()->getBorderStyle()) ||
self::mapBorderStyle($this->_style->getBorders()->getTop()->getBorderStyle()) || self::mapBorderStyle($this->style->getBorders()->getTop()->getBorderStyle()) ||
self::mapBorderStyle($this->_style->getBorders()->getLeft()->getBorderStyle()) || self::mapBorderStyle($this->style->getBorders()->getLeft()->getBorderStyle()) ||
self::mapBorderStyle($this->_style->getBorders()->getRight()->getBorderStyle())) ? 1 : 0; self::mapBorderStyle($this->style->getBorders()->getRight()->getBorderStyle())) ? 1 : 0;
$atr_pat = ($this->foregroundColor != 0x40) ? 1 : 0; $atr_pat = ($this->foregroundColor != 0x40) ? 1 : 0;
$atr_pat = ($this->backgroundColor != 0x41) ? 1 : $atr_pat; $atr_pat = ($this->backgroundColor != 0x41) ? 1 : $atr_pat;
$atr_pat = self::mapFillType($this->_style->getFill()->getFillType()) ? 1 : $atr_pat; $atr_pat = self::mapFillType($this->style->getFill()->getFillType()) ? 1 : $atr_pat;
$atr_prot = self::mapLocked($this->_style->getProtection()->getLocked()) $atr_prot = self::mapLocked($this->style->getProtection()->getLocked())
| self::mapHidden($this->_style->getProtection()->getHidden()); | self::mapHidden($this->style->getProtection()->getHidden());
// Zero the default border colour if the border has not been set. // Zero the default border colour if the border has not been set.
if (self::mapBorderStyle($this->_style->getBorders()->getBottom()->getBorderStyle()) == 0) { if (self::mapBorderStyle($this->style->getBorders()->getBottom()->getBorderStyle()) == 0) {
$this->bottomBorderColor = 0; $this->bottomBorderColor = 0;
} }
if (self::mapBorderStyle($this->_style->getBorders()->getTop()->getBorderStyle()) == 0) { if (self::mapBorderStyle($this->style->getBorders()->getTop()->getBorderStyle()) == 0) {
$this->topBorderColor = 0; $this->topBorderColor = 0;
} }
if (self::mapBorderStyle($this->_style->getBorders()->getRight()->getBorderStyle()) == 0) { if (self::mapBorderStyle($this->style->getBorders()->getRight()->getBorderStyle()) == 0) {
$this->rightBorderColor = 0; $this->rightBorderColor = 0;
} }
if (self::mapBorderStyle($this->_style->getBorders()->getLeft()->getBorderStyle()) == 0) { if (self::mapBorderStyle($this->style->getBorders()->getLeft()->getBorderStyle()) == 0) {
$this->leftBorderColor = 0; $this->leftBorderColor = 0;
} }
if (self::mapBorderStyle($this->_style->getBorders()->getDiagonal()->getBorderStyle()) == 0) { if (self::mapBorderStyle($this->style->getBorders()->getDiagonal()->getBorderStyle()) == 0) {
$this->_diag_color = 0; $this->diagColor = 0;
} }
$record = 0x00E0; // Record identifier $record = 0x00E0; // Record identifier
@ -194,9 +209,9 @@ class Xf
$ifnt = $this->fontIndex; // Index to FONT record $ifnt = $this->fontIndex; // Index to FONT record
$ifmt = $this->numberFormatIndex; // Index to FORMAT record $ifmt = $this->numberFormatIndex; // Index to FORMAT record
$align = $this->mapHAlign($this->_style->getAlignment()->getHorizontal()); // Alignment $align = $this->mapHAlign($this->style->getAlignment()->getHorizontal()); // Alignment
$align |= (int) $this->_style->getAlignment()->getWrapText() << 3; $align |= (int) $this->style->getAlignment()->getWrapText() << 3;
$align |= self::mapVAlign($this->_style->getAlignment()->getVertical()) << 4; $align |= self::mapVAlign($this->style->getAlignment()->getVertical()) << 4;
$align |= $this->textJustLast << 7; $align |= $this->textJustLast << 7;
$used_attrib = $atr_num << 2; $used_attrib = $atr_num << 2;
@ -209,14 +224,14 @@ class Xf
$icv = $this->foregroundColor; // fg and bg pattern colors $icv = $this->foregroundColor; // fg and bg pattern colors
$icv |= $this->backgroundColor << 7; $icv |= $this->backgroundColor << 7;
$border1 = self::mapBorderStyle($this->_style->getBorders()->getLeft()->getBorderStyle()); // Border line style and color $border1 = self::mapBorderStyle($this->style->getBorders()->getLeft()->getBorderStyle()); // Border line style and color
$border1 |= self::mapBorderStyle($this->_style->getBorders()->getRight()->getBorderStyle()) << 4; $border1 |= self::mapBorderStyle($this->style->getBorders()->getRight()->getBorderStyle()) << 4;
$border1 |= self::mapBorderStyle($this->_style->getBorders()->getTop()->getBorderStyle()) << 8; $border1 |= self::mapBorderStyle($this->style->getBorders()->getTop()->getBorderStyle()) << 8;
$border1 |= self::mapBorderStyle($this->_style->getBorders()->getBottom()->getBorderStyle()) << 12; $border1 |= self::mapBorderStyle($this->style->getBorders()->getBottom()->getBorderStyle()) << 12;
$border1 |= $this->leftBorderColor << 16; $border1 |= $this->leftBorderColor << 16;
$border1 |= $this->rightBorderColor << 23; $border1 |= $this->rightBorderColor << 23;
$diagonalDirection = $this->_style->getBorders()->getDiagonalDirection(); $diagonalDirection = $this->style->getBorders()->getDiagonalDirection();
$diag_tl_to_rb = $diagonalDirection == Borders::DIAGONAL_BOTH $diag_tl_to_rb = $diagonalDirection == Borders::DIAGONAL_BOTH
|| $diagonalDirection == Borders::DIAGONAL_DOWN; || $diagonalDirection == Borders::DIAGONAL_DOWN;
$diag_tr_to_lb = $diagonalDirection == Borders::DIAGONAL_BOTH $diag_tr_to_lb = $diagonalDirection == Borders::DIAGONAL_BOTH
@ -226,18 +241,18 @@ class Xf
$border2 = $this->topBorderColor; // Border color $border2 = $this->topBorderColor; // Border color
$border2 |= $this->bottomBorderColor << 7; $border2 |= $this->bottomBorderColor << 7;
$border2 |= $this->_diag_color << 14; $border2 |= $this->diagColor << 14;
$border2 |= self::mapBorderStyle($this->_style->getBorders()->getDiagonal()->getBorderStyle()) << 21; $border2 |= self::mapBorderStyle($this->style->getBorders()->getDiagonal()->getBorderStyle()) << 21;
$border2 |= self::mapFillType($this->_style->getFill()->getFillType()) << 26; $border2 |= self::mapFillType($this->style->getFill()->getFillType()) << 26;
$header = pack('vv', $record, $length); $header = pack('vv', $record, $length);
//BIFF8 options: identation, shrinkToFit and text direction //BIFF8 options: identation, shrinkToFit and text direction
$biff8_options = $this->_style->getAlignment()->getIndent(); $biff8_options = $this->style->getAlignment()->getIndent();
$biff8_options |= (int) $this->_style->getAlignment()->getShrinkToFit() << 4; $biff8_options |= (int) $this->style->getAlignment()->getShrinkToFit() << 4;
$data = pack('vvvC', $ifnt, $ifmt, $style, $align); $data = pack('vvvC', $ifnt, $ifmt, $style, $align);
$data .= pack('CCC', self::mapTextRotation($this->_style->getAlignment()->getTextRotation()), $biff8_options, $used_attrib); $data .= pack('CCC', self::mapTextRotation($this->style->getAlignment()->getTextRotation()), $biff8_options, $used_attrib);
$data .= pack('VVv', $border1, $border2, $icv); $data .= pack('VVv', $border1, $border2, $icv);
return $header . $data; return $header . $data;
@ -300,7 +315,7 @@ class Xf
*/ */
public function setDiagColor($colorIndex): void public function setDiagColor($colorIndex): void
{ {
$this->_diag_color = $colorIndex; $this->diagColor = $colorIndex;
} }
/** /**

View File

@ -219,10 +219,12 @@ class Chart extends WriterPart
$chartTypes = self::getChartType($plotArea); $chartTypes = self::getChartType($plotArea);
$catIsMultiLevelSeries = $valIsMultiLevelSeries = false; $catIsMultiLevelSeries = $valIsMultiLevelSeries = false;
$plotGroupingType = ''; $plotGroupingType = '';
$chartType = null;
foreach ($chartTypes as $chartType) { foreach ($chartTypes as $chartType) {
$objWriter->startElement('c:' . $chartType); $objWriter->startElement('c:' . $chartType);
$groupCount = $plotArea->getPlotGroupCount(); $groupCount = $plotArea->getPlotGroupCount();
$plotGroup = null;
for ($i = 0; $i < $groupCount; ++$i) { for ($i = 0; $i < $groupCount; ++$i) {
$plotGroup = $plotArea->getPlotGroupByIndex($i); $plotGroup = $plotArea->getPlotGroupByIndex($i);
$groupType = $plotGroup->getPlotType(); $groupType = $plotGroup->getPlotType();
@ -244,7 +246,7 @@ class Chart extends WriterPart
$this->writeDataLabels($objWriter, $layout); $this->writeDataLabels($objWriter, $layout);
if ($chartType === DataSeries::TYPE_LINECHART) { if ($chartType === DataSeries::TYPE_LINECHART && $plotGroup) {
// Line only, Line3D can't be smoothed // Line only, Line3D can't be smoothed
$objWriter->startElement('c:smooth'); $objWriter->startElement('c:smooth');
$objWriter->writeAttribute('val', (int) $plotGroup->getSmoothLine()); $objWriter->writeAttribute('val', (int) $plotGroup->getSmoothLine());
@ -1079,6 +1081,7 @@ class Chart extends WriterPart
} }
} }
$plotSeriesIdx = 0;
foreach ($plotSeriesOrder as $plotSeriesIdx => $plotSeriesRef) { foreach ($plotSeriesOrder as $plotSeriesIdx => $plotSeriesRef) {
$objWriter->startElement('c:ser'); $objWriter->startElement('c:ser');

View File

@ -2,7 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Weekday; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\WeekDay;
class WeekDayTest extends AllSetupTeardown class WeekDayTest extends AllSetupTeardown
{ {
@ -28,8 +28,8 @@ class WeekDayTest extends AllSetupTeardown
public function testWEEKDAYwith1904Calendar(): void public function testWEEKDAYwith1904Calendar(): void
{ {
self::setMac1904(); self::setMac1904();
self::assertEquals(7, Weekday::funcWeekDay('1904-01-02')); self::assertEquals(7, WeekDay::funcWeekDay('1904-01-02'));
self::assertEquals(6, Weekday::funcWeekDay('1904-01-01')); self::assertEquals(6, WeekDay::funcWeekDay('1904-01-01'));
self::assertEquals(6, Weekday::funcWeekDay(null)); self::assertEquals(6, WeekDay::funcWeekDay(null));
} }
} }

View File

@ -37,7 +37,7 @@ class XmlScannerTest extends TestCase
self::assertEquals($expectedResult, $result); self::assertEquals($expectedResult, $result);
// php 8.+ deprecated libxml_disable_entity_loader() - It's on by default // php 8.+ deprecated libxml_disable_entity_loader() - It's on by default
if (\PHP_VERSION_ID < 80000) { if (isset($oldDisableEntityLoaderState)) {
libxml_disable_entity_loader($oldDisableEntityLoaderState); libxml_disable_entity_loader($oldDisableEntityLoaderState);
} }
} }