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:
parent
a2bb825bc5
commit
a189d933f2
|
|
@ -124,6 +124,37 @@ jobs:
|
|||
- name: Code style with PHP_CodeSniffer
|
||||
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:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@
|
|||
"check": [
|
||||
"php-cs-fixer fix --ansi --dry-run --diff",
|
||||
"phpcs",
|
||||
"phpunit --color=always"
|
||||
"phpunit --color=always",
|
||||
"phpstan analyse --ansi"
|
||||
],
|
||||
"fix": [
|
||||
"php-cs-fixer fix --ansi"
|
||||
|
|
@ -79,6 +80,7 @@
|
|||
"jpgraph/jpgraph": "^4.0",
|
||||
"mpdf/mpdf": "^8.0",
|
||||
"phpcompatibility/php-compatibility": "^9.3",
|
||||
"phpstan/phpstan": "^0.12.82",
|
||||
"phpunit/phpunit": "^8.5",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"tecnickcom/tcpdf": "^6.3"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "6c8f34baf3385a533fade30a9a9ad6f1",
|
||||
"content-hash": "89b62d75519340c289a3a763245f1ca0",
|
||||
"packages": [
|
||||
{
|
||||
"name": "ezyang/htmlpurifier",
|
||||
|
|
@ -1963,6 +1963,66 @@
|
|||
},
|
||||
"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",
|
||||
"version": "7.0.14",
|
||||
|
|
|
|||
|
|
@ -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\.$~'
|
||||
|
|
@ -3154,6 +3154,7 @@ class Calculation
|
|||
// Return Excel errors "as is"
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Return strings wrapped in quotes
|
||||
return self::FORMULA_STRING_QUOTE . $value . self::FORMULA_STRING_QUOTE;
|
||||
} elseif ((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
|
||||
|
|
@ -3794,13 +3795,13 @@ class Calculation
|
|||
$pCellParent = ($pCell !== null) ? $pCell->getWorksheet() : null;
|
||||
|
||||
$regexpMatchString = '/^(' . self::CALCULATION_REGEXP_FUNCTION .
|
||||
'|' . self::CALCULATION_REGEXP_CELLREF .
|
||||
'|' . self::CALCULATION_REGEXP_NUMBER .
|
||||
'|' . self::CALCULATION_REGEXP_STRING .
|
||||
'|' . self::CALCULATION_REGEXP_OPENBRACE .
|
||||
'|' . self::CALCULATION_REGEXP_DEFINEDNAME .
|
||||
'|' . self::CALCULATION_REGEXP_ERROR .
|
||||
')/sui';
|
||||
'|' . self::CALCULATION_REGEXP_CELLREF .
|
||||
'|' . self::CALCULATION_REGEXP_NUMBER .
|
||||
'|' . self::CALCULATION_REGEXP_STRING .
|
||||
'|' . self::CALCULATION_REGEXP_OPENBRACE .
|
||||
'|' . self::CALCULATION_REGEXP_DEFINEDNAME .
|
||||
'|' . self::CALCULATION_REGEXP_ERROR .
|
||||
')/sui';
|
||||
|
||||
// Start with initialisation
|
||||
$index = 0;
|
||||
|
|
@ -3939,6 +3940,7 @@ class Calculation
|
|||
}
|
||||
// Check the argument count
|
||||
$argumentCountError = false;
|
||||
$expectedArgumentCountString = null;
|
||||
if (is_numeric($expectedArgumentCount)) {
|
||||
if ($expectedArgumentCount < 0) {
|
||||
if ($argumentCount > abs($expectedArgumentCount)) {
|
||||
|
|
@ -4203,7 +4205,7 @@ class Calculation
|
|||
((preg_match('/^' . self::CALCULATION_REGEXP_CELLREF . '.*/Ui', substr($formula, $index), $match)) &&
|
||||
($output[count($output) - 1]['type'] == 'Cell Reference') ||
|
||||
(preg_match('/^' . self::CALCULATION_REGEXP_DEFINEDNAME . '.*/miu', substr($formula, $index), $match)) &&
|
||||
($output[count($output) - 1]['type'] == 'Defined Name' || $output[count($output) - 1]['type'] == 'Value')
|
||||
($output[count($output) - 1]['type'] == 'Defined Name' || $output[count($output) - 1]['type'] == 'Value')
|
||||
)
|
||||
) {
|
||||
while (
|
||||
|
|
@ -4645,6 +4647,9 @@ class Calculation
|
|||
$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
|
||||
$passByReference = false;
|
||||
$passCellReference = false;
|
||||
$functionCall = null;
|
||||
if (isset(self::$phpSpreadsheetFunctions[$functionName])) {
|
||||
$functionCall = self::$phpSpreadsheetFunctions[$functionName]['functionCall'];
|
||||
$passByReference = isset(self::$phpSpreadsheetFunctions[$functionName]['passByReference']);
|
||||
|
|
@ -4945,6 +4950,9 @@ class Calculation
|
|||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception('Unsupported binary comparison operation');
|
||||
}
|
||||
|
||||
// Log the result details
|
||||
|
|
@ -5062,6 +5070,9 @@ class Calculation
|
|||
$result = $operand1 ** $operand2;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception('Unsupported numeric binary operation');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -651,7 +651,7 @@ class DateTime
|
|||
*
|
||||
* 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:
|
||||
* ISOWEEKNUM(dateValue)
|
||||
|
|
@ -663,7 +663,7 @@ class DateTime
|
|||
*/
|
||||
public static function ISOWEEKNUM($dateValue = 1)
|
||||
{
|
||||
return DateTimeExcel\IsoweekNum::funcIsoWeekNum($dateValue);
|
||||
return DateTimeExcel\IsoWeekNum::funcIsoWeekNum($dateValue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ class Financial
|
|||
{
|
||||
$pmt = self::PMT($rate, $nper, $pv, $fv, $type);
|
||||
$capital = $pv;
|
||||
$interest = 0;
|
||||
$principal = 0;
|
||||
for ($i = 1; $i <= $per; ++$i) {
|
||||
$interest = ($type && $i == 1) ? 0 : -$capital * $rate;
|
||||
$principal = $pmt - $interest;
|
||||
|
|
|
|||
|
|
@ -301,6 +301,8 @@ class JpGraph implements IRenderer
|
|||
$seriesPlots = [];
|
||||
if ($grouping == 'percentStacked') {
|
||||
$sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
|
||||
} else {
|
||||
$sumValues = [];
|
||||
}
|
||||
|
||||
// Loop through each data series in turn
|
||||
|
|
@ -376,6 +378,8 @@ class JpGraph implements IRenderer
|
|||
$seriesPlots = [];
|
||||
if ($grouping == 'percentStacked') {
|
||||
$sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
|
||||
} else {
|
||||
$sumValues = [];
|
||||
}
|
||||
|
||||
// Loop through each data series in turn
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ abstract class IOFactory
|
|||
$reader = self::createReader($guessedReader);
|
||||
|
||||
// Let's see if we are lucky
|
||||
if (isset($reader) && $reader->canRead($filename)) {
|
||||
if ($reader->canRead($filename)) {
|
||||
return $reader;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -801,9 +801,10 @@ class Xls extends BaseReader
|
|||
}
|
||||
|
||||
// treat MSODRAWINGGROUP records, workbook-level Escher
|
||||
$escherWorkbook = null;
|
||||
if (!$this->readDataOnly && $this->drawingGroupData) {
|
||||
$escherWorkbook = new Escher();
|
||||
$reader = new Xls\Escher($escherWorkbook);
|
||||
$escher = new Escher();
|
||||
$reader = new Xls\Escher($escher);
|
||||
$escherWorkbook = $reader->load($this->drawingGroupData);
|
||||
}
|
||||
|
||||
|
|
@ -1133,38 +1134,40 @@ class Xls extends BaseReader
|
|||
continue 2;
|
||||
}
|
||||
|
||||
$BSECollection = $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection();
|
||||
$BSE = $BSECollection[$BSEindex - 1];
|
||||
$blipType = $BSE->getBlipType();
|
||||
if ($escherWorkbook) {
|
||||
$BSECollection = $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection();
|
||||
$BSE = $BSECollection[$BSEindex - 1];
|
||||
$blipType = $BSE->getBlipType();
|
||||
|
||||
// need check because some blip types are not supported by Escher reader such as EMF
|
||||
if ($blip = $BSE->getBlip()) {
|
||||
$ih = imagecreatefromstring($blip->getData());
|
||||
$drawing = new MemoryDrawing();
|
||||
$drawing->setImageResource($ih);
|
||||
// need check because some blip types are not supported by Escher reader such as EMF
|
||||
if ($blip = $BSE->getBlip()) {
|
||||
$ih = imagecreatefromstring($blip->getData());
|
||||
$drawing = new MemoryDrawing();
|
||||
$drawing->setImageResource($ih);
|
||||
|
||||
// width, height, offsetX, offsetY
|
||||
$drawing->setResizeProportional(false);
|
||||
$drawing->setWidth($width);
|
||||
$drawing->setHeight($height);
|
||||
$drawing->setOffsetX($offsetX);
|
||||
$drawing->setOffsetY($offsetY);
|
||||
// width, height, offsetX, offsetY
|
||||
$drawing->setResizeProportional(false);
|
||||
$drawing->setWidth($width);
|
||||
$drawing->setHeight($height);
|
||||
$drawing->setOffsetX($offsetX);
|
||||
$drawing->setOffsetY($offsetY);
|
||||
|
||||
switch ($blipType) {
|
||||
case BSE::BLIPTYPE_JPEG:
|
||||
$drawing->setRenderingFunction(MemoryDrawing::RENDERING_JPEG);
|
||||
$drawing->setMimeType(MemoryDrawing::MIMETYPE_JPEG);
|
||||
switch ($blipType) {
|
||||
case BSE::BLIPTYPE_JPEG:
|
||||
$drawing->setRenderingFunction(MemoryDrawing::RENDERING_JPEG);
|
||||
$drawing->setMimeType(MemoryDrawing::MIMETYPE_JPEG);
|
||||
|
||||
break;
|
||||
case BSE::BLIPTYPE_PNG:
|
||||
$drawing->setRenderingFunction(MemoryDrawing::RENDERING_PNG);
|
||||
$drawing->setMimeType(MemoryDrawing::MIMETYPE_PNG);
|
||||
break;
|
||||
case BSE::BLIPTYPE_PNG:
|
||||
$drawing->setRenderingFunction(MemoryDrawing::RENDERING_PNG);
|
||||
$drawing->setMimeType(MemoryDrawing::MIMETYPE_PNG);
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
$drawing->setWorksheet($this->phpSheet);
|
||||
$drawing->setCoordinates($spContainer->getStartCoordinates());
|
||||
}
|
||||
|
||||
$drawing->setWorksheet($this->phpSheet);
|
||||
$drawing->setCoordinates($spContainer->getStartCoordinates());
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -2742,6 +2745,7 @@ class Xls extends BaseReader
|
|||
$sheetType = ord($recordData[5]);
|
||||
|
||||
// offset: 6; size: var; sheet name
|
||||
$rec_name = null;
|
||||
if ($this->version == self::XLS_BIFF8) {
|
||||
$string = self::readUnicodeStringShort(substr($recordData, 6));
|
||||
$rec_name = $string['value'];
|
||||
|
|
@ -3018,12 +3022,14 @@ class Xls extends BaseReader
|
|||
// bit: 3; mask: 0x03; 0 = ordinary; 1 = Rich-Text
|
||||
$hasRichText = (($optionFlags & 0x08) != 0);
|
||||
|
||||
$formattingRuns = 0;
|
||||
if ($hasRichText) {
|
||||
// number of Rich-Text formatting runs
|
||||
$formattingRuns = self::getUInt2d($recordData, $pos);
|
||||
$pos += 2;
|
||||
}
|
||||
|
||||
$extendedRunLength = 0;
|
||||
if ($hasAsian) {
|
||||
// size of Asian phonetic setting
|
||||
$extendedRunLength = self::getInt4d($recordData, $pos);
|
||||
|
|
@ -3034,6 +3040,7 @@ class Xls extends BaseReader
|
|||
$len = ($isCompressed) ? $numChars : $numChars * 2;
|
||||
|
||||
// look up limit position - Check it again to be sure that no error occurs when parsing SST structure
|
||||
$limitpos = null;
|
||||
foreach ($spliceOffsets as $spliceOffset) {
|
||||
// it can happen that the string is empty, therefore we need
|
||||
// <= and not just <
|
||||
|
|
@ -4385,6 +4392,8 @@ class Xls extends BaseReader
|
|||
|
||||
// offset: 4; size: 2; index to first visible colum
|
||||
$firstVisibleColumn = self::getUInt2d($recordData, 4);
|
||||
$zoomscaleInPageBreakPreview = 0;
|
||||
$zoomscaleInNormalView = 0;
|
||||
if ($this->version === self::XLS_BIFF8) {
|
||||
// offset: 8; size: 2; not used
|
||||
// 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;
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new PhpSpreadsheetException('Unsupported BIFF8 constant');
|
||||
}
|
||||
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class Color
|
|||
if ($color <= 0x07 || $color >= 0x40) {
|
||||
// special built-in 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
|
||||
return $palette[$color - 8];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -430,7 +430,7 @@ class Xlsx extends BaseReader
|
|||
'SimpleXMLElement',
|
||||
Settings::getLibXmlLoaderOptions()
|
||||
);
|
||||
if (isset($xmlStrings, $xmlStrings->si)) {
|
||||
if (isset($xmlStrings->si)) {
|
||||
foreach ($xmlStrings->si as $val) {
|
||||
if (isset($val->t)) {
|
||||
$sharedStrings[] = StringHelper::controlCharacterOOXML2PHP((string) $val->t);
|
||||
|
|
@ -511,10 +511,7 @@ class Xlsx extends BaseReader
|
|||
$numFmt = NumberFormat::builtInFormatCode((int) $xf['numFmtId']);
|
||||
}
|
||||
}
|
||||
$quotePrefix = false;
|
||||
if (isset($xf['quotePrefix'])) {
|
||||
$quotePrefix = (bool) $xf['quotePrefix'];
|
||||
}
|
||||
$quotePrefix = (bool) ($xf['quotePrefix'] ?? false);
|
||||
|
||||
$style = (object) [
|
||||
'numFmt' => $numFmt ?? NumberFormat::FORMAT_GENERAL,
|
||||
|
|
@ -544,6 +541,8 @@ class Xlsx extends BaseReader
|
|||
}
|
||||
}
|
||||
|
||||
$quotePrefix = (bool) ($xf['quotePrefix'] ?? false);
|
||||
|
||||
$cellStyle = (object) [
|
||||
'numFmt' => $numFmt,
|
||||
'font' => $xmlStyles->fonts->font[(int) ($xf['fontId'])],
|
||||
|
|
@ -1081,6 +1080,7 @@ class Xlsx extends BaseReader
|
|||
}
|
||||
if ($xmlSheet->drawing && !$this->readDataOnly) {
|
||||
$unparsedDrawings = [];
|
||||
$fileDrawing = null;
|
||||
foreach ($xmlSheet->drawing as $drawing) {
|
||||
$drawingRelId = (string) self::getArrayItem($drawing->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id');
|
||||
$fileDrawing = $drawings[$drawingRelId];
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class Chart
|
|||
|
||||
$XaxisLabel = $YaxisLabel = $legend = $title = null;
|
||||
$dispBlanksAs = $plotVisOnly = null;
|
||||
|
||||
$plotArea = null;
|
||||
foreach ($chartElementsC as $chartElementKey => $chartElement) {
|
||||
switch ($chartElementKey) {
|
||||
case 'chart':
|
||||
|
|
|
|||
|
|
@ -436,6 +436,7 @@ class Xml extends BaseReader
|
|||
// Create new Worksheet
|
||||
$spreadsheet->createSheet();
|
||||
$spreadsheet->setActiveSheetIndex($worksheetID);
|
||||
$worksheetName = '';
|
||||
if (isset($worksheet_ss['Name'])) {
|
||||
$worksheetName = (string) $worksheet_ss['Name'];
|
||||
// Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in
|
||||
|
|
|
|||
|
|
@ -171,6 +171,8 @@ class Drawing
|
|||
|
||||
// Process the header
|
||||
// Structure: http://www.fastgraph.com/help/bmp_header_format.html
|
||||
$width = 0;
|
||||
$height = 0;
|
||||
if (substr($header, 0, 4) == '424d') {
|
||||
// Cut it in parts of 2 bytes
|
||||
$header_parts = str_split($header, 2);
|
||||
|
|
|
|||
|
|
@ -244,6 +244,7 @@ class Font
|
|||
|
||||
// Try to get the exact text width in pixels
|
||||
$approximate = self::$autoSizeMethod == self::AUTOSIZE_METHOD_APPROX;
|
||||
$columnWidth = 0;
|
||||
if (!$approximate) {
|
||||
$columnWidthAdjust = ceil(self::getTextWidthPixelsExact('n', $font, 0) * 1.07);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ namespace PhpOffice\PhpSpreadsheet\Shared\JAMA;
|
|||
* conditioned, or even singular, so the validity of the equation
|
||||
* A = V*D*inverse(V) depends upon V.cond().
|
||||
*
|
||||
* @author Paul Meagher
|
||||
* @author Paul Meagher
|
||||
*
|
||||
* @version 1.1
|
||||
* @version 1.1
|
||||
*/
|
||||
class EigenvalueDecomposition
|
||||
{
|
||||
|
|
@ -70,6 +70,11 @@ class EigenvalueDecomposition
|
|||
|
||||
private $cdivi;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $A;
|
||||
|
||||
/**
|
||||
* Symmetric Householder reduction to tridiagonal form.
|
||||
*/
|
||||
|
|
@ -80,6 +85,7 @@ class EigenvalueDecomposition
|
|||
// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
|
||||
// Fortran subroutine in EISPACK.
|
||||
$this->d = $this->V[$this->n - 1];
|
||||
$j = 0;
|
||||
// Householder reduction to tridiagonal form.
|
||||
for ($i = $this->n - 1; $i > 0; --$i) {
|
||||
$i_ = $i - 1;
|
||||
|
|
@ -781,9 +787,9 @@ class EigenvalueDecomposition
|
|||
/**
|
||||
* 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->n = $Arg->getColumnDimension();
|
||||
|
|
@ -848,6 +854,7 @@ class EigenvalueDecomposition
|
|||
*/
|
||||
public function getD()
|
||||
{
|
||||
$D = [];
|
||||
for ($i = 0; $i < $this->n; ++$i) {
|
||||
$D[$i] = array_fill(0, $this->n, 0.0);
|
||||
$D[$i][$i] = $this->d[$i];
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ class LUDecomposition
|
|||
*/
|
||||
public function getL()
|
||||
{
|
||||
$L = [];
|
||||
for ($i = 0; $i < $this->m; ++$i) {
|
||||
for ($j = 0; $j < $this->n; ++$j) {
|
||||
if ($i > $j) {
|
||||
|
|
@ -159,6 +160,7 @@ class LUDecomposition
|
|||
*/
|
||||
public function getU()
|
||||
{
|
||||
$U = [];
|
||||
for ($i = 0; $i < $this->n; ++$i) {
|
||||
for ($j = 0; $j < $this->n; ++$j) {
|
||||
if ($i <= $j) {
|
||||
|
|
|
|||
|
|
@ -476,6 +476,7 @@ class SingularValueDecomposition
|
|||
*/
|
||||
public function getS()
|
||||
{
|
||||
$S = [];
|
||||
for ($i = 0; $i < $this->n; ++$i) {
|
||||
for ($j = 0; $j < $this->n; ++$j) {
|
||||
$S[$i][$j] = 0.0;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ namespace PhpOffice\PhpSpreadsheet\Shared;
|
|||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\OLE\ChainedBlockStream;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\OLE\PPS\Root;
|
||||
|
|
@ -317,7 +318,7 @@ class OLE
|
|||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
throw new Exception('Unsupported PPS type');
|
||||
}
|
||||
fseek($fh, 1, SEEK_CUR);
|
||||
$pps->Type = $type;
|
||||
|
|
@ -496,7 +497,7 @@ class OLE
|
|||
*/
|
||||
public static function localDateToOLE($date)
|
||||
{
|
||||
if (!isset($date)) {
|
||||
if (!$date) {
|
||||
return "\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ class Trend
|
|||
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
|
||||
// Start by generating an instance of each available Trend method
|
||||
$bestFit = [];
|
||||
$bestFitValue = [];
|
||||
foreach (self::$trendTypes as $trendMethod) {
|
||||
$className = '\PhpOffice\PhpSpreadsheet\Shared\Trend\\' . $trendType . 'BestFit';
|
||||
$bestFit[$trendMethod] = new $className($yValues, $xValues, $const);
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class Spreadsheet
|
|||
/**
|
||||
* Calculation Engine.
|
||||
*
|
||||
* @var Calculation
|
||||
* @var null|Calculation
|
||||
*/
|
||||
private $calculationEngine;
|
||||
|
||||
|
|
@ -505,8 +505,8 @@ class Spreadsheet
|
|||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->calculationEngine = null;
|
||||
$this->disconnectWorksheets();
|
||||
$this->calculationEngine = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -527,7 +527,7 @@ class Spreadsheet
|
|||
/**
|
||||
* Return the calculation engine for this worksheet.
|
||||
*
|
||||
* @return Calculation
|
||||
* @return null|Calculation
|
||||
*/
|
||||
public function getCalculationEngine()
|
||||
{
|
||||
|
|
@ -1343,6 +1343,7 @@ class Spreadsheet
|
|||
// remove cellXfs without references and create mapping so we can update xfIndex
|
||||
// for all cells and columns
|
||||
$countNeededCellXfs = 0;
|
||||
$map = [];
|
||||
foreach ($this->cellXfCollection as $index => $cellXf) {
|
||||
if ($countReferencesCellXf[$index] > 0 || $index == 0) { // we must never remove the first cellXf
|
||||
++$countNeededCellXfs;
|
||||
|
|
|
|||
|
|
@ -47,11 +47,8 @@ class Border extends Supervisor
|
|||
* @param bool $isSupervisor Flag indicating if this is a supervisor or not
|
||||
* Leave this value at default unless you understand exactly what
|
||||
* 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?
|
||||
parent::__construct($isSupervisor);
|
||||
|
|
|
|||
|
|
@ -95,21 +95,18 @@ class Borders extends Supervisor
|
|||
* @param bool $isSupervisor Flag indicating if this is a supervisor or not
|
||||
* Leave this value at default unless you understand exactly what
|
||||
* 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?
|
||||
parent::__construct($isSupervisor);
|
||||
|
||||
// Initialise values
|
||||
$this->left = new Border($isSupervisor, $isConditional);
|
||||
$this->right = new Border($isSupervisor, $isConditional);
|
||||
$this->top = new Border($isSupervisor, $isConditional);
|
||||
$this->bottom = new Border($isSupervisor, $isConditional);
|
||||
$this->diagonal = new Border($isSupervisor, $isConditional);
|
||||
$this->left = new Border($isSupervisor);
|
||||
$this->right = new Border($isSupervisor);
|
||||
$this->top = new Border($isSupervisor);
|
||||
$this->bottom = new Border($isSupervisor);
|
||||
$this->diagonal = new Border($isSupervisor);
|
||||
$this->diagonalDirection = self::DIAGONAL_NONE;
|
||||
|
||||
// Specially for supervisor
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class NumberFormatter
|
|||
if ($maskingBlockCount > 1) {
|
||||
$maskingBlocks = array_reverse($maskingBlocks[0]);
|
||||
|
||||
$offset = 0;
|
||||
foreach ($maskingBlocks as $block) {
|
||||
$size = strlen($block[0]);
|
||||
$divisor = 10 ** $size;
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ class Style extends Supervisor
|
|||
// Initialise values
|
||||
$this->font = new Font($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->numberFormat = new NumberFormat($isSupervisor, $isConditional);
|
||||
$this->protection = new Protection($isSupervisor, $isConditional);
|
||||
|
|
@ -257,11 +257,11 @@ class Style extends Supervisor
|
|||
// start column index for region
|
||||
$colStart = ($x == 3) ?
|
||||
Coordinate::stringFromColumnIndex($rangeEnd[0])
|
||||
: Coordinate::stringFromColumnIndex($rangeStart[0] + $x - 1);
|
||||
: Coordinate::stringFromColumnIndex($rangeStart[0] + $x - 1);
|
||||
// end column index for region
|
||||
$colEnd = ($x == 1) ?
|
||||
Coordinate::stringFromColumnIndex($rangeStart[0])
|
||||
: Coordinate::stringFromColumnIndex($rangeEnd[0] - $xMax + $x);
|
||||
: Coordinate::stringFromColumnIndex($rangeEnd[0] - $xMax + $x);
|
||||
|
||||
for ($y = 1; $y <= $yMax; ++$y) {
|
||||
// which edges are touching the region
|
||||
|
|
@ -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
|
||||
switch ($selectionType) {
|
||||
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;
|
||||
}
|
||||
$oldXfIndexes = $this->getOldXfIndexes($selectionType, $rangeStart, $rangeEnd, $rangeStart0, $rangeEnd0, $pStyles);
|
||||
|
||||
// clone each of the affected styles, apply the style array, and add the new styles to the workbook
|
||||
$workbook = $this->getActiveSheet()->getParent();
|
||||
$newXfIndexes = [];
|
||||
foreach ($oldXfIndexes as $oldXfIndex => $dummy) {
|
||||
$style = $workbook->getCellXfByIndex($oldXfIndex);
|
||||
$newStyle = clone $style;
|
||||
|
|
@ -472,6 +427,57 @@ class Style extends Supervisor
|
|||
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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -779,6 +779,9 @@ class AutoFilter
|
|||
case AutoFilter\Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER:
|
||||
$ruleValues = [];
|
||||
$dataRowCount = $rangeEnd[1] - $rangeStart[1];
|
||||
$toptenRuleType = null;
|
||||
$ruleValue = null;
|
||||
$ruleOperator = null;
|
||||
foreach ($rules as $rule) {
|
||||
// We should only ever have one Dynamic Filter Rule anyway
|
||||
$toptenRuleType = $rule->getGrouping();
|
||||
|
|
|
|||
|
|
@ -420,6 +420,7 @@ class Xls extends BaseWriter
|
|||
|
||||
private function processDrawing(BstoreContainer &$bstoreContainer, BaseDrawing $drawing): void
|
||||
{
|
||||
$blipType = null;
|
||||
$blipData = '';
|
||||
$filename = $drawing->getPath();
|
||||
|
||||
|
|
|
|||
|
|
@ -747,7 +747,7 @@ class Parser
|
|||
return pack('C', 0xFF);
|
||||
}
|
||||
|
||||
private function convertDefinedName(string $name): void
|
||||
private function convertDefinedName(string $name): string
|
||||
{
|
||||
if (strlen($name) > 255) {
|
||||
throw new WriterException('Defined Name is too long');
|
||||
|
|
@ -764,7 +764,8 @@ class Parser
|
|||
$ptgRef = pack('Cvxx', $this->ptg['ptgName'], $nameReference);
|
||||
|
||||
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()
|
||||
{
|
||||
$token = '';
|
||||
$i = $this->currentCharacter;
|
||||
$formula_length = strlen($this->formula);
|
||||
// eat up white spaces
|
||||
|
|
|
|||
|
|
@ -1344,32 +1344,13 @@ class Worksheet extends BIFFwriter
|
|||
*/
|
||||
private function writeColinfo($col_array): void
|
||||
{
|
||||
if (isset($col_array[0])) {
|
||||
$colFirst = $col_array[0];
|
||||
}
|
||||
if (isset($col_array[1])) {
|
||||
$colLast = $col_array[1];
|
||||
}
|
||||
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;
|
||||
}
|
||||
$colFirst = $col_array[0] ?? null;
|
||||
$colLast = $col_array[1] ?? null;
|
||||
$coldx = $col_array[2] ?? 8.43;
|
||||
$xfIndex = $col_array[3] ?? 15;
|
||||
$grbit = $col_array[4] ?? 0;
|
||||
$level = $col_array[5] ?? 0;
|
||||
|
||||
$record = 0x007D; // Record identifier
|
||||
$length = 0x000C; // Number of bytes to follow
|
||||
|
||||
|
|
@ -1425,13 +1406,6 @@ class Worksheet extends BIFFwriter
|
|||
$irefAct = 0; // Active cell ref
|
||||
$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
|
||||
if ($rwFirst > $rwLast) {
|
||||
[$rwFirst, $rwLast] = [$rwLast, $rwFirst];
|
||||
|
|
@ -1660,7 +1634,7 @@ class Worksheet extends BIFFwriter
|
|||
if (!isset($rwTop)) {
|
||||
$rwTop = $y;
|
||||
}
|
||||
if (!isset($colLeft)) {
|
||||
if (!$colLeft) {
|
||||
$colLeft = $x;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1668,7 +1642,7 @@ class Worksheet extends BIFFwriter
|
|||
if (!isset($rwTop)) {
|
||||
$rwTop = 0;
|
||||
}
|
||||
if (!isset($colLeft)) {
|
||||
if (!$colLeft) {
|
||||
$colLeft = 0;
|
||||
}
|
||||
|
||||
|
|
@ -1684,7 +1658,7 @@ class Worksheet extends BIFFwriter
|
|||
// Determine which pane should be active. There is also the undocumented
|
||||
// option to override this should it be necessary: may be removed later.
|
||||
//
|
||||
if (!isset($pnnAct)) {
|
||||
if (!$pnnAct) {
|
||||
if ($x != 0 && $y != 0) {
|
||||
$pnnAct = 0; // Bottom right
|
||||
}
|
||||
|
|
@ -2974,9 +2948,9 @@ class Worksheet extends BIFFwriter
|
|||
private function writeCFRule(Conditional $conditional): void
|
||||
{
|
||||
$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) {
|
||||
$type = 0x02;
|
||||
$operatorType = 0x00;
|
||||
|
|
@ -3141,6 +3115,11 @@ class Worksheet extends BIFFwriter
|
|||
// Text direction
|
||||
$flags |= (1 == 0 ? 0x80000000 : 0);
|
||||
|
||||
$dataBlockFont = null;
|
||||
$dataBlockAlign = null;
|
||||
$dataBlockBorder = null;
|
||||
$dataBlockFill = null;
|
||||
|
||||
// Data Blocks
|
||||
if ($bFormatFont == 1) {
|
||||
// Font Name
|
||||
|
|
@ -4398,15 +4377,6 @@ class Worksheet extends BIFFwriter
|
|||
$dataBlockFill = pack('v', $blockFillPatternStyle);
|
||||
$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);
|
||||
if ($bFormatFont == 1) { // Block Formatting : OK
|
||||
|
|
@ -4422,7 +4392,7 @@ class Worksheet extends BIFFwriter
|
|||
$data .= $dataBlockFill;
|
||||
}
|
||||
if ($bFormatProt == 1) {
|
||||
$data .= $dataBlockProtection;
|
||||
$data .= $this->getDataBlockProtection($conditional);
|
||||
}
|
||||
if ($operand1 !== null) {
|
||||
$data .= $operand1;
|
||||
|
|
@ -4486,4 +4456,17 @@ class Worksheet extends BIFFwriter
|
|||
$data .= $cellRange;
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,6 +115,21 @@ class Xf
|
|||
*/
|
||||
private $rightBorderColor;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $diag;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $diagColor;
|
||||
|
||||
/**
|
||||
* @var Style
|
||||
*/
|
||||
private $style;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
|
|
@ -132,14 +147,14 @@ class Xf
|
|||
$this->foregroundColor = 0x40;
|
||||
$this->backgroundColor = 0x41;
|
||||
|
||||
$this->_diag = 0;
|
||||
$this->diag = 0;
|
||||
|
||||
$this->bottomBorderColor = 0x40;
|
||||
$this->topBorderColor = 0x40;
|
||||
$this->leftBorderColor = 0x40;
|
||||
$this->rightBorderColor = 0x40;
|
||||
$this->_diag_color = 0x40;
|
||||
$this->_style = $style;
|
||||
$this->diagColor = 0x40;
|
||||
$this->style = $style;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -153,39 +168,39 @@ class Xf
|
|||
if ($this->isStyleXf) {
|
||||
$style = 0xFFF5;
|
||||
} else {
|
||||
$style = self::mapLocked($this->_style->getProtection()->getLocked());
|
||||
$style |= self::mapHidden($this->_style->getProtection()->getHidden()) << 1;
|
||||
$style = self::mapLocked($this->style->getProtection()->getLocked());
|
||||
$style |= self::mapHidden($this->style->getProtection()->getHidden()) << 1;
|
||||
}
|
||||
|
||||
// Flags to indicate if attributes have been set.
|
||||
$atr_num = ($this->numberFormatIndex != 0) ? 1 : 0;
|
||||
$atr_fnt = ($this->fontIndex != 0) ? 1 : 0;
|
||||
$atr_alc = ((int) $this->_style->getAlignment()->getWrapText()) ? 1 : 0;
|
||||
$atr_bdr = (self::mapBorderStyle($this->_style->getBorders()->getBottom()->getBorderStyle()) ||
|
||||
self::mapBorderStyle($this->_style->getBorders()->getTop()->getBorderStyle()) ||
|
||||
self::mapBorderStyle($this->_style->getBorders()->getLeft()->getBorderStyle()) ||
|
||||
self::mapBorderStyle($this->_style->getBorders()->getRight()->getBorderStyle())) ? 1 : 0;
|
||||
$atr_alc = ((int) $this->style->getAlignment()->getWrapText()) ? 1 : 0;
|
||||
$atr_bdr = (self::mapBorderStyle($this->style->getBorders()->getBottom()->getBorderStyle()) ||
|
||||
self::mapBorderStyle($this->style->getBorders()->getTop()->getBorderStyle()) ||
|
||||
self::mapBorderStyle($this->style->getBorders()->getLeft()->getBorderStyle()) ||
|
||||
self::mapBorderStyle($this->style->getBorders()->getRight()->getBorderStyle())) ? 1 : 0;
|
||||
$atr_pat = ($this->foregroundColor != 0x40) ? 1 : 0;
|
||||
$atr_pat = ($this->backgroundColor != 0x41) ? 1 : $atr_pat;
|
||||
$atr_pat = self::mapFillType($this->_style->getFill()->getFillType()) ? 1 : $atr_pat;
|
||||
$atr_prot = self::mapLocked($this->_style->getProtection()->getLocked())
|
||||
| self::mapHidden($this->_style->getProtection()->getHidden());
|
||||
$atr_pat = self::mapFillType($this->style->getFill()->getFillType()) ? 1 : $atr_pat;
|
||||
$atr_prot = self::mapLocked($this->style->getProtection()->getLocked())
|
||||
| self::mapHidden($this->style->getProtection()->getHidden());
|
||||
|
||||
// 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;
|
||||
}
|
||||
if (self::mapBorderStyle($this->_style->getBorders()->getTop()->getBorderStyle()) == 0) {
|
||||
if (self::mapBorderStyle($this->style->getBorders()->getTop()->getBorderStyle()) == 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;
|
||||
}
|
||||
if (self::mapBorderStyle($this->_style->getBorders()->getLeft()->getBorderStyle()) == 0) {
|
||||
if (self::mapBorderStyle($this->style->getBorders()->getLeft()->getBorderStyle()) == 0) {
|
||||
$this->leftBorderColor = 0;
|
||||
}
|
||||
if (self::mapBorderStyle($this->_style->getBorders()->getDiagonal()->getBorderStyle()) == 0) {
|
||||
$this->_diag_color = 0;
|
||||
if (self::mapBorderStyle($this->style->getBorders()->getDiagonal()->getBorderStyle()) == 0) {
|
||||
$this->diagColor = 0;
|
||||
}
|
||||
|
||||
$record = 0x00E0; // Record identifier
|
||||
|
|
@ -194,9 +209,9 @@ class Xf
|
|||
$ifnt = $this->fontIndex; // Index to FONT record
|
||||
$ifmt = $this->numberFormatIndex; // Index to FORMAT record
|
||||
|
||||
$align = $this->mapHAlign($this->_style->getAlignment()->getHorizontal()); // Alignment
|
||||
$align |= (int) $this->_style->getAlignment()->getWrapText() << 3;
|
||||
$align |= self::mapVAlign($this->_style->getAlignment()->getVertical()) << 4;
|
||||
$align = $this->mapHAlign($this->style->getAlignment()->getHorizontal()); // Alignment
|
||||
$align |= (int) $this->style->getAlignment()->getWrapText() << 3;
|
||||
$align |= self::mapVAlign($this->style->getAlignment()->getVertical()) << 4;
|
||||
$align |= $this->textJustLast << 7;
|
||||
|
||||
$used_attrib = $atr_num << 2;
|
||||
|
|
@ -209,35 +224,35 @@ class Xf
|
|||
$icv = $this->foregroundColor; // fg and bg pattern colors
|
||||
$icv |= $this->backgroundColor << 7;
|
||||
|
||||
$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()->getTop()->getBorderStyle()) << 8;
|
||||
$border1 |= self::mapBorderStyle($this->_style->getBorders()->getBottom()->getBorderStyle()) << 12;
|
||||
$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()->getTop()->getBorderStyle()) << 8;
|
||||
$border1 |= self::mapBorderStyle($this->style->getBorders()->getBottom()->getBorderStyle()) << 12;
|
||||
$border1 |= $this->leftBorderColor << 16;
|
||||
$border1 |= $this->rightBorderColor << 23;
|
||||
|
||||
$diagonalDirection = $this->_style->getBorders()->getDiagonalDirection();
|
||||
$diagonalDirection = $this->style->getBorders()->getDiagonalDirection();
|
||||
$diag_tl_to_rb = $diagonalDirection == Borders::DIAGONAL_BOTH
|
||||
|| $diagonalDirection == Borders::DIAGONAL_DOWN;
|
||||
|| $diagonalDirection == Borders::DIAGONAL_DOWN;
|
||||
$diag_tr_to_lb = $diagonalDirection == Borders::DIAGONAL_BOTH
|
||||
|| $diagonalDirection == Borders::DIAGONAL_UP;
|
||||
|| $diagonalDirection == Borders::DIAGONAL_UP;
|
||||
$border1 |= $diag_tl_to_rb << 30;
|
||||
$border1 |= $diag_tr_to_lb << 31;
|
||||
|
||||
$border2 = $this->topBorderColor; // Border color
|
||||
$border2 |= $this->bottomBorderColor << 7;
|
||||
$border2 |= $this->_diag_color << 14;
|
||||
$border2 |= self::mapBorderStyle($this->_style->getBorders()->getDiagonal()->getBorderStyle()) << 21;
|
||||
$border2 |= self::mapFillType($this->_style->getFill()->getFillType()) << 26;
|
||||
$border2 |= $this->diagColor << 14;
|
||||
$border2 |= self::mapBorderStyle($this->style->getBorders()->getDiagonal()->getBorderStyle()) << 21;
|
||||
$border2 |= self::mapFillType($this->style->getFill()->getFillType()) << 26;
|
||||
|
||||
$header = pack('vv', $record, $length);
|
||||
|
||||
//BIFF8 options: identation, shrinkToFit and text direction
|
||||
$biff8_options = $this->_style->getAlignment()->getIndent();
|
||||
$biff8_options |= (int) $this->_style->getAlignment()->getShrinkToFit() << 4;
|
||||
$biff8_options = $this->style->getAlignment()->getIndent();
|
||||
$biff8_options |= (int) $this->style->getAlignment()->getShrinkToFit() << 4;
|
||||
|
||||
$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);
|
||||
|
||||
return $header . $data;
|
||||
|
|
@ -300,7 +315,7 @@ class Xf
|
|||
*/
|
||||
public function setDiagColor($colorIndex): void
|
||||
{
|
||||
$this->_diag_color = $colorIndex;
|
||||
$this->diagColor = $colorIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -219,10 +219,12 @@ class Chart extends WriterPart
|
|||
$chartTypes = self::getChartType($plotArea);
|
||||
$catIsMultiLevelSeries = $valIsMultiLevelSeries = false;
|
||||
$plotGroupingType = '';
|
||||
$chartType = null;
|
||||
foreach ($chartTypes as $chartType) {
|
||||
$objWriter->startElement('c:' . $chartType);
|
||||
|
||||
$groupCount = $plotArea->getPlotGroupCount();
|
||||
$plotGroup = null;
|
||||
for ($i = 0; $i < $groupCount; ++$i) {
|
||||
$plotGroup = $plotArea->getPlotGroupByIndex($i);
|
||||
$groupType = $plotGroup->getPlotType();
|
||||
|
|
@ -244,7 +246,7 @@ class Chart extends WriterPart
|
|||
|
||||
$this->writeDataLabels($objWriter, $layout);
|
||||
|
||||
if ($chartType === DataSeries::TYPE_LINECHART) {
|
||||
if ($chartType === DataSeries::TYPE_LINECHART && $plotGroup) {
|
||||
// Line only, Line3D can't be smoothed
|
||||
$objWriter->startElement('c:smooth');
|
||||
$objWriter->writeAttribute('val', (int) $plotGroup->getSmoothLine());
|
||||
|
|
@ -1079,6 +1081,7 @@ class Chart extends WriterPart
|
|||
}
|
||||
}
|
||||
|
||||
$plotSeriesIdx = 0;
|
||||
foreach ($plotSeriesOrder as $plotSeriesIdx => $plotSeriesRef) {
|
||||
$objWriter->startElement('c:ser');
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Weekday;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\WeekDay;
|
||||
|
||||
class WeekDayTest extends AllSetupTeardown
|
||||
{
|
||||
|
|
@ -28,8 +28,8 @@ class WeekDayTest extends AllSetupTeardown
|
|||
public function testWEEKDAYwith1904Calendar(): void
|
||||
{
|
||||
self::setMac1904();
|
||||
self::assertEquals(7, Weekday::funcWeekDay('1904-01-02'));
|
||||
self::assertEquals(6, Weekday::funcWeekDay('1904-01-01'));
|
||||
self::assertEquals(6, Weekday::funcWeekDay(null));
|
||||
self::assertEquals(7, WeekDay::funcWeekDay('1904-01-02'));
|
||||
self::assertEquals(6, WeekDay::funcWeekDay('1904-01-01'));
|
||||
self::assertEquals(6, WeekDay::funcWeekDay(null));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class XmlScannerTest extends TestCase
|
|||
self::assertEquals($expectedResult, $result);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue