Merge branch 'master' into master

This commit is contained in:
Mark Baker 2022-06-14 12:34:02 +02:00 committed by GitHub
commit c749cb5e83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1965 additions and 698 deletions

View File

@ -19,9 +19,15 @@ and this project adheres to [Semantic Versioning](https://semver.org).
- Added Worksheet visibility in Ods Writer [PR #2850](https://github.com/PHPOffice/PhpSpreadsheet/pull/2850) - Added Worksheet visibility in Ods Writer [PR #2850](https://github.com/PHPOffice/PhpSpreadsheet/pull/2850)
- Allow Csv Reader to treat string as contents of file [Issue #1285](https://github.com/PHPOffice/PhpSpreadsheet/issues/1285) [PR #2792](https://github.com/PHPOffice/PhpSpreadsheet/pull/2792) - Allow Csv Reader to treat string as contents of file [Issue #1285](https://github.com/PHPOffice/PhpSpreadsheet/issues/1285) [PR #2792](https://github.com/PHPOffice/PhpSpreadsheet/pull/2792)
- Allow Csv Reader to store null string rather than leave cell empty [Issue #2840](https://github.com/PHPOffice/PhpSpreadsheet/issues/2840) [PR #2842](https://github.com/PHPOffice/PhpSpreadsheet/pull/2842) - Allow Csv Reader to store null string rather than leave cell empty [Issue #2840](https://github.com/PHPOffice/PhpSpreadsheet/issues/2840) [PR #2842](https://github.com/PHPOffice/PhpSpreadsheet/pull/2842)
- Provide new Worksheet methods to identify if a row or column is "empty", making allowance for different definitions of "empty":
- Treat rows/columns containing no cell records as empty (default)
- Treat cells containing a null value as empty
- Treat cells containing an empty string as empty
### Changed ### Changed
- Better enforcement of value modification to match specified datatype when using setValueExplicit()
- Relax validation of merge cells to allow merge for a single cell reference [Issue #2776](https://github.com/PHPOffice/PhpSpreadsheet/issues/2776)
- Memory and speed improvements, particularly for the Cell Collection, and the Writers. - Memory and speed improvements, particularly for the Cell Collection, and the Writers.
See [the Discussion section on github](https://github.com/PHPOffice/PhpSpreadsheet/discussions/2821) for details of performance across versions See [the Discussion section on github](https://github.com/PHPOffice/PhpSpreadsheet/discussions/2821) for details of performance across versions

View File

@ -1170,21 +1170,11 @@ parameters:
count: 2 count: 2
path: src/PhpSpreadsheet/Chart/DataSeries.php path: src/PhpSpreadsheet/Chart/DataSeries.php
-
message: "#^Parameter \\#1 \\$angle of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setShadowAngle\\(\\) expects int, int\\|null given\\.$#"
count: 1
path: src/PhpSpreadsheet/Chart/GridLines.php
- -
message: "#^Parameter \\#1 \\$color of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setGlowColor\\(\\) expects string, string\\|null given\\.$#" message: "#^Parameter \\#1 \\$color of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setGlowColor\\(\\) expects string, string\\|null given\\.$#"
count: 1 count: 1
path: src/PhpSpreadsheet/Chart/GridLines.php path: src/PhpSpreadsheet/Chart/GridLines.php
-
message: "#^Parameter \\#1 \\$distance of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setShadowDistance\\(\\) expects float, float\\|null given\\.$#"
count: 1
path: src/PhpSpreadsheet/Chart/GridLines.php
- -
message: "#^Parameter \\#2 \\$alpha of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setGlowColor\\(\\) expects int, int\\|null given\\.$#" message: "#^Parameter \\#2 \\$alpha of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setGlowColor\\(\\) expects int, int\\|null given\\.$#"
count: 1 count: 1
@ -1275,36 +1265,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Chart/Properties.php path: src/PhpSpreadsheet/Chart/Properties.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getTrueAlpha\\(\\) has no return type specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Chart/Properties.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getTrueAlpha\\(\\) has parameter \\$alpha with no type specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Chart/Properties.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:setColorProperties\\(\\) has no return type specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Chart/Properties.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:setColorProperties\\(\\) has parameter \\$alpha with no type specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Chart/Properties.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:setColorProperties\\(\\) has parameter \\$color with no type specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Chart/Properties.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:setColorProperties\\(\\) has parameter \\$colorType with no type specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Chart/Properties.php
- -
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:formatDataSetLabels\\(\\) has no return type specified\\.$#" message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:formatDataSetLabels\\(\\) has no return type specified\\.$#"
count: 1 count: 1
@ -3155,26 +3115,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Shared/StringHelper.php path: src/PhpSpreadsheet/Shared/StringHelper.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:mbIsUpper\\(\\) has no return type specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Shared/StringHelper.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:mbIsUpper\\(\\) has parameter \\$character with no type specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Shared/StringHelper.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:mbStrSplit\\(\\) has no return type specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Shared/StringHelper.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:mbStrSplit\\(\\) has parameter \\$string with no type specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Shared/StringHelper.php
- -
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:sanitizeUTF8\\(\\) should return string but returns string\\|false\\.$#" message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:sanitizeUTF8\\(\\) should return string but returns string\\|false\\.$#"
count: 1 count: 1
@ -3200,11 +3140,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Shared/StringHelper.php path: src/PhpSpreadsheet/Shared/StringHelper.php
-
message: "#^Variable \\$textValue on left side of \\?\\? always exists and is not nullable\\.$#"
count: 3
path: src/PhpSpreadsheet/Shared/StringHelper.php
- -
message: "#^Static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\TimeZone\\:\\:validateTimeZone\\(\\) is unused\\.$#" message: "#^Static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\TimeZone\\:\\:validateTimeZone\\(\\) is unused\\.$#"
count: 1 count: 1
@ -3655,11 +3590,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Worksheet/CellIterator.php path: src/PhpSpreadsheet/Worksheet/CellIterator.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Column\\:\\:\\$parent \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#"
count: 1
path: src/PhpSpreadsheet/Worksheet/Column.php
- -
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Drawing\\\\Shadow\\:\\:\\$color \\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\|null\\.$#" message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Drawing\\\\Shadow\\:\\:\\$color \\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\|null\\.$#"
count: 1 count: 1
@ -3685,11 +3615,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Worksheet/PageSetup.php path: src/PhpSpreadsheet/Worksheet/PageSetup.php
-
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Row\\:\\:\\$worksheet \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#"
count: 1
path: src/PhpSpreadsheet/Worksheet/Row.php
- -
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\SheetView\\:\\:\\$sheetViewTypes has no type specified\\.$#" message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\SheetView\\:\\:\\$sheetViewTypes has no type specified\\.$#"
count: 1 count: 1
@ -4477,12 +4402,12 @@ parameters:
- -
message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, array\\|int\\|string given\\.$#" message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, array\\|int\\|string given\\.$#"
count: 8 count: 2
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
- -
message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, array\\|int\\|string\\|null given\\.$#" message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, array\\|int\\|string\\|null given\\.$#"
count: 2 count: 1
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
- -
@ -4525,11 +4450,6 @@ parameters:
count: 2 count: 2
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
-
message: "#^Part \\$xAxis\\-\\>getShadowProperty\\('effect'\\) \\(array\\|int\\|string\\|null\\) of encapsed string cannot be cast to string\\.$#"
count: 1
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
- -
message: "#^Part \\$xAxis\\-\\>getShadowProperty\\(\\['color', 'type'\\]\\) \\(array\\|int\\|string\\|null\\) of encapsed string cannot be cast to string\\.$#" message: "#^Part \\$xAxis\\-\\>getShadowProperty\\(\\['color', 'type'\\]\\) \\(array\\|int\\|string\\|null\\) of encapsed string cannot be cast to string\\.$#"
count: 1 count: 1

View File

@ -3088,7 +3088,7 @@ class Calculation
} }
// Test whether we have any language data for this language (any locale) // Test whether we have any language data for this language (any locale)
if (in_array($language, self::$validLocaleLanguages)) { if (in_array($language, self::$validLocaleLanguages, true)) {
// initialise language/locale settings // initialise language/locale settings
self::$localeFunctions = []; self::$localeFunctions = [];
self::$localeArgumentSeparator = ','; self::$localeArgumentSeparator = ',';

View File

@ -152,7 +152,7 @@ class Functions
if ($condition === '') { if ($condition === '') {
return '=""'; return '=""';
} }
if (!is_string($condition) || !in_array($condition[0], ['>', '<', '='])) { if (!is_string($condition) || !in_array($condition[0], ['>', '<', '='], true)) {
$condition = self::operandSpecialHandling($condition); $condition = self::operandSpecialHandling($condition);
if (is_bool($condition)) { if (is_bool($condition)) {
return '=' . ($condition ? 'TRUE' : 'FALSE'); return '=' . ($condition ? 'TRUE' : 'FALSE');

View File

@ -47,7 +47,7 @@ class ErrorValue
return false; return false;
} }
return in_array($value, ExcelError::$errorCodes) || $value === ExcelError::CALC(); return in_array($value, ExcelError::$errorCodes, true) || $value === ExcelError::CALC();
} }
/** /**

View File

@ -11,7 +11,7 @@ class ExcelError
/** /**
* List of error codes. * List of error codes.
* *
* @var array * @var array<string, string>
*/ */
public static $errorCodes = [ public static $errorCodes = [
'null' => '#NULL!', 'null' => '#NULL!',
@ -60,7 +60,7 @@ class ExcelError
* *
* @return string #NULL! * @return string #NULL!
*/ */
public static function null() public static function null(): string
{ {
return self::$errorCodes['null']; return self::$errorCodes['null'];
} }
@ -72,7 +72,7 @@ class ExcelError
* *
* @return string #NUM! * @return string #NUM!
*/ */
public static function NAN() public static function NAN(): string
{ {
return self::$errorCodes['num']; return self::$errorCodes['num'];
} }
@ -84,7 +84,7 @@ class ExcelError
* *
* @return string #REF! * @return string #REF!
*/ */
public static function REF() public static function REF(): string
{ {
return self::$errorCodes['reference']; return self::$errorCodes['reference'];
} }
@ -100,7 +100,7 @@ class ExcelError
* *
* @return string #N/A! * @return string #N/A!
*/ */
public static function NA() public static function NA(): string
{ {
return self::$errorCodes['na']; return self::$errorCodes['na'];
} }
@ -112,7 +112,7 @@ class ExcelError
* *
* @return string #VALUE! * @return string #VALUE!
*/ */
public static function VALUE() public static function VALUE(): string
{ {
return self::$errorCodes['value']; return self::$errorCodes['value'];
} }
@ -124,7 +124,7 @@ class ExcelError
* *
* @return string #NAME? * @return string #NAME?
*/ */
public static function NAME() public static function NAME(): string
{ {
return self::$errorCodes['name']; return self::$errorCodes['name'];
} }
@ -134,7 +134,7 @@ class ExcelError
* *
* @return string #DIV/0! * @return string #DIV/0!
*/ */
public static function DIV0() public static function DIV0(): string
{ {
return self::$errorCodes['divisionbyzero']; return self::$errorCodes['divisionbyzero'];
} }
@ -142,9 +142,9 @@ class ExcelError
/** /**
* CALC. * CALC.
* *
* @return string #Not Yet Implemented * @return string #CALC!
*/ */
public static function CALC() public static function CALC(): string
{ {
return '#CALC!'; return '#CALC!';
} }

View File

@ -73,7 +73,7 @@ class HLookup extends LookupBase
// break if we have passed possible keys // break if we have passed possible keys
$bothNumeric = is_numeric($lookupValue) && is_numeric($rowData); $bothNumeric = is_numeric($lookupValue) && is_numeric($rowData);
$bothNotNumeric = !is_numeric($lookupValue) && !is_numeric($rowData); $bothNotNumeric = !is_numeric($lookupValue) && !is_numeric($rowData);
$cellDataLower = StringHelper::strToLower($rowData); $cellDataLower = StringHelper::strToLower((string) $rowData);
if ( if (
$notExactMatch && $notExactMatch &&

View File

@ -90,7 +90,7 @@ class VLookup extends LookupBase
foreach ($lookupArray as $rowKey => $rowData) { foreach ($lookupArray as $rowKey => $rowData) {
$bothNumeric = is_numeric($lookupValue) && is_numeric($rowData[$column]); $bothNumeric = is_numeric($lookupValue) && is_numeric($rowData[$column]);
$bothNotNumeric = !is_numeric($lookupValue) && !is_numeric($rowData[$column]); $bothNotNumeric = !is_numeric($lookupValue) && !is_numeric($rowData[$column]);
$cellDataLower = StringHelper::strToLower($rowData[$column]); $cellDataLower = StringHelper::strToLower((string) $rowData[$column]);
// break if we have passed possible keys // break if we have passed possible keys
if ( if (

View File

@ -202,6 +202,11 @@ class Cell
* *
* @param mixed $value Value * @param mixed $value Value
* @param string $dataType Explicit data type, see DataType::TYPE_* * @param string $dataType Explicit data type, see DataType::TYPE_*
* Note that PhpSpreadsheet does not validate that the value and datatype are consistent, in using this
* method, then it is your responsibility as an end-user developer to validate that the value and
* the datatype match.
* If you do mismatch value and datatpe, then the value you enter may be changed to match the datatype
* that you specify.
* *
* @return Cell * @return Cell
*/ */
@ -210,7 +215,7 @@ class Cell
// set the value according to data type // set the value according to data type
switch ($dataType) { switch ($dataType) {
case DataType::TYPE_NULL: case DataType::TYPE_NULL:
$this->value = $value; $this->value = null;
break; break;
case DataType::TYPE_STRING2: case DataType::TYPE_STRING2:

View File

@ -21,7 +21,7 @@ class DataType
/** /**
* List of error codes. * List of error codes.
* *
* @var array * @var array<string, int>
*/ */
private static $errorCodes = [ private static $errorCodes = [
'#NULL!' => 0, '#NULL!' => 0,
@ -36,7 +36,7 @@ class DataType
/** /**
* Get list of error codes. * Get list of error codes.
* *
* @return array * @return array<string, int>
*/ */
public static function getErrorCodes() public static function getErrorCodes()
{ {
@ -48,7 +48,7 @@ class DataType
* *
* @param null|RichText|string $textValue Value to sanitize to an Excel string * @param null|RichText|string $textValue Value to sanitize to an Excel string
* *
* @return null|RichText|string Sanitized value * @return RichText|string Sanitized value
*/ */
public static function checkString($textValue) public static function checkString($textValue)
{ {
@ -58,7 +58,7 @@ class DataType
} }
// string must never be longer than 32,767 characters, truncate if necessary // string must never be longer than 32,767 characters, truncate if necessary
$textValue = StringHelper::substring($textValue, 0, 32767); $textValue = StringHelper::substring((string) $textValue, 0, 32767);
// we require that newline is represented as "\n" in core, not as "\r\n" or "\r" // we require that newline is represented as "\n" in core, not as "\r\n" or "\r"
$textValue = str_replace(["\r\n", "\r"], "\n", $textValue); $textValue = str_replace(["\r\n", "\r"], "\n", $textValue);

View File

@ -89,25 +89,7 @@ class Axis extends Properties
* *
* @var mixed[] * @var mixed[]
*/ */
private $shadowProperties = [ private $shadowProperties = Properties::PRESETS_OPTIONS[0];
'presets' => self::SHADOW_PRESETS_NOSHADOW,
'effect' => null,
'color' => [
'type' => self::EXCEL_COLOR_TYPE_STANDARD,
'value' => 'black',
'alpha' => 40,
],
'size' => [
'sx' => null,
'sy' => null,
'kx' => null,
],
'blur' => null,
'direction' => null,
'distance' => null,
'algn' => null,
'rotWithShape' => null,
];
/** /**
* Glow Properties. * Glow Properties.
@ -340,6 +322,20 @@ class Axis extends Properties
return $this->getLineStyleArrowSize($this->lineStyleProperties['arrow'][$arrow]['size'], 'len'); return $this->getLineStyleArrowSize($this->lineStyleProperties['arrow'][$arrow]['size'], 'len');
} }
/**
* @param mixed $value
*/
public function setShadowProperty(string $propertyName, $value): self
{
if ($propertyName === 'color' && is_array($value)) {
$this->setShadowColor($value['value'], $value['alpha'], $value['type']);
} else {
$this->shadowProperties[$propertyName] = $value;
}
return $this;
}
/** /**
* Set Shadow Properties. * Set Shadow Properties.
* *
@ -379,6 +375,8 @@ class Axis extends Properties
return $this; return $this;
} }
private const SHADOW_ARRAY_KEYS = ['size', 'color'];
/** /**
* Set Shadow Properties from Mapped Values. * Set Shadow Properties from Mapped Values.
* *
@ -391,12 +389,10 @@ class Axis extends Properties
$base_reference = $reference; $base_reference = $reference;
foreach ($propertiesMap as $property_key => $property_val) { foreach ($propertiesMap as $property_key => $property_val) {
if (is_array($property_val)) { if (is_array($property_val)) {
if ($reference === null) { if (in_array($property_key, self::SHADOW_ARRAY_KEYS, true)) {
$reference = &$this->shadowProperties[$property_key]; $reference = &$this->shadowProperties[$property_key];
} else { $this->setShadowPropertiesMapValues($property_val, $reference);
$reference = &$reference[$property_key];
} }
$this->setShadowPropertiesMapValues($property_val, $reference);
} else { } else {
if ($base_reference === null) { if ($base_reference === null) {
$this->shadowProperties[$property_key] = $property_val; $this->shadowProperties[$property_key] = $property_val;
@ -435,7 +431,7 @@ class Axis extends Properties
private function setShadowBlur($blur) private function setShadowBlur($blur)
{ {
if ($blur !== null) { if ($blur !== null) {
$this->shadowProperties['blur'] = (string) $this->getExcelPointsWidth($blur); $this->shadowProperties['blur'] = $blur;
} }
return $this; return $this;
@ -444,14 +440,14 @@ class Axis extends Properties
/** /**
* Set Shadow Angle. * Set Shadow Angle.
* *
* @param null|int $angle * @param null|float|int $angle
* *
* @return $this * @return $this
*/ */
private function setShadowAngle($angle) private function setShadowAngle($angle)
{ {
if ($angle !== null) { if (is_numeric($angle)) {
$this->shadowProperties['direction'] = (string) $this->getExcelPointsAngle($angle); $this->shadowProperties['direction'] = $angle;
} }
return $this; return $this;
@ -467,7 +463,7 @@ class Axis extends Properties
private function setShadowDistance($distance) private function setShadowDistance($distance)
{ {
if ($distance !== null) { if ($distance !== null) {
$this->shadowProperties['distance'] = (string) $this->getExcelPointsWidth($distance); $this->shadowProperties['distance'] = $distance;
} }
return $this; return $this;
@ -525,7 +521,7 @@ class Axis extends Properties
private function setGlowSize($size) private function setGlowSize($size)
{ {
if ($size !== null) { if ($size !== null) {
$this->glowProperties['size'] = $this->getExcelPointsWidth($size); $this->glowProperties['size'] = $size;
} }
return $this; return $this;
@ -555,7 +551,7 @@ class Axis extends Properties
public function setSoftEdges($size): void public function setSoftEdges($size): void
{ {
if ($size !== null) { if ($size !== null) {
$this->softEdges['size'] = (string) $this->getExcelPointsWidth($size); $this->softEdges['size'] = $size;
} }
} }

View File

@ -45,25 +45,7 @@ class GridLines extends Properties
], ],
]; ];
private $shadowProperties = [ private $shadowProperties = Properties::PRESETS_OPTIONS[0];
'presets' => self::SHADOW_PRESETS_NOSHADOW,
'effect' => null,
'color' => [
'type' => self::EXCEL_COLOR_TYPE_STANDARD,
'value' => 'black',
'alpha' => 85,
],
'size' => [
'sx' => null,
'sy' => null,
'kx' => null,
],
'blur' => null,
'direction' => null,
'distance' => null,
'algn' => null,
'rotWithShape' => null,
];
private $glowProperties = [ private $glowProperties = [
'size' => null, 'size' => null,
@ -202,6 +184,18 @@ class GridLines extends Properties
->setGlowColor($colorValue, $colorAlpha, $colorType); ->setGlowColor($colorValue, $colorAlpha, $colorType);
} }
/**
* Get Glow Property.
*
* @param array|string $property
*
* @return null|string
*/
public function getGlowProperty($property)
{
return $this->getArrayElementsValue($this->glowProperties, $property);
}
/** /**
* Get Glow Color Property. * Get Glow Color Property.
* *
@ -233,7 +227,7 @@ class GridLines extends Properties
*/ */
private function setGlowSize($size) private function setGlowSize($size)
{ {
$this->glowProperties['size'] = $this->getExcelPointsWidth((float) $size); $this->glowProperties['size'] = $size;
return $this; return $this;
} }
@ -253,7 +247,7 @@ class GridLines extends Properties
$this->glowProperties['color']['value'] = (string) $color; $this->glowProperties['color']['value'] = (string) $color;
} }
if ($alpha !== null) { if ($alpha !== null) {
$this->glowProperties['color']['alpha'] = $this->getTrueAlpha((int) $alpha); $this->glowProperties['color']['alpha'] = (int) $alpha;
} }
if ($colorType !== null) { if ($colorType !== null) {
$this->glowProperties['color']['type'] = (string) $colorType; $this->glowProperties['color']['type'] = (string) $colorType;
@ -275,16 +269,27 @@ class GridLines extends Properties
return $this->getLineStyleArrowSize($this->lineProperties['style']['arrow'][$arrowSelector]['size'], $propertySelector); return $this->getLineStyleArrowSize($this->lineProperties['style']['arrow'][$arrowSelector]['size'], $propertySelector);
} }
/**
* @param mixed $value
*/
public function setShadowProperty(string $propertyName, $value): self
{
$this->activateObject();
$this->shadowProperties[$propertyName] = $value;
return $this;
}
/** /**
* Set Shadow Properties. * Set Shadow Properties.
* *
* @param int $presets * @param int $presets
* @param string $colorValue * @param string $colorValue
* @param string $colorType * @param string $colorType
* @param string $colorAlpha * @param null|float|int|string $colorAlpha
* @param string $blur * @param null|float $blur
* @param int $angle * @param null|int $angle
* @param float $distance * @param null|float $distance
*/ */
public function setShadowProperties($presets, $colorValue = null, $colorType = null, $colorAlpha = null, $blur = null, $angle = null, $distance = null): void public function setShadowProperties($presets, $colorValue = null, $colorType = null, $colorAlpha = null, $blur = null, $angle = null, $distance = null): void
{ {
@ -292,10 +297,10 @@ class GridLines extends Properties
->setShadowPresetsProperties((int) $presets) ->setShadowPresetsProperties((int) $presets)
->setShadowColor( ->setShadowColor(
$colorValue ?? $this->shadowProperties['color']['value'], $colorValue ?? $this->shadowProperties['color']['value'],
$colorAlpha === null ? (int) $this->shadowProperties['color']['alpha'] : $this->getTrueAlpha($colorAlpha), $colorAlpha === null ? (int) $this->shadowProperties['color']['alpha'] : (int) $colorAlpha,
$colorType ?? $this->shadowProperties['color']['type'] $colorType ?? $this->shadowProperties['color']['type']
) )
->setShadowBlur((float) $blur) ->setShadowBlur($blur)
->setShadowAngle($angle) ->setShadowAngle($angle)
->setShadowDistance($distance); ->setShadowDistance($distance);
} }
@ -315,6 +320,8 @@ class GridLines extends Properties
return $this; return $this;
} }
private const SHADOW_ARRAY_KEYS = ['size', 'color'];
/** /**
* Set Shadow Properties Values. * Set Shadow Properties Values.
* *
@ -327,12 +334,10 @@ class GridLines extends Properties
$base_reference = $reference; $base_reference = $reference;
foreach ($propertiesMap as $property_key => $property_val) { foreach ($propertiesMap as $property_key => $property_val) {
if (is_array($property_val)) { if (is_array($property_val)) {
if ($reference === null) { if (in_array($property_key, self::SHADOW_ARRAY_KEYS, true)) {
$reference = &$this->shadowProperties[$property_key]; $reference = &$this->shadowProperties[$property_key];
} else { $this->setShadowPropertiesMapValues($property_val, $reference);
$reference = &$reference[$property_key];
} }
$this->setShadowPropertiesMapValues($property_val, $reference);
} else { } else {
if ($base_reference === null) { if ($base_reference === null) {
$this->shadowProperties[$property_key] = $property_val; $this->shadowProperties[$property_key] = $property_val;
@ -360,7 +365,7 @@ class GridLines extends Properties
$this->shadowProperties['color']['value'] = (string) $color; $this->shadowProperties['color']['value'] = (string) $color;
} }
if ($alpha !== null) { if ($alpha !== null) {
$this->shadowProperties['color']['alpha'] = $this->getTrueAlpha((int) $alpha); $this->shadowProperties['color']['alpha'] = (int) $alpha;
} }
if ($colorType !== null) { if ($colorType !== null) {
$this->shadowProperties['color']['type'] = (string) $colorType; $this->shadowProperties['color']['type'] = (string) $colorType;
@ -372,14 +377,14 @@ class GridLines extends Properties
/** /**
* Set Shadow Blur. * Set Shadow Blur.
* *
* @param float $blur * @param ?float $blur
* *
* @return $this * @return $this
*/ */
private function setShadowBlur($blur) private function setShadowBlur($blur)
{ {
if ($blur !== null) { if ($blur !== null) {
$this->shadowProperties['blur'] = (string) $this->getExcelPointsWidth($blur); $this->shadowProperties['blur'] = $blur;
} }
return $this; return $this;
@ -388,14 +393,14 @@ class GridLines extends Properties
/** /**
* Set Shadow Angle. * Set Shadow Angle.
* *
* @param int $angle * @param null|float|int|string $angle
* *
* @return $this * @return $this
*/ */
private function setShadowAngle($angle) private function setShadowAngle($angle)
{ {
if ($angle !== null) { if (is_numeric($angle)) {
$this->shadowProperties['direction'] = (string) $this->getExcelPointsAngle($angle); $this->shadowProperties['direction'] = $angle;
} }
return $this; return $this;
@ -404,14 +409,14 @@ class GridLines extends Properties
/** /**
* Set Shadow Distance. * Set Shadow Distance.
* *
* @param float $distance * @param ?float $distance
* *
* @return $this * @return $this
*/ */
private function setShadowDistance($distance) private function setShadowDistance($distance)
{ {
if ($distance !== null) { if ($distance !== null) {
$this->shadowProperties['distance'] = (string) $this->getExcelPointsWidth($distance); $this->shadowProperties['distance'] = $distance;
} }
return $this; return $this;
@ -434,11 +439,11 @@ class GridLines extends Properties
* *
* @param float $size * @param float $size
*/ */
public function setSoftEdgesSize($size): void public function setSoftEdges($size): void
{ {
if ($size !== null) { if ($size !== null) {
$this->activateObject(); $this->activateObject();
$this->softEdges['size'] = (string) $this->getExcelPointsWidth($size); $this->softEdges['size'] = $size;
} }
} }

View File

@ -110,7 +110,10 @@ abstract class Properties
const SHADOW_PRESETS_PERSPECTIVE_UPPER_LEFT = 21; const SHADOW_PRESETS_PERSPECTIVE_UPPER_LEFT = 21;
const SHADOW_PRESETS_PERSPECTIVE_LOWER_RIGHT = 22; const SHADOW_PRESETS_PERSPECTIVE_LOWER_RIGHT = 22;
const SHADOW_PRESETS_PERSPECTIVE_LOWER_LEFT = 23; const SHADOW_PRESETS_PERSPECTIVE_LOWER_LEFT = 23;
const POINTS_WIDTH_MULTIPLIER = 12700; const POINTS_WIDTH_MULTIPLIER = 12700;
const ANGLE_MULTIPLIER = 60000; // direction and size-kx size-ky
const PERCENTAGE_MULTIPLIER = 100000; // size sx and sy
/** /**
* @param float $width * @param float $width
@ -122,27 +125,58 @@ abstract class Properties
return $width * self::POINTS_WIDTH_MULTIPLIER; return $width * self::POINTS_WIDTH_MULTIPLIER;
} }
/** public static function pointsToXml(float $width): string
* @param float $angle
*
* @return float
*/
protected function getExcelPointsAngle($angle)
{ {
return $angle * 60000; return (string) (int) ($width * self::POINTS_WIDTH_MULTIPLIER);
} }
protected function getTrueAlpha($alpha) public static function xmlToPoints(string $width): float
{
return ((float) $width) / self::POINTS_WIDTH_MULTIPLIER;
}
public static function angleToXml(float $angle): string
{
return (string) (int) ($angle * self::ANGLE_MULTIPLIER);
}
public static function xmlToAngle(string $angle): float
{
return ((float) $angle) / self::ANGLE_MULTIPLIER;
}
public static function tenthOfPercentToXml(float $value): string
{
return (string) (int) ($value * self::PERCENTAGE_MULTIPLIER);
}
public static function xmlToTenthOfPercent(string $value): float
{
return ((float) $value) / self::PERCENTAGE_MULTIPLIER;
}
public static function alphaToXml(int $alpha): string
{ {
return (string) (100 - $alpha) . '000'; return (string) (100 - $alpha) . '000';
} }
protected function setColorProperties($color, $alpha, $colorType) /**
* @param float|int|string $alpha
*/
public static function alphaFromXml($alpha): int
{
return 100 - ((int) $alpha / 1000);
}
/**
* @param null|float|int|string $alpha
*/
protected function setColorProperties(?string $color, $alpha, ?string $colorType): array
{ {
return [ return [
'type' => (string) $colorType, 'type' => $colorType,
'value' => (string) $color, 'value' => $color,
'alpha' => (string) $this->getTrueAlpha($alpha), 'alpha' => (int) $alpha,
]; ];
} }
@ -163,196 +197,217 @@ abstract class Properties
return $sizes[$arraySelector][$arrayKaySelector]; return $sizes[$arraySelector][$arrayKaySelector];
} }
protected const PRESETS_OPTIONS = [
//NONE
0 => [
'presets' => self::SHADOW_PRESETS_NOSHADOW,
'effect' => null,
'color' => [
'type' => self::EXCEL_COLOR_TYPE_STANDARD,
'value' => 'black',
'alpha' => 40,
],
'size' => [
'sx' => null,
'sy' => null,
'kx' => null,
'ky' => null,
],
'blur' => null,
'direction' => null,
'distance' => null,
'algn' => null,
'rotWithShape' => null,
],
//OUTER
1 => [
'effect' => 'outerShdw',
'blur' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 38100 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 2700000 / self::ANGLE_MULTIPLIER,
'algn' => 'tl',
'rotWithShape' => '0',
],
2 => [
'effect' => 'outerShdw',
'blur' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 38100 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 5400000 / self::ANGLE_MULTIPLIER,
'algn' => 't',
'rotWithShape' => '0',
],
3 => [
'effect' => 'outerShdw',
'blur' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 38100 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 8100000 / self::ANGLE_MULTIPLIER,
'algn' => 'tr',
'rotWithShape' => '0',
],
4 => [
'effect' => 'outerShdw',
'blur' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 38100 / self::POINTS_WIDTH_MULTIPLIER,
'algn' => 'l',
'rotWithShape' => '0',
],
5 => [
'effect' => 'outerShdw',
'size' => [
'sx' => 102000 / self::PERCENTAGE_MULTIPLIER,
'sy' => 102000 / self::PERCENTAGE_MULTIPLIER,
],
'blur' => 63500 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 38100 / self::POINTS_WIDTH_MULTIPLIER,
'algn' => 'ctr',
'rotWithShape' => '0',
],
6 => [
'effect' => 'outerShdw',
'blur' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 38100 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 10800000 / self::ANGLE_MULTIPLIER,
'algn' => 'r',
'rotWithShape' => '0',
],
7 => [
'effect' => 'outerShdw',
'blur' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 38100 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 18900000 / self::ANGLE_MULTIPLIER,
'algn' => 'bl',
'rotWithShape' => '0',
],
8 => [
'effect' => 'outerShdw',
'blur' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 38100 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 16200000 / self::ANGLE_MULTIPLIER,
'rotWithShape' => '0',
],
9 => [
'effect' => 'outerShdw',
'blur' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 38100 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 13500000 / self::ANGLE_MULTIPLIER,
'algn' => 'br',
'rotWithShape' => '0',
],
//INNER
10 => [
'effect' => 'innerShdw',
'blur' => 63500 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 2700000 / self::ANGLE_MULTIPLIER,
],
11 => [
'effect' => 'innerShdw',
'blur' => 63500 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 5400000 / self::ANGLE_MULTIPLIER,
],
12 => [
'effect' => 'innerShdw',
'blur' => 63500 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 8100000 / self::ANGLE_MULTIPLIER,
],
13 => [
'effect' => 'innerShdw',
'blur' => 63500 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
],
14 => [
'effect' => 'innerShdw',
'blur' => 114300 / self::POINTS_WIDTH_MULTIPLIER,
],
15 => [
'effect' => 'innerShdw',
'blur' => 63500 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 10800000 / self::ANGLE_MULTIPLIER,
],
16 => [
'effect' => 'innerShdw',
'blur' => 63500 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 18900000 / self::ANGLE_MULTIPLIER,
],
17 => [
'effect' => 'innerShdw',
'blur' => 63500 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 16200000 / self::ANGLE_MULTIPLIER,
],
18 => [
'effect' => 'innerShdw',
'blur' => 63500 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 50800 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 13500000 / self::ANGLE_MULTIPLIER,
],
//perspective
19 => [
'effect' => 'outerShdw',
'blur' => 152400 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 317500 / self::POINTS_WIDTH_MULTIPLIER,
'size' => [
'sx' => 90000 / self::PERCENTAGE_MULTIPLIER,
'sy' => -19000 / self::PERCENTAGE_MULTIPLIER,
],
'direction' => 5400000 / self::ANGLE_MULTIPLIER,
'rotWithShape' => '0',
],
20 => [
'effect' => 'outerShdw',
'blur' => 76200 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 18900000 / self::ANGLE_MULTIPLIER,
'size' => [
'sy' => 23000 / self::PERCENTAGE_MULTIPLIER,
'kx' => -1200000 / self::ANGLE_MULTIPLIER,
],
'algn' => 'bl',
'rotWithShape' => '0',
],
21 => [
'effect' => 'outerShdw',
'blur' => 76200 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 13500000 / self::ANGLE_MULTIPLIER,
'size' => [
'sy' => 23000 / self::PERCENTAGE_MULTIPLIER,
'kx' => 1200000 / self::ANGLE_MULTIPLIER,
],
'algn' => 'br',
'rotWithShape' => '0',
],
22 => [
'effect' => 'outerShdw',
'blur' => 76200 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 12700 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 2700000 / self::ANGLE_MULTIPLIER,
'size' => [
'sy' => -23000 / self::PERCENTAGE_MULTIPLIER,
'kx' => -800400 / self::ANGLE_MULTIPLIER,
],
'algn' => 'bl',
'rotWithShape' => '0',
],
23 => [
'effect' => 'outerShdw',
'blur' => 76200 / self::POINTS_WIDTH_MULTIPLIER,
'distance' => 12700 / self::POINTS_WIDTH_MULTIPLIER,
'direction' => 8100000 / self::ANGLE_MULTIPLIER,
'size' => [
'sy' => -23000 / self::PERCENTAGE_MULTIPLIER,
'kx' => 800400 / self::ANGLE_MULTIPLIER,
],
'algn' => 'br',
'rotWithShape' => '0',
],
];
protected function getShadowPresetsMap($presetsOption) protected function getShadowPresetsMap($presetsOption)
{ {
$presets_options = [ return self::PRESETS_OPTIONS[$presetsOption] ?? self::PRESETS_OPTIONS[0];
//OUTER
1 => [
'effect' => 'outerShdw',
'blur' => '50800',
'distance' => '38100',
'direction' => '2700000',
'algn' => 'tl',
'rotWithShape' => '0',
],
2 => [
'effect' => 'outerShdw',
'blur' => '50800',
'distance' => '38100',
'direction' => '5400000',
'algn' => 't',
'rotWithShape' => '0',
],
3 => [
'effect' => 'outerShdw',
'blur' => '50800',
'distance' => '38100',
'direction' => '8100000',
'algn' => 'tr',
'rotWithShape' => '0',
],
4 => [
'effect' => 'outerShdw',
'blur' => '50800',
'distance' => '38100',
'algn' => 'l',
'rotWithShape' => '0',
],
5 => [
'effect' => 'outerShdw',
'size' => [
'sx' => '102000',
'sy' => '102000',
],
'blur' => '63500',
'distance' => '38100',
'algn' => 'ctr',
'rotWithShape' => '0',
],
6 => [
'effect' => 'outerShdw',
'blur' => '50800',
'distance' => '38100',
'direction' => '10800000',
'algn' => 'r',
'rotWithShape' => '0',
],
7 => [
'effect' => 'outerShdw',
'blur' => '50800',
'distance' => '38100',
'direction' => '18900000',
'algn' => 'bl',
'rotWithShape' => '0',
],
8 => [
'effect' => 'outerShdw',
'blur' => '50800',
'distance' => '38100',
'direction' => '16200000',
'rotWithShape' => '0',
],
9 => [
'effect' => 'outerShdw',
'blur' => '50800',
'distance' => '38100',
'direction' => '13500000',
'algn' => 'br',
'rotWithShape' => '0',
],
//INNER
10 => [
'effect' => 'innerShdw',
'blur' => '63500',
'distance' => '50800',
'direction' => '2700000',
],
11 => [
'effect' => 'innerShdw',
'blur' => '63500',
'distance' => '50800',
'direction' => '5400000',
],
12 => [
'effect' => 'innerShdw',
'blur' => '63500',
'distance' => '50800',
'direction' => '8100000',
],
13 => [
'effect' => 'innerShdw',
'blur' => '63500',
'distance' => '50800',
],
14 => [
'effect' => 'innerShdw',
'blur' => '114300',
],
15 => [
'effect' => 'innerShdw',
'blur' => '63500',
'distance' => '50800',
'direction' => '10800000',
],
16 => [
'effect' => 'innerShdw',
'blur' => '63500',
'distance' => '50800',
'direction' => '18900000',
],
17 => [
'effect' => 'innerShdw',
'blur' => '63500',
'distance' => '50800',
'direction' => '16200000',
],
18 => [
'effect' => 'innerShdw',
'blur' => '63500',
'distance' => '50800',
'direction' => '13500000',
],
//perspective
19 => [
'effect' => 'outerShdw',
'blur' => '152400',
'distance' => '317500',
'size' => [
'sx' => '90000',
'sy' => '-19000',
],
'direction' => '5400000',
'rotWithShape' => '0',
],
20 => [
'effect' => 'outerShdw',
'blur' => '76200',
'direction' => '18900000',
'size' => [
'sy' => '23000',
'kx' => '-1200000',
],
'algn' => 'bl',
'rotWithShape' => '0',
],
21 => [
'effect' => 'outerShdw',
'blur' => '76200',
'direction' => '13500000',
'size' => [
'sy' => '23000',
'kx' => '1200000',
],
'algn' => 'br',
'rotWithShape' => '0',
],
22 => [
'effect' => 'outerShdw',
'blur' => '76200',
'distance' => '12700',
'direction' => '2700000',
'size' => [
'sy' => '-23000',
'kx' => '-800400',
],
'algn' => 'bl',
'rotWithShape' => '0',
],
23 => [
'effect' => 'outerShdw',
'blur' => '76200',
'distance' => '12700',
'direction' => '8100000',
'size' => [
'sy' => '-23000',
'kx' => '800400',
],
'algn' => 'br',
'rotWithShape' => '0',
],
];
return $presets_options[$presetsOption];
} }
protected function getArrayElementsValue($properties, $elements) protected function getArrayElementsValue($properties, $elements)

View File

@ -6,6 +6,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
use PhpOffice\PhpSpreadsheet\Chart\Axis; use PhpOffice\PhpSpreadsheet\Chart\Axis;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\GridLines;
use PhpOffice\PhpSpreadsheet\Chart\Layout; use PhpOffice\PhpSpreadsheet\Chart\Layout;
use PhpOffice\PhpSpreadsheet\Chart\Legend; use PhpOffice\PhpSpreadsheet\Chart\Legend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
@ -71,6 +72,7 @@ class Chart
$rotX = $rotY = $rAngAx = $perspective = null; $rotX = $rotY = $rAngAx = $perspective = null;
$xAxis = new Axis(); $xAxis = new Axis();
$yAxis = new Axis(); $yAxis = new Axis();
$majorGridlines = $minorGridlines = null;
foreach ($chartElementsC as $chartElementKey => $chartElement) { foreach ($chartElementsC as $chartElementKey => $chartElement) {
switch ($chartElementKey) { switch ($chartElementKey) {
case 'chart': case 'chart':
@ -108,26 +110,52 @@ class Chart
break; break;
case 'valAx': case 'valAx':
$whichAxis = null; $whichAxis = null;
if (isset($chartDetail->title, $chartDetail->axPos)) { $axPos = null;
$axisLabel = $this->chartTitle($chartDetail->title->children($this->cNamespace)); if (isset($chartDetail->axPos)) {
$axPos = self::getAttribute($chartDetail->axPos, 'val', 'string'); $axPos = self::getAttribute($chartDetail->axPos, 'val', 'string');
switch ($axPos) { switch ($axPos) {
case 't': case 't':
case 'b': case 'b':
$XaxisLabel = $axisLabel;
$whichAxis = $xAxis; $whichAxis = $xAxis;
break; break;
case 'r': case 'r':
case 'l': case 'l':
$YaxisLabel = $axisLabel;
$whichAxis = $yAxis; $whichAxis = $yAxis;
break; break;
} }
} }
if (isset($chartDetail->title)) {
$axisLabel = $this->chartTitle($chartDetail->title->children($this->cNamespace));
switch ($axPos) {
case 't':
case 'b':
$XaxisLabel = $axisLabel;
break;
case 'r':
case 'l':
$YaxisLabel = $axisLabel;
break;
}
}
$this->readEffects($chartDetail, $whichAxis); $this->readEffects($chartDetail, $whichAxis);
if (isset($chartDetail->majorGridlines)) {
$majorGridlines = new GridLines();
if (isset($chartDetail->majorGridlines->spPr)) {
$this->readEffects($chartDetail->majorGridlines, $majorGridlines);
}
}
if (isset($chartDetail->minorGridlines)) {
$minorGridlines = new GridLines();
if (isset($chartDetail->minorGridlines->spPr)) {
$this->readEffects($chartDetail->minorGridlines, $minorGridlines);
}
}
break; break;
case 'barChart': case 'barChart':
@ -249,7 +277,7 @@ class Chart
} }
} }
} }
$chart = new \PhpOffice\PhpSpreadsheet\Chart\Chart($chartName, $title, $legend, $plotArea, $plotVisOnly, (string) $dispBlanksAs, $XaxisLabel, $YaxisLabel, $xAxis, $yAxis); $chart = new \PhpOffice\PhpSpreadsheet\Chart\Chart($chartName, $title, $legend, $plotArea, $plotVisOnly, (string) $dispBlanksAs, $XaxisLabel, $YaxisLabel, $xAxis, $yAxis, $majorGridlines, $minorGridlines);
if (is_int($rotX)) { if (is_int($rotX)) {
$chart->setRotX($rotX); $chart->setRotX($rotX);
} }
@ -893,7 +921,7 @@ class Chart
} }
/** /**
* @param null|Axis $chartObject may be extended to include other types * @param null|Axis|GridLines $chartObject may be extended to include other types
*/ */
private function readEffects(SimpleXMLElement $chartDetail, $chartObject): void private function readEffects(SimpleXMLElement $chartDetail, $chartObject): void
{ {
@ -905,18 +933,75 @@ class Chart
if (isset($sppr->effectLst->glow)) { if (isset($sppr->effectLst->glow)) {
$axisGlowSize = (float) self::getAttribute($sppr->effectLst->glow, 'rad', 'integer') / Properties::POINTS_WIDTH_MULTIPLIER; $axisGlowSize = (float) self::getAttribute($sppr->effectLst->glow, 'rad', 'integer') / Properties::POINTS_WIDTH_MULTIPLIER;
if ($axisGlowSize != 0.0) { if ($axisGlowSize != 0.0) {
$srgbClr = $schemeClr = ''; $colorArray = $this->readColor($sppr->effectLst->glow);
$colorArray = $this->readColor($sppr->effectLst->glow, $srgbClr, $schemeClr);
$chartObject->setGlowProperties($axisGlowSize, $colorArray['value'], $colorArray['alpha'], $colorArray['type']); $chartObject->setGlowProperties($axisGlowSize, $colorArray['value'], $colorArray['alpha'], $colorArray['type']);
} }
} }
if (isset($sppr->effectLst->softEdge)) { if (isset($sppr->effectLst->softEdge)) {
$chartObject->setSoftEdges((float) self::getAttribute($sppr->effectLst->softEdge, 'rad', 'string') / Properties::POINTS_WIDTH_MULTIPLIER); /** @var string */
$softEdgeSize = self::getAttribute($sppr->effectLst->softEdge, 'rad', 'string');
if (is_numeric($softEdgeSize)) {
$chartObject->setSoftEdges((float) Properties::xmlToPoints($softEdgeSize));
}
}
$type = '';
foreach (self::SHADOW_TYPES as $shadowType) {
if (isset($sppr->effectLst->$shadowType)) {
$type = $shadowType;
break;
}
}
if ($type !== '') {
/** @var string */
$blur = self::getAttribute($sppr->effectLst->$type, 'blurRad', 'string');
$blur = is_numeric($blur) ? Properties::xmlToPoints($blur) : null;
/** @var string */
$dist = self::getAttribute($sppr->effectLst->$type, 'dist', 'string');
$dist = is_numeric($dist) ? Properties::xmlToPoints($dist) : null;
/** @var string */
$direction = self::getAttribute($sppr->effectLst->$type, 'dir', 'string');
$direction = is_numeric($direction) ? Properties::xmlToAngle($direction) : null;
$algn = self::getAttribute($sppr->effectLst->$type, 'algn', 'string');
$rot = self::getAttribute($sppr->effectLst->$type, 'rotWithShape', 'string');
$size = [];
foreach (['sx', 'sy'] as $sizeType) {
$sizeValue = self::getAttribute($sppr->effectLst->$type, $sizeType, 'string');
if (is_numeric($sizeValue)) {
$size[$sizeType] = Properties::xmlToTenthOfPercent((string) $sizeValue);
} else {
$size[$sizeType] = null;
}
}
foreach (['kx', 'ky'] as $sizeType) {
$sizeValue = self::getAttribute($sppr->effectLst->$type, $sizeType, 'string');
if (is_numeric($sizeValue)) {
$size[$sizeType] = Properties::xmlToAngle((string) $sizeValue);
} else {
$size[$sizeType] = null;
}
}
$colorArray = $this->readColor($sppr->effectLst->$type);
$chartObject
->setShadowProperty('effect', $type)
->setShadowProperty('blur', $blur)
->setShadowProperty('direction', $direction)
->setShadowProperty('distance', $dist)
->setShadowProperty('algn', $algn)
->setShadowProperty('rotWithShape', $rot)
->setShadowProperty('size', $size)
->setShadowProperty('color', $colorArray);
} }
} }
private function readColor(SimpleXMLElement $colorXml, ?string &$srgbClr, ?string &$schemeClr): array private const SHADOW_TYPES = [
'outerShdw',
'innerShdw',
];
private function readColor(SimpleXMLElement $colorXml, ?string &$srgbClr = null, ?string &$schemeClr = null): array
{ {
$result = [ $result = [
'type' => null, 'type' => null,
@ -927,16 +1012,27 @@ class Chart
$result['type'] = Properties::EXCEL_COLOR_TYPE_ARGB; $result['type'] = Properties::EXCEL_COLOR_TYPE_ARGB;
$result['value'] = $srgbClr = self::getAttribute($colorXml->srgbClr, 'val', 'string'); $result['value'] = $srgbClr = self::getAttribute($colorXml->srgbClr, 'val', 'string');
if (isset($colorXml->srgbClr->alpha)) { if (isset($colorXml->srgbClr->alpha)) {
$alpha = (int) self::getAttribute($colorXml->srgbClr->alpha, 'val', 'string'); /** @var string */
$alpha = 100 - (int) ($alpha / 1000); $alpha = self::getAttribute($colorXml->srgbClr->alpha, 'val', 'string');
$alpha = Properties::alphaFromXml($alpha);
$result['alpha'] = $alpha; $result['alpha'] = $alpha;
} }
} elseif (isset($colorXml->schemeClr)) { } elseif (isset($colorXml->schemeClr)) {
$result['type'] = Properties::EXCEL_COLOR_TYPE_SCHEME; $result['type'] = Properties::EXCEL_COLOR_TYPE_SCHEME;
$result['value'] = $schemeClr = self::getAttribute($colorXml->schemeClr, 'val', 'string'); $result['value'] = $schemeClr = self::getAttribute($colorXml->schemeClr, 'val', 'string');
if (isset($colorXml->schemeClr->alpha)) { if (isset($colorXml->schemeClr->alpha)) {
$alpha = (int) self::getAttribute($colorXml->schemeClr->alpha, 'val', 'string'); /** @var string */
$alpha = 100 - (int) ($alpha / 1000); $alpha = self::getAttribute($colorXml->schemeClr->alpha, 'val', 'string');
$alpha = Properties::alphaFromXml($alpha);
$result['alpha'] = $alpha;
}
} elseif (isset($colorXml->prstClr)) {
$result['type'] = Properties::EXCEL_COLOR_TYPE_STANDARD;
$result['value'] = self::getAttribute($colorXml->prstClr, 'val', 'string');
if (isset($colorXml->prstClr->alpha)) {
/** @var string */
$alpha = self::getAttribute($colorXml->prstClr->alpha, 'val', 'string');
$alpha = Properties::alphaFromXml($alpha);
$result['alpha'] = $alpha; $result['alpha'] = $alpha;
} }
} }

View File

@ -399,7 +399,7 @@ class ReferenceHelper
return $highestColumn . $row; return $highestColumn . $row;
}, range(1, $highestRow)), }, range(1, $highestRow)),
function ($coordinate) use ($allCoordinates) { function ($coordinate) use ($allCoordinates) {
return !in_array($coordinate, $allCoordinates); return in_array($coordinate, $allCoordinates, true) === false;
} }
); );
@ -929,7 +929,7 @@ class ReferenceHelper
$coordinate = Coordinate::stringFromColumnIndex($j + 1) . $i; $coordinate = Coordinate::stringFromColumnIndex($j + 1) . $i;
$worksheet->removeConditionalStyles($coordinate); $worksheet->removeConditionalStyles($coordinate);
if ($worksheet->cellExists($coordinate)) { if ($worksheet->cellExists($coordinate)) {
$worksheet->getCell($coordinate)->setValueExplicit('', DataType::TYPE_NULL); $worksheet->getCell($coordinate)->setValueExplicit(null, DataType::TYPE_NULL);
$worksheet->getCell($coordinate)->setXfIndex(0); $worksheet->getCell($coordinate)->setXfIndex(0);
} }
} }
@ -945,7 +945,7 @@ class ReferenceHelper
$coordinate = Coordinate::stringFromColumnIndex($i + 1) . $j; $coordinate = Coordinate::stringFromColumnIndex($i + 1) . $j;
$worksheet->removeConditionalStyles($coordinate); $worksheet->removeConditionalStyles($coordinate);
if ($worksheet->cellExists($coordinate)) { if ($worksheet->cellExists($coordinate)) {
$worksheet->getCell($coordinate)->setValueExplicit('', DataType::TYPE_NULL); $worksheet->getCell($coordinate)->setValueExplicit(null, DataType::TYPE_NULL);
$worksheet->getCell($coordinate)->setXfIndex(0); $worksheet->getCell($coordinate)->setXfIndex(0);
} }
} }

View File

@ -329,12 +329,8 @@ class StringHelper
/** /**
* Try to sanitize UTF8, stripping invalid byte sequences. Not perfect. Does not surrogate characters. * Try to sanitize UTF8, stripping invalid byte sequences. Not perfect. Does not surrogate characters.
*
* @param string $textValue
*
* @return string
*/ */
public static function sanitizeUTF8($textValue) public static function sanitizeUTF8(string $textValue): string
{ {
if (self::getIsIconvEnabled()) { if (self::getIsIconvEnabled()) {
$textValue = @iconv('UTF-8', 'UTF-8', $textValue); $textValue = @iconv('UTF-8', 'UTF-8', $textValue);
@ -349,12 +345,8 @@ class StringHelper
/** /**
* Check if a string contains UTF8 data. * Check if a string contains UTF8 data.
*
* @param string $textValue
*
* @return bool
*/ */
public static function isUTF8($textValue) public static function isUTF8(string $textValue): bool
{ {
return $textValue === '' || preg_match('/^./su', $textValue) === 1; return $textValue === '' || preg_match('/^./su', $textValue) === 1;
} }
@ -364,10 +356,8 @@ class StringHelper
* point as decimal separator in case locale is other than English. * point as decimal separator in case locale is other than English.
* *
* @param mixed $numericValue * @param mixed $numericValue
*
* @return string
*/ */
public static function formatNumber($numericValue) public static function formatNumber($numericValue): string
{ {
if (is_float($numericValue)) { if (is_float($numericValue)) {
return str_replace(',', '.', $numericValue); return str_replace(',', '.', $numericValue);
@ -385,10 +375,8 @@ class StringHelper
* *
* @param string $textValue UTF-8 encoded string * @param string $textValue UTF-8 encoded string
* @param mixed[] $arrcRuns Details of rich text runs in $value * @param mixed[] $arrcRuns Details of rich text runs in $value
*
* @return string
*/ */
public static function UTF8toBIFF8UnicodeShort($textValue, $arrcRuns = []) public static function UTF8toBIFF8UnicodeShort(string $textValue, array $arrcRuns = []): string
{ {
// character count // character count
$ln = self::countCharacters($textValue, 'UTF-8'); $ln = self::countCharacters($textValue, 'UTF-8');
@ -419,10 +407,8 @@ class StringHelper
* see OpenOffice.org's Documentation of the Microsoft Excel File Format, sect. 2.5.3. * see OpenOffice.org's Documentation of the Microsoft Excel File Format, sect. 2.5.3.
* *
* @param string $textValue UTF-8 encoded string * @param string $textValue UTF-8 encoded string
*
* @return string
*/ */
public static function UTF8toBIFF8UnicodeLong($textValue) public static function UTF8toBIFF8UnicodeLong(string $textValue): string
{ {
// character count // character count
$ln = self::countCharacters($textValue, 'UTF-8'); $ln = self::countCharacters($textValue, 'UTF-8');
@ -436,13 +422,10 @@ class StringHelper
/** /**
* Convert string from one encoding to another. * Convert string from one encoding to another.
* *
* @param string $textValue
* @param string $to Encoding to convert to, e.g. 'UTF-8' * @param string $to Encoding to convert to, e.g. 'UTF-8'
* @param string $from Encoding to convert from, e.g. 'UTF-16LE' * @param string $from Encoding to convert from, e.g. 'UTF-16LE'
*
* @return string
*/ */
public static function convertEncoding($textValue, $to, $from) public static function convertEncoding(string $textValue, string $to, string $from): string
{ {
if (self::getIsIconvEnabled()) { if (self::getIsIconvEnabled()) {
$result = iconv($from, $to . self::$iconvOptions, $textValue); $result = iconv($from, $to . self::$iconvOptions, $textValue);
@ -457,52 +440,45 @@ class StringHelper
/** /**
* Get character count. * Get character count.
* *
* @param string $textValue
* @param string $encoding Encoding * @param string $encoding Encoding
* *
* @return int Character count * @return int Character count
*/ */
public static function countCharacters($textValue, $encoding = 'UTF-8') public static function countCharacters(string $textValue, string $encoding = 'UTF-8'): int
{ {
return mb_strlen($textValue ?? '', $encoding); return mb_strlen($textValue, $encoding);
} }
/** /**
* Get a substring of a UTF-8 encoded string. * Get a substring of a UTF-8 encoded string.
* *
* @param null|string $textValue UTF-8 encoded string * @param string $textValue UTF-8 encoded string
* @param int $offset Start offset * @param int $offset Start offset
* @param int $length Maximum number of characters in substring * @param int $length Maximum number of characters in substring
*
* @return string
*/ */
public static function substring($textValue, $offset, $length = 0) public static function substring(string $textValue, int $offset, int $length = 0): string
{ {
return mb_substr($textValue ?? '', $offset, $length, 'UTF-8'); return mb_substr($textValue, $offset, $length, 'UTF-8');
} }
/** /**
* Convert a UTF-8 encoded string to upper case. * Convert a UTF-8 encoded string to upper case.
* *
* @param string $textValue UTF-8 encoded string * @param string $textValue UTF-8 encoded string
*
* @return string
*/ */
public static function strToUpper($textValue) public static function strToUpper(string $textValue): string
{ {
return mb_convert_case($textValue ?? '', MB_CASE_UPPER, 'UTF-8'); return mb_convert_case($textValue, MB_CASE_UPPER, 'UTF-8');
} }
/** /**
* Convert a UTF-8 encoded string to lower case. * Convert a UTF-8 encoded string to lower case.
* *
* @param string $textValue UTF-8 encoded string * @param string $textValue UTF-8 encoded string
*
* @return string
*/ */
public static function strToLower($textValue) public static function strToLower(string $textValue): string
{ {
return mb_convert_case($textValue ?? '', MB_CASE_LOWER, 'UTF-8'); return mb_convert_case($textValue, MB_CASE_LOWER, 'UTF-8');
} }
/** /**
@ -510,24 +486,27 @@ class StringHelper
* (uppercase every first character in each word, lower case all other characters). * (uppercase every first character in each word, lower case all other characters).
* *
* @param string $textValue UTF-8 encoded string * @param string $textValue UTF-8 encoded string
*
* @return string
*/ */
public static function strToTitle($textValue) public static function strToTitle(string $textValue): string
{ {
return mb_convert_case($textValue, MB_CASE_TITLE, 'UTF-8'); return mb_convert_case($textValue, MB_CASE_TITLE, 'UTF-8');
} }
public static function mbIsUpper($character) public static function mbIsUpper(string $character): bool
{ {
return mb_strtolower($character, 'UTF-8') != $character; return mb_strtolower($character, 'UTF-8') !== $character;
} }
public static function mbStrSplit($string) /**
* Splits a UTF-8 string into an array of individual characters.
*/
public static function mbStrSplit(string $string): array
{ {
// Split at all position not after the start: ^ // Split at all position not after the start: ^
// and not before the end: $ // and not before the end: $
return preg_split('/(?<!^)(?!$)/u', $string); $split = preg_split('/(?<!^)(?!$)/u', $string);
return ($split === false) ? [] : $split;
} }
/** /**
@ -535,10 +514,8 @@ class StringHelper
* and all lowercase characters become uppercase. * and all lowercase characters become uppercase.
* *
* @param string $textValue UTF-8 encoded string * @param string $textValue UTF-8 encoded string
*
* @return string
*/ */
public static function strCaseReverse($textValue) public static function strCaseReverse(string $textValue): string
{ {
$characters = self::mbStrSplit($textValue); $characters = self::mbStrSplit($textValue);
foreach ($characters as &$character) { foreach ($characters as &$character) {
@ -557,10 +534,8 @@ class StringHelper
* and convert it to a numeric if it is. * and convert it to a numeric if it is.
* *
* @param string $operand string value to test * @param string $operand string value to test
*
* @return bool
*/ */
public static function convertToNumberIfFraction(&$operand) public static function convertToNumberIfFraction(string &$operand): bool
{ {
if (preg_match('/^' . self::STRING_REGEXP_FRACTION . '$/i', $operand, $match)) { if (preg_match('/^' . self::STRING_REGEXP_FRACTION . '$/i', $operand, $match)) {
$sign = ($match[1] == '-') ? '-' : '+'; $sign = ($match[1] == '-') ? '-' : '+';
@ -578,10 +553,8 @@ class StringHelper
/** /**
* Get the decimal separator. If it has not yet been set explicitly, try to obtain number * Get the decimal separator. If it has not yet been set explicitly, try to obtain number
* formatting information from locale. * formatting information from locale.
*
* @return string
*/ */
public static function getDecimalSeparator() public static function getDecimalSeparator(): string
{ {
if (!isset(self::$decimalSeparator)) { if (!isset(self::$decimalSeparator)) {
$localeconv = localeconv(); $localeconv = localeconv();
@ -603,7 +576,7 @@ class StringHelper
* *
* @param string $separator Character for decimal separator * @param string $separator Character for decimal separator
*/ */
public static function setDecimalSeparator($separator): void public static function setDecimalSeparator(string $separator): void
{ {
self::$decimalSeparator = $separator; self::$decimalSeparator = $separator;
} }
@ -611,10 +584,8 @@ class StringHelper
/** /**
* Get the thousands separator. If it has not yet been set explicitly, try to obtain number * Get the thousands separator. If it has not yet been set explicitly, try to obtain number
* formatting information from locale. * formatting information from locale.
*
* @return string
*/ */
public static function getThousandsSeparator() public static function getThousandsSeparator(): string
{ {
if (!isset(self::$thousandsSeparator)) { if (!isset(self::$thousandsSeparator)) {
$localeconv = localeconv(); $localeconv = localeconv();
@ -636,7 +607,7 @@ class StringHelper
* *
* @param string $separator Character for thousands separator * @param string $separator Character for thousands separator
*/ */
public static function setThousandsSeparator($separator): void public static function setThousandsSeparator(string $separator): void
{ {
self::$thousandsSeparator = $separator; self::$thousandsSeparator = $separator;
} }
@ -644,10 +615,8 @@ class StringHelper
/** /**
* Get the currency code. If it has not yet been set explicitly, try to obtain the * Get the currency code. If it has not yet been set explicitly, try to obtain the
* symbol information from locale. * symbol information from locale.
*
* @return string
*/ */
public static function getCurrencyCode() public static function getCurrencyCode(): string
{ {
if (!empty(self::$currencyCode)) { if (!empty(self::$currencyCode)) {
return self::$currencyCode; return self::$currencyCode;
@ -674,7 +643,7 @@ class StringHelper
* *
* @param string $currencyCode Character for currency code * @param string $currencyCode Character for currency code
*/ */
public static function setCurrencyCode($currencyCode): void public static function setCurrencyCode(string $currencyCode): void
{ {
self::$currencyCode = $currencyCode; self::$currencyCode = $currencyCode;
} }
@ -682,11 +651,11 @@ class StringHelper
/** /**
* Convert SYLK encoded string to UTF-8. * Convert SYLK encoded string to UTF-8.
* *
* @param string $textValue * @param string $textValue SYLK encoded string
* *
* @return string UTF-8 encoded string * @return string UTF-8 encoded string
*/ */
public static function SYLKtoUTF8($textValue) public static function SYLKtoUTF8(string $textValue): string
{ {
self::buildCharacterSets(); self::buildCharacterSets();

View File

@ -21,9 +21,9 @@ class TimeZone
* *
* @return bool Success or failure * @return bool Success or failure
*/ */
private static function validateTimeZone($timezoneName) private static function validateTimeZone(string $timezoneName): bool
{ {
return in_array($timezoneName, DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC)); return in_array($timezoneName, DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC), true);
} }
/** /**
@ -33,7 +33,7 @@ class TimeZone
* *
* @return bool Success or failure * @return bool Success or failure
*/ */
public static function setTimeZone($timezoneName) public static function setTimeZone(string $timezoneName): bool
{ {
if (self::validateTimezone($timezoneName)) { if (self::validateTimezone($timezoneName)) {
self::$timezone = $timezoneName; self::$timezone = $timezoneName;
@ -49,7 +49,7 @@ class TimeZone
* *
* @return string Timezone (e.g. 'Europe/London') * @return string Timezone (e.g. 'Europe/London')
*/ */
public static function getTimeZone() public static function getTimeZone(): string
{ {
return self::$timezone; return self::$timezone;
} }
@ -63,7 +63,7 @@ class TimeZone
* *
* @return int Number of seconds for timezone adjustment * @return int Number of seconds for timezone adjustment
*/ */
public static function getTimeZoneAdjustment($timezoneName, $timestamp) public static function getTimeZoneAdjustment(?string $timezoneName, $timestamp): int
{ {
$timezoneName = $timezoneName ?? self::$timezone; $timezoneName = $timezoneName ?? self::$timezone;
$dtobj = Date::dateTimeFromTimestamp("$timestamp"); $dtobj = Date::dateTimeFromTimestamp("$timestamp");

View File

@ -12,6 +12,10 @@ use PhpOffice\PhpSpreadsheet\Collection\Cells;
*/ */
abstract class CellIterator implements Iterator abstract class CellIterator implements Iterator
{ {
public const TREAT_NULL_VALUE_AS_EMPTY_CELL = 1;
public const TREAT_EMPTY_STRING_AS_EMPTY_CELL = 2;
/** /**
* Worksheet to iterate. * Worksheet to iterate.
* *

View File

@ -9,7 +9,7 @@ class Column
* *
* @var Worksheet * @var Worksheet
*/ */
private $parent; private $worksheet;
/** /**
* Column index. * Column index.
@ -23,10 +23,10 @@ class Column
* *
* @param string $columnIndex * @param string $columnIndex
*/ */
public function __construct(?Worksheet $parent = null, $columnIndex = 'A') public function __construct(Worksheet $worksheet, $columnIndex = 'A')
{ {
// Set parent and column index // Set parent and column index
$this->parent = $parent; $this->worksheet = $worksheet;
$this->columnIndex = $columnIndex; $this->columnIndex = $columnIndex;
} }
@ -36,7 +36,7 @@ class Column
public function __destruct() public function __destruct()
{ {
// @phpstan-ignore-next-line // @phpstan-ignore-next-line
$this->parent = null; $this->worksheet = null;
} }
/** /**
@ -57,6 +57,53 @@ class Column
*/ */
public function getCellIterator($startRow = 1, $endRow = null) public function getCellIterator($startRow = 1, $endRow = null)
{ {
return new ColumnCellIterator($this->parent, $this->columnIndex, $startRow, $endRow); return new ColumnCellIterator($this->worksheet, $this->columnIndex, $startRow, $endRow);
}
/**
* Returns a boolean true if the column contains no cells. By default, this means that no cell records exist in the
* collection for this column. false will be returned otherwise.
* This rule can be modified by passing a $definitionOfEmptyFlags value:
* 1 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL If the only cells in the collection are null value
* cells, then the column will be considered empty.
* 2 - CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL If the only cells in the collection are empty
* string value cells, then the column will be considered empty.
* 3 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL | CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL
* If the only cells in the collection are null value or empty string value cells, then the column
* will be considered empty.
*
* @param int $definitionOfEmptyFlags
* Possible Flag Values are:
* CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL
* CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL
*/
public function isEmpty(int $definitionOfEmptyFlags = 0): bool
{
$nullValueCellIsEmpty = (bool) ($definitionOfEmptyFlags & CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL);
$emptyStringCellIsEmpty = (bool) ($definitionOfEmptyFlags & CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL);
$cellIterator = $this->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(true);
foreach ($cellIterator as $cell) {
$value = $cell->getValue();
if ($value === null && $nullValueCellIsEmpty === true) {
continue;
}
if ($value === '' && $emptyStringCellIsEmpty === true) {
continue;
}
return false;
}
return true;
}
/**
* Returns bound worksheet.
*/
public function getWorksheet(): Worksheet
{
return $this->worksheet;
} }
} }

View File

@ -23,7 +23,7 @@ class Row
* *
* @param int $rowIndex * @param int $rowIndex
*/ */
public function __construct(?Worksheet $worksheet = null, $rowIndex = 1) public function __construct(Worksheet $worksheet, $rowIndex = 1)
{ {
// Set parent and row index // Set parent and row index
$this->worksheet = $worksheet; $this->worksheet = $worksheet;
@ -59,6 +59,45 @@ class Row
return new RowCellIterator($this->worksheet, $this->rowIndex, $startColumn, $endColumn); return new RowCellIterator($this->worksheet, $this->rowIndex, $startColumn, $endColumn);
} }
/**
* Returns a boolean true if the row contains no cells. By default, this means that no cell records exist in the
* collection for this row. false will be returned otherwise.
* This rule can be modified by passing a $definitionOfEmptyFlags value:
* 1 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL If the only cells in the collection are null value
* cells, then the row will be considered empty.
* 2 - CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL If the only cells in the collection are empty
* string value cells, then the row will be considered empty.
* 3 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL | CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL
* If the only cells in the collection are null value or empty string value cells, then the row
* will be considered empty.
*
* @param int $definitionOfEmptyFlags
* Possible Flag Values are:
* CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL
* CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL
*/
public function isEmpty(int $definitionOfEmptyFlags = 0): bool
{
$nullValueCellIsEmpty = (bool) ($definitionOfEmptyFlags & CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL);
$emptyStringCellIsEmpty = (bool) ($definitionOfEmptyFlags & CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL);
$cellIterator = $this->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(true);
foreach ($cellIterator as $cell) {
$value = $cell->getValue();
if ($value === null && $nullValueCellIsEmpty === true) {
continue;
}
if ($value === '' && $emptyStringCellIsEmpty === true) {
continue;
}
return false;
}
return true;
}
/** /**
* Returns bound worksheet. * Returns bound worksheet.
*/ */

View File

@ -1177,6 +1177,11 @@ class Worksheet implements IComparable
* or as an array of [$columnIndex, $row] (e.g. [3, 5]), or a CellAddress object. * or as an array of [$columnIndex, $row] (e.g. [3, 5]), or a CellAddress object.
* @param mixed $value Value of the cell * @param mixed $value Value of the cell
* @param string $dataType Explicit data type, see DataType::TYPE_* * @param string $dataType Explicit data type, see DataType::TYPE_*
* Note that PhpSpreadsheet does not validate that the value and datatype are consistent, in using this
* method, then it is your responsibility as an end-user developer to validate that the value and
* the datatype match.
* If you do mismatch value and datatpe, then the value you enter may be changed to match the datatype
* that you specify.
* *
* @return $this * @return $this
*/ */
@ -1199,6 +1204,11 @@ class Worksheet implements IComparable
* @param int $row Numeric row coordinate of the cell * @param int $row Numeric row coordinate of the cell
* @param mixed $value Value of the cell * @param mixed $value Value of the cell
* @param string $dataType Explicit data type, see DataType::TYPE_* * @param string $dataType Explicit data type, see DataType::TYPE_*
* Note that PhpSpreadsheet does not validate that the value and datatype are consistent, in using this
* method, then it is your responsibility as an end-user developer to validate that the value and
* the datatype match.
* If you do mismatch value and datatpe, then the value you enter may be changed to match the datatype
* that you specify.
* *
* @return $this * @return $this
*/ */
@ -1752,31 +1762,39 @@ class Worksheet implements IComparable
{ {
$range = Functions::trimSheetFromCellReference(Validations::validateCellRange($range)); $range = Functions::trimSheetFromCellReference(Validations::validateCellRange($range));
if (preg_match('/^([A-Z]+)(\\d+):([A-Z]+)(\\d+)$/', $range, $matches) === 1) { if (strpos($range, ':') === false) {
$this->mergeCells[$range] = $range; $range .= ":{$range}";
$firstRow = (int) $matches[2]; }
$lastRow = (int) $matches[4];
$firstColumn = $matches[1];
$lastColumn = $matches[3];
$firstColumnIndex = Coordinate::columnIndexFromString($firstColumn);
$lastColumnIndex = Coordinate::columnIndexFromString($lastColumn);
$numberRows = $lastRow - $firstRow;
$numberColumns = $lastColumnIndex - $firstColumnIndex;
// create upper left cell if it does not already exist if (preg_match('/^([A-Z]+)(\\d+):([A-Z]+)(\\d+)$/', $range, $matches) !== 1) {
$upperLeft = "{$firstColumn}{$firstRow}"; throw new Exception('Merge must be on a valid range of cells.');
if (!$this->cellExists($upperLeft)) { }
$this->getCell($upperLeft)->setValueExplicit(null, DataType::TYPE_NULL);
}
// Blank out the rest of the cells in the range (if they exist) $this->mergeCells[$range] = $range;
if ($numberRows > $numberColumns) { $firstRow = (int) $matches[2];
$this->clearMergeCellsByColumn($firstColumn, $lastColumn, $firstRow, $lastRow, $upperLeft); $lastRow = (int) $matches[4];
} else { $firstColumn = $matches[1];
$this->clearMergeCellsByRow($firstColumn, $lastColumnIndex, $firstRow, $lastRow, $upperLeft); $lastColumn = $matches[3];
} $firstColumnIndex = Coordinate::columnIndexFromString($firstColumn);
$lastColumnIndex = Coordinate::columnIndexFromString($lastColumn);
$numberRows = $lastRow - $firstRow;
$numberColumns = $lastColumnIndex - $firstColumnIndex;
if ($numberRows === 1 && $numberColumns === 1) {
return $this;
}
// create upper left cell if it does not already exist
$upperLeft = "{$firstColumn}{$firstRow}";
if (!$this->cellExists($upperLeft)) {
$this->getCell($upperLeft)->setValueExplicit(null, DataType::TYPE_NULL);
}
// Blank out the rest of the cells in the range (if they exist)
if ($numberRows > $numberColumns) {
$this->clearMergeCellsByColumn($firstColumn, $lastColumn, $firstRow, $lastRow, $upperLeft);
} else { } else {
throw new Exception('Merge must be set on a range of cells.'); $this->clearMergeCellsByRow($firstColumn, $lastColumnIndex, $firstRow, $lastRow, $upperLeft);
} }
return $this; return $this;
@ -3259,6 +3277,66 @@ class Worksheet implements IComparable
return clone $this; return clone $this;
} }
/**
* Returns a boolean true if the specified row contains no cells. By default, this means that no cell records
* exist in the collection for this row. false will be returned otherwise.
* This rule can be modified by passing a $definitionOfEmptyFlags value:
* 1 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL If the only cells in the collection are null value
* cells, then the row will be considered empty.
* 2 - CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL If the only cells in the collection are empty
* string value cells, then the row will be considered empty.
* 3 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL | CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL
* If the only cells in the collection are null value or empty string value cells, then the row
* will be considered empty.
*
* @param int $definitionOfEmptyFlags
* Possible Flag Values are:
* CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL
* CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL
*/
public function isEmptyRow(int $rowId, int $definitionOfEmptyFlags = 0): bool
{
try {
$iterator = new RowIterator($this, $rowId, $rowId);
$iterator->seek($rowId);
$row = $iterator->current();
} catch (Exception $e) {
return true;
}
return $row->isEmpty($definitionOfEmptyFlags);
}
/**
* Returns a boolean true if the specified column contains no cells. By default, this means that no cell records
* exist in the collection for this column. false will be returned otherwise.
* This rule can be modified by passing a $definitionOfEmptyFlags value:
* 1 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL If the only cells in the collection are null value
* cells, then the column will be considered empty.
* 2 - CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL If the only cells in the collection are empty
* string value cells, then the column will be considered empty.
* 3 - CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL | CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL
* If the only cells in the collection are null value or empty string value cells, then the column
* will be considered empty.
*
* @param int $definitionOfEmptyFlags
* Possible Flag Values are:
* CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL
* CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL
*/
public function isEmptyColumn(string $columnId, int $definitionOfEmptyFlags = 0): bool
{
try {
$iterator = new ColumnIterator($this, $columnId, $columnId);
$iterator->seek($columnId);
$column = $iterator->current();
} catch (Exception $e) {
return true;
}
return $column->isEmpty($definitionOfEmptyFlags);
}
/** /**
* Implement PHP __clone to create a deep clone, not just a shallow copy. * Implement PHP __clone to create a deep clone, not just a shallow copy.
*/ */

View File

@ -1744,7 +1744,7 @@ class Html extends BaseWriter
while ($c++ < $e) { while ($c++ < $e) {
$baseCell = $this->isSpannedCell[$sheetIndex][$rowIndex][$c]['baseCell']; $baseCell = $this->isSpannedCell[$sheetIndex][$rowIndex][$c]['baseCell'];
if (!in_array($baseCell, $adjustedBaseCells)) { if (!in_array($baseCell, $adjustedBaseCells, true)) {
// subtract rowspan by 1 // subtract rowspan by 1
--$this->isBaseCell[$sheetIndex][$baseCell[0]][$baseCell[1]]['rowspan']; --$this->isBaseCell[$sheetIndex][$baseCell[0]][$baseCell[1]]['rowspan'];
$adjustedBaseCells[] = $baseCell; $adjustedBaseCells[] = $baseCell;

View File

@ -9,6 +9,7 @@ use PhpOffice\PhpSpreadsheet\Chart\GridLines;
use PhpOffice\PhpSpreadsheet\Chart\Layout; use PhpOffice\PhpSpreadsheet\Chart\Layout;
use PhpOffice\PhpSpreadsheet\Chart\Legend; use PhpOffice\PhpSpreadsheet\Chart\Legend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea; use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException; use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
@ -499,22 +500,9 @@ class Chart extends WriterPart
$objWriter->startElement('c:spPr'); $objWriter->startElement('c:spPr');
$objWriter->startElement('a:effectLst'); $objWriter->startElement('a:effectLst');
if ($yAxis->getGlowProperty('size') !== null) { $this->writeGlow($objWriter, $yAxis);
$objWriter->startElement('a:glow'); $this->writeShadow($objWriter, $yAxis);
$objWriter->writeAttribute('rad', $yAxis->getGlowProperty('size')); $this->writeSoftEdge($objWriter, $yAxis);
$objWriter->startElement("a:{$yAxis->getGlowProperty(['color', 'type'])}");
$objWriter->writeAttribute('val', (string) $yAxis->getGlowProperty(['color', 'value']));
$objWriter->startElement('a:alpha');
$objWriter->writeAttribute('val', (string) $yAxis->getGlowProperty(['color', 'alpha']));
$objWriter->endElement();
$objWriter->endElement();
$objWriter->endElement();
}
if ($yAxis->getSoftEdgesSize() !== null) {
$objWriter->startElement('a:softEdge');
$objWriter->writeAttribute('rad', $yAxis->getSoftEdgesSize());
$objWriter->endElement(); //end softEdge
}
$objWriter->endElement(); // effectLst $objWriter->endElement(); // effectLst
$objWriter->endElement(); // spPr $objWriter->endElement(); // spPr
@ -640,61 +628,9 @@ class Chart extends WriterPart
$objWriter->endElement(); //end ln $objWriter->endElement(); //end ln
} }
$objWriter->startElement('a:effectLst'); $objWriter->startElement('a:effectLst');
$this->writeGlow($objWriter, $majorGridlines);
if ($majorGridlines->getGlowSize() !== null) { $this->writeShadow($objWriter, $majorGridlines);
$objWriter->startElement('a:glow'); $this->writeSoftEdge($objWriter, $majorGridlines);
$objWriter->writeAttribute('rad', $majorGridlines->getGlowSize());
$objWriter->startElement("a:{$majorGridlines->getGlowColor('type')}");
$objWriter->writeAttribute('val', $majorGridlines->getGlowColor('value'));
$objWriter->startElement('a:alpha');
$objWriter->writeAttribute('val', $majorGridlines->getGlowColor('alpha'));
$objWriter->endElement(); //end alpha
$objWriter->endElement(); //end schemeClr
$objWriter->endElement(); //end glow
}
if ($majorGridlines->getShadowProperty('presets') !== null) {
$objWriter->startElement("a:{$majorGridlines->getShadowProperty('effect')}");
if ($majorGridlines->getShadowProperty('blur') !== null) {
$objWriter->writeAttribute('blurRad', $majorGridlines->getShadowProperty('blur'));
}
if ($majorGridlines->getShadowProperty('distance') !== null) {
$objWriter->writeAttribute('dist', $majorGridlines->getShadowProperty('distance'));
}
if ($majorGridlines->getShadowProperty('direction') !== null) {
$objWriter->writeAttribute('dir', $majorGridlines->getShadowProperty('direction'));
}
if ($majorGridlines->getShadowProperty('algn') !== null) {
$objWriter->writeAttribute('algn', $majorGridlines->getShadowProperty('algn'));
}
if ($majorGridlines->getShadowProperty(['size', 'sx']) !== null) {
$objWriter->writeAttribute('sx', $majorGridlines->getShadowProperty(['size', 'sx']));
}
if ($majorGridlines->getShadowProperty(['size', 'sy']) !== null) {
$objWriter->writeAttribute('sy', $majorGridlines->getShadowProperty(['size', 'sy']));
}
if ($majorGridlines->getShadowProperty(['size', 'kx']) !== null) {
$objWriter->writeAttribute('kx', $majorGridlines->getShadowProperty(['size', 'kx']));
}
if ($majorGridlines->getShadowProperty('rotWithShape') !== null) {
$objWriter->writeAttribute('rotWithShape', $majorGridlines->getShadowProperty('rotWithShape'));
}
$objWriter->startElement("a:{$majorGridlines->getShadowProperty(['color', 'type'])}");
$objWriter->writeAttribute('val', $majorGridlines->getShadowProperty(['color', 'value']));
$objWriter->startElement('a:alpha');
$objWriter->writeAttribute('val', $majorGridlines->getShadowProperty(['color', 'alpha']));
$objWriter->endElement(); //end alpha
$objWriter->endElement(); //end color:type
$objWriter->endElement(); //end shadow
}
if ($majorGridlines->getSoftEdgesSize() !== null) {
$objWriter->startElement('a:softEdge');
$objWriter->writeAttribute('rad', $majorGridlines->getSoftEdgesSize());
$objWriter->endElement(); //end softEdge
}
$objWriter->endElement(); //end effectLst $objWriter->endElement(); //end effectLst
$objWriter->endElement(); //end spPr $objWriter->endElement(); //end spPr
@ -748,61 +684,11 @@ class Chart extends WriterPart
} }
$objWriter->startElement('a:effectLst'); $objWriter->startElement('a:effectLst');
$this->writeGlow($objWriter, $minorGridlines);
if ($minorGridlines->getGlowSize() !== null) { $this->writeShadow($objWriter, $minorGridlines);
$objWriter->startElement('a:glow'); $this->writeSoftEdge($objWriter, $minorGridlines);
$objWriter->writeAttribute('rad', $minorGridlines->getGlowSize());
$objWriter->startElement("a:{$minorGridlines->getGlowColor('type')}");
$objWriter->writeAttribute('val', $minorGridlines->getGlowColor('value'));
$objWriter->startElement('a:alpha');
$objWriter->writeAttribute('val', $minorGridlines->getGlowColor('alpha'));
$objWriter->endElement(); //end alpha
$objWriter->endElement(); //end schemeClr
$objWriter->endElement(); //end glow
}
if ($minorGridlines->getShadowProperty('presets') !== null) {
$objWriter->startElement("a:{$minorGridlines->getShadowProperty('effect')}");
if ($minorGridlines->getShadowProperty('blur') !== null) {
$objWriter->writeAttribute('blurRad', $minorGridlines->getShadowProperty('blur'));
}
if ($minorGridlines->getShadowProperty('distance') !== null) {
$objWriter->writeAttribute('dist', $minorGridlines->getShadowProperty('distance'));
}
if ($minorGridlines->getShadowProperty('direction') !== null) {
$objWriter->writeAttribute('dir', $minorGridlines->getShadowProperty('direction'));
}
if ($minorGridlines->getShadowProperty('algn') !== null) {
$objWriter->writeAttribute('algn', $minorGridlines->getShadowProperty('algn'));
}
if ($minorGridlines->getShadowProperty(['size', 'sx']) !== null) {
$objWriter->writeAttribute('sx', $minorGridlines->getShadowProperty(['size', 'sx']));
}
if ($minorGridlines->getShadowProperty(['size', 'sy']) !== null) {
$objWriter->writeAttribute('sy', $minorGridlines->getShadowProperty(['size', 'sy']));
}
if ($minorGridlines->getShadowProperty(['size', 'kx']) !== null) {
$objWriter->writeAttribute('kx', $minorGridlines->getShadowProperty(['size', 'kx']));
}
if ($minorGridlines->getShadowProperty('rotWithShape') !== null) {
$objWriter->writeAttribute('rotWithShape', $minorGridlines->getShadowProperty('rotWithShape'));
}
$objWriter->startElement("a:{$minorGridlines->getShadowProperty(['color', 'type'])}");
$objWriter->writeAttribute('val', $minorGridlines->getShadowProperty(['color', 'value']));
$objWriter->startElement('a:alpha');
$objWriter->writeAttribute('val', $minorGridlines->getShadowProperty(['color', 'alpha']));
$objWriter->endElement(); //end alpha
$objWriter->endElement(); //end color:type
$objWriter->endElement(); //end shadow
}
if ($minorGridlines->getSoftEdgesSize() !== null) {
$objWriter->startElement('a:softEdge');
$objWriter->writeAttribute('rad', $minorGridlines->getSoftEdgesSize());
$objWriter->endElement(); //end softEdge
}
$objWriter->endElement(); //end effectLst $objWriter->endElement(); //end effectLst
$objWriter->endElement(); //end spPr $objWriter->endElement(); //end spPr
$objWriter->endElement(); //end minorGridLines $objWriter->endElement(); //end minorGridLines
} }
@ -925,64 +811,11 @@ class Chart extends WriterPart
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('a:effectLst'); $objWriter->startElement('a:effectLst');
$this->writeGlow($objWriter, $xAxis);
if ($xAxis->getGlowProperty('size') !== null) { $this->writeShadow($objWriter, $xAxis);
$objWriter->startElement('a:glow'); $this->writeSoftEdge($objWriter, $xAxis);
$objWriter->writeAttribute('rad', $xAxis->getGlowProperty('size'));
$objWriter->startElement("a:{$xAxis->getGlowProperty(['color', 'type'])}");
$objWriter->writeAttribute('val', (string) $xAxis->getGlowProperty(['color', 'value']));
$objWriter->startElement('a:alpha');
$objWriter->writeAttribute('val', (string) $xAxis->getGlowProperty(['color', 'alpha']));
$objWriter->endElement();
$objWriter->endElement();
$objWriter->endElement();
}
if ($xAxis->getShadowProperty('presets') !== null) {
$objWriter->startElement("a:{$xAxis->getShadowProperty('effect')}");
if ($xAxis->getShadowProperty('blur') !== null) {
$objWriter->writeAttribute('blurRad', $xAxis->getShadowProperty('blur'));
}
if ($xAxis->getShadowProperty('distance') !== null) {
$objWriter->writeAttribute('dist', $xAxis->getShadowProperty('distance'));
}
if ($xAxis->getShadowProperty('direction') !== null) {
$objWriter->writeAttribute('dir', $xAxis->getShadowProperty('direction'));
}
if ($xAxis->getShadowProperty('algn') !== null) {
$objWriter->writeAttribute('algn', $xAxis->getShadowProperty('algn'));
}
if ($xAxis->getShadowProperty(['size', 'sx']) !== null) {
$objWriter->writeAttribute('sx', $xAxis->getShadowProperty(['size', 'sx']));
}
if ($xAxis->getShadowProperty(['size', 'sy']) !== null) {
$objWriter->writeAttribute('sy', $xAxis->getShadowProperty(['size', 'sy']));
}
if ($xAxis->getShadowProperty(['size', 'kx']) !== null) {
$objWriter->writeAttribute('kx', $xAxis->getShadowProperty(['size', 'kx']));
}
if ($xAxis->getShadowProperty('rotWithShape') !== null) {
$objWriter->writeAttribute('rotWithShape', $xAxis->getShadowProperty('rotWithShape'));
}
$objWriter->startElement("a:{$xAxis->getShadowProperty(['color', 'type'])}");
$objWriter->writeAttribute('val', $xAxis->getShadowProperty(['color', 'value']));
$objWriter->startElement('a:alpha');
$objWriter->writeAttribute('val', $xAxis->getShadowProperty(['color', 'alpha']));
$objWriter->endElement();
$objWriter->endElement();
$objWriter->endElement();
}
if ($xAxis->getSoftEdgesSize() !== null) {
$objWriter->startElement('a:softEdge');
$objWriter->writeAttribute('rad', $xAxis->getSoftEdgesSize());
$objWriter->endElement();
}
$objWriter->endElement(); //effectList $objWriter->endElement(); //effectList
$objWriter->endElement(); //end spPr $objWriter->endElement(); //end spPr
if ($id1 !== '0') { if ($id1 !== '0') {
@ -1658,4 +1491,100 @@ class Chart extends WriterPart
$objWriter->endElement(); $objWriter->endElement();
} }
/**
* Write shadow properties.
*
* @param Axis|GridLines $xAxis
*/
private function writeShadow(XMLWriter $objWriter, $xAxis): void
{
if ($xAxis->getShadowProperty('effect') === null) {
return;
}
/** @var string */
$effect = $xAxis->getShadowProperty('effect');
$objWriter->startElement("a:$effect");
if (is_numeric($xAxis->getShadowProperty('blur'))) {
$objWriter->writeAttribute('blurRad', Properties::pointsToXml((float) $xAxis->getShadowProperty('blur')));
}
if (is_numeric($xAxis->getShadowProperty('distance'))) {
$objWriter->writeAttribute('dist', Properties::pointsToXml((float) $xAxis->getShadowProperty('distance')));
}
if (is_numeric($xAxis->getShadowProperty('direction'))) {
$objWriter->writeAttribute('dir', Properties::angleToXml((float) $xAxis->getShadowProperty('direction')));
}
if ($xAxis->getShadowProperty('algn') !== null) {
$objWriter->writeAttribute('algn', $xAxis->getShadowProperty('algn'));
}
foreach (['sx', 'sy'] as $sizeType) {
$sizeValue = $xAxis->getShadowProperty(['size', $sizeType]);
if (is_numeric($sizeValue)) {
$objWriter->writeAttribute($sizeType, Properties::tenthOfPercentToXml((float) $sizeValue));
}
}
foreach (['kx', 'ky'] as $sizeType) {
$sizeValue = $xAxis->getShadowProperty(['size', $sizeType]);
if (is_numeric($sizeValue)) {
$objWriter->writeAttribute($sizeType, Properties::angleToXml((float) $sizeValue));
}
}
if ($xAxis->getShadowProperty('rotWithShape') !== null) {
$objWriter->writeAttribute('rotWithShape', $xAxis->getShadowProperty('rotWithShape'));
}
$objWriter->startElement("a:{$xAxis->getShadowProperty(['color', 'type'])}");
$objWriter->writeAttribute('val', $xAxis->getShadowProperty(['color', 'value']));
$alpha = $xAxis->getShadowProperty(['color', 'alpha']);
if (is_numeric($alpha)) {
$objWriter->startElement('a:alpha');
$objWriter->writeAttribute('val', Properties::alphaToXml((int) $alpha));
$objWriter->endElement();
}
$objWriter->endElement();
$objWriter->endElement();
}
/**
* Write glow properties.
*
* @param Axis|GridLines $yAxis
*/
private function writeGlow(XMLWriter $objWriter, $yAxis): void
{
$size = $yAxis->getGlowProperty('size');
if (empty($size)) {
return;
}
$objWriter->startElement('a:glow');
$objWriter->writeAttribute('rad', Properties::pointsToXml((float) $size));
$objWriter->startElement("a:{$yAxis->getGlowProperty(['color', 'type'])}");
$objWriter->writeAttribute('val', (string) $yAxis->getGlowProperty(['color', 'value']));
$alpha = $yAxis->getGlowProperty(['color', 'alpha']);
if (is_numeric($alpha)) {
$objWriter->startElement('a:alpha');
$objWriter->writeAttribute('val', Properties::alphaToXml((int) $alpha));
$objWriter->endElement(); // alpha
}
$objWriter->endElement(); // color
$objWriter->endElement(); // glow
}
/**
* Write soft edge properties.
*
* @param Axis|GridLines $yAxis
*/
private function writeSoftEdge(XMLWriter $objWriter, $yAxis): void
{
$softEdgeSize = $yAxis->getSoftEdgesSize();
if (empty($softEdgeSize)) {
return;
}
$objWriter->startElement('a:softEdge');
$objWriter->writeAttribute('rad', Properties::pointsToXml((float) $softEdgeSize));
$objWriter->endElement(); //end softEdge
}
} }

View File

@ -100,7 +100,7 @@ class MergedCellTest extends TestCase
$sheet->mergeCells($range); $sheet->mergeCells($range);
self::fail("Expected invalid merge range $range"); self::fail("Expected invalid merge range $range");
} catch (SpreadException $e) { } catch (SpreadException $e) {
self::assertSame('Merge must be set on a range of cells.', $e->getMessage()); self::assertSame('Merge must be on a valid range of cells.', $e->getMessage());
} }
} }
@ -109,7 +109,8 @@ class MergedCellTest extends TestCase
$spreadSheet = new Spreadsheet(); $spreadSheet = new Spreadsheet();
$dataSheet = $spreadSheet->getActiveSheet(); $dataSheet = $spreadSheet->getActiveSheet();
$this->setBadRange($dataSheet, 'B1'); // TODO - Reinstate full validation and disallow single cell merging for version 2.0
// $this->setBadRange($dataSheet, 'B1');
$this->setBadRange($dataSheet, 'Invalid'); $this->setBadRange($dataSheet, 'Invalid');
$this->setBadRange($dataSheet, '1'); $this->setBadRange($dataSheet, '1');
$this->setBadRange($dataSheet, 'C'); $this->setBadRange($dataSheet, 'C');

View File

@ -1,6 +1,6 @@
<?php <?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx; namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
@ -106,21 +106,21 @@ class AxisGlowTest extends AbstractFunctional
); );
$yAxis = $chart->getChartAxisY(); $yAxis = $chart->getChartAxisY();
$xAxis = $chart->getChartAxisX(); $xAxis = $chart->getChartAxisX();
$yAxis->setGlowProperties(10, 'FFFF00', 30, Properties::EXCEL_COLOR_TYPE_ARGB); $yGlowSize = 10.0;
$expectedSize = 127000.0; $yAxis->setGlowProperties($yGlowSize, 'FFFF00', 30, Properties::EXCEL_COLOR_TYPE_ARGB);
$expectedGlowColor = [ $expectedGlowColor = [
'type' => 'srgbClr', 'type' => 'srgbClr',
'value' => 'FFFF00', 'value' => 'FFFF00',
'alpha' => '70000', 'alpha' => 30,
]; ];
$yAxis->setSoftEdges(2.5); $softEdgesY = 2.5;
$xAxis->setSoftEdges(5); $yAxis->setSoftEdges($softEdgesY);
$expectedSoftEdgesY = '31750'; $softEdgesX = 5;
$expectedSoftEdgesX = '63500'; $xAxis->setSoftEdges($softEdgesX);
self::assertEquals($expectedSize, $yAxis->getGlowProperty('size')); self::assertEquals($yGlowSize, $yAxis->getGlowProperty('size'));
self::assertEquals($expectedGlowColor, $yAxis->getGlowProperty('color')); self::assertEquals($expectedGlowColor, $yAxis->getGlowProperty('color'));
self::assertEquals($expectedSoftEdgesY, $yAxis->getSoftEdgesSize()); self::assertEquals($softEdgesY, $yAxis->getSoftEdgesSize());
self::assertEquals($expectedSoftEdgesX, $xAxis->getSoftEdgesSize()); self::assertEquals($softEdgesX, $xAxis->getSoftEdgesSize());
// Set the position where the chart should appear in the worksheet // Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7'); $chart->setTopLeftPosition('A7');
@ -142,9 +142,9 @@ class AxisGlowTest extends AbstractFunctional
$chart2 = $charts2[0]; $chart2 = $charts2[0];
self::assertNotNull($chart2); self::assertNotNull($chart2);
$yAxis2 = $chart2->getChartAxisY(); $yAxis2 = $chart2->getChartAxisY();
self::assertEquals($expectedSize, $yAxis2->getGlowProperty('size')); self::assertEquals($yGlowSize, $yAxis2->getGlowProperty('size'));
self::assertEquals($expectedGlowColor, $yAxis2->getGlowProperty('color')); self::assertEquals($expectedGlowColor, $yAxis2->getGlowProperty('color'));
self::assertEquals($expectedSoftEdgesY, $yAxis2->getSoftEdgesSize()); self::assertEquals($softEdgesY, $yAxis2->getSoftEdgesSize());
$xAxis2 = $chart2->getChartAxisX(); $xAxis2 = $chart2->getChartAxisX();
self::assertNull($xAxis2->getGlowProperty('size')); self::assertNull($xAxis2->getGlowProperty('size'));
$reloadedSpreadsheet->disconnectWorksheets(); $reloadedSpreadsheet->disconnectWorksheets();
@ -229,14 +229,14 @@ class AxisGlowTest extends AbstractFunctional
$yAxisLabel // yAxisLabel $yAxisLabel // yAxisLabel
); );
$yAxis = $chart->getChartAxisX(); // deliberate $yAxis = $chart->getChartAxisX(); // deliberate
$yAxis->setGlowProperties(20, 'accent1', 20, Properties::EXCEL_COLOR_TYPE_SCHEME); $yGlowSize = 20.0;
$expectedSize = 254000.0; $yAxis->setGlowProperties($yGlowSize, 'accent1', 20, Properties::EXCEL_COLOR_TYPE_SCHEME);
$expectedGlowColor = [ $expectedGlowColor = [
'type' => 'schemeClr', 'type' => 'schemeClr',
'value' => 'accent1', 'value' => 'accent1',
'alpha' => '80000', 'alpha' => 20,
]; ];
self::assertEquals($expectedSize, $yAxis->getGlowProperty('size')); self::assertEquals($yGlowSize, $yAxis->getGlowProperty('size'));
self::assertEquals($expectedGlowColor, $yAxis->getGlowProperty('color')); self::assertEquals($expectedGlowColor, $yAxis->getGlowProperty('color'));
// Set the position where the chart should appear in the worksheet // Set the position where the chart should appear in the worksheet
@ -259,7 +259,7 @@ class AxisGlowTest extends AbstractFunctional
$chart2 = $charts2[0]; $chart2 = $charts2[0];
self::assertNotNull($chart2); self::assertNotNull($chart2);
$yAxis2 = $chart2->getChartAxisX(); // deliberate $yAxis2 = $chart2->getChartAxisX(); // deliberate
self::assertEquals($expectedSize, $yAxis2->getGlowProperty('size')); self::assertEquals($yGlowSize, $yAxis2->getGlowProperty('size'));
self::assertEquals($expectedGlowColor, $yAxis2->getGlowProperty('color')); self::assertEquals($expectedGlowColor, $yAxis2->getGlowProperty('color'));
$xAxis2 = $chart2->getChartAxisY(); // deliberate $xAxis2 = $chart2->getChartAxisY(); // deliberate
self::assertNull($xAxis2->getGlowProperty('size')); self::assertNull($xAxis2->getGlowProperty('size'));

View File

@ -0,0 +1,184 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class AxisShadowTest extends AbstractFunctional
{
public function readCharts(XlsxReader $reader): void
{
$reader->setIncludeCharts(true);
}
public function writeCharts(XlsxWriter $writer): void
{
$writer->setIncludeCharts(true);
}
public function testGlowY(): void
{
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->fromArray(
[
['', 2010, 2011, 2012],
['Q1', 12, 15, 21],
['Q2', 56, 73, 86],
['Q3', 52, 61, 69],
['Q4', 30, 32, 0],
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_AREACHART, // plotType
DataSeries::GROUPING_PERCENT_STACKED, // plotGrouping
range(0, count($dataSeriesValues) - 1), // plotOrder
$dataSeriesLabels, // plotLabel
$xAxisTickValues, // plotCategory
$dataSeriesValues // plotValues
);
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false);
$title = new Title('Test %age-Stacked Area Chart');
$yAxisLabel = new Title('Value ($k)');
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
$legend, // legend
$plotArea, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
null, // xAxisLabel
$yAxisLabel // yAxisLabel
);
$yAxis = $chart->getChartAxisY();
$expectedY = [
'effect' => 'outerShdw',
'algn' => 'tl',
'blur' => 5,
'direction' => 45,
'distance' => 3,
'rotWithShape' => 0,
'color' => [
'type' => Properties::EXCEL_COLOR_TYPE_STANDARD,
'value' => 'black',
'alpha' => 40,
],
];
foreach ($expectedY as $key => $value) {
$yAxis->setShadowProperty($key, $value);
}
foreach ($expectedY as $key => $value) {
self::assertEquals($value, $yAxis->getShadowProperty($key), $key);
}
$xAxis = $chart->getChartAxisX();
$expectedX = [
'effect' => 'outerShdw',
'algn' => 'bl',
'blur' => 6,
'direction' => 315,
'distance' => 3,
'rotWithShape' => 0,
'size' => [
'sx' => null,
'sy' => 254,
'kx' => -94,
'ky' => null,
],
'color' => [
'type' => Properties::EXCEL_COLOR_TYPE_ARGB,
'value' => 'FF0000',
'alpha' => 20,
],
];
foreach ($expectedX as $key => $value) {
$xAxis->setShadowProperty($key, $value);
}
foreach ($expectedX as $key => $value) {
self::assertEquals($value, $xAxis->getShadowProperty($key), $key);
}
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('H20');
// Add the chart to the worksheet
$worksheet->addChart($chart);
/** @var callable */
$callableReader = [$this, 'readCharts'];
/** @var callable */
$callableWriter = [$this, 'writeCharts'];
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter);
$spreadsheet->disconnectWorksheets();
$sheet = $reloadedSpreadsheet->getActiveSheet();
$charts2 = $sheet->getChartCollection();
self::assertCount(1, $charts2);
$chart2 = $charts2[0];
self::assertNotNull($chart2);
$yAxis2 = $chart2->getChartAxisY();
foreach ($expectedY as $key => $value) {
self::assertEquals($value, $yAxis2->getShadowProperty($key), $key);
}
$xAxis2 = $chart2->getChartAxisX();
foreach ($expectedX as $key => $value) {
self::assertEquals($value, $xAxis2->getShadowProperty($key), $key);
}
$reloadedSpreadsheet->disconnectWorksheets();
}
}

View File

@ -1,6 +1,6 @@
<?php <?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx; namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Axis; use PhpOffice\PhpSpreadsheet\Chart\Axis;
use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\Chart;

View File

@ -1,6 +1,6 @@
<?php <?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx; namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader; use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\RichText\RichText;

View File

@ -1,6 +1,6 @@
<?php <?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx; namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader; use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\RichText\RichText;

View File

@ -1,6 +1,6 @@
<?php <?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx; namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Properties; use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader; use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;

View File

@ -1,6 +1,6 @@
<?php <?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx; namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader; use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;

View File

@ -1,6 +1,6 @@
<?php <?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx; namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\IOFactory;

View File

@ -0,0 +1,187 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\GridLines;
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class GridlinesShadowGlowTest extends AbstractFunctional
{
public function readCharts(XlsxReader $reader): void
{
$reader->setIncludeCharts(true);
}
public function writeCharts(XlsxWriter $writer): void
{
$writer->setIncludeCharts(true);
}
public function testGlowY(): void
{
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->fromArray(
[
['', 2010, 2011, 2012],
['Q1', 12, 15, 21],
['Q2', 56, 73, 86],
['Q3', 52, 61, 69],
['Q4', 30, 32, 0],
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_LINECHART, // plotType
DataSeries::GROUPING_PERCENT_STACKED, // plotGrouping
range(0, count($dataSeriesValues) - 1), // plotOrder
$dataSeriesLabels, // plotLabel
$xAxisTickValues, // plotCategory
$dataSeriesValues // plotValues
);
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false);
$title = new Title('Test %age-Stacked Area Chart');
$yAxisLabel = new Title('Value ($k)');
$majorGridlines = new GridLines();
$majorGlowSize = 10.0;
$majorGridlines->setGlowProperties($majorGlowSize, 'FFFF00', 30, Properties::EXCEL_COLOR_TYPE_ARGB);
$softEdgeSize = 2.5;
$majorGridlines->setSoftEdges($softEdgeSize);
$expectedGlowColor = [
'type' => 'srgbClr',
'value' => 'FFFF00',
'alpha' => 30,
];
self::assertEquals($majorGlowSize, $majorGridlines->getGlowProperty('size'));
self::assertEquals($majorGlowSize, $majorGridlines->getGlowSize());
self::assertEquals($expectedGlowColor['value'], $majorGridlines->getGlowColor('value'));
self::assertEquals($expectedGlowColor, $majorGridlines->getGlowProperty('color'));
self::assertEquals($softEdgeSize, $majorGridlines->getSoftEdgesSize());
$minorGridlines = new GridLines();
$expectedShadow = [
'effect' => 'outerShdw',
'algn' => 'tl',
'blur' => 4,
'direction' => 45,
'distance' => 3,
'rotWithShape' => 0,
'color' => [
'type' => Properties::EXCEL_COLOR_TYPE_STANDARD,
'value' => 'black',
'alpha' => 40,
],
];
foreach ($expectedShadow as $key => $value) {
$minorGridlines->setShadowProperty($key, $value);
}
foreach ($expectedShadow as $key => $value) {
self::assertEquals($value, $minorGridlines->getShadowProperty($key), $key);
}
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
$legend, // legend
$plotArea, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
null, // xAxisLabel
$yAxisLabel, // yAxisLabel
null, // xAxis
null, // yAxis
$majorGridlines,
$minorGridlines
);
$majorGridlines2 = $chart->getMajorGridlines();
self::assertEquals($majorGlowSize, $majorGridlines2->getGlowProperty('size'));
self::assertEquals($expectedGlowColor, $majorGridlines2->getGlowProperty('color'));
self::assertEquals($softEdgeSize, $majorGridlines2->getSoftEdgesSize());
$minorGridlines2 = $chart->getMinorGridlines();
foreach ($expectedShadow as $key => $value) {
self::assertEquals($value, $minorGridlines2->getShadowProperty($key), $key);
}
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('H20');
// Add the chart to the worksheet
$worksheet->addChart($chart);
/** @var callable */
$callableReader = [$this, 'readCharts'];
/** @var callable */
$callableWriter = [$this, 'writeCharts'];
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter);
$spreadsheet->disconnectWorksheets();
$sheet = $reloadedSpreadsheet->getActiveSheet();
$charts2 = $sheet->getChartCollection();
self::assertCount(1, $charts2);
$chart2 = $charts2[0];
self::assertNotNull($chart2);
$majorGridlines3 = $chart2->getMajorGridlines();
self::assertEquals($majorGlowSize, $majorGridlines3->getGlowProperty('size'));
self::assertEquals($expectedGlowColor, $majorGridlines3->getGlowProperty('color'));
self::assertEquals($softEdgeSize, $majorGridlines3->getSoftEdgesSize());
$minorGridlines3 = $chart->getMinorGridlines();
foreach ($expectedShadow as $key => $value) {
self::assertEquals($value, $minorGridlines3->getShadowProperty($key), $key);
}
$reloadedSpreadsheet->disconnectWorksheets();
}
}

View File

@ -0,0 +1,157 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\Shared\File;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
use PHPUnit\Framework\TestCase;
class MultiplierTest extends TestCase
{
public function testMultiplier(): void
{
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->fromArray(
[
['', 2010, 2011, 2012],
['Q1', 12, 15, 21],
['Q2', 56, 73, 86],
['Q3', 52, 61, 69],
['Q4', 30, 32, 0],
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_AREACHART, // plotType
DataSeries::GROUPING_PERCENT_STACKED, // plotGrouping
range(0, count($dataSeriesValues) - 1), // plotOrder
$dataSeriesLabels, // plotLabel
$xAxisTickValues, // plotCategory
$dataSeriesValues // plotValues
);
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false);
$title = new Title('Test %age-Stacked Area Chart');
$yAxisLabel = new Title('Value ($k)');
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
$legend, // legend
$plotArea, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
null, // xAxisLabel
$yAxisLabel // yAxisLabel
);
$xAxis = $chart->getChartAxisX();
$expectedX = [
'effect' => 'outerShdw',
'algn' => 'bl',
'blur' => 6,
'direction' => 315,
'distance' => 3,
'rotWithShape' => 0,
'size' => [
'sx' => null,
'sy' => 254,
'kx' => -94,
'ky' => null,
],
'color' => [
'type' => Properties::EXCEL_COLOR_TYPE_ARGB,
'value' => 'FF0000',
'alpha' => 20,
],
];
$expectedXmlX = [
'<a:outerShdw ',
' algn="bl"',
' blurRad="76200"',
' dir="18900000"',
' dist="38100"',
' rotWithShape="0"',
' sy="25400000"',
' kx="-5640000"',
'<a:srgbClr val="FF0000">',
'<a:alpha val="80000"/>',
];
$expectedXmlNoX = [
' sx=',
' ky=',
];
foreach ($expectedX as $key => $value) {
$xAxis->setShadowProperty($key, $value);
}
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('H20');
// Add the chart to the worksheet
$worksheet->addChart($chart);
$writer = new XlsxWriter($spreadsheet);
$writer->setIncludeCharts(true);
$writerChart = new XlsxWriter\Chart($writer);
$data = $writerChart->writeChart($chart);
// confirm that file contains expected tags
foreach ($expectedXmlX as $expected) {
self::assertSame(1, substr_count($data, $expected), $expected);
}
foreach ($expectedXmlNoX as $expected) {
self::assertSame(0, substr_count($data, $expected), $expected);
}
$spreadsheet->disconnectWorksheets();
}
}

View File

@ -0,0 +1,183 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Axis;
use PhpOffice\PhpSpreadsheet\Chart\GridLines;
use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PHPUnit\Framework\TestCase;
class ShadowPresetsTest extends TestCase
{
public function testGridlineShadowPresets(): void
{
$gridlines = new GridLines();
$gridlines->setShadowProperties(17);
$expectedShadow = [
'effect' => 'innerShdw',
'distance' => 4,
'direction' => 270,
'blur' => 5,
];
foreach ($expectedShadow as $key => $value) {
self::assertEquals($gridlines->getShadowProperty($key), $value, $key);
}
}
public function testGridlineShadowPresetsWithArray(): void
{
$gridlines = new GridLines();
$gridlines->setShadowProperties(20);
$expectedShadow = [
'effect' => 'outerShdw',
'blur' => 6,
'direction' => 315,
'size' => [
'sx' => null,
'sy' => 0.23,
'kx' => -20,
'ky' => null,
],
'algn' => 'bl',
'rotWithShape' => '0',
];
foreach ($expectedShadow as $key => $value) {
self::assertEquals($gridlines->getShadowProperty($key), $value, $key);
}
}
public function testAxisShadowPresets(): void
{
$axis = new Axis();
$axis->setShadowProperties(9);
$expectedShadow = [
'effect' => 'outerShdw',
'blur' => 4,
'distance' => 3,
'direction' => 225,
'algn' => 'br',
'rotWithShape' => '0',
];
foreach ($expectedShadow as $key => $value) {
self::assertEquals($axis->getShadowProperty($key), $value, $key);
}
}
public function testAxisShadowPresetsWithChanges(): void
{
$axis = new Axis();
$axis->setShadowProperties(
9, // preset
'FF0000', // colorValue
'srgbClr', // colorType
20, // alpha
6, // blur
30, // direction
4, // distance
);
$expectedShadow = [
'effect' => 'outerShdw',
'blur' => 6,
'distance' => 4,
'direction' => 30,
'algn' => 'br',
'rotWithShape' => '0',
'color' => [
'value' => 'FF0000',
'type' => 'srgbClr',
'alpha' => 20,
],
];
foreach ($expectedShadow as $key => $value) {
self::assertEquals($axis->getShadowProperty($key), $value, $key);
}
}
public function testGridlinesShadowPresetsWithChanges(): void
{
$gridline = new GridLines();
$gridline->setShadowProperties(
9, // preset
'FF0000', // colorValue
'srgbClr', // colorType
20, // alpha
6, // blur
30, // direction
4, // distance
);
$expectedShadow = [
'effect' => 'outerShdw',
'blur' => 6,
'distance' => 4,
'direction' => 30,
'algn' => 'br',
'rotWithShape' => '0',
'color' => [
'value' => 'FF0000',
'type' => 'srgbClr',
'alpha' => 20,
],
];
foreach ($expectedShadow as $key => $value) {
self::assertEquals($gridline->getShadowProperty($key), $value, $key);
}
}
public function testOutOfRangePresets(): void
{
$axis = new Axis();
$axis->setShadowProperties(99);
$expectedShadow = [
'presets' => Properties::SHADOW_PRESETS_NOSHADOW,
'effect' => null,
'color' => [
'type' => Properties::EXCEL_COLOR_TYPE_STANDARD,
'value' => 'black',
'alpha' => 40,
],
'size' => [
'sx' => null,
'sy' => null,
'kx' => null,
'ky' => null,
],
'blur' => null,
'direction' => null,
'distance' => null,
'algn' => null,
'rotWithShape' => null,
];
foreach ($expectedShadow as $key => $value) {
self::assertEquals($value, $axis->getShadowProperty($key), $key);
}
}
public function testOutOfRangeGridlines(): void
{
$gridline = new GridLines();
$gridline->setShadowProperties(99);
$expectedShadow = [
'presets' => Properties::SHADOW_PRESETS_NOSHADOW,
'effect' => null,
'color' => [
'type' => Properties::EXCEL_COLOR_TYPE_STANDARD,
'value' => 'black',
'alpha' => 40,
],
'size' => [
'sx' => null,
'sy' => null,
'kx' => null,
'ky' => null,
],
'blur' => null,
'direction' => null,
'distance' => null,
'algn' => null,
'rotWithShape' => null,
];
foreach ($expectedShadow as $key => $value) {
self::assertEquals($value, $gridline->getShadowProperty($key), $key);
}
}
}

View File

@ -0,0 +1,154 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Worksheet;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\CellIterator;
use PhpOffice\PhpSpreadsheet\Worksheet\ColumnIterator;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PHPUnit\Framework\TestCase;
class ColumnIteratorEmptyTest extends TestCase
{
private static function getPopulatedSheet(Spreadsheet $spreadsheet): Worksheet
{
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValueExplicit('A1', 'Hello World', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('C2', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('D2', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('E2', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('E3', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('F2', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('F3', 'PHP', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('G2', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('G3', 'PHP', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('H2', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('H3', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('H4', 'PHP', DataType::TYPE_STRING);
return $sheet;
}
/**
* @dataProvider emptyColumnBasic
*/
public function testIteratorEmptyColumn(string $columnId, bool $expectedEmpty): void
{
$spreadsheet = new Spreadsheet();
$sheet = self::getPopulatedSheet($spreadsheet);
$iterator = new ColumnIterator($sheet, 'A', 'I');
$iterator->seek($columnId);
$row = $iterator->current();
$isEmpty = $row->isEmpty();
self::assertSame($expectedEmpty, $isEmpty);
$spreadsheet->disconnectWorksheets();
}
public function emptyColumnBasic(): array
{
return [
['A', false],
['B', true],
['C', false],
['D', false],
['E', false],
['F', false],
['G', false],
['H', false],
['I', true],
];
}
/**
* @dataProvider emptyColumnNullAsEmpty
*/
public function testIteratorEmptyColumnWithNull(string $columnId, bool $expectedEmpty): void
{
$spreadsheet = new Spreadsheet();
$sheet = self::getPopulatedSheet($spreadsheet);
$iterator = new ColumnIterator($sheet, 'A', 'I');
$iterator->seek($columnId);
$row = $iterator->current();
$isEmpty = $row->isEmpty(CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL);
self::assertSame($expectedEmpty, $isEmpty);
$spreadsheet->disconnectWorksheets();
}
public function emptyColumnNullAsEmpty(): array
{
return [
['A', false],
['B', true],
['C', true],
['D', false],
['E', false],
['F', false],
['G', false],
['H', false],
['I', true],
];
}
/**
* @dataProvider emptyColumnEmptyStringAsEmpty
*/
public function testIteratorEmptyColumnWithEmptyString(string $columnId, bool $expectedEmpty): void
{
$spreadsheet = new Spreadsheet();
$sheet = self::getPopulatedSheet($spreadsheet);
$iterator = new ColumnIterator($sheet, 'A', 'I');
$iterator->seek($columnId);
$row = $iterator->current();
$isEmpty = $row->isEmpty(CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL);
self::assertSame($expectedEmpty, $isEmpty);
$spreadsheet->disconnectWorksheets();
}
public function emptyColumnEmptyStringAsEmpty(): array
{
return [
['A', false],
['B', true],
['C', false],
['D', true],
['E', false],
['F', false],
['G', false],
['H', false],
['I', true],
];
}
/**
* @dataProvider emptyColumnNullAndEmptyStringAsEmpty
*/
public function testIteratorEmptyColumnWithNullAndEmptyString(string $columnId, bool $expectedEmpty): void
{
$spreadsheet = new Spreadsheet();
$sheet = self::getPopulatedSheet($spreadsheet);
$iterator = new ColumnIterator($sheet, 'A', 'I');
$iterator->seek($columnId);
$row = $iterator->current();
$isEmpty = $row->isEmpty(
CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL | CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL
);
self::assertSame($expectedEmpty, $isEmpty);
$spreadsheet->disconnectWorksheets();
}
public function emptyColumnNullAndEmptyStringAsEmpty(): array
{
return [
['A', false],
['B', true],
['C', true],
['D', true],
['E', true],
['F', false],
['G', false],
['H', false],
['I', true],
];
}
}

View File

@ -0,0 +1,154 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Worksheet;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\CellIterator;
use PhpOffice\PhpSpreadsheet\Worksheet\RowIterator;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PHPUnit\Framework\TestCase;
class RowIteratorEmptyTest extends TestCase
{
private static function getPopulatedSheet(Spreadsheet $spreadsheet): Worksheet
{
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValueExplicit('A1', 'Hello World', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('B3', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('B4', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('B5', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('C5', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('B6', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('C6', 'PHP', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('B7', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('C7', 'PHP', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('B8', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('C8', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('D8', 'PHP', DataType::TYPE_STRING);
return $sheet;
}
/**
* @dataProvider emptyRowBasic
*/
public function testIteratorEmptyRow(int $rowId, bool $expectedEmpty): void
{
$spreadsheet = new Spreadsheet();
$sheet = self::getPopulatedSheet($spreadsheet);
$iterator = new RowIterator($sheet, 1, 9);
$iterator->seek($rowId);
$row = $iterator->current();
$isEmpty = $row->isEmpty();
self::assertSame($expectedEmpty, $isEmpty);
$spreadsheet->disconnectWorksheets();
}
public function emptyRowBasic(): array
{
return [
[1, false],
[2, true],
[3, false],
[4, false],
[5, false],
[6, false],
[7, false],
[8, false],
[9, true],
];
}
/**
* @dataProvider emptyRowNullAsEmpty
*/
public function testIteratorEmptyRowWithNull(int $rowId, bool $expectedEmpty): void
{
$spreadsheet = new Spreadsheet();
$sheet = self::getPopulatedSheet($spreadsheet);
$iterator = new RowIterator($sheet, 1, 9);
$iterator->seek($rowId);
$row = $iterator->current();
$isEmpty = $row->isEmpty(CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL);
self::assertSame($expectedEmpty, $isEmpty);
$spreadsheet->disconnectWorksheets();
}
public function emptyRowNullAsEmpty(): array
{
return [
[1, false],
[2, true],
[3, true],
[4, false],
[5, false],
[6, false],
[7, false],
[8, false],
[9, true],
];
}
/**
* @dataProvider emptyRowEmptyStringAsEmpty
*/
public function testIteratorEmptyRowWithEmptyString(int $rowId, bool $expectedEmpty): void
{
$spreadsheet = new Spreadsheet();
$sheet = self::getPopulatedSheet($spreadsheet);
$iterator = new RowIterator($sheet, 1, 9);
$iterator->seek($rowId);
$row = $iterator->current();
$isEmpty = $row->isEmpty(CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL);
self::assertSame($expectedEmpty, $isEmpty);
$spreadsheet->disconnectWorksheets();
}
public function emptyRowEmptyStringAsEmpty(): array
{
return [
[1, false],
[2, true],
[3, false],
[4, true],
[5, false],
[6, false],
[7, false],
[8, false],
[9, true],
];
}
/**
* @dataProvider emptyRowNullAndEmptyStringAsEmpty
*/
public function testIteratorEmptyRowWithNullAndEmptyString(int $rowId, bool $expectedEmpty): void
{
$spreadsheet = new Spreadsheet();
$sheet = self::getPopulatedSheet($spreadsheet);
$iterator = new RowIterator($sheet, 1, 9);
$iterator->seek($rowId);
$row = $iterator->current();
$isEmpty = $row->isEmpty(
CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL | CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL
);
self::assertSame($expectedEmpty, $isEmpty);
$spreadsheet->disconnectWorksheets();
}
public function emptyRowNullAndEmptyStringAsEmpty(): array
{
return [
[1, false],
[2, true],
[3, true],
[4, true],
[5, true],
[6, false],
[7, false],
[8, false],
[9, true],
];
}
}

View File

@ -3,7 +3,9 @@
namespace PhpOffice\PhpSpreadsheetTests\Worksheet; namespace PhpOffice\PhpSpreadsheetTests\Worksheet;
use Exception; use Exception;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\CellIterator;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@ -405,4 +407,100 @@ class WorksheetTest extends TestCase
self::assertSame($expectedData, $worksheet->toArray()); self::assertSame($expectedData, $worksheet->toArray());
self::assertSame($expectedHighestRow, $worksheet->getHighestRow()); self::assertSame($expectedHighestRow, $worksheet->getHighestRow());
} }
private static function getPopulatedSheetForEmptyRowTest(Spreadsheet $spreadsheet): Worksheet
{
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValueExplicit('A1', 'Hello World', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('B3', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('B4', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('B5', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('C5', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('B6', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('C6', 'PHP', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('B7', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('C7', 'PHP', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('B8', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('C8', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('D8', 'PHP', DataType::TYPE_STRING);
return $sheet;
}
private static function getPopulatedSheetForEmptyColumnTest(Spreadsheet $spreadsheet): Worksheet
{
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValueExplicit('A1', 'Hello World', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('C2', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('D2', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('E2', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('E3', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('F2', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('F3', 'PHP', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('G2', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('G3', 'PHP', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('H2', null, DataType::TYPE_NULL);
$sheet->setCellValueExplicit('H3', '', DataType::TYPE_STRING);
$sheet->setCellValueExplicit('H4', 'PHP', DataType::TYPE_STRING);
return $sheet;
}
/**
* @dataProvider emptyRowProvider
*/
public function testIsEmptyRow(int $rowId, bool $expectedEmpty): void
{
$spreadsheet = new Spreadsheet();
$sheet = self::getPopulatedSheetForEmptyRowTest($spreadsheet);
$isEmpty = $sheet->isEmptyRow($rowId, CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL | CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL);
self::assertSame($expectedEmpty, $isEmpty);
$spreadsheet->disconnectWorksheets();
}
public function emptyRowProvider(): array
{
return [
[1, false],
[2, true],
[3, true],
[4, true],
[5, true],
[6, false],
[7, false],
[8, false],
[9, true],
];
}
/**
* @dataProvider emptyColumnProvider
*/
public function testIsEmptyColumn(string $columnId, bool $expectedEmpty): void
{
$spreadsheet = new Spreadsheet();
$sheet = self::getPopulatedSheetForEmptyColumnTest($spreadsheet);
$isEmpty = $sheet->isEmptyColumn($columnId, CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL | CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL);
self::assertSame($expectedEmpty, $isEmpty);
$spreadsheet->disconnectWorksheets();
}
public function emptyColumnProvider(): array
{
return [
['A', false],
['B', true],
['C', true],
['D', true],
['E', true],
['F', false],
['G', false],
['H', false],
['I', true],
];
}
} }