package and depencies

This commit is contained in:
RafficMohammed
2023-01-08 02:57:24 +05:30
parent d5332eb421
commit 1d54b8bc7f
4309 changed files with 193331 additions and 172289 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -49,7 +49,7 @@ class Column
/**
* Autofilter.
*
* @var AutoFilter
* @var null|AutoFilter
*/
private $parent;
@@ -77,27 +77,34 @@ class Column
/**
* Autofilter Column Rules.
*
* @var array of Column\Rule
* @var Column\Rule[]
*/
private $ruleset = [];
/**
* Autofilter Column Dynamic Attributes.
*
* @var array of mixed
* @var mixed[]
*/
private $attributes = [];
/**
* Create a new Column.
*
* @param string $pColumn Column (e.g. A)
* @param AutoFilter $pParent Autofilter for this column
* @param string $column Column (e.g. A)
* @param AutoFilter $parent Autofilter for this column
*/
public function __construct($pColumn, ?AutoFilter $pParent = null)
public function __construct($column, ?AutoFilter $parent = null)
{
$this->columnIndex = $pColumn;
$this->parent = $pParent;
$this->columnIndex = $column;
$this->parent = $parent;
}
public function setEvaluatedFalse(): void
{
if ($this->parent !== null) {
$this->parent->setEvaluated(false);
}
}
/**
@@ -113,19 +120,20 @@ class Column
/**
* Set AutoFilter column index as string eg: 'A'.
*
* @param string $pColumn Column (e.g. A)
* @param string $column Column (e.g. A)
*
* @return $this
*/
public function setColumnIndex($pColumn)
public function setColumnIndex($column)
{
$this->setEvaluatedFalse();
// Uppercase coordinate
$pColumn = strtoupper($pColumn);
$column = strtoupper($column);
if ($this->parent !== null) {
$this->parent->testColumnInRange($pColumn);
$this->parent->testColumnInRange($column);
}
$this->columnIndex = $pColumn;
$this->columnIndex = $column;
return $this;
}
@@ -133,7 +141,7 @@ class Column
/**
* Get this Column's AutoFilter Parent.
*
* @return AutoFilter
* @return null|AutoFilter
*/
public function getParent()
{
@@ -143,13 +151,12 @@ class Column
/**
* Set this Column's AutoFilter Parent.
*
* @param AutoFilter $pParent
*
* @return $this
*/
public function setParent(?AutoFilter $pParent = null)
public function setParent(?AutoFilter $parent = null)
{
$this->parent = $pParent;
$this->setEvaluatedFalse();
$this->parent = $parent;
return $this;
}
@@ -167,17 +174,21 @@ class Column
/**
* Set AutoFilter Type.
*
* @param string $pFilterType
* @param string $filterType
*
* @return $this
*/
public function setFilterType($pFilterType)
public function setFilterType($filterType)
{
if (!in_array($pFilterType, self::$filterTypes)) {
$this->setEvaluatedFalse();
if (!in_array($filterType, self::$filterTypes)) {
throw new PhpSpreadsheetException('Invalid filter type for column AutoFilter.');
}
if ($filterType === self::AUTOFILTER_FILTERTYPE_CUSTOMFILTER && count($this->ruleset) > 2) {
throw new PhpSpreadsheetException('No more than 2 rules are allowed in a Custom Filter');
}
$this->filterType = $pFilterType;
$this->filterType = $filterType;
return $this;
}
@@ -195,19 +206,20 @@ class Column
/**
* Set AutoFilter Multiple Rules And/Or.
*
* @param string $pJoin And/Or
* @param string $join And/Or
*
* @return $this
*/
public function setJoin($pJoin)
public function setJoin($join)
{
$this->setEvaluatedFalse();
// Lowercase And/Or
$pJoin = strtolower($pJoin);
if (!in_array($pJoin, self::$ruleJoins)) {
$join = strtolower($join);
if (!in_array($join, self::$ruleJoins)) {
throw new PhpSpreadsheetException('Invalid rule connection for column AutoFilter.');
}
$this->join = $pJoin;
$this->join = $join;
return $this;
}
@@ -215,12 +227,13 @@ class Column
/**
* Set AutoFilter Attributes.
*
* @param string[] $attributes
* @param mixed[] $attributes
*
* @return $this
*/
public function setAttributes(array $attributes)
public function setAttributes($attributes)
{
$this->setEvaluatedFalse();
$this->attributes = $attributes;
return $this;
@@ -229,14 +242,15 @@ class Column
/**
* Set An AutoFilter Attribute.
*
* @param string $pName Attribute Name
* @param string $pValue Attribute Value
* @param string $name Attribute Name
* @param int|string $value Attribute Value
*
* @return $this
*/
public function setAttribute($pName, $pValue)
public function setAttribute($name, $value)
{
$this->attributes[$pName] = $pValue;
$this->setEvaluatedFalse();
$this->attributes[$name] = $value;
return $this;
}
@@ -244,7 +258,7 @@ class Column
/**
* Get AutoFilter Column Attributes.
*
* @return string[]
* @return int[]|string[]
*/
public function getAttributes()
{
@@ -254,19 +268,24 @@ class Column
/**
* Get specific AutoFilter Column Attribute.
*
* @param string $pName Attribute Name
* @param string $name Attribute Name
*
* @return string
* @return null|int|string
*/
public function getAttribute($pName)
public function getAttribute($name)
{
if (isset($this->attributes[$pName])) {
return $this->attributes[$pName];
if (isset($this->attributes[$name])) {
return $this->attributes[$name];
}
return null;
}
public function ruleCount(): int
{
return count($this->ruleset);
}
/**
* Get all AutoFilter Column Rules.
*
@@ -280,17 +299,17 @@ class Column
/**
* Get a specified AutoFilter Column Rule.
*
* @param int $pIndex Rule index in the ruleset array
* @param int $index Rule index in the ruleset array
*
* @return Column\Rule
*/
public function getRule($pIndex)
public function getRule($index)
{
if (!isset($this->ruleset[$pIndex])) {
$this->ruleset[$pIndex] = new Column\Rule($this);
if (!isset($this->ruleset[$index])) {
$this->ruleset[$index] = new Column\Rule($this);
}
return $this->ruleset[$pIndex];
return $this->ruleset[$index];
}
/**
@@ -300,6 +319,10 @@ class Column
*/
public function createRule()
{
$this->setEvaluatedFalse();
if ($this->filterType === self::AUTOFILTER_FILTERTYPE_CUSTOMFILTER && count($this->ruleset) >= 2) {
throw new PhpSpreadsheetException('No more than 2 rules are allowed in a Custom Filter');
}
$this->ruleset[] = new Column\Rule($this);
return end($this->ruleset);
@@ -310,10 +333,11 @@ class Column
*
* @return $this
*/
public function addRule(Column\Rule $pRule)
public function addRule(Column\Rule $rule)
{
$pRule->setParent($this);
$this->ruleset[] = $pRule;
$this->setEvaluatedFalse();
$rule->setParent($this);
$this->ruleset[] = $rule;
return $this;
}
@@ -322,14 +346,15 @@ class Column
* Delete a specified AutoFilter Column Rule
* If the number of rules is reduced to 1, then we reset And/Or logic to Or.
*
* @param int $pIndex Rule index in the ruleset array
* @param int $index Rule index in the ruleset array
*
* @return $this
*/
public function deleteRule($pIndex)
public function deleteRule($index)
{
if (isset($this->ruleset[$pIndex])) {
unset($this->ruleset[$pIndex]);
$this->setEvaluatedFalse();
if (isset($this->ruleset[$index])) {
unset($this->ruleset[$index]);
// If we've just deleted down to a single rule, then reset And/Or joining to Or
if (count($this->ruleset) <= 1) {
$this->setJoin(self::AUTOFILTER_COLUMN_JOIN_OR);
@@ -346,6 +371,7 @@ class Column
*/
public function clearRules()
{
$this->setEvaluatedFalse();
$this->ruleset = [];
$this->setJoin(self::AUTOFILTER_COLUMN_JOIN_OR);
@@ -370,8 +396,6 @@ class Column
$cloned->setParent($this); // attach the new cloned Rule to this new cloned Autofilter Cloned object
$this->ruleset[$k] = $cloned;
}
} elseif (is_object($value)) {
$this->$key = clone $value;
} else {
$this->$key = $value;
}

View File

@@ -13,7 +13,7 @@ class Rule
const AUTOFILTER_RULETYPE_DYNAMICFILTER = 'dynamicFilter';
const AUTOFILTER_RULETYPE_TOPTENFILTER = 'top10Filter';
private static $ruleTypes = [
private const RULE_TYPES = [
// Currently we're not handling
// colorFilter
// extLst
@@ -32,7 +32,7 @@ class Rule
const AUTOFILTER_RULETYPE_DATEGROUP_MINUTE = 'minute';
const AUTOFILTER_RULETYPE_DATEGROUP_SECOND = 'second';
private static $dateTimeGroups = [
private const DATE_TIME_GROUPS = [
self::AUTOFILTER_RULETYPE_DATEGROUP_YEAR,
self::AUTOFILTER_RULETYPE_DATEGROUP_MONTH,
self::AUTOFILTER_RULETYPE_DATEGROUP_DAY,
@@ -88,7 +88,7 @@ class Rule
const AUTOFILTER_RULETYPE_DYNAMIC_ABOVEAVERAGE = 'aboveAverage';
const AUTOFILTER_RULETYPE_DYNAMIC_BELOWAVERAGE = 'belowAverage';
private static $dynamicTypes = [
private const DYNAMIC_TYPES = [
self::AUTOFILTER_RULETYPE_DYNAMIC_YESTERDAY,
self::AUTOFILTER_RULETYPE_DYNAMIC_TODAY,
self::AUTOFILTER_RULETYPE_DYNAMIC_TOMORROW,
@@ -125,15 +125,7 @@ class Rule
self::AUTOFILTER_RULETYPE_DYNAMIC_BELOWAVERAGE,
];
/*
* The only valid filter rule operators for filter and customFilter types are:
* <xsd:enumeration value="equal"/>
* <xsd:enumeration value="lessThan"/>
* <xsd:enumeration value="lessThanOrEqual"/>
* <xsd:enumeration value="notEqual"/>
* <xsd:enumeration value="greaterThanOrEqual"/>
* <xsd:enumeration value="greaterThan"/>
*/
// Filter rule operators for filter and customFilter types.
const AUTOFILTER_COLUMN_RULE_EQUAL = 'equal';
const AUTOFILTER_COLUMN_RULE_NOTEQUAL = 'notEqual';
const AUTOFILTER_COLUMN_RULE_GREATERTHAN = 'greaterThan';
@@ -141,7 +133,7 @@ class Rule
const AUTOFILTER_COLUMN_RULE_LESSTHAN = 'lessThan';
const AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL = 'lessThanOrEqual';
private static $operators = [
private const OPERATORS = [
self::AUTOFILTER_COLUMN_RULE_EQUAL,
self::AUTOFILTER_COLUMN_RULE_NOTEQUAL,
self::AUTOFILTER_COLUMN_RULE_GREATERTHAN,
@@ -153,7 +145,7 @@ class Rule
const AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE = 'byValue';
const AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT = 'byPercent';
private static $topTenValue = [
private const TOP_TEN_VALUE = [
self::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE,
self::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT,
];
@@ -161,49 +153,27 @@ class Rule
const AUTOFILTER_COLUMN_RULE_TOPTEN_TOP = 'top';
const AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM = 'bottom';
private static $topTenType = [
private const TOP_TEN_TYPE = [
self::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP,
self::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM,
];
// Rule Operators (Numeric, Boolean etc)
// const AUTOFILTER_COLUMN_RULE_BETWEEN = 'between'; // greaterThanOrEqual 1 && lessThanOrEqual 2
// Unimplented Rule Operators (Numeric, Boolean etc)
// const AUTOFILTER_COLUMN_RULE_BETWEEN = 'between'; // greaterThanOrEqual 1 && lessThanOrEqual 2
// Rule Operators (Numeric Special) which are translated to standard numeric operators with calculated values
// const AUTOFILTER_COLUMN_RULE_TOPTEN = 'topTen'; // greaterThan calculated value
// const AUTOFILTER_COLUMN_RULE_TOPTENPERCENT = 'topTenPercent'; // greaterThan calculated value
// const AUTOFILTER_COLUMN_RULE_ABOVEAVERAGE = 'aboveAverage'; // Value is calculated as the average
// const AUTOFILTER_COLUMN_RULE_BELOWAVERAGE = 'belowAverage'; // Value is calculated as the average
// Rule Operators (String) which are set as wild-carded values
// const AUTOFILTER_COLUMN_RULE_BEGINSWITH = 'beginsWith'; // A*
// const AUTOFILTER_COLUMN_RULE_ENDSWITH = 'endsWith'; // *Z
// const AUTOFILTER_COLUMN_RULE_CONTAINS = 'contains'; // *B*
// const AUTOFILTER_COLUMN_RULE_DOESNTCONTAIN = 'notEqual'; // notEqual *B*
// const AUTOFILTER_COLUMN_RULE_BEGINSWITH = 'beginsWith'; // A*
// const AUTOFILTER_COLUMN_RULE_ENDSWITH = 'endsWith'; // *Z
// const AUTOFILTER_COLUMN_RULE_CONTAINS = 'contains'; // *B*
// const AUTOFILTER_COLUMN_RULE_DOESNTCONTAIN = 'notEqual'; // notEqual *B*
// Rule Operators (Date Special) which are translated to standard numeric operators with calculated values
// const AUTOFILTER_COLUMN_RULE_BEFORE = 'lessThan';
// const AUTOFILTER_COLUMN_RULE_AFTER = 'greaterThan';
// const AUTOFILTER_COLUMN_RULE_YESTERDAY = 'yesterday';
// const AUTOFILTER_COLUMN_RULE_TODAY = 'today';
// const AUTOFILTER_COLUMN_RULE_TOMORROW = 'tomorrow';
// const AUTOFILTER_COLUMN_RULE_LASTWEEK = 'lastWeek';
// const AUTOFILTER_COLUMN_RULE_THISWEEK = 'thisWeek';
// const AUTOFILTER_COLUMN_RULE_NEXTWEEK = 'nextWeek';
// const AUTOFILTER_COLUMN_RULE_LASTMONTH = 'lastMonth';
// const AUTOFILTER_COLUMN_RULE_THISMONTH = 'thisMonth';
// const AUTOFILTER_COLUMN_RULE_NEXTMONTH = 'nextMonth';
// const AUTOFILTER_COLUMN_RULE_LASTQUARTER = 'lastQuarter';
// const AUTOFILTER_COLUMN_RULE_THISQUARTER = 'thisQuarter';
// const AUTOFILTER_COLUMN_RULE_NEXTQUARTER = 'nextQuarter';
// const AUTOFILTER_COLUMN_RULE_LASTYEAR = 'lastYear';
// const AUTOFILTER_COLUMN_RULE_THISYEAR = 'thisYear';
// const AUTOFILTER_COLUMN_RULE_NEXTYEAR = 'nextYear';
// const AUTOFILTER_COLUMN_RULE_YEARTODATE = 'yearToDate'; // <dynamicFilter val="40909" type="yearToDate" maxVal="41113"/>
// const AUTOFILTER_COLUMN_RULE_ALLDATESINMONTH = 'allDatesInMonth'; // <dynamicFilter type="M2"/> for Month/February
// const AUTOFILTER_COLUMN_RULE_ALLDATESINQUARTER = 'allDatesInQuarter'; // <dynamicFilter type="Q2"/> for Quarter 2
// const AUTOFILTER_COLUMN_RULE_BEFORE = 'lessThan';
// const AUTOFILTER_COLUMN_RULE_AFTER = 'greaterThan';
/**
* Autofilter Column.
*
* @var Column
* @var ?Column
*/
private $parent;
@@ -217,7 +187,7 @@ class Rule
/**
* Autofilter Rule Value.
*
* @var string
* @var int|int[]|string|string[]
*/
private $value = '';
@@ -237,12 +207,17 @@ class Rule
/**
* Create a new Rule.
*
* @param Column $pParent
*/
public function __construct(?Column $pParent = null)
public function __construct(?Column $parent = null)
{
$this->parent = $pParent;
$this->parent = $parent;
}
private function setEvaluatedFalse(): void
{
if ($this->parent !== null) {
$this->parent->setEvaluatedFalse();
}
}
/**
@@ -258,17 +233,18 @@ class Rule
/**
* Set AutoFilter Rule Type.
*
* @param string $pRuleType see self::AUTOFILTER_RULETYPE_*
* @param string $ruleType see self::AUTOFILTER_RULETYPE_*
*
* @return $this
*/
public function setRuleType($pRuleType)
public function setRuleType($ruleType)
{
if (!in_array($pRuleType, self::$ruleTypes)) {
$this->setEvaluatedFalse();
if (!in_array($ruleType, self::RULE_TYPES)) {
throw new PhpSpreadsheetException('Invalid rule type for column AutoFilter Rule.');
}
$this->ruleType = $pRuleType;
$this->ruleType = $ruleType;
return $this;
}
@@ -276,7 +252,7 @@ class Rule
/**
* Get AutoFilter Rule Value.
*
* @return string
* @return int|int[]|string|string[]
*/
public function getValue()
{
@@ -286,31 +262,32 @@ class Rule
/**
* Set AutoFilter Rule Value.
*
* @param string|string[] $pValue
* @param int|int[]|string|string[] $value
*
* @return $this
*/
public function setValue($pValue)
public function setValue($value)
{
if (is_array($pValue)) {
$this->setEvaluatedFalse();
if (is_array($value)) {
$grouping = -1;
foreach ($pValue as $key => $value) {
foreach ($value as $key => $v) {
// Validate array entries
if (!in_array($key, self::$dateTimeGroups)) {
if (!in_array($key, self::DATE_TIME_GROUPS)) {
// Remove any invalid entries from the value array
unset($pValue[$key]);
unset($value[$key]);
} else {
// Work out what the dateTime grouping will be
$grouping = max($grouping, array_search($key, self::$dateTimeGroups));
$grouping = max($grouping, array_search($key, self::DATE_TIME_GROUPS));
}
}
if (count($pValue) == 0) {
if (count($value) == 0) {
throw new PhpSpreadsheetException('Invalid rule value for column AutoFilter Rule.');
}
// Set the dateTime grouping that we've anticipated
$this->setGrouping(self::$dateTimeGroups[$grouping]);
$this->setGrouping(self::DATE_TIME_GROUPS[$grouping]);
}
$this->value = $pValue;
$this->value = $value;
return $this;
}
@@ -328,22 +305,23 @@ class Rule
/**
* Set AutoFilter Rule Operator.
*
* @param string $pOperator see self::AUTOFILTER_COLUMN_RULE_*
* @param string $operator see self::AUTOFILTER_COLUMN_RULE_*
*
* @return $this
*/
public function setOperator($pOperator)
public function setOperator($operator)
{
if (empty($pOperator)) {
$pOperator = self::AUTOFILTER_COLUMN_RULE_EQUAL;
$this->setEvaluatedFalse();
if (empty($operator)) {
$operator = self::AUTOFILTER_COLUMN_RULE_EQUAL;
}
if (
(!in_array($pOperator, self::$operators)) &&
(!in_array($pOperator, self::$topTenValue))
(!in_array($operator, self::OPERATORS)) &&
(!in_array($operator, self::TOP_TEN_VALUE))
) {
throw new PhpSpreadsheetException('Invalid operator for column AutoFilter Rule.');
}
$this->operator = $pOperator;
$this->operator = $operator;
return $this;
}
@@ -361,21 +339,22 @@ class Rule
/**
* Set AutoFilter Rule Grouping.
*
* @param string $pGrouping
* @param string $grouping
*
* @return $this
*/
public function setGrouping($pGrouping)
public function setGrouping($grouping)
{
$this->setEvaluatedFalse();
if (
($pGrouping !== null) &&
(!in_array($pGrouping, self::$dateTimeGroups)) &&
(!in_array($pGrouping, self::$dynamicTypes)) &&
(!in_array($pGrouping, self::$topTenType))
($grouping !== null) &&
(!in_array($grouping, self::DATE_TIME_GROUPS)) &&
(!in_array($grouping, self::DYNAMIC_TYPES)) &&
(!in_array($grouping, self::TOP_TEN_TYPE))
) {
throw new PhpSpreadsheetException('Invalid rule type for column AutoFilter Rule.');
throw new PhpSpreadsheetException('Invalid grouping for column AutoFilter Rule.');
}
$this->grouping = $pGrouping;
$this->grouping = $grouping;
return $this;
}
@@ -383,21 +362,22 @@ class Rule
/**
* Set AutoFilter Rule.
*
* @param string $pOperator see self::AUTOFILTER_COLUMN_RULE_*
* @param string|string[] $pValue
* @param string $pGrouping
* @param string $operator see self::AUTOFILTER_COLUMN_RULE_*
* @param int|int[]|string|string[] $value
* @param string $grouping
*
* @return $this
*/
public function setRule($pOperator, $pValue, $pGrouping = null)
public function setRule($operator, $value, $grouping = null)
{
$this->setOperator($pOperator);
$this->setValue($pValue);
$this->setEvaluatedFalse();
$this->setOperator($operator);
$this->setValue($value);
// Only set grouping if it's been passed in as a user-supplied argument,
// otherwise we're calculating it when we setValue() and don't want to overwrite that
// If the user supplies an argumnet for grouping, then on their own head be it
if ($pGrouping !== null) {
$this->setGrouping($pGrouping);
if ($grouping !== null) {
$this->setGrouping($grouping);
}
return $this;
@@ -406,7 +386,7 @@ class Rule
/**
* Get this Rule's AutoFilter Column Parent.
*
* @return Column
* @return ?Column
*/
public function getParent()
{
@@ -416,13 +396,12 @@ class Rule
/**
* Set this Rule's AutoFilter Column Parent.
*
* @param Column $pParent
*
* @return $this
*/
public function setParent(?Column $pParent = null)
public function setParent(?Column $parent = null)
{
$this->parent = $pParent;
$this->setEvaluatedFalse();
$this->parent = $parent;
return $this;
}
@@ -435,11 +414,9 @@ class Rule
$vars = get_object_vars($this);
foreach ($vars as $key => $value) {
if (is_object($value)) {
if ($key == 'parent') {
if ($key == 'parent') { // this is only object
// Detach from autofilter column parent
$this->$key = null;
} else {
$this->$key = clone $value;
}
} else {
$this->$key = $value;

View File

@@ -8,6 +8,22 @@ use PhpOffice\PhpSpreadsheet\IComparable;
class BaseDrawing implements IComparable
{
const EDIT_AS_ABSOLUTE = 'absolute';
const EDIT_AS_ONECELL = 'oneCell';
const EDIT_AS_TWOCELL = 'twoCell';
private const VALID_EDIT_AS = [
self::EDIT_AS_ABSOLUTE,
self::EDIT_AS_ONECELL,
self::EDIT_AS_TWOCELL,
];
/**
* The editAs attribute, used only with two cell anchor.
*
* @var string
*/
protected $editAs = '';
/**
* Image counter.
*
@@ -27,19 +43,19 @@ class BaseDrawing implements IComparable
*
* @var string
*/
protected $name;
protected $name = '';
/**
* Description.
*
* @var string
*/
protected $description;
protected $description = '';
/**
* Worksheet.
*
* @var Worksheet
* @var null|Worksheet
*/
protected $worksheet;
@@ -48,49 +64,84 @@ class BaseDrawing implements IComparable
*
* @var string
*/
protected $coordinates;
protected $coordinates = 'A1';
/**
* Offset X.
*
* @var int
*/
protected $offsetX;
protected $offsetX = 0;
/**
* Offset Y.
*
* @var int
*/
protected $offsetY;
protected $offsetY = 0;
/**
* Coordinates2.
*
* @var string
*/
protected $coordinates2 = '';
/**
* Offset X2.
*
* @var int
*/
protected $offsetX2 = 0;
/**
* Offset Y2.
*
* @var int
*/
protected $offsetY2 = 0;
/**
* Width.
*
* @var int
*/
protected $width;
protected $width = 0;
/**
* Height.
*
* @var int
*/
protected $height;
protected $height = 0;
/**
* Pixel width of image. See $width for the size the Drawing will be in the sheet.
*
* @var int
*/
protected $imageWidth = 0;
/**
* Pixel width of image. See $height for the size the Drawing will be in the sheet.
*
* @var int
*/
protected $imageHeight = 0;
/**
* Proportional resize.
*
* @var bool
*/
protected $resizeProportional;
protected $resizeProportional = true;
/**
* Rotation.
*
* @var int
*/
protected $rotation;
protected $rotation = 0;
/**
* Shadow.
@@ -106,93 +157,56 @@ class BaseDrawing implements IComparable
*/
private $hyperlink;
/**
* Image type.
*
* @var int
*/
protected $type = IMAGETYPE_UNKNOWN;
/**
* Create a new BaseDrawing.
*/
public function __construct()
{
// Initialise values
$this->name = '';
$this->description = '';
$this->worksheet = null;
$this->coordinates = 'A1';
$this->offsetX = 0;
$this->offsetY = 0;
$this->width = 0;
$this->height = 0;
$this->resizeProportional = true;
$this->rotation = 0;
$this->shadow = new Drawing\Shadow();
$this->setShadow();
// Set image index
++self::$imageCounter;
$this->imageIndex = self::$imageCounter;
}
/**
* Get image index.
*
* @return int
*/
public function getImageIndex()
public function getImageIndex(): int
{
return $this->imageIndex;
}
/**
* Get Name.
*
* @return string
*/
public function getName()
public function getName(): string
{
return $this->name;
}
/**
* Set Name.
*
* @param string $pValue
*
* @return $this
*/
public function setName($pValue)
public function setName(string $name): self
{
$this->name = $pValue;
$this->name = $name;
return $this;
}
/**
* Get Description.
*
* @return string
*/
public function getDescription()
public function getDescription(): string
{
return $this->description;
}
/**
* Set Description.
*
* @param string $description
*
* @return $this
*/
public function setDescription($description)
public function setDescription(string $description): self
{
$this->description = $description;
return $this;
}
/**
* Get Worksheet.
*
* @return Worksheet
*/
public function getWorksheet()
public function getWorksheet(): ?Worksheet
{
return $this->worksheet;
}
@@ -200,26 +214,25 @@ class BaseDrawing implements IComparable
/**
* Set Worksheet.
*
* @param Worksheet $pValue
* @param bool $pOverrideOld If a Worksheet has already been assigned, overwrite it and remove image from old Worksheet?
*
* @return $this
* @param bool $overrideOld If a Worksheet has already been assigned, overwrite it and remove image from old Worksheet?
*/
public function setWorksheet(?Worksheet $pValue = null, $pOverrideOld = false)
public function setWorksheet(?Worksheet $worksheet = null, bool $overrideOld = false): self
{
if ($this->worksheet === null) {
// Add drawing to \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet
$this->worksheet = $pValue;
$this->worksheet->getCell($this->coordinates);
$this->worksheet->getDrawingCollection()->append($this);
if ($worksheet !== null) {
$this->worksheet = $worksheet;
$this->worksheet->getCell($this->coordinates);
$this->worksheet->getDrawingCollection()->append($this);
}
} else {
if ($pOverrideOld) {
if ($overrideOld) {
// Remove drawing from old \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet
$iterator = $this->worksheet->getDrawingCollection()->getIterator();
while ($iterator->valid()) {
if ($iterator->current()->getHashCode() === $this->getHashCode()) {
$this->worksheet->getDrawingCollection()->offsetUnset($iterator->key());
$this->worksheet->getDrawingCollection()->offsetUnset(/** @scrutinizer ignore-type */ $iterator->key());
$this->worksheet = null;
break;
@@ -227,7 +240,7 @@ class BaseDrawing implements IComparable
}
// Set new \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet
$this->setWorksheet($pValue);
$this->setWorksheet($worksheet);
} else {
throw new PhpSpreadsheetException('A Worksheet has already been assigned. Drawings can only exist on one \\PhpOffice\\PhpSpreadsheet\\Worksheet.');
}
@@ -236,136 +249,112 @@ class BaseDrawing implements IComparable
return $this;
}
/**
* Get Coordinates.
*
* @return string
*/
public function getCoordinates()
public function getCoordinates(): string
{
return $this->coordinates;
}
/**
* Set Coordinates.
*
* @param string $pValue eg: 'A1'
*
* @return $this
*/
public function setCoordinates($pValue)
public function setCoordinates(string $coordinates): self
{
$this->coordinates = $pValue;
$this->coordinates = $coordinates;
return $this;
}
/**
* Get OffsetX.
*
* @return int
*/
public function getOffsetX()
public function getOffsetX(): int
{
return $this->offsetX;
}
/**
* Set OffsetX.
*
* @param int $pValue
*
* @return $this
*/
public function setOffsetX($pValue)
public function setOffsetX(int $offsetX): self
{
$this->offsetX = $pValue;
$this->offsetX = $offsetX;
return $this;
}
/**
* Get OffsetY.
*
* @return int
*/
public function getOffsetY()
public function getOffsetY(): int
{
return $this->offsetY;
}
/**
* Set OffsetY.
*
* @param int $pValue
*
* @return $this
*/
public function setOffsetY($pValue)
public function setOffsetY(int $offsetY): self
{
$this->offsetY = $pValue;
$this->offsetY = $offsetY;
return $this;
}
/**
* Get Width.
*
* @return int
*/
public function getWidth()
public function getCoordinates2(): string
{
return $this->coordinates2;
}
public function setCoordinates2(string $coordinates2): self
{
$this->coordinates2 = $coordinates2;
return $this;
}
public function getOffsetX2(): int
{
return $this->offsetX2;
}
public function setOffsetX2(int $offsetX2): self
{
$this->offsetX2 = $offsetX2;
return $this;
}
public function getOffsetY2(): int
{
return $this->offsetY2;
}
public function setOffsetY2(int $offsetY2): self
{
$this->offsetY2 = $offsetY2;
return $this;
}
public function getWidth(): int
{
return $this->width;
}
/**
* Set Width.
*
* @param int $pValue
*
* @return $this
*/
public function setWidth($pValue)
public function setWidth(int $width): self
{
// Resize proportional?
if ($this->resizeProportional && $pValue != 0) {
if ($this->resizeProportional && $width != 0) {
$ratio = $this->height / ($this->width != 0 ? $this->width : 1);
$this->height = round($ratio * $pValue);
$this->height = (int) round($ratio * $width);
}
// Set width
$this->width = $pValue;
$this->width = $width;
return $this;
}
/**
* Get Height.
*
* @return int
*/
public function getHeight()
public function getHeight(): int
{
return $this->height;
}
/**
* Set Height.
*
* @param int $pValue
*
* @return $this
*/
public function setHeight($pValue)
public function setHeight(int $height): self
{
// Resize proportional?
if ($this->resizeProportional && $pValue != 0) {
if ($this->resizeProportional && $height != 0) {
$ratio = $this->width / ($this->height != 0 ? $this->height : 1);
$this->width = round($ratio * $pValue);
$this->width = (int) round($ratio * $height);
}
// Set height
$this->height = $pValue;
$this->height = $height;
return $this;
}
@@ -380,22 +369,17 @@ class BaseDrawing implements IComparable
* </code>
*
* @author Vincent@luo MSN:kele_100@hotmail.com
*
* @param int $width
* @param int $height
*
* @return $this
*/
public function setWidthAndHeight($width, $height)
public function setWidthAndHeight(int $width, int $height): self
{
$xratio = $width / ($this->width != 0 ? $this->width : 1);
$yratio = $height / ($this->height != 0 ? $this->height : 1);
if ($this->resizeProportional && !($width == 0 || $height == 0)) {
if (($xratio * $this->height) < $height) {
$this->height = ceil($xratio * $this->height);
$this->height = (int) ceil($xratio * $this->height);
$this->width = $width;
} else {
$this->width = ceil($yratio * $this->width);
$this->width = (int) ceil($yratio * $this->width);
$this->height = $height;
}
} else {
@@ -406,74 +390,38 @@ class BaseDrawing implements IComparable
return $this;
}
/**
* Get ResizeProportional.
*
* @return bool
*/
public function getResizeProportional()
public function getResizeProportional(): bool
{
return $this->resizeProportional;
}
/**
* Set ResizeProportional.
*
* @param bool $pValue
*
* @return $this
*/
public function setResizeProportional($pValue)
public function setResizeProportional(bool $resizeProportional): self
{
$this->resizeProportional = $pValue;
$this->resizeProportional = $resizeProportional;
return $this;
}
/**
* Get Rotation.
*
* @return int
*/
public function getRotation()
public function getRotation(): int
{
return $this->rotation;
}
/**
* Set Rotation.
*
* @param int $pValue
*
* @return $this
*/
public function setRotation($pValue)
public function setRotation(int $rotation): self
{
$this->rotation = $pValue;
$this->rotation = $rotation;
return $this;
}
/**
* Get Shadow.
*
* @return Drawing\Shadow
*/
public function getShadow()
public function getShadow(): Drawing\Shadow
{
return $this->shadow;
}
/**
* Set Shadow.
*
* @param Drawing\Shadow $pValue
*
* @return $this
*/
public function setShadow(?Drawing\Shadow $pValue = null)
public function setShadow(?Drawing\Shadow $shadow = null): self
{
$this->shadow = $pValue;
$this->shadow = $shadow ?? new Drawing\Shadow();
return $this;
}
@@ -488,10 +436,13 @@ class BaseDrawing implements IComparable
return md5(
$this->name .
$this->description .
$this->worksheet->getHashCode() .
(($this->worksheet === null) ? '' : $this->worksheet->getHashCode()) .
$this->coordinates .
$this->offsetX .
$this->offsetY .
$this->coordinates2 .
$this->offsetX2 .
$this->offsetY2 .
$this->width .
$this->height .
$this->rotation .
@@ -517,16 +468,68 @@ class BaseDrawing implements IComparable
}
}
public function setHyperlink(?Hyperlink $pHyperlink = null): void
public function setHyperlink(?Hyperlink $hyperlink = null): void
{
$this->hyperlink = $pHyperlink;
$this->hyperlink = $hyperlink;
}
/**
* @return null|Hyperlink
*/
public function getHyperlink()
public function getHyperlink(): ?Hyperlink
{
return $this->hyperlink;
}
/**
* Set Fact Sizes and Type of Image.
*/
protected function setSizesAndType(string $path): void
{
if ($this->imageWidth === 0 && $this->imageHeight === 0 && $this->type === IMAGETYPE_UNKNOWN) {
$imageData = getimagesize($path);
if (!empty($imageData)) {
$this->imageWidth = $imageData[0];
$this->imageHeight = $imageData[1];
$this->type = $imageData[2];
}
}
if ($this->width === 0 && $this->height === 0) {
$this->width = $this->imageWidth;
$this->height = $this->imageHeight;
}
}
/**
* Get Image Type.
*/
public function getType(): int
{
return $this->type;
}
public function getImageWidth(): int
{
return $this->imageWidth;
}
public function getImageHeight(): int
{
return $this->imageHeight;
}
public function getEditAs(): string
{
return $this->editAs;
}
public function setEditAs(string $editAs): self
{
$this->editAs = $editAs;
return $this;
}
public function validEditAs(): bool
{
return in_array($this->editAs, self::VALID_EDIT_AS, true);
}
}

View File

@@ -2,10 +2,21 @@
namespace PhpOffice\PhpSpreadsheet\Worksheet;
use Iterator;
use Iterator as NativeIterator;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Collection\Cells;
abstract class CellIterator implements Iterator
/**
* @template TKey
*
* @implements NativeIterator<TKey, Cell>
*/
abstract class CellIterator implements NativeIterator
{
public const TREAT_NULL_VALUE_AS_EMPTY_CELL = 1;
public const TREAT_EMPTY_STRING_AS_EMPTY_CELL = 2;
/**
* Worksheet to iterate.
*
@@ -13,6 +24,13 @@ abstract class CellIterator implements Iterator
*/
protected $worksheet;
/**
* Cell Collection to iterate.
*
* @var Cells
*/
protected $cellCollection;
/**
* Iterate only existing cells.
*
@@ -25,15 +43,14 @@ abstract class CellIterator implements Iterator
*/
public function __destruct()
{
$this->worksheet = null;
// @phpstan-ignore-next-line
$this->worksheet = $this->cellCollection = null;
}
/**
* Get loop only existing cells.
*
* @return bool
*/
public function getIterateOnlyExistingCells()
public function getIterateOnlyExistingCells(): bool
{
return $this->onlyExistingCells;
}
@@ -45,10 +62,8 @@ abstract class CellIterator implements Iterator
/**
* Set the iterator to loop only existing cells.
*
* @param bool $value
*/
public function setIterateOnlyExistingCells($value): void
public function setIterateOnlyExistingCells(bool $value): void
{
$this->onlyExistingCells = (bool) $value;

View File

@@ -9,7 +9,7 @@ class Column
*
* @var Worksheet
*/
private $parent;
private $worksheet;
/**
* Column index.
@@ -21,13 +21,12 @@ class Column
/**
* Create a new column.
*
* @param Worksheet $parent
* @param string $columnIndex
*/
public function __construct(?Worksheet $parent = null, $columnIndex = 'A')
public function __construct(Worksheet $worksheet, $columnIndex = 'A')
{
// Set parent and column index
$this->parent = $parent;
$this->worksheet = $worksheet;
$this->columnIndex = $columnIndex;
}
@@ -36,15 +35,14 @@ class Column
*/
public function __destruct()
{
$this->parent = null;
// @phpstan-ignore-next-line
$this->worksheet = null;
}
/**
* Get column index as string eg: 'A'.
*
* @return string
*/
public function getColumnIndex()
public function getColumnIndex(): string
{
return $this->columnIndex;
}
@@ -59,6 +57,54 @@ class Column
*/
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) {
/** @scrutinizer ignore-call */
$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

@@ -2,9 +2,13 @@
namespace PhpOffice\PhpSpreadsheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
/**
* @extends CellIterator<int>
*/
class ColumnCellIterator extends CellIterator
{
/**
@@ -17,7 +21,7 @@ class ColumnCellIterator extends CellIterator
/**
* Column index.
*
* @var string
* @var int
*/
private $columnIndex;
@@ -38,15 +42,16 @@ class ColumnCellIterator extends CellIterator
/**
* Create a new row iterator.
*
* @param Worksheet $subject The worksheet to iterate over
* @param Worksheet $worksheet The worksheet to iterate over
* @param string $columnIndex The column that we want to iterate
* @param int $startRow The row number at which to start iterating
* @param int $endRow Optionally, the row number at which to stop iterating
*/
public function __construct(?Worksheet $subject = null, $columnIndex = 'A', $startRow = 1, $endRow = null)
public function __construct(Worksheet $worksheet, $columnIndex = 'A', $startRow = 1, $endRow = null)
{
// Set subject
$this->worksheet = $subject;
$this->worksheet = $worksheet;
$this->cellCollection = $worksheet->getCellCollection();
$this->columnIndex = Coordinate::columnIndexFromString($columnIndex);
$this->resetEnd($endRow);
$this->resetStart($startRow);
@@ -59,7 +64,7 @@ class ColumnCellIterator extends CellIterator
*
* @return $this
*/
public function resetStart($startRow = 1)
public function resetStart(int $startRow = 1)
{
$this->startRow = $startRow;
$this->adjustForExistingOnlyRange();
@@ -77,7 +82,7 @@ class ColumnCellIterator extends CellIterator
*/
public function resetEnd($endRow = null)
{
$this->endRow = ($endRow) ? $endRow : $this->worksheet->getHighestRow();
$this->endRow = $endRow ?: $this->worksheet->getHighestRow();
$this->adjustForExistingOnlyRange();
return $this;
@@ -90,9 +95,12 @@ class ColumnCellIterator extends CellIterator
*
* @return $this
*/
public function seek($row = 1)
public function seek(int $row = 1)
{
if ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $row))) {
if (
$this->onlyExistingCells &&
(!$this->cellCollection->has(Coordinate::stringFromColumnIndex($this->columnIndex) . $row))
) {
throw new PhpSpreadsheetException('In "IterateOnlyExistingCells" mode and Cell does not exist');
}
if (($row < $this->startRow) || ($row > $this->endRow)) {
@@ -113,20 +121,20 @@ class ColumnCellIterator extends CellIterator
/**
* Return the current cell in this worksheet column.
*
* @return \PhpOffice\PhpSpreadsheet\Cell\Cell
*/
public function current()
public function current(): ?Cell
{
return $this->worksheet->getCellByColumnAndRow($this->columnIndex, $this->currentRow);
$cellAddress = Coordinate::stringFromColumnIndex($this->columnIndex) . $this->currentRow;
return $this->cellCollection->has($cellAddress)
? $this->cellCollection->get($cellAddress)
: $this->worksheet->createNewCell($cellAddress);
}
/**
* Return the current iterator key.
*
* @return int
*/
public function key()
public function key(): int
{
return $this->currentRow;
}
@@ -136,12 +144,13 @@ class ColumnCellIterator extends CellIterator
*/
public function next(): void
{
$columnAddress = Coordinate::stringFromColumnIndex($this->columnIndex);
do {
++$this->currentRow;
} while (
($this->onlyExistingCells) &&
(!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->currentRow)) &&
($this->currentRow <= $this->endRow)
($this->currentRow <= $this->endRow) &&
(!$this->cellCollection->has($columnAddress . $this->currentRow))
);
}
@@ -150,21 +159,20 @@ class ColumnCellIterator extends CellIterator
*/
public function prev(): void
{
$columnAddress = Coordinate::stringFromColumnIndex($this->columnIndex);
do {
--$this->currentRow;
} while (
($this->onlyExistingCells) &&
(!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->currentRow)) &&
($this->currentRow >= $this->startRow)
($this->currentRow >= $this->startRow) &&
(!$this->cellCollection->has($columnAddress . $this->currentRow))
);
}
/**
* Indicate if more rows exist in the worksheet range of rows that we're iterating.
*
* @return bool
*/
public function valid()
public function valid(): bool
{
return $this->currentRow <= $this->endRow && $this->currentRow >= $this->startRow;
}
@@ -175,14 +183,15 @@ class ColumnCellIterator extends CellIterator
protected function adjustForExistingOnlyRange(): void
{
if ($this->onlyExistingCells) {
$columnAddress = Coordinate::stringFromColumnIndex($this->columnIndex);
while (
(!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->startRow)) &&
(!$this->cellCollection->has($columnAddress . $this->startRow)) &&
($this->startRow <= $this->endRow)
) {
++$this->startRow;
}
while (
(!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->endRow)) &&
(!$this->cellCollection->has($columnAddress . $this->endRow)) &&
($this->endRow >= $this->startRow)
) {
--$this->endRow;

View File

@@ -2,6 +2,9 @@
namespace PhpOffice\PhpSpreadsheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Helper\Dimension as CssDimension;
class ColumnDimension extends Dimension
{
/**
@@ -30,12 +33,12 @@ class ColumnDimension extends Dimension
/**
* Create a new ColumnDimension.
*
* @param string $pIndex Character column index
* @param string $index Character column index
*/
public function __construct($pIndex = 'A')
public function __construct($index = 'A')
{
// Initialise values
$this->columnIndex = $pIndex;
$this->columnIndex = $index;
// set dimension as unformatted by default
parent::__construct(0);
@@ -43,24 +46,36 @@ class ColumnDimension extends Dimension
/**
* Get column index as string eg: 'A'.
*
* @return string
*/
public function getColumnIndex()
public function getColumnIndex(): string
{
return $this->columnIndex;
}
/**
* Set column index as string eg: 'A'.
*
* @param string $pValue
*
* @return $this
*/
public function setColumnIndex($pValue)
public function setColumnIndex(string $index): self
{
$this->columnIndex = $pValue;
$this->columnIndex = $index;
return $this;
}
/**
* Get column index as numeric.
*/
public function getColumnNumeric(): int
{
return Coordinate::columnIndexFromString($this->columnIndex);
}
/**
* Set column index as numeric.
*/
public function setColumnNumeric(int $index): self
{
$this->columnIndex = Coordinate::stringFromColumnIndex($index);
return $this;
}
@@ -68,33 +83,42 @@ class ColumnDimension extends Dimension
/**
* Get Width.
*
* @return float
* Each unit of column width is equal to the width of one character in the default font size. A value of -1
* tells Excel to display this column in its default width.
* By default, this will be the return value; but this method also accepts an optional unit of measure argument
* and will convert the returned value to the specified UoM..
*/
public function getWidth()
public function getWidth(?string $unitOfMeasure = null): float
{
return $this->width;
return ($unitOfMeasure === null || $this->width < 0)
? $this->width
: (new CssDimension((string) $this->width))->toUnit($unitOfMeasure);
}
/**
* Set Width.
*
* @param float $pValue
* Each unit of column width is equal to the width of one character in the default font size. A value of -1
* tells Excel to display this column in its default width.
* By default, this will be the unit of measure for the passed value; but this method also accepts an
* optional unit of measure argument, and will convert the value from the specified UoM using an
* approximation method.
*
* @return $this
*/
public function setWidth($pValue)
public function setWidth(float $width, ?string $unitOfMeasure = null)
{
$this->width = $pValue;
$this->width = ($unitOfMeasure === null || $width < 0)
? $width
: (new CssDimension("{$width}{$unitOfMeasure}"))->width();
return $this;
}
/**
* Get Auto Size.
*
* @return bool
*/
public function getAutoSize()
public function getAutoSize(): bool
{
return $this->autoSize;
}
@@ -102,13 +126,11 @@ class ColumnDimension extends Dimension
/**
* Set Auto Size.
*
* @param bool $pValue
*
* @return $this
*/
public function setAutoSize($pValue)
public function setAutoSize(bool $autosizeEnabled)
{
$this->autoSize = $pValue;
$this->autoSize = $autosizeEnabled;
return $this;
}

View File

@@ -2,12 +2,15 @@
namespace PhpOffice\PhpSpreadsheet\Worksheet;
use Iterator;
use Iterator as NativeIterator;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
class ColumnIterator implements Iterator
/**
* @implements NativeIterator<string, Column>
*/
class ColumnIterator implements NativeIterator
{
/**
* Worksheet to iterate.
@@ -57,6 +60,7 @@ class ColumnIterator implements Iterator
*/
public function __destruct()
{
// @phpstan-ignore-next-line
$this->worksheet = null;
}
@@ -67,11 +71,13 @@ class ColumnIterator implements Iterator
*
* @return $this
*/
public function resetStart($startColumn = 'A')
public function resetStart(string $startColumn = 'A')
{
$startColumnIndex = Coordinate::columnIndexFromString($startColumn);
if ($startColumnIndex > Coordinate::columnIndexFromString($this->worksheet->getHighestColumn())) {
throw new Exception("Start column ({$startColumn}) is beyond highest column ({$this->worksheet->getHighestColumn()})");
throw new Exception(
"Start column ({$startColumn}) is beyond highest column ({$this->worksheet->getHighestColumn()})"
);
}
$this->startColumnIndex = $startColumnIndex;
@@ -92,7 +98,7 @@ class ColumnIterator implements Iterator
*/
public function resetEnd($endColumn = null)
{
$endColumn = $endColumn ? $endColumn : $this->worksheet->getHighestColumn();
$endColumn = $endColumn ?: $this->worksheet->getHighestColumn();
$this->endColumnIndex = Coordinate::columnIndexFromString($endColumn);
return $this;
@@ -105,11 +111,13 @@ class ColumnIterator implements Iterator
*
* @return $this
*/
public function seek($column = 'A')
public function seek(string $column = 'A')
{
$column = Coordinate::columnIndexFromString($column);
if (($column < $this->startColumnIndex) || ($column > $this->endColumnIndex)) {
throw new PhpSpreadsheetException("Column $column is out of range ({$this->startColumnIndex} - {$this->endColumnIndex})");
throw new PhpSpreadsheetException(
"Column $column is out of range ({$this->startColumnIndex} - {$this->endColumnIndex})"
);
}
$this->currentColumnIndex = $column;
@@ -126,20 +134,16 @@ class ColumnIterator implements Iterator
/**
* Return the current column in this worksheet.
*
* @return Column
*/
public function current()
public function current(): Column
{
return new Column($this->worksheet, Coordinate::stringFromColumnIndex($this->currentColumnIndex));
}
/**
* Return the current iterator key.
*
* @return string
*/
public function key()
public function key(): string
{
return Coordinate::stringFromColumnIndex($this->currentColumnIndex);
}
@@ -162,10 +166,8 @@ class ColumnIterator implements Iterator
/**
* Indicate if more columns exist in the worksheet range of columns that we're iterating.
*
* @return bool
*/
public function valid()
public function valid(): bool
{
return $this->currentColumnIndex <= $this->endColumnIndex && $this->currentColumnIndex >= $this->startColumnIndex;
}

View File

@@ -47,10 +47,8 @@ abstract class Dimension
/**
* Get Visible.
*
* @return bool
*/
public function getVisible()
public function getVisible(): bool
{
return $this->visible;
}
@@ -58,23 +56,19 @@ abstract class Dimension
/**
* Set Visible.
*
* @param bool $pValue
*
* @return $this
*/
public function setVisible($pValue)
public function setVisible(bool $visible)
{
$this->visible = (bool) $pValue;
$this->visible = $visible;
return $this;
}
/**
* Get Outline Level.
*
* @return int
*/
public function getOutlineLevel()
public function getOutlineLevel(): int
{
return $this->outlineLevel;
}
@@ -83,27 +77,23 @@ abstract class Dimension
* Set Outline Level.
* Value must be between 0 and 7.
*
* @param int $pValue
*
* @return $this
*/
public function setOutlineLevel($pValue)
public function setOutlineLevel(int $level)
{
if ($pValue < 0 || $pValue > 7) {
if ($level < 0 || $level > 7) {
throw new PhpSpreadsheetException('Outline level must range between 0 and 7.');
}
$this->outlineLevel = $pValue;
$this->outlineLevel = $level;
return $this;
}
/**
* Get Collapsed.
*
* @return bool
*/
public function getCollapsed()
public function getCollapsed(): bool
{
return $this->collapsed;
}
@@ -111,13 +101,11 @@ abstract class Dimension
/**
* Set Collapsed.
*
* @param bool $pValue
*
* @return $this
*/
public function setCollapsed($pValue)
public function setCollapsed(bool $collapsed)
{
$this->collapsed = (bool) $pValue;
$this->collapsed = $collapsed;
return $this;
}
@@ -127,7 +115,7 @@ abstract class Dimension
*
* @return int
*/
public function getXfIndex()
public function getXfIndex(): ?int
{
return $this->xfIndex;
}
@@ -135,29 +123,12 @@ abstract class Dimension
/**
* Set index to cellXf.
*
* @param int $pValue
*
* @return $this
*/
public function setXfIndex($pValue)
public function setXfIndex(int $XfIndex)
{
$this->xfIndex = $pValue;
$this->xfIndex = $XfIndex;
return $this;
}
/**
* Implement PHP __clone to create a deep clone, not just a shallow copy.
*/
public function __clone()
{
$vars = get_object_vars($this);
foreach ($vars as $key => $value) {
if (is_object($value)) {
$this->$key = clone $value;
} else {
$this->$key = $value;
}
}
}
}

View File

@@ -3,9 +3,17 @@
namespace PhpOffice\PhpSpreadsheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
use ZipArchive;
class Drawing extends BaseDrawing
{
const IMAGE_TYPES_CONVERTION_MAP = [
IMAGETYPE_GIF => IMAGETYPE_PNG,
IMAGETYPE_JPEG => IMAGETYPE_JPEG,
IMAGETYPE_PNG => IMAGETYPE_PNG,
IMAGETYPE_BMP => IMAGETYPE_PNG,
];
/**
* Path.
*
@@ -13,6 +21,13 @@ class Drawing extends BaseDrawing
*/
private $path;
/**
* Whether or not we are dealing with a URL.
*
* @var bool
*/
private $isUrl;
/**
* Create a new Drawing.
*/
@@ -20,6 +35,7 @@ class Drawing extends BaseDrawing
{
// Initialise values
$this->path = '';
$this->isUrl = false;
// Initialize parent
parent::__construct();
@@ -37,15 +53,10 @@ class Drawing extends BaseDrawing
/**
* Get indexed filename (using image index).
*
* @return string
*/
public function getIndexedFilename()
public function getIndexedFilename(): string
{
$fileName = $this->getFilename();
$fileName = str_replace(' ', '_', $fileName);
return str_replace('.' . $this->getExtension(), '', $fileName) . $this->getImageIndex() . '.' . $this->getExtension();
return md5($this->path) . '.' . $this->getExtension();
}
/**
@@ -60,6 +71,20 @@ class Drawing extends BaseDrawing
return $exploded[count($exploded) - 1];
}
/**
* Get full filepath to store drawing in zip archive.
*
* @return string
*/
public function getMediaFilename()
{
if (!array_key_exists($this->type, self::IMAGE_TYPES_CONVERTION_MAP)) {
throw new PhpSpreadsheetException('Unsupported image type in comment background. Supported types: PNG, JPEG, BMP, GIF.');
}
return sprintf('image%d%s', $this->getImageIndex(), $this->getImageFileExtensionForSave());
}
/**
* Get Path.
*
@@ -73,31 +98,68 @@ class Drawing extends BaseDrawing
/**
* Set Path.
*
* @param string $pValue File path
* @param bool $pVerifyFile Verify file
* @param string $path File path
* @param bool $verifyFile Verify file
* @param ZipArchive $zip Zip archive instance
*
* @return $this
*/
public function setPath($pValue, $pVerifyFile = true)
public function setPath($path, $verifyFile = true, $zip = null)
{
if ($pVerifyFile) {
if (file_exists($pValue)) {
$this->path = $pValue;
if ($this->width == 0 && $this->height == 0) {
// Get width/height
[$this->width, $this->height] = getimagesize($pValue);
if ($verifyFile && preg_match('~^data:image/[a-z]+;base64,~', $path) !== 1) {
// Check if a URL has been passed. https://stackoverflow.com/a/2058596/1252979
if (filter_var($path, FILTER_VALIDATE_URL)) {
$this->path = $path;
// Implicit that it is a URL, rather store info than running check above on value in other places.
$this->isUrl = true;
$imageContents = file_get_contents($path);
$filePath = tempnam(sys_get_temp_dir(), 'Drawing');
if ($filePath) {
file_put_contents($filePath, $imageContents);
if (file_exists($filePath)) {
$this->setSizesAndType($filePath);
unlink($filePath);
}
}
} elseif (file_exists($path)) {
$this->path = $path;
$this->setSizesAndType($path);
} elseif ($zip instanceof ZipArchive) {
$zipPath = explode('#', $path)[1];
if ($zip->locateName($zipPath) !== false) {
$this->path = $path;
$this->setSizesAndType($path);
}
} else {
throw new PhpSpreadsheetException("File $pValue not found!");
throw new PhpSpreadsheetException("File $path not found!");
}
} else {
$this->path = $pValue;
$this->path = $path;
}
return $this;
}
/**
* Get isURL.
*/
public function getIsURL(): bool
{
return $this->isUrl;
}
/**
* Set isURL.
*
* @return $this
*/
public function setIsURL(bool $isUrl): self
{
$this->isUrl = $isUrl;
return $this;
}
/**
* Get hash code.
*
@@ -111,4 +173,42 @@ class Drawing extends BaseDrawing
__CLASS__
);
}
/**
* Get Image Type for Save.
*/
public function getImageTypeForSave(): int
{
if (!array_key_exists($this->type, self::IMAGE_TYPES_CONVERTION_MAP)) {
throw new PhpSpreadsheetException('Unsupported image type in comment background. Supported types: PNG, JPEG, BMP, GIF.');
}
return self::IMAGE_TYPES_CONVERTION_MAP[$this->type];
}
/**
* Get Image file extention for Save.
*/
public function getImageFileExtensionForSave(bool $includeDot = true): string
{
if (!array_key_exists($this->type, self::IMAGE_TYPES_CONVERTION_MAP)) {
throw new PhpSpreadsheetException('Unsupported image type in comment background. Supported types: PNG, JPEG, BMP, GIF.');
}
$result = image_type_to_extension(self::IMAGE_TYPES_CONVERTION_MAP[$this->type], $includeDot);
return "$result";
}
/**
* Get Image mime type.
*/
public function getImageMimeType(): string
{
if (!array_key_exists($this->type, self::IMAGE_TYPES_CONVERTION_MAP)) {
throw new PhpSpreadsheetException('Unsupported image type in comment background. Supported types: PNG, JPEG, BMP, GIF.');
}
return image_type_to_mime_type(self::IMAGE_TYPES_CONVERTION_MAP[$this->type]);
}
}

View File

@@ -52,7 +52,7 @@ class Shadow implements IComparable
/**
* Shadow alignment.
*
* @var int
* @var string
*/
private $alignment;
@@ -98,13 +98,13 @@ class Shadow implements IComparable
/**
* Set Visible.
*
* @param bool $pValue
* @param bool $visible
*
* @return $this
*/
public function setVisible($pValue)
public function setVisible($visible)
{
$this->visible = $pValue;
$this->visible = $visible;
return $this;
}
@@ -122,13 +122,13 @@ class Shadow implements IComparable
/**
* Set Blur radius.
*
* @param int $pValue
* @param int $blurRadius
*
* @return $this
*/
public function setBlurRadius($pValue)
public function setBlurRadius($blurRadius)
{
$this->blurRadius = $pValue;
$this->blurRadius = $blurRadius;
return $this;
}
@@ -146,13 +146,13 @@ class Shadow implements IComparable
/**
* Set Shadow distance.
*
* @param int $pValue
* @param int $distance
*
* @return $this
*/
public function setDistance($pValue)
public function setDistance($distance)
{
$this->distance = $pValue;
$this->distance = $distance;
return $this;
}
@@ -170,13 +170,13 @@ class Shadow implements IComparable
/**
* Set Shadow direction (in degrees).
*
* @param int $pValue
* @param int $direction
*
* @return $this
*/
public function setDirection($pValue)
public function setDirection($direction)
{
$this->direction = $pValue;
$this->direction = $direction;
return $this;
}
@@ -184,7 +184,7 @@ class Shadow implements IComparable
/**
* Get Shadow alignment.
*
* @return int
* @return string
*/
public function getAlignment()
{
@@ -194,13 +194,13 @@ class Shadow implements IComparable
/**
* Set Shadow alignment.
*
* @param int $pValue
* @param string $alignment
*
* @return $this
*/
public function setAlignment($pValue)
public function setAlignment($alignment)
{
$this->alignment = $pValue;
$this->alignment = $alignment;
return $this;
}
@@ -218,13 +218,11 @@ class Shadow implements IComparable
/**
* Set Color.
*
* @param Color $pValue
*
* @return $this
*/
public function setColor(?Color $pValue = null)
public function setColor(?Color $color = null)
{
$this->color = $pValue;
$this->color = $color;
return $this;
}
@@ -242,13 +240,13 @@ class Shadow implements IComparable
/**
* Set Alpha.
*
* @param int $pValue
* @param int $alpha
*
* @return $this
*/
public function setAlpha($pValue)
public function setAlpha($alpha)
{
$this->alpha = $pValue;
$this->alpha = $alpha;
return $this;
}

View File

@@ -170,13 +170,13 @@ class HeaderFooter
/**
* Set OddHeader.
*
* @param string $pValue
* @param string $oddHeader
*
* @return $this
*/
public function setOddHeader($pValue)
public function setOddHeader($oddHeader)
{
$this->oddHeader = $pValue;
$this->oddHeader = $oddHeader;
return $this;
}
@@ -194,13 +194,13 @@ class HeaderFooter
/**
* Set OddFooter.
*
* @param string $pValue
* @param string $oddFooter
*
* @return $this
*/
public function setOddFooter($pValue)
public function setOddFooter($oddFooter)
{
$this->oddFooter = $pValue;
$this->oddFooter = $oddFooter;
return $this;
}
@@ -218,13 +218,13 @@ class HeaderFooter
/**
* Set EvenHeader.
*
* @param string $pValue
* @param string $eventHeader
*
* @return $this
*/
public function setEvenHeader($pValue)
public function setEvenHeader($eventHeader)
{
$this->evenHeader = $pValue;
$this->evenHeader = $eventHeader;
return $this;
}
@@ -242,13 +242,13 @@ class HeaderFooter
/**
* Set EvenFooter.
*
* @param string $pValue
* @param string $evenFooter
*
* @return $this
*/
public function setEvenFooter($pValue)
public function setEvenFooter($evenFooter)
{
$this->evenFooter = $pValue;
$this->evenFooter = $evenFooter;
return $this;
}
@@ -266,13 +266,13 @@ class HeaderFooter
/**
* Set FirstHeader.
*
* @param string $pValue
* @param string $firstHeader
*
* @return $this
*/
public function setFirstHeader($pValue)
public function setFirstHeader($firstHeader)
{
$this->firstHeader = $pValue;
$this->firstHeader = $firstHeader;
return $this;
}
@@ -290,13 +290,13 @@ class HeaderFooter
/**
* Set FirstFooter.
*
* @param string $pValue
* @param string $firstFooter
*
* @return $this
*/
public function setFirstFooter($pValue)
public function setFirstFooter($firstFooter)
{
$this->firstFooter = $pValue;
$this->firstFooter = $firstFooter;
return $this;
}
@@ -314,13 +314,13 @@ class HeaderFooter
/**
* Set DifferentOddEven.
*
* @param bool $pValue
* @param bool $differentOddEvent
*
* @return $this
*/
public function setDifferentOddEven($pValue)
public function setDifferentOddEven($differentOddEvent)
{
$this->differentOddEven = $pValue;
$this->differentOddEven = $differentOddEvent;
return $this;
}
@@ -338,13 +338,13 @@ class HeaderFooter
/**
* Set DifferentFirst.
*
* @param bool $pValue
* @param bool $differentFirst
*
* @return $this
*/
public function setDifferentFirst($pValue)
public function setDifferentFirst($differentFirst)
{
$this->differentFirst = $pValue;
$this->differentFirst = $differentFirst;
return $this;
}
@@ -362,13 +362,13 @@ class HeaderFooter
/**
* Set ScaleWithDocument.
*
* @param bool $pValue
* @param bool $scaleWithDocument
*
* @return $this
*/
public function setScaleWithDocument($pValue)
public function setScaleWithDocument($scaleWithDocument)
{
$this->scaleWithDocument = $pValue;
$this->scaleWithDocument = $scaleWithDocument;
return $this;
}
@@ -386,13 +386,13 @@ class HeaderFooter
/**
* Set AlignWithMargins.
*
* @param bool $pValue
* @param bool $alignWithMargins
*
* @return $this
*/
public function setAlignWithMargins($pValue)
public function setAlignWithMargins($alignWithMargins)
{
$this->alignWithMargins = $pValue;
$this->alignWithMargins = $alignWithMargins;
return $this;
}

View File

@@ -4,6 +4,9 @@ namespace PhpOffice\PhpSpreadsheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
/**
* @implements \Iterator<int, Worksheet>
*/
class Iterator implements \Iterator
{
/**
@@ -29,14 +32,6 @@ class Iterator implements \Iterator
$this->subject = $subject;
}
/**
* Destructor.
*/
public function __destruct()
{
$this->subject = null;
}
/**
* Rewind iterator.
*/
@@ -47,20 +42,16 @@ class Iterator implements \Iterator
/**
* Current Worksheet.
*
* @return Worksheet
*/
public function current()
public function current(): Worksheet
{
return $this->subject->getSheet($this->position);
}
/**
* Current key.
*
* @return int
*/
public function key()
public function key(): int
{
return $this->position;
}
@@ -75,10 +66,8 @@ class Iterator implements \Iterator
/**
* Are there more Worksheet instances available?
*
* @return bool
*/
public function valid()
public function valid(): bool
{
return $this->position < $this->subject->getSheetCount() && $this->position >= 0;
}

View File

@@ -3,6 +3,8 @@
namespace PhpOffice\PhpSpreadsheet\Worksheet;
use GdImage;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Shared\File;
class MemoryDrawing extends BaseDrawing
{
@@ -18,10 +20,16 @@ class MemoryDrawing extends BaseDrawing
const MIMETYPE_GIF = 'image/gif';
const MIMETYPE_JPEG = 'image/jpeg';
const SUPPORTED_MIME_TYPES = [
self::MIMETYPE_GIF,
self::MIMETYPE_JPEG,
self::MIMETYPE_PNG,
];
/**
* Image resource.
*
* @var GdImage|resource
* @var null|GdImage|resource
*/
private $imageResource;
@@ -46,25 +54,204 @@ class MemoryDrawing extends BaseDrawing
*/
private $uniqueName;
/** @var null|resource */
private $alwaysNull;
/**
* Create a new MemoryDrawing.
*/
public function __construct()
{
// Initialise values
$this->imageResource = null;
$this->renderingFunction = self::RENDERING_DEFAULT;
$this->mimeType = self::MIMETYPE_DEFAULT;
$this->uniqueName = md5(mt_rand(0, 9999) . time() . mt_rand(0, 9999));
$this->alwaysNull = null;
// Initialize parent
parent::__construct();
}
public function __destruct()
{
if ($this->imageResource) {
$rslt = @imagedestroy($this->imageResource);
// "Fix" for Scrutinizer
$this->imageResource = $rslt ? null : $this->alwaysNull;
}
}
public function __clone()
{
parent::__clone();
$this->cloneResource();
}
private function cloneResource(): void
{
if (!$this->imageResource) {
return;
}
$width = (int) imagesx($this->imageResource);
$height = (int) imagesy($this->imageResource);
if (imageistruecolor($this->imageResource)) {
$clone = imagecreatetruecolor($width, $height);
if (!$clone) {
throw new Exception('Could not clone image resource');
}
imagealphablending($clone, false);
imagesavealpha($clone, true);
} else {
$clone = imagecreate($width, $height);
if (!$clone) {
throw new Exception('Could not clone image resource');
}
// If the image has transparency...
$transparent = imagecolortransparent($this->imageResource);
if ($transparent >= 0) {
$rgb = imagecolorsforindex($this->imageResource, $transparent);
if (empty($rgb)) {
throw new Exception('Could not get image colors');
}
imagesavealpha($clone, true);
$color = imagecolorallocatealpha($clone, $rgb['red'], $rgb['green'], $rgb['blue'], $rgb['alpha']);
if ($color === false) {
throw new Exception('Could not get image alpha color');
}
imagefill($clone, 0, 0, $color);
}
}
//Create the Clone!!
imagecopy($clone, $this->imageResource, 0, 0, 0, 0, $width, $height);
$this->imageResource = $clone;
}
/**
* @param resource $imageStream Stream data to be converted to a Memory Drawing
*
* @throws Exception
*/
public static function fromStream($imageStream): self
{
$streamValue = stream_get_contents($imageStream);
if ($streamValue === false) {
throw new Exception('Unable to read data from stream');
}
return self::fromString($streamValue);
}
/**
* @param string $imageString String data to be converted to a Memory Drawing
*
* @throws Exception
*/
public static function fromString(string $imageString): self
{
$gdImage = @imagecreatefromstring($imageString);
if ($gdImage === false) {
throw new Exception('Value cannot be converted to an image');
}
$mimeType = self::identifyMimeType($imageString);
$renderingFunction = self::identifyRenderingFunction($mimeType);
$drawing = new self();
$drawing->setImageResource($gdImage);
$drawing->setRenderingFunction($renderingFunction);
$drawing->setMimeType($mimeType);
return $drawing;
}
private static function identifyRenderingFunction(string $mimeType): string
{
switch ($mimeType) {
case self::MIMETYPE_PNG:
return self::RENDERING_PNG;
case self::MIMETYPE_JPEG:
return self::RENDERING_JPEG;
case self::MIMETYPE_GIF:
return self::RENDERING_GIF;
}
return self::RENDERING_DEFAULT;
}
/**
* @throws Exception
*/
private static function identifyMimeType(string $imageString): string
{
$temporaryFileName = File::temporaryFilename();
file_put_contents($temporaryFileName, $imageString);
$mimeType = self::identifyMimeTypeUsingExif($temporaryFileName);
if ($mimeType !== null) {
unlink($temporaryFileName);
return $mimeType;
}
$mimeType = self::identifyMimeTypeUsingGd($temporaryFileName);
if ($mimeType !== null) {
unlink($temporaryFileName);
return $mimeType;
}
unlink($temporaryFileName);
return self::MIMETYPE_DEFAULT;
}
private static function identifyMimeTypeUsingExif(string $temporaryFileName): ?string
{
if (function_exists('exif_imagetype')) {
$imageType = @exif_imagetype($temporaryFileName);
$mimeType = ($imageType) ? image_type_to_mime_type($imageType) : null;
return self::supportedMimeTypes($mimeType);
}
return null;
}
private static function identifyMimeTypeUsingGd(string $temporaryFileName): ?string
{
if (function_exists('getimagesize')) {
$imageSize = @getimagesize($temporaryFileName);
if (is_array($imageSize)) {
$mimeType = $imageSize['mime'] ?? null;
return self::supportedMimeTypes($mimeType);
}
}
return null;
}
private static function supportedMimeTypes(?string $mimeType = null): ?string
{
if (in_array($mimeType, self::SUPPORTED_MIME_TYPES, true)) {
return $mimeType;
}
return null;
}
/**
* Get image resource.
*
* @return GdImage|resource
* @return null|GdImage|resource
*/
public function getImageResource()
{
@@ -84,8 +271,8 @@ class MemoryDrawing extends BaseDrawing
if ($this->imageResource !== null) {
// Get width/height
$this->width = imagesx($this->imageResource);
$this->height = imagesy($this->imageResource);
$this->width = (int) imagesx($this->imageResource);
$this->height = (int) imagesy($this->imageResource);
}
return $this;
@@ -141,10 +328,8 @@ class MemoryDrawing extends BaseDrawing
/**
* Get indexed filename (using image index).
*
* @return string
*/
public function getIndexedFilename()
public function getIndexedFilename(): string
{
$extension = strtolower($this->getMimeType());
$extension = explode('/', $extension);

View File

@@ -66,13 +66,13 @@ class PageMargins
/**
* Set Left.
*
* @param float $pValue
* @param float $left
*
* @return $this
*/
public function setLeft($pValue)
public function setLeft($left)
{
$this->left = $pValue;
$this->left = $left;
return $this;
}
@@ -90,13 +90,13 @@ class PageMargins
/**
* Set Right.
*
* @param float $pValue
* @param float $right
*
* @return $this
*/
public function setRight($pValue)
public function setRight($right)
{
$this->right = $pValue;
$this->right = $right;
return $this;
}
@@ -114,13 +114,13 @@ class PageMargins
/**
* Set Top.
*
* @param float $pValue
* @param float $top
*
* @return $this
*/
public function setTop($pValue)
public function setTop($top)
{
$this->top = $pValue;
$this->top = $top;
return $this;
}
@@ -138,13 +138,13 @@ class PageMargins
/**
* Set Bottom.
*
* @param float $pValue
* @param float $bottom
*
* @return $this
*/
public function setBottom($pValue)
public function setBottom($bottom)
{
$this->bottom = $pValue;
$this->bottom = $bottom;
return $this;
}
@@ -162,13 +162,13 @@ class PageMargins
/**
* Set Header.
*
* @param float $pValue
* @param float $header
*
* @return $this
*/
public function setHeader($pValue)
public function setHeader($header)
{
$this->header = $pValue;
$this->header = $header;
return $this;
}
@@ -186,13 +186,13 @@ class PageMargins
/**
* Set Footer.
*
* @param float $pValue
* @param float $footer
*
* @return $this
*/
public function setFooter($pValue)
public function setFooter($footer)
{
$this->footer = $pValue;
$this->footer = $footer;
return $this;
}

View File

@@ -160,18 +160,32 @@ class PageSetup
const PAGEORDER_DOWN_THEN_OVER = 'downThenOver';
/**
* Paper size.
* Paper size default.
*
* @var int
*/
private $paperSize = self::PAPERSIZE_LETTER;
private static $paperSizeDefault = self::PAPERSIZE_LETTER;
/**
* Paper size.
*
* @var ?int
*/
private $paperSize;
/**
* Orientation default.
*
* @var string
*/
private static $orientationDefault = self::ORIENTATION_DEFAULT;
/**
* Orientation.
*
* @var string
*/
private $orientation = self::ORIENTATION_DEFAULT;
private $orientation;
/**
* Scale (Print Scale).
@@ -238,17 +252,18 @@ class PageSetup
/**
* Print area.
*
* @var string
* @var null|string
*/
private $printArea;
/**
* First page number.
*
* @var int
* @var ?int
*/
private $firstPageNumber;
/** @var string */
private $pageOrder = self::PAGEORDER_DOWN_THEN_OVER;
/**
@@ -256,6 +271,7 @@ class PageSetup
*/
public function __construct()
{
$this->orientation = self::$orientationDefault;
}
/**
@@ -265,23 +281,39 @@ class PageSetup
*/
public function getPaperSize()
{
return $this->paperSize;
return $this->paperSize ?? self::$paperSizeDefault;
}
/**
* Set Paper Size.
*
* @param int $pValue see self::PAPERSIZE_*
* @param int $paperSize see self::PAPERSIZE_*
*
* @return $this
*/
public function setPaperSize($pValue)
public function setPaperSize($paperSize)
{
$this->paperSize = $pValue;
$this->paperSize = $paperSize;
return $this;
}
/**
* Get Paper Size default.
*/
public static function getPaperSizeDefault(): int
{
return self::$paperSizeDefault;
}
/**
* Set Paper Size Default.
*/
public static function setPaperSizeDefault(int $paperSize): void
{
self::$paperSizeDefault = $paperSize;
}
/**
* Get Orientation.
*
@@ -295,17 +327,31 @@ class PageSetup
/**
* Set Orientation.
*
* @param string $pValue see self::ORIENTATION_*
* @param string $orientation see self::ORIENTATION_*
*
* @return $this
*/
public function setOrientation($pValue)
public function setOrientation($orientation)
{
$this->orientation = $pValue;
if ($orientation === self::ORIENTATION_LANDSCAPE || $orientation === self::ORIENTATION_PORTRAIT || $orientation === self::ORIENTATION_DEFAULT) {
$this->orientation = $orientation;
}
return $this;
}
public static function getOrientationDefault(): string
{
return self::$orientationDefault;
}
public static function setOrientationDefault(string $orientation): void
{
if ($orientation === self::ORIENTATION_LANDSCAPE || $orientation === self::ORIENTATION_PORTRAIT || $orientation === self::ORIENTATION_DEFAULT) {
self::$orientationDefault = $orientation;
}
}
/**
* Get Scale.
*
@@ -321,18 +367,18 @@ class PageSetup
* Print scaling. Valid values range from 10 to 400
* This setting is overridden when fitToWidth and/or fitToHeight are in use.
*
* @param null|int $pValue
* @param bool $pUpdate Update fitToPage so scaling applies rather than fitToHeight / fitToWidth
* @param null|int $scale
* @param bool $update Update fitToPage so scaling applies rather than fitToHeight / fitToWidth
*
* @return $this
*/
public function setScale($pValue, $pUpdate = true)
public function setScale($scale, $update = true)
{
// Microsoft Office Excel 2007 only allows setting a scale between 10 and 400 via the user interface,
// but it is apparently still able to handle any scale >= 0, where 0 results in 100
if (($pValue >= 0) || $pValue === null) {
$this->scale = $pValue;
if ($pUpdate) {
if ($scale === null || $scale >= 0) {
$this->scale = $scale;
if ($update) {
$this->fitToPage = false;
}
} else {
@@ -355,13 +401,13 @@ class PageSetup
/**
* Set Fit To Page.
*
* @param bool $pValue
* @param bool $fitToPage
*
* @return $this
*/
public function setFitToPage($pValue)
public function setFitToPage($fitToPage)
{
$this->fitToPage = $pValue;
$this->fitToPage = $fitToPage;
return $this;
}
@@ -379,15 +425,15 @@ class PageSetup
/**
* Set Fit To Height.
*
* @param null|int $pValue
* @param bool $pUpdate Update fitToPage so it applies rather than scaling
* @param null|int $fitToHeight
* @param bool $update Update fitToPage so it applies rather than scaling
*
* @return $this
*/
public function setFitToHeight($pValue, $pUpdate = true)
public function setFitToHeight($fitToHeight, $update = true)
{
$this->fitToHeight = $pValue;
if ($pUpdate) {
$this->fitToHeight = $fitToHeight;
if ($update) {
$this->fitToPage = true;
}
@@ -407,15 +453,15 @@ class PageSetup
/**
* Set Fit To Width.
*
* @param null|int $pValue
* @param bool $pUpdate Update fitToPage so it applies rather than scaling
* @param null|int $value
* @param bool $update Update fitToPage so it applies rather than scaling
*
* @return $this
*/
public function setFitToWidth($pValue, $pUpdate = true)
public function setFitToWidth($value, $update = true)
{
$this->fitToWidth = $pValue;
if ($pUpdate) {
$this->fitToWidth = $value;
if ($update) {
$this->fitToPage = true;
}
@@ -429,7 +475,7 @@ class PageSetup
*/
public function isColumnsToRepeatAtLeftSet()
{
if (is_array($this->columnsToRepeatAtLeft)) {
if (!empty($this->columnsToRepeatAtLeft)) {
if ($this->columnsToRepeatAtLeft[0] != '' && $this->columnsToRepeatAtLeft[1] != '') {
return true;
}
@@ -451,13 +497,13 @@ class PageSetup
/**
* Set Columns to repeat at left.
*
* @param array $pValue Containing start column and end column, empty array if option unset
* @param array $columnsToRepeatAtLeft Containing start column and end column, empty array if option unset
*
* @return $this
*/
public function setColumnsToRepeatAtLeft(array $pValue)
public function setColumnsToRepeatAtLeft(array $columnsToRepeatAtLeft)
{
$this->columnsToRepeatAtLeft = $pValue;
$this->columnsToRepeatAtLeft = $columnsToRepeatAtLeft;
return $this;
}
@@ -465,14 +511,14 @@ class PageSetup
/**
* Set Columns to repeat at left by start and end.
*
* @param string $pStart eg: 'A'
* @param string $pEnd eg: 'B'
* @param string $start eg: 'A'
* @param string $end eg: 'B'
*
* @return $this
*/
public function setColumnsToRepeatAtLeftByStartAndEnd($pStart, $pEnd)
public function setColumnsToRepeatAtLeftByStartAndEnd($start, $end)
{
$this->columnsToRepeatAtLeft = [$pStart, $pEnd];
$this->columnsToRepeatAtLeft = [$start, $end];
return $this;
}
@@ -484,7 +530,7 @@ class PageSetup
*/
public function isRowsToRepeatAtTopSet()
{
if (is_array($this->rowsToRepeatAtTop)) {
if (!empty($this->rowsToRepeatAtTop)) {
if ($this->rowsToRepeatAtTop[0] != 0 && $this->rowsToRepeatAtTop[1] != 0) {
return true;
}
@@ -506,13 +552,13 @@ class PageSetup
/**
* Set Rows to repeat at top.
*
* @param array $pValue Containing start column and end column, empty array if option unset
* @param array $rowsToRepeatAtTop Containing start column and end column, empty array if option unset
*
* @return $this
*/
public function setRowsToRepeatAtTop(array $pValue)
public function setRowsToRepeatAtTop(array $rowsToRepeatAtTop)
{
$this->rowsToRepeatAtTop = $pValue;
$this->rowsToRepeatAtTop = $rowsToRepeatAtTop;
return $this;
}
@@ -520,14 +566,14 @@ class PageSetup
/**
* Set Rows to repeat at top by start and end.
*
* @param int $pStart eg: 1
* @param int $pEnd eg: 1
* @param int $start eg: 1
* @param int $end eg: 1
*
* @return $this
*/
public function setRowsToRepeatAtTopByStartAndEnd($pStart, $pEnd)
public function setRowsToRepeatAtTopByStartAndEnd($start, $end)
{
$this->rowsToRepeatAtTop = [$pStart, $pEnd];
$this->rowsToRepeatAtTop = [$start, $end];
return $this;
}
@@ -595,7 +641,7 @@ class PageSetup
if ($index == 0) {
return $this->printArea;
}
$printAreas = explode(',', $this->printArea);
$printAreas = explode(',', (string) $this->printArea);
if (isset($printAreas[$index - 1])) {
return $printAreas[$index - 1];
}
@@ -618,7 +664,7 @@ class PageSetup
if ($index == 0) {
return $this->printArea !== null;
}
$printAreas = explode(',', $this->printArea);
$printAreas = explode(',', (string) $this->printArea);
return isset($printAreas[$index - 1]);
}
@@ -638,7 +684,7 @@ class PageSetup
if ($index == 0) {
$this->printArea = null;
} else {
$printAreas = explode(',', $this->printArea);
$printAreas = explode(',', (string) $this->printArea);
if (isset($printAreas[$index - 1])) {
unset($printAreas[$index - 1]);
$this->printArea = implode(',', $printAreas);
@@ -686,7 +732,7 @@ class PageSetup
if ($index == 0) {
$this->printArea = $value;
} else {
$printAreas = explode(',', $this->printArea);
$printAreas = explode(',', (string) $this->printArea);
if ($index < 0) {
$index = count($printAreas) - abs($index) + 1;
}
@@ -700,9 +746,9 @@ class PageSetup
if ($index == 0) {
$this->printArea = $this->printArea ? ($this->printArea . ',' . $value) : $value;
} else {
$printAreas = explode(',', $this->printArea);
$printAreas = explode(',', (string) $this->printArea);
if ($index < 0) {
$index = abs($index) - 1;
$index = (int) abs($index) - 1;
}
if ($index > count($printAreas)) {
throw new PhpSpreadsheetException('Invalid index for setting print range.');
@@ -795,7 +841,7 @@ class PageSetup
/**
* Get first page number.
*
* @return int
* @return ?int
*/
public function getFirstPageNumber()
{
@@ -805,7 +851,7 @@ class PageSetup
/**
* Set first page number.
*
* @param int $value
* @param ?int $value
*
* @return $this
*/

View File

@@ -18,116 +18,116 @@ class Protection
const ALGORITHM_WHIRLPOOL = 'WHIRLPOOL';
/**
* Sheet.
* Autofilters are locked when sheet is protected, default true.
*
* @var bool
* @var ?bool
*/
private $sheet = false;
private $autoFilter;
/**
* Objects.
* Deleting columns is locked when sheet is protected, default true.
*
* @var bool
* @var ?bool
*/
private $objects = false;
private $deleteColumns;
/**
* Scenarios.
* Deleting rows is locked when sheet is protected, default true.
*
* @var bool
* @var ?bool
*/
private $scenarios = false;
private $deleteRows;
/**
* Format cells.
* Formatting cells is locked when sheet is protected, default true.
*
* @var bool
* @var ?bool
*/
private $formatCells = false;
private $formatCells;
/**
* Format columns.
* Formatting columns is locked when sheet is protected, default true.
*
* @var bool
* @var ?bool
*/
private $formatColumns = false;
private $formatColumns;
/**
* Format rows.
* Formatting rows is locked when sheet is protected, default true.
*
* @var bool
* @var ?bool
*/
private $formatRows = false;
private $formatRows;
/**
* Insert columns.
* Inserting columns is locked when sheet is protected, default true.
*
* @var bool
* @var ?bool
*/
private $insertColumns = false;
private $insertColumns;
/**
* Insert rows.
* Inserting hyperlinks is locked when sheet is protected, default true.
*
* @var bool
* @var ?bool
*/
private $insertRows = false;
private $insertHyperlinks;
/**
* Insert hyperlinks.
* Inserting rows is locked when sheet is protected, default true.
*
* @var bool
* @var ?bool
*/
private $insertHyperlinks = false;
private $insertRows;
/**
* Delete columns.
* Objects are locked when sheet is protected, default false.
*
* @var bool
* @var ?bool
*/
private $deleteColumns = false;
private $objects;
/**
* Delete rows.
* Pivot tables are locked when the sheet is protected, default true.
*
* @var bool
* @var ?bool
*/
private $deleteRows = false;
private $pivotTables;
/**
* Select locked cells.
* Scenarios are locked when sheet is protected, default false.
*
* @var bool
* @var ?bool
*/
private $selectLockedCells = false;
private $scenarios;
/**
* Sort.
* Selection of locked cells is locked when sheet is protected, default false.
*
* @var bool
* @var ?bool
*/
private $sort = false;
private $selectLockedCells;
/**
* AutoFilter.
* Selection of unlocked cells is locked when sheet is protected, default false.
*
* @var bool
* @var ?bool
*/
private $autoFilter = false;
private $selectUnlockedCells;
/**
* Pivot tables.
* Sheet is locked when sheet is protected, default false.
*
* @var bool
* @var ?bool
*/
private $pivotTables = false;
private $sheet;
/**
* Select unlocked cells.
* Sorting is locked when sheet is protected, default true.
*
* @var bool
* @var ?bool
*/
private $selectUnlockedCells = false;
private $sort;
/**
* Hashed password.
@@ -166,409 +166,217 @@ class Protection
/**
* Is some sort of protection enabled?
*
* @return bool
*/
public function isProtectionEnabled()
public function isProtectionEnabled(): bool
{
return $this->sheet ||
$this->objects ||
$this->scenarios ||
$this->formatCells ||
$this->formatColumns ||
$this->formatRows ||
$this->insertColumns ||
$this->insertRows ||
$this->insertHyperlinks ||
$this->deleteColumns ||
$this->deleteRows ||
$this->selectLockedCells ||
$this->sort ||
$this->autoFilter ||
$this->pivotTables ||
$this->selectUnlockedCells;
return
$this->password !== '' ||
isset($this->sheet) ||
isset($this->objects) ||
isset($this->scenarios) ||
isset($this->formatCells) ||
isset($this->formatColumns) ||
isset($this->formatRows) ||
isset($this->insertColumns) ||
isset($this->insertRows) ||
isset($this->insertHyperlinks) ||
isset($this->deleteColumns) ||
isset($this->deleteRows) ||
isset($this->selectLockedCells) ||
isset($this->sort) ||
isset($this->autoFilter) ||
isset($this->pivotTables) ||
isset($this->selectUnlockedCells);
}
/**
* Get Sheet.
*
* @return bool
*/
public function getSheet()
public function getSheet(): ?bool
{
return $this->sheet;
}
/**
* Set Sheet.
*
* @param bool $pValue
*
* @return $this
*/
public function setSheet($pValue)
public function setSheet(?bool $sheet): self
{
$this->sheet = $pValue;
$this->sheet = $sheet;
return $this;
}
/**
* Get Objects.
*
* @return bool
*/
public function getObjects()
public function getObjects(): ?bool
{
return $this->objects;
}
/**
* Set Objects.
*
* @param bool $pValue
*
* @return $this
*/
public function setObjects($pValue)
public function setObjects(?bool $objects): self
{
$this->objects = $pValue;
$this->objects = $objects;
return $this;
}
/**
* Get Scenarios.
*
* @return bool
*/
public function getScenarios()
public function getScenarios(): ?bool
{
return $this->scenarios;
}
/**
* Set Scenarios.
*
* @param bool $pValue
*
* @return $this
*/
public function setScenarios($pValue)
public function setScenarios(?bool $scenarios): self
{
$this->scenarios = $pValue;
$this->scenarios = $scenarios;
return $this;
}
/**
* Get FormatCells.
*
* @return bool
*/
public function getFormatCells()
public function getFormatCells(): ?bool
{
return $this->formatCells;
}
/**
* Set FormatCells.
*
* @param bool $pValue
*
* @return $this
*/
public function setFormatCells($pValue)
public function setFormatCells(?bool $formatCells): self
{
$this->formatCells = $pValue;
$this->formatCells = $formatCells;
return $this;
}
/**
* Get FormatColumns.
*
* @return bool
*/
public function getFormatColumns()
public function getFormatColumns(): ?bool
{
return $this->formatColumns;
}
/**
* Set FormatColumns.
*
* @param bool $pValue
*
* @return $this
*/
public function setFormatColumns($pValue)
public function setFormatColumns(?bool $formatColumns): self
{
$this->formatColumns = $pValue;
$this->formatColumns = $formatColumns;
return $this;
}
/**
* Get FormatRows.
*
* @return bool
*/
public function getFormatRows()
public function getFormatRows(): ?bool
{
return $this->formatRows;
}
/**
* Set FormatRows.
*
* @param bool $pValue
*
* @return $this
*/
public function setFormatRows($pValue)
public function setFormatRows(?bool $formatRows): self
{
$this->formatRows = $pValue;
$this->formatRows = $formatRows;
return $this;
}
/**
* Get InsertColumns.
*
* @return bool
*/
public function getInsertColumns()
public function getInsertColumns(): ?bool
{
return $this->insertColumns;
}
/**
* Set InsertColumns.
*
* @param bool $pValue
*
* @return $this
*/
public function setInsertColumns($pValue)
public function setInsertColumns(?bool $insertColumns): self
{
$this->insertColumns = $pValue;
$this->insertColumns = $insertColumns;
return $this;
}
/**
* Get InsertRows.
*
* @return bool
*/
public function getInsertRows()
public function getInsertRows(): ?bool
{
return $this->insertRows;
}
/**
* Set InsertRows.
*
* @param bool $pValue
*
* @return $this
*/
public function setInsertRows($pValue)
public function setInsertRows(?bool $insertRows): self
{
$this->insertRows = $pValue;
$this->insertRows = $insertRows;
return $this;
}
/**
* Get InsertHyperlinks.
*
* @return bool
*/
public function getInsertHyperlinks()
public function getInsertHyperlinks(): ?bool
{
return $this->insertHyperlinks;
}
/**
* Set InsertHyperlinks.
*
* @param bool $pValue
*
* @return $this
*/
public function setInsertHyperlinks($pValue)
public function setInsertHyperlinks(?bool $insertHyperLinks): self
{
$this->insertHyperlinks = $pValue;
$this->insertHyperlinks = $insertHyperLinks;
return $this;
}
/**
* Get DeleteColumns.
*
* @return bool
*/
public function getDeleteColumns()
public function getDeleteColumns(): ?bool
{
return $this->deleteColumns;
}
/**
* Set DeleteColumns.
*
* @param bool $pValue
*
* @return $this
*/
public function setDeleteColumns($pValue)
public function setDeleteColumns(?bool $deleteColumns): self
{
$this->deleteColumns = $pValue;
$this->deleteColumns = $deleteColumns;
return $this;
}
/**
* Get DeleteRows.
*
* @return bool
*/
public function getDeleteRows()
public function getDeleteRows(): ?bool
{
return $this->deleteRows;
}
/**
* Set DeleteRows.
*
* @param bool $pValue
*
* @return $this
*/
public function setDeleteRows($pValue)
public function setDeleteRows(?bool $deleteRows): self
{
$this->deleteRows = $pValue;
$this->deleteRows = $deleteRows;
return $this;
}
/**
* Get SelectLockedCells.
*
* @return bool
*/
public function getSelectLockedCells()
public function getSelectLockedCells(): ?bool
{
return $this->selectLockedCells;
}
/**
* Set SelectLockedCells.
*
* @param bool $pValue
*
* @return $this
*/
public function setSelectLockedCells($pValue)
public function setSelectLockedCells(?bool $selectLockedCells): self
{
$this->selectLockedCells = $pValue;
$this->selectLockedCells = $selectLockedCells;
return $this;
}
/**
* Get Sort.
*
* @return bool
*/
public function getSort()
public function getSort(): ?bool
{
return $this->sort;
}
/**
* Set Sort.
*
* @param bool $pValue
*
* @return $this
*/
public function setSort($pValue)
public function setSort(?bool $sort): self
{
$this->sort = $pValue;
$this->sort = $sort;
return $this;
}
/**
* Get AutoFilter.
*
* @return bool
*/
public function getAutoFilter()
public function getAutoFilter(): ?bool
{
return $this->autoFilter;
}
/**
* Set AutoFilter.
*
* @param bool $pValue
*
* @return $this
*/
public function setAutoFilter($pValue)
public function setAutoFilter(?bool $autoFilter): self
{
$this->autoFilter = $pValue;
$this->autoFilter = $autoFilter;
return $this;
}
/**
* Get PivotTables.
*
* @return bool
*/
public function getPivotTables()
public function getPivotTables(): ?bool
{
return $this->pivotTables;
}
/**
* Set PivotTables.
*
* @param bool $pValue
*
* @return $this
*/
public function setPivotTables($pValue)
public function setPivotTables(?bool $pivotTables): self
{
$this->pivotTables = $pValue;
$this->pivotTables = $pivotTables;
return $this;
}
/**
* Get SelectUnlockedCells.
*
* @return bool
*/
public function getSelectUnlockedCells()
public function getSelectUnlockedCells(): ?bool
{
return $this->selectUnlockedCells;
}
/**
* Set SelectUnlockedCells.
*
* @param bool $pValue
*
* @return $this
*/
public function setSelectUnlockedCells($pValue)
public function setSelectUnlockedCells(?bool $selectUnlockedCells): self
{
$this->selectUnlockedCells = $pValue;
$this->selectUnlockedCells = $selectUnlockedCells;
return $this;
}
@@ -586,24 +394,29 @@ class Protection
/**
* Set Password.
*
* @param string $pValue
* @param bool $pAlreadyHashed If the password has already been hashed, set this to true
* @param string $password
* @param bool $alreadyHashed If the password has already been hashed, set this to true
*
* @return $this
*/
public function setPassword($pValue, $pAlreadyHashed = false)
public function setPassword($password, $alreadyHashed = false)
{
if (!$pAlreadyHashed) {
if (!$alreadyHashed) {
$salt = $this->generateSalt();
$this->setSalt($salt);
$pValue = PasswordHasher::hashPassword($pValue, $this->getAlgorithm(), $this->getSalt(), $this->getSpinCount());
$password = PasswordHasher::hashPassword($password, $this->getAlgorithm(), $this->getSalt(), $this->getSpinCount());
}
$this->password = $pValue;
$this->password = $password;
return $this;
}
public function setHashValue(string $password): self
{
return $this->setPassword($password, true);
}
/**
* Create a pseudorandom string.
*/
@@ -623,25 +436,36 @@ class Protection
/**
* Set algorithm name.
*/
public function setAlgorithm(string $algorithm): void
public function setAlgorithm(string $algorithm): self
{
$this->algorithm = $algorithm;
return $this->setAlgorithmName($algorithm);
}
/**
* Get salt value.
* Set algorithm name.
*/
public function setAlgorithmName(string $algorithm): self
{
$this->algorithm = $algorithm;
return $this;
}
public function getSalt(): string
{
return $this->salt;
}
/**
* Set salt value.
*/
public function setSalt(string $salt): void
public function setSalt(string $salt): self
{
return $this->setSaltValue($salt);
}
public function setSaltValue(string $salt): self
{
$this->salt = $salt;
return $this;
}
/**
@@ -655,9 +479,11 @@ class Protection
/**
* Set spin count.
*/
public function setSpinCount(int $spinCount): void
public function setSpinCount(int $spinCount): self
{
$this->spinCount = $spinCount;
return $this;
}
/**
@@ -665,7 +491,7 @@ class Protection
*/
public function verify(string $password): bool
{
if (!$this->isProtectionEnabled()) {
if ($this->password === '') {
return true;
}

View File

@@ -21,10 +21,9 @@ class Row
/**
* Create a new row.
*
* @param Worksheet $worksheet
* @param int $rowIndex
*/
public function __construct(?Worksheet $worksheet = null, $rowIndex = 1)
public function __construct(Worksheet $worksheet, $rowIndex = 1)
{
// Set parent and row index
$this->worksheet = $worksheet;
@@ -36,15 +35,13 @@ class Row
*/
public function __destruct()
{
$this->worksheet = null;
$this->worksheet = null; // @phpstan-ignore-line
}
/**
* Get row index.
*
* @return int
*/
public function getRowIndex()
public function getRowIndex(): int
{
return $this->rowIndex;
}
@@ -63,11 +60,49 @@ class Row
}
/**
* Returns bound worksheet.
* 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.
*
* @return Worksheet
* @param int $definitionOfEmptyFlags
* Possible Flag Values are:
* CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL
* CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL
*/
public function getWorksheet()
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) {
/** @scrutinizer ignore-call */
$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

@@ -2,9 +2,13 @@
namespace PhpOffice\PhpSpreadsheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
/**
* @extends CellIterator<string>
*/
class RowCellIterator extends CellIterator
{
/**
@@ -43,10 +47,11 @@ class RowCellIterator extends CellIterator
* @param string $startColumn The column address at which to start iterating
* @param string $endColumn Optionally, the column address at which to stop iterating
*/
public function __construct(?Worksheet $worksheet = null, $rowIndex = 1, $startColumn = 'A', $endColumn = null)
public function __construct(Worksheet $worksheet, $rowIndex = 1, $startColumn = 'A', $endColumn = null)
{
// Set subject and row index
$this->worksheet = $worksheet;
$this->cellCollection = $worksheet->getCellCollection();
$this->rowIndex = $rowIndex;
$this->resetEnd($endColumn);
$this->resetStart($startColumn);
@@ -59,7 +64,7 @@ class RowCellIterator extends CellIterator
*
* @return $this
*/
public function resetStart($startColumn = 'A')
public function resetStart(string $startColumn = 'A')
{
$this->startColumnIndex = Coordinate::columnIndexFromString($startColumn);
$this->adjustForExistingOnlyRange();
@@ -77,7 +82,7 @@ class RowCellIterator extends CellIterator
*/
public function resetEnd($endColumn = null)
{
$endColumn = $endColumn ? $endColumn : $this->worksheet->getHighestColumn();
$endColumn = $endColumn ?: $this->worksheet->getHighestColumn();
$this->endColumnIndex = Coordinate::columnIndexFromString($endColumn);
$this->adjustForExistingOnlyRange();
@@ -91,17 +96,16 @@ class RowCellIterator extends CellIterator
*
* @return $this
*/
public function seek($column = 'A')
public function seek(string $column = 'A')
{
$columnx = $column;
$column = Coordinate::columnIndexFromString($column);
if ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($column, $this->rowIndex))) {
$columnId = Coordinate::columnIndexFromString($column);
if ($this->onlyExistingCells && !($this->cellCollection->has($column . $this->rowIndex))) {
throw new PhpSpreadsheetException('In "IterateOnlyExistingCells" mode and Cell does not exist');
}
if (($column < $this->startColumnIndex) || ($column > $this->endColumnIndex)) {
throw new PhpSpreadsheetException("Column $columnx is out of range ({$this->startColumnIndex} - {$this->endColumnIndex})");
if (($columnId < $this->startColumnIndex) || ($columnId > $this->endColumnIndex)) {
throw new PhpSpreadsheetException("Column $column is out of range ({$this->startColumnIndex} - {$this->endColumnIndex})");
}
$this->currentColumnIndex = $column;
$this->currentColumnIndex = $columnId;
return $this;
}
@@ -116,20 +120,20 @@ class RowCellIterator extends CellIterator
/**
* Return the current cell in this worksheet row.
*
* @return \PhpOffice\PhpSpreadsheet\Cell\Cell
*/
public function current()
public function current(): ?Cell
{
return $this->worksheet->getCellByColumnAndRow($this->currentColumnIndex, $this->rowIndex);
$cellAddress = Coordinate::stringFromColumnIndex($this->currentColumnIndex) . $this->rowIndex;
return $this->cellCollection->has($cellAddress)
? $this->cellCollection->get($cellAddress)
: $this->worksheet->createNewCell($cellAddress);
}
/**
* Return the current iterator key.
*
* @return string
*/
public function key()
public function key(): string
{
return Coordinate::stringFromColumnIndex($this->currentColumnIndex);
}
@@ -141,7 +145,7 @@ class RowCellIterator extends CellIterator
{
do {
++$this->currentColumnIndex;
} while (($this->onlyExistingCells) && (!$this->worksheet->cellExistsByColumnAndRow($this->currentColumnIndex, $this->rowIndex)) && ($this->currentColumnIndex <= $this->endColumnIndex));
} while (($this->onlyExistingCells) && (!$this->cellCollection->has(Coordinate::stringFromColumnIndex($this->currentColumnIndex) . $this->rowIndex)) && ($this->currentColumnIndex <= $this->endColumnIndex));
}
/**
@@ -151,25 +155,21 @@ class RowCellIterator extends CellIterator
{
do {
--$this->currentColumnIndex;
} while (($this->onlyExistingCells) && (!$this->worksheet->cellExistsByColumnAndRow($this->currentColumnIndex, $this->rowIndex)) && ($this->currentColumnIndex >= $this->startColumnIndex));
} while (($this->onlyExistingCells) && (!$this->cellCollection->has(Coordinate::stringFromColumnIndex($this->currentColumnIndex) . $this->rowIndex)) && ($this->currentColumnIndex >= $this->startColumnIndex));
}
/**
* Indicate if more columns exist in the worksheet range of columns that we're iterating.
*
* @return bool
*/
public function valid()
public function valid(): bool
{
return $this->currentColumnIndex <= $this->endColumnIndex && $this->currentColumnIndex >= $this->startColumnIndex;
}
/**
* Return the current iterator position.
*
* @return int
*/
public function getCurrentColumnIndex()
public function getCurrentColumnIndex(): int
{
return $this->currentColumnIndex;
}
@@ -180,10 +180,10 @@ class RowCellIterator extends CellIterator
protected function adjustForExistingOnlyRange(): void
{
if ($this->onlyExistingCells) {
while ((!$this->worksheet->cellExistsByColumnAndRow($this->startColumnIndex, $this->rowIndex)) && ($this->startColumnIndex <= $this->endColumnIndex)) {
while ((!$this->cellCollection->has(Coordinate::stringFromColumnIndex($this->startColumnIndex) . $this->rowIndex)) && ($this->startColumnIndex <= $this->endColumnIndex)) {
++$this->startColumnIndex;
}
while ((!$this->worksheet->cellExistsByColumnAndRow($this->endColumnIndex, $this->rowIndex)) && ($this->endColumnIndex >= $this->startColumnIndex)) {
while ((!$this->cellCollection->has(Coordinate::stringFromColumnIndex($this->endColumnIndex) . $this->rowIndex)) && ($this->endColumnIndex >= $this->startColumnIndex)) {
--$this->endColumnIndex;
}
}

View File

@@ -2,6 +2,8 @@
namespace PhpOffice\PhpSpreadsheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Helper\Dimension as CssDimension;
class RowDimension extends Dimension
{
/**
@@ -30,12 +32,12 @@ class RowDimension extends Dimension
/**
* Create a new RowDimension.
*
* @param int $pIndex Numeric row index
* @param int $index Numeric row index
*/
public function __construct($pIndex = 0)
public function __construct($index = 0)
{
// Initialise values
$this->rowIndex = $pIndex;
$this->rowIndex = $index;
// set dimension as unformatted by default
parent::__construct(null);
@@ -43,10 +45,8 @@ class RowDimension extends Dimension
/**
* Get Row Index.
*
* @return int
*/
public function getRowIndex()
public function getRowIndex(): int
{
return $this->rowIndex;
}
@@ -54,47 +54,52 @@ class RowDimension extends Dimension
/**
* Set Row Index.
*
* @param int $pValue
*
* @return $this
*/
public function setRowIndex($pValue)
public function setRowIndex(int $index)
{
$this->rowIndex = $pValue;
$this->rowIndex = $index;
return $this;
}
/**
* Get Row Height.
* By default, this will be in points; but this method also accepts an optional unit of measure
* argument, and will convert the value from points to the specified UoM.
* A value of -1 tells Excel to display this column in its default height.
*
* @return float
*/
public function getRowHeight()
public function getRowHeight(?string $unitOfMeasure = null)
{
return $this->height;
return ($unitOfMeasure === null || $this->height < 0)
? $this->height
: (new CssDimension($this->height . CssDimension::UOM_POINTS))->toUnit($unitOfMeasure);
}
/**
* Set Row Height.
*
* @param float $pValue
* @param float $height in points. A value of -1 tells Excel to display this column in its default height.
* By default, this will be the passed argument value; but this method also accepts an optional unit of measure
* argument, and will convert the passed argument value to points from the specified UoM
*
* @return $this
*/
public function setRowHeight($pValue)
public function setRowHeight($height, ?string $unitOfMeasure = null)
{
$this->height = $pValue;
$this->height = ($unitOfMeasure === null || $height < 0)
? $height
: (new CssDimension("{$height}{$unitOfMeasure}"))->height();
return $this;
}
/**
* Get ZeroHeight.
*
* @return bool
*/
public function getZeroHeight()
public function getZeroHeight(): bool
{
return $this->zeroHeight;
}
@@ -102,13 +107,11 @@ class RowDimension extends Dimension
/**
* Set ZeroHeight.
*
* @param bool $pValue
*
* @return $this
*/
public function setZeroHeight($pValue)
public function setZeroHeight(bool $zeroHeight)
{
$this->zeroHeight = $pValue;
$this->zeroHeight = $zeroHeight;
return $this;
}

View File

@@ -2,10 +2,13 @@
namespace PhpOffice\PhpSpreadsheet\Worksheet;
use Iterator;
use Iterator as NativeIterator;
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
class RowIterator implements Iterator
/**
* @implements NativeIterator<int, Row>
*/
class RowIterator implements NativeIterator
{
/**
* Worksheet to iterate.
@@ -50,14 +53,6 @@ class RowIterator implements Iterator
$this->resetStart($startRow);
}
/**
* Destructor.
*/
public function __destruct()
{
$this->subject = null;
}
/**
* (Re)Set the start row and the current row pointer.
*
@@ -65,10 +60,12 @@ class RowIterator implements Iterator
*
* @return $this
*/
public function resetStart($startRow = 1)
public function resetStart(int $startRow = 1)
{
if ($startRow > $this->subject->getHighestRow()) {
throw new PhpSpreadsheetException("Start row ({$startRow}) is beyond highest row ({$this->subject->getHighestRow()})");
throw new PhpSpreadsheetException(
"Start row ({$startRow}) is beyond highest row ({$this->subject->getHighestRow()})"
);
}
$this->startRow = $startRow;
@@ -89,7 +86,7 @@ class RowIterator implements Iterator
*/
public function resetEnd($endRow = null)
{
$this->endRow = ($endRow) ? $endRow : $this->subject->getHighestRow();
$this->endRow = $endRow ?: $this->subject->getHighestRow();
return $this;
}
@@ -101,7 +98,7 @@ class RowIterator implements Iterator
*
* @return $this
*/
public function seek($row = 1)
public function seek(int $row = 1)
{
if (($row < $this->startRow) || ($row > $this->endRow)) {
throw new PhpSpreadsheetException("Row $row is out of range ({$this->startRow} - {$this->endRow})");
@@ -121,20 +118,16 @@ class RowIterator implements Iterator
/**
* Return the current row in this worksheet.
*
* @return Row
*/
public function current()
public function current(): Row
{
return new Row($this->subject, $this->position);
}
/**
* Return the current iterator key.
*
* @return int
*/
public function key()
public function key(): int
{
return $this->position;
}
@@ -157,10 +150,8 @@ class RowIterator implements Iterator
/**
* Indicate if more rows exist in the worksheet range of rows that we're iterating.
*
* @return bool
*/
public function valid()
public function valid(): bool
{
return $this->position <= $this->endRow && $this->position >= $this->startRow;
}

View File

@@ -11,7 +11,7 @@ class SheetView
const SHEETVIEW_PAGE_LAYOUT = 'pageLayout';
const SHEETVIEW_PAGE_BREAK_PREVIEW = 'pageBreakPreview';
private static $sheetViewTypes = [
private const SHEET_VIEW_TYPES = [
self::SHEETVIEW_NORMAL,
self::SHEETVIEW_PAGE_LAYOUT,
self::SHEETVIEW_PAGE_BREAK_PREVIEW,
@@ -22,7 +22,7 @@ class SheetView
*
* Valid values range from 10 to 400.
*
* @var int
* @var ?int
*/
private $zoomScale = 100;
@@ -31,7 +31,7 @@ class SheetView
*
* Valid values range from 10 to 400.
*
* @var int
* @var ?int
*/
private $zoomScaleNormal = 100;
@@ -64,7 +64,7 @@ class SheetView
/**
* Get ZoomScale.
*
* @return int
* @return ?int
*/
public function getZoomScale()
{
@@ -75,16 +75,16 @@ class SheetView
* Set ZoomScale.
* Valid values range from 10 to 400.
*
* @param int $pValue
* @param ?int $zoomScale
*
* @return $this
*/
public function setZoomScale($pValue)
public function setZoomScale($zoomScale)
{
// Microsoft Office Excel 2007 only allows setting a scale between 10 and 400 via the user interface,
// but it is apparently still able to handle any scale >= 1
if (($pValue >= 1) || $pValue === null) {
$this->zoomScale = $pValue;
if ($zoomScale === null || $zoomScale >= 1) {
$this->zoomScale = $zoomScale;
} else {
throw new PhpSpreadsheetException('Scale must be greater than or equal to 1.');
}
@@ -95,7 +95,7 @@ class SheetView
/**
* Get ZoomScaleNormal.
*
* @return int
* @return ?int
*/
public function getZoomScaleNormal()
{
@@ -106,14 +106,14 @@ class SheetView
* Set ZoomScale.
* Valid values range from 10 to 400.
*
* @param int $pValue
* @param ?int $zoomScaleNormal
*
* @return $this
*/
public function setZoomScaleNormal($pValue)
public function setZoomScaleNormal($zoomScaleNormal)
{
if (($pValue >= 1) || $pValue === null) {
$this->zoomScaleNormal = $pValue;
if ($zoomScaleNormal === null || $zoomScaleNormal >= 1) {
$this->zoomScaleNormal = $zoomScaleNormal;
} else {
throw new PhpSpreadsheetException('Scale must be greater than or equal to 1.');
}
@@ -124,11 +124,11 @@ class SheetView
/**
* Set ShowZeroes setting.
*
* @param bool $pValue
* @param bool $showZeros
*/
public function setShowZeros($pValue): void
public function setShowZeros($showZeros): void
{
$this->showZeros = $pValue;
$this->showZeros = $showZeros;
}
/**
@@ -157,18 +157,18 @@ class SheetView
* 'pageLayout' self::SHEETVIEW_PAGE_LAYOUT
* 'pageBreakPreview' self::SHEETVIEW_PAGE_BREAK_PREVIEW
*
* @param string $pValue
* @param ?string $sheetViewType
*
* @return $this
*/
public function setView($pValue)
public function setView($sheetViewType)
{
// MS Excel 2007 allows setting the view to 'normal', 'pageLayout' or 'pageBreakPreview' via the user interface
if ($pValue === null) {
$pValue = self::SHEETVIEW_NORMAL;
if ($sheetViewType === null) {
$sheetViewType = self::SHEETVIEW_NORMAL;
}
if (in_array($pValue, self::$sheetViewTypes)) {
$this->sheetviewType = $pValue;
if (in_array($sheetViewType, self::SHEET_VIEW_TYPES)) {
$this->sheetviewType = $sheetViewType;
} else {
throw new PhpSpreadsheetException('Invalid sheetview layout type.');
}

View File

@@ -0,0 +1,585 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Cell\AddressRange;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Table\TableStyle;
class Table
{
/**
* Table Name.
*
* @var string
*/
private $name;
/**
* Show Header Row.
*
* @var bool
*/
private $showHeaderRow = true;
/**
* Show Totals Row.
*
* @var bool
*/
private $showTotalsRow = false;
/**
* Table Range.
*
* @var string
*/
private $range = '';
/**
* Table Worksheet.
*
* @var null|Worksheet
*/
private $workSheet;
/**
* Table allow filter.
*
* @var bool
*/
private $allowFilter = true;
/**
* Table Column.
*
* @var Table\Column[]
*/
private $columns = [];
/**
* Table Style.
*
* @var TableStyle
*/
private $style;
/**
* Table AutoFilter.
*
* @var AutoFilter
*/
private $autoFilter;
/**
* Create a new Table.
*
* @param AddressRange|array<int>|string $range
* A simple string containing a Cell range like 'A1:E10' is permitted
* or passing in an array of [$fromColumnIndex, $fromRow, $toColumnIndex, $toRow] (e.g. [3, 5, 6, 8]),
* or an AddressRange object.
* @param string $name (e.g. Table1)
*/
public function __construct($range = '', string $name = '')
{
$this->style = new TableStyle();
$this->autoFilter = new AutoFilter($range);
$this->setRange($range);
$this->setName($name);
}
/**
* Get Table name.
*/
public function getName(): string
{
return $this->name;
}
/**
* Set Table name.
*
* @throws PhpSpreadsheetException
*/
public function setName(string $name): self
{
$name = trim($name);
if (!empty($name)) {
if (strlen($name) === 1 && in_array($name, ['C', 'c', 'R', 'r'])) {
throw new PhpSpreadsheetException('The table name is invalid');
}
if (StringHelper::countCharacters($name) > 255) {
throw new PhpSpreadsheetException('The table name cannot be longer than 255 characters');
}
// Check for A1 or R1C1 cell reference notation
if (
preg_match(Coordinate::A1_COORDINATE_REGEX, $name) ||
preg_match('/^R\[?\-?[0-9]*\]?C\[?\-?[0-9]*\]?$/i', $name)
) {
throw new PhpSpreadsheetException('The table name can\'t be the same as a cell reference');
}
if (!preg_match('/^[\p{L}_\\\\]/iu', $name)) {
throw new PhpSpreadsheetException('The table name must begin a name with a letter, an underscore character (_), or a backslash (\)');
}
if (!preg_match('/^[\p{L}_\\\\][\p{L}\p{M}0-9\._]+$/iu', $name)) {
throw new PhpSpreadsheetException('The table name contains invalid characters');
}
$this->checkForDuplicateTableNames($name, $this->workSheet);
$this->updateStructuredReferences($name);
}
$this->name = $name;
return $this;
}
/**
* @throws PhpSpreadsheetException
*/
private function checkForDuplicateTableNames(string $name, ?Worksheet $worksheet): void
{
// Remember that table names are case-insensitive
$tableName = StringHelper::strToLower($name);
if ($worksheet !== null && StringHelper::strToLower($this->name) !== $name) {
$spreadsheet = $worksheet->getParent();
foreach ($spreadsheet->getWorksheetIterator() as $sheet) {
foreach ($sheet->getTableCollection() as $table) {
if (StringHelper::strToLower($table->getName()) === $tableName && $table != $this) {
throw new PhpSpreadsheetException("Spreadsheet already contains a table named '{$this->name}'");
}
}
}
}
}
private function updateStructuredReferences(string $name): void
{
if ($this->workSheet === null || $this->name === null || $this->name === '') {
return;
}
// Remember that table names are case-insensitive
if (StringHelper::strToLower($this->name) !== StringHelper::strToLower($name)) {
// We need to check all formula cells that might contain fully-qualified Structured References
// that refer to this table, and update those formulae to reference the new table name
$spreadsheet = $this->workSheet->getParent();
foreach ($spreadsheet->getWorksheetIterator() as $sheet) {
$this->updateStructuredReferencesInCells($sheet, $name);
}
$this->updateStructuredReferencesInNamedFormulae($spreadsheet, $name);
}
}
private function updateStructuredReferencesInCells(Worksheet $worksheet, string $newName): void
{
$pattern = '/' . preg_quote($this->name) . '\[/mui';
foreach ($worksheet->getCoordinates(false) as $coordinate) {
$cell = $worksheet->getCell($coordinate);
if ($cell->getDataType() === DataType::TYPE_FORMULA) {
$formula = $cell->getValue();
if (preg_match($pattern, $formula) === 1) {
$formula = preg_replace($pattern, "{$newName}[", $formula);
$cell->setValueExplicit($formula, DataType::TYPE_FORMULA);
}
}
}
}
private function updateStructuredReferencesInNamedFormulae(Spreadsheet $spreadsheet, string $newName): void
{
$pattern = '/' . preg_quote($this->name) . '\[/mui';
foreach ($spreadsheet->getNamedFormulae() as $namedFormula) {
$formula = $namedFormula->getValue();
if (preg_match($pattern, $formula) === 1) {
$formula = preg_replace($pattern, "{$newName}[", $formula);
$namedFormula->setValue($formula); // @phpstan-ignore-line
}
}
}
/**
* Get show Header Row.
*/
public function getShowHeaderRow(): bool
{
return $this->showHeaderRow;
}
/**
* Set show Header Row.
*/
public function setShowHeaderRow(bool $showHeaderRow): self
{
$this->showHeaderRow = $showHeaderRow;
return $this;
}
/**
* Get show Totals Row.
*/
public function getShowTotalsRow(): bool
{
return $this->showTotalsRow;
}
/**
* Set show Totals Row.
*/
public function setShowTotalsRow(bool $showTotalsRow): self
{
$this->showTotalsRow = $showTotalsRow;
return $this;
}
/**
* Get allow filter.
* If false, autofiltering is disabled for the table, if true it is enabled.
*/
public function getAllowFilter(): bool
{
return $this->allowFilter;
}
/**
* Set show Autofiltering.
* Disabling autofiltering has the same effect as hiding the filter button on all the columns in the table.
*/
public function setAllowFilter(bool $allowFilter): self
{
$this->allowFilter = $allowFilter;
return $this;
}
/**
* Get Table Range.
*/
public function getRange(): string
{
return $this->range;
}
/**
* Set Table Cell Range.
*
* @param AddressRange|array<int>|string $range
* A simple string containing a Cell range like 'A1:E10' is permitted
* or passing in an array of [$fromColumnIndex, $fromRow, $toColumnIndex, $toRow] (e.g. [3, 5, 6, 8]),
* or an AddressRange object.
*/
public function setRange($range = ''): self
{
// extract coordinate
if ($range !== '') {
[, $range] = Worksheet::extractSheetTitle(Validations::validateCellRange($range), true);
}
if (empty($range)) {
// Discard all column rules
$this->columns = [];
$this->range = '';
return $this;
}
if (strpos($range, ':') === false) {
throw new PhpSpreadsheetException('Table must be set on a range of cells.');
}
[$width, $height] = Coordinate::rangeDimension($range);
if ($width < 1 || $height < 2) {
throw new PhpSpreadsheetException('The table range must be at least 1 column and 2 rows');
}
$this->range = $range;
$this->autoFilter->setRange($range);
// Discard any column rules that are no longer valid within this range
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range);
foreach ($this->columns as $key => $value) {
$colIndex = Coordinate::columnIndexFromString($key);
if (($rangeStart[0] > $colIndex) || ($rangeEnd[0] < $colIndex)) {
unset($this->columns[$key]);
}
}
return $this;
}
/**
* Set Table Cell Range to max row.
*/
public function setRangeToMaxRow(): self
{
if ($this->workSheet !== null) {
$thisrange = $this->range;
$range = (string) preg_replace('/\\d+$/', (string) $this->workSheet->getHighestRow(), $thisrange);
if ($range !== $thisrange) {
$this->setRange($range);
}
}
return $this;
}
/**
* Get Table's Worksheet.
*/
public function getWorksheet(): ?Worksheet
{
return $this->workSheet;
}
/**
* Set Table's Worksheet.
*/
public function setWorksheet(?Worksheet $worksheet = null): self
{
if ($this->name !== '' && $worksheet !== null) {
$spreadsheet = $worksheet->getParent();
$tableName = StringHelper::strToUpper($this->name);
foreach ($spreadsheet->getWorksheetIterator() as $sheet) {
foreach ($sheet->getTableCollection() as $table) {
if (StringHelper::strToUpper($table->getName()) === $tableName) {
throw new PhpSpreadsheetException("Workbook already contains a table named '{$this->name}'");
}
}
}
}
$this->workSheet = $worksheet;
$this->autoFilter->setParent($worksheet);
return $this;
}
/**
* Get all Table Columns.
*
* @return Table\Column[]
*/
public function getColumns(): array
{
return $this->columns;
}
/**
* Validate that the specified column is in the Table range.
*
* @param string $column Column name (e.g. A)
*
* @return int The column offset within the table range
*/
public function isColumnInRange(string $column): int
{
if (empty($this->range)) {
throw new PhpSpreadsheetException('No table range is defined.');
}
$columnIndex = Coordinate::columnIndexFromString($column);
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range);
if (($rangeStart[0] > $columnIndex) || ($rangeEnd[0] < $columnIndex)) {
throw new PhpSpreadsheetException('Column is outside of current table range.');
}
return $columnIndex - $rangeStart[0];
}
/**
* Get a specified Table Column Offset within the defined Table range.
*
* @param string $column Column name (e.g. A)
*
* @return int The offset of the specified column within the table range
*/
public function getColumnOffset($column): int
{
return $this->isColumnInRange($column);
}
/**
* Get a specified Table Column.
*
* @param string $column Column name (e.g. A)
*/
public function getColumn($column): Table\Column
{
$this->isColumnInRange($column);
if (!isset($this->columns[$column])) {
$this->columns[$column] = new Table\Column($column, $this);
}
return $this->columns[$column];
}
/**
* Get a specified Table Column by it's offset.
*
* @param int $columnOffset Column offset within range (starting from 0)
*/
public function getColumnByOffset($columnOffset): Table\Column
{
[$rangeStart, $rangeEnd] = Coordinate::rangeBoundaries($this->range);
$pColumn = Coordinate::stringFromColumnIndex($rangeStart[0] + $columnOffset);
return $this->getColumn($pColumn);
}
/**
* Set Table.
*
* @param string|Table\Column $columnObjectOrString
* A simple string containing a Column ID like 'A' is permitted
*/
public function setColumn($columnObjectOrString): self
{
if ((is_string($columnObjectOrString)) && (!empty($columnObjectOrString))) {
$column = $columnObjectOrString;
} elseif (is_object($columnObjectOrString) && ($columnObjectOrString instanceof Table\Column)) {
$column = $columnObjectOrString->getColumnIndex();
} else {
throw new PhpSpreadsheetException('Column is not within the table range.');
}
$this->isColumnInRange($column);
if (is_string($columnObjectOrString)) {
$this->columns[$columnObjectOrString] = new Table\Column($columnObjectOrString, $this);
} else {
$columnObjectOrString->setTable($this);
$this->columns[$column] = $columnObjectOrString;
}
ksort($this->columns);
return $this;
}
/**
* Clear a specified Table Column.
*
* @param string $column Column name (e.g. A)
*/
public function clearColumn($column): self
{
$this->isColumnInRange($column);
if (isset($this->columns[$column])) {
unset($this->columns[$column]);
}
return $this;
}
/**
* Shift an Table Column Rule to a different column.
*
* Note: This method bypasses validation of the destination column to ensure it is within this Table range.
* Nor does it verify whether any column rule already exists at $toColumn, but will simply override any existing value.
* Use with caution.
*
* @param string $fromColumn Column name (e.g. A)
* @param string $toColumn Column name (e.g. B)
*/
public function shiftColumn($fromColumn, $toColumn): self
{
$fromColumn = strtoupper($fromColumn);
$toColumn = strtoupper($toColumn);
if (($fromColumn !== null) && (isset($this->columns[$fromColumn])) && ($toColumn !== null)) {
$this->columns[$fromColumn]->setTable();
$this->columns[$fromColumn]->setColumnIndex($toColumn);
$this->columns[$toColumn] = $this->columns[$fromColumn];
$this->columns[$toColumn]->setTable($this);
unset($this->columns[$fromColumn]);
ksort($this->columns);
}
return $this;
}
/**
* Get table Style.
*/
public function getStyle(): Table\TableStyle
{
return $this->style;
}
/**
* Set table Style.
*/
public function setStyle(TableStyle $style): self
{
$this->style = $style;
return $this;
}
/**
* Get AutoFilter.
*/
public function getAutoFilter(): AutoFilter
{
return $this->autoFilter;
}
/**
* Set AutoFilter.
*/
public function setAutoFilter(AutoFilter $autoFilter): self
{
$this->autoFilter = $autoFilter;
return $this;
}
/**
* Implement PHP __clone to create a deep clone, not just a shallow copy.
*/
public function __clone()
{
$vars = get_object_vars($this);
foreach ($vars as $key => $value) {
if (is_object($value)) {
if ($key === 'workSheet') {
// Detach from worksheet
$this->{$key} = null;
} else {
$this->{$key} = clone $value;
}
} elseif ((is_array($value)) && ($key === 'columns')) {
// The columns array of \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\Table objects
$this->{$key} = [];
foreach ($value as $k => $v) {
$this->{$key}[$k] = clone $v;
// attach the new cloned Column to this new cloned Table object
$this->{$key}[$k]->setTable($this);
}
} else {
$this->{$key} = $value;
}
}
}
/**
* toString method replicates previous behavior by returning the range if object is
* referenced as a property of its worksheet.
*/
public function __toString()
{
return (string) $this->range;
}
}

View File

@@ -0,0 +1,254 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Worksheet\Table;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Table;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class Column
{
/**
* Table Column Index.
*
* @var string
*/
private $columnIndex = '';
/**
* Show Filter Button.
*
* @var bool
*/
private $showFilterButton = true;
/**
* Total Row Label.
*
* @var string
*/
private $totalsRowLabel;
/**
* Total Row Function.
*
* @var string
*/
private $totalsRowFunction;
/**
* Total Row Formula.
*
* @var string
*/
private $totalsRowFormula;
/**
* Column Formula.
*
* @var string
*/
private $columnFormula;
/**
* Table.
*
* @var null|Table
*/
private $table;
/**
* Create a new Column.
*
* @param string $column Column (e.g. A)
* @param Table $table Table for this column
*/
public function __construct($column, ?Table $table = null)
{
$this->columnIndex = $column;
$this->table = $table;
}
/**
* Get Table column index as string eg: 'A'.
*/
public function getColumnIndex(): string
{
return $this->columnIndex;
}
/**
* Set Table column index as string eg: 'A'.
*
* @param string $column Column (e.g. A)
*/
public function setColumnIndex($column): self
{
// Uppercase coordinate
$column = strtoupper($column);
if ($this->table !== null) {
$this->table->isColumnInRange($column);
}
$this->columnIndex = $column;
return $this;
}
/**
* Get show Filter Button.
*/
public function getShowFilterButton(): bool
{
return $this->showFilterButton;
}
/**
* Set show Filter Button.
*/
public function setShowFilterButton(bool $showFilterButton): self
{
$this->showFilterButton = $showFilterButton;
return $this;
}
/**
* Get total Row Label.
*/
public function getTotalsRowLabel(): ?string
{
return $this->totalsRowLabel;
}
/**
* Set total Row Label.
*/
public function setTotalsRowLabel(string $totalsRowLabel): self
{
$this->totalsRowLabel = $totalsRowLabel;
return $this;
}
/**
* Get total Row Function.
*/
public function getTotalsRowFunction(): ?string
{
return $this->totalsRowFunction;
}
/**
* Set total Row Function.
*/
public function setTotalsRowFunction(string $totalsRowFunction): self
{
$this->totalsRowFunction = $totalsRowFunction;
return $this;
}
/**
* Get total Row Formula.
*/
public function getTotalsRowFormula(): ?string
{
return $this->totalsRowFormula;
}
/**
* Set total Row Formula.
*/
public function setTotalsRowFormula(string $totalsRowFormula): self
{
$this->totalsRowFormula = $totalsRowFormula;
return $this;
}
/**
* Get column Formula.
*/
public function getColumnFormula(): ?string
{
return $this->columnFormula;
}
/**
* Set column Formula.
*/
public function setColumnFormula(string $columnFormula): self
{
$this->columnFormula = $columnFormula;
return $this;
}
/**
* Get this Column's Table.
*/
public function getTable(): ?Table
{
return $this->table;
}
/**
* Set this Column's Table.
*/
public function setTable(?Table $table = null): self
{
$this->table = $table;
return $this;
}
public static function updateStructuredReferences(?Worksheet $workSheet, ?string $oldTitle, string $newTitle): void
{
if ($workSheet === null || $oldTitle === null || $oldTitle === '') {
return;
}
// Remember that table headings are case-insensitive
if (StringHelper::strToLower($oldTitle) !== StringHelper::strToLower($newTitle)) {
// We need to check all formula cells that might contain Structured References that refer
// to this column, and update those formulae to reference the new column text
$spreadsheet = $workSheet->getParent();
foreach ($spreadsheet->getWorksheetIterator() as $sheet) {
self::updateStructuredReferencesInCells($sheet, $oldTitle, $newTitle);
}
self::updateStructuredReferencesInNamedFormulae($spreadsheet, $oldTitle, $newTitle);
}
}
private static function updateStructuredReferencesInCells(Worksheet $worksheet, string $oldTitle, string $newTitle): void
{
$pattern = '/\[(@?)' . preg_quote($oldTitle) . '\]/mui';
foreach ($worksheet->getCoordinates(false) as $coordinate) {
$cell = $worksheet->getCell($coordinate);
if ($cell->getDataType() === DataType::TYPE_FORMULA) {
$formula = $cell->getValue();
if (preg_match($pattern, $formula) === 1) {
$formula = preg_replace($pattern, "[$1{$newTitle}]", $formula);
$cell->setValueExplicit($formula, DataType::TYPE_FORMULA);
}
}
}
}
private static function updateStructuredReferencesInNamedFormulae(Spreadsheet $spreadsheet, string $oldTitle, string $newTitle): void
{
$pattern = '/\[(@?)' . preg_quote($oldTitle) . '\]/mui';
foreach ($spreadsheet->getNamedFormulae() as $namedFormula) {
$formula = $namedFormula->getValue();
if (preg_match($pattern, $formula) === 1) {
$formula = preg_replace($pattern, "[$1{$newTitle}]", $formula);
$namedFormula->setValue($formula); // @phpstan-ignore-line
}
}
}
}

View File

@@ -0,0 +1,230 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Worksheet\Table;
use PhpOffice\PhpSpreadsheet\Worksheet\Table;
class TableStyle
{
const TABLE_STYLE_NONE = '';
const TABLE_STYLE_LIGHT1 = 'TableStyleLight1';
const TABLE_STYLE_LIGHT2 = 'TableStyleLight2';
const TABLE_STYLE_LIGHT3 = 'TableStyleLight3';
const TABLE_STYLE_LIGHT4 = 'TableStyleLight4';
const TABLE_STYLE_LIGHT5 = 'TableStyleLight5';
const TABLE_STYLE_LIGHT6 = 'TableStyleLight6';
const TABLE_STYLE_LIGHT7 = 'TableStyleLight7';
const TABLE_STYLE_LIGHT8 = 'TableStyleLight8';
const TABLE_STYLE_LIGHT9 = 'TableStyleLight9';
const TABLE_STYLE_LIGHT10 = 'TableStyleLight10';
const TABLE_STYLE_LIGHT11 = 'TableStyleLight11';
const TABLE_STYLE_LIGHT12 = 'TableStyleLight12';
const TABLE_STYLE_LIGHT13 = 'TableStyleLight13';
const TABLE_STYLE_LIGHT14 = 'TableStyleLight14';
const TABLE_STYLE_LIGHT15 = 'TableStyleLight15';
const TABLE_STYLE_LIGHT16 = 'TableStyleLight16';
const TABLE_STYLE_LIGHT17 = 'TableStyleLight17';
const TABLE_STYLE_LIGHT18 = 'TableStyleLight18';
const TABLE_STYLE_LIGHT19 = 'TableStyleLight19';
const TABLE_STYLE_LIGHT20 = 'TableStyleLight20';
const TABLE_STYLE_LIGHT21 = 'TableStyleLight21';
const TABLE_STYLE_MEDIUM1 = 'TableStyleMedium1';
const TABLE_STYLE_MEDIUM2 = 'TableStyleMedium2';
const TABLE_STYLE_MEDIUM3 = 'TableStyleMedium3';
const TABLE_STYLE_MEDIUM4 = 'TableStyleMedium4';
const TABLE_STYLE_MEDIUM5 = 'TableStyleMedium5';
const TABLE_STYLE_MEDIUM6 = 'TableStyleMedium6';
const TABLE_STYLE_MEDIUM7 = 'TableStyleMedium7';
const TABLE_STYLE_MEDIUM8 = 'TableStyleMedium8';
const TABLE_STYLE_MEDIUM9 = 'TableStyleMedium9';
const TABLE_STYLE_MEDIUM10 = 'TableStyleMedium10';
const TABLE_STYLE_MEDIUM11 = 'TableStyleMedium11';
const TABLE_STYLE_MEDIUM12 = 'TableStyleMedium12';
const TABLE_STYLE_MEDIUM13 = 'TableStyleMedium13';
const TABLE_STYLE_MEDIUM14 = 'TableStyleMedium14';
const TABLE_STYLE_MEDIUM15 = 'TableStyleMedium15';
const TABLE_STYLE_MEDIUM16 = 'TableStyleMedium16';
const TABLE_STYLE_MEDIUM17 = 'TableStyleMedium17';
const TABLE_STYLE_MEDIUM18 = 'TableStyleMedium18';
const TABLE_STYLE_MEDIUM19 = 'TableStyleMedium19';
const TABLE_STYLE_MEDIUM20 = 'TableStyleMedium20';
const TABLE_STYLE_MEDIUM21 = 'TableStyleMedium21';
const TABLE_STYLE_MEDIUM22 = 'TableStyleMedium22';
const TABLE_STYLE_MEDIUM23 = 'TableStyleMedium23';
const TABLE_STYLE_MEDIUM24 = 'TableStyleMedium24';
const TABLE_STYLE_MEDIUM25 = 'TableStyleMedium25';
const TABLE_STYLE_MEDIUM26 = 'TableStyleMedium26';
const TABLE_STYLE_MEDIUM27 = 'TableStyleMedium27';
const TABLE_STYLE_MEDIUM28 = 'TableStyleMedium28';
const TABLE_STYLE_DARK1 = 'TableStyleDark1';
const TABLE_STYLE_DARK2 = 'TableStyleDark2';
const TABLE_STYLE_DARK3 = 'TableStyleDark3';
const TABLE_STYLE_DARK4 = 'TableStyleDark4';
const TABLE_STYLE_DARK5 = 'TableStyleDark5';
const TABLE_STYLE_DARK6 = 'TableStyleDark6';
const TABLE_STYLE_DARK7 = 'TableStyleDark7';
const TABLE_STYLE_DARK8 = 'TableStyleDark8';
const TABLE_STYLE_DARK9 = 'TableStyleDark9';
const TABLE_STYLE_DARK10 = 'TableStyleDark10';
const TABLE_STYLE_DARK11 = 'TableStyleDark11';
/**
* Theme.
*
* @var string
*/
private $theme;
/**
* Show First Column.
*
* @var bool
*/
private $showFirstColumn = false;
/**
* Show Last Column.
*
* @var bool
*/
private $showLastColumn = false;
/**
* Show Row Stripes.
*
* @var bool
*/
private $showRowStripes = false;
/**
* Show Column Stripes.
*
* @var bool
*/
private $showColumnStripes = false;
/**
* Table.
*
* @var null|Table
*/
private $table;
/**
* Create a new Table Style.
*
* @param string $theme (e.g. TableStyle::TABLE_STYLE_MEDIUM2)
*/
public function __construct(string $theme = self::TABLE_STYLE_MEDIUM2)
{
$this->theme = $theme;
}
/**
* Get theme.
*/
public function getTheme(): string
{
return $this->theme;
}
/**
* Set theme.
*/
public function setTheme(string $theme): self
{
$this->theme = $theme;
return $this;
}
/**
* Get show First Column.
*/
public function getShowFirstColumn(): bool
{
return $this->showFirstColumn;
}
/**
* Set show First Column.
*/
public function setShowFirstColumn(bool $showFirstColumn): self
{
$this->showFirstColumn = $showFirstColumn;
return $this;
}
/**
* Get show Last Column.
*/
public function getShowLastColumn(): bool
{
return $this->showLastColumn;
}
/**
* Set show Last Column.
*/
public function setShowLastColumn(bool $showLastColumn): self
{
$this->showLastColumn = $showLastColumn;
return $this;
}
/**
* Get show Row Stripes.
*/
public function getShowRowStripes(): bool
{
return $this->showRowStripes;
}
/**
* Set show Row Stripes.
*/
public function setShowRowStripes(bool $showRowStripes): self
{
$this->showRowStripes = $showRowStripes;
return $this;
}
/**
* Get show Column Stripes.
*/
public function getShowColumnStripes(): bool
{
return $this->showColumnStripes;
}
/**
* Set show Column Stripes.
*/
public function setShowColumnStripes(bool $showColumnStripes): self
{
$this->showColumnStripes = $showColumnStripes;
return $this;
}
/**
* Get this Style's Table.
*/
public function getTable(): ?Table
{
return $this->table;
}
/**
* Set this Style's Table.
*/
public function setTable(?Table $table = null): self
{
$this->table = $table;
return $this;
}
}

View File

@@ -0,0 +1,115 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Cell\AddressRange;
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
use PhpOffice\PhpSpreadsheet\Cell\CellRange;
use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException;
class Validations
{
/**
* Validate a cell address.
*
* @param null|array<int>|CellAddress|string $cellAddress Coordinate of the cell as a string, eg: 'C5';
* or as an array of [$columnIndex, $row] (e.g. [3, 5]), or a CellAddress object.
*/
public static function validateCellAddress($cellAddress): string
{
if (is_string($cellAddress)) {
[$worksheet, $address] = Worksheet::extractSheetTitle($cellAddress, true);
// if (!empty($worksheet) && $worksheet !== $this->getTitle()) {
// throw new Exception('Reference is not for this worksheet');
// }
return empty($worksheet) ? strtoupper("$address") : $worksheet . '!' . strtoupper("$address");
}
if (is_array($cellAddress)) {
$cellAddress = CellAddress::fromColumnRowArray($cellAddress);
}
return (string) $cellAddress;
}
/**
* Validate a cell address or cell range.
*
* @param AddressRange|array<int>|CellAddress|int|string $cellRange Coordinate of the cells as a string, eg: 'C5:F12';
* or as an array of [$fromColumnIndex, $fromRow, $toColumnIndex, $toRow] (e.g. [3, 5, 6, 12]),
* or as a CellAddress or AddressRange object.
*/
public static function validateCellOrCellRange($cellRange): string
{
if (is_string($cellRange) || is_numeric($cellRange)) {
// Convert a single column reference like 'A' to 'A:A',
// a single row reference like '1' to '1:1'
$cellRange = (string) preg_replace('/^([A-Z]+|\d+)$/', '${1}:${1}', (string) $cellRange);
} elseif (is_object($cellRange) && $cellRange instanceof CellAddress) {
$cellRange = new CellRange($cellRange, $cellRange);
}
return self::validateCellRange($cellRange);
}
/**
* Validate a cell range.
*
* @param AddressRange|array<int>|string $cellRange Coordinate of the cells as a string, eg: 'C5:F12';
* or as an array of [$fromColumnIndex, $fromRow, $toColumnIndex, $toRow] (e.g. [3, 5, 6, 12]),
* or as an AddressRange object.
*/
public static function validateCellRange($cellRange): string
{
if (is_string($cellRange)) {
[$worksheet, $addressRange] = Worksheet::extractSheetTitle($cellRange, true);
// Convert Column ranges like 'A:C' to 'A1:C1048576'
// or Row ranges like '1:3' to 'A1:XFD3'
$addressRange = (string) preg_replace(
['/^([A-Z]+):([A-Z]+)$/i', '/^(\\d+):(\\d+)$/'],
['${1}1:${2}1048576', 'A${1}:XFD${2}'],
$addressRange
);
return empty($worksheet) ? strtoupper($addressRange) : $worksheet . '!' . strtoupper($addressRange);
}
if (is_array($cellRange)) {
switch (count($cellRange)) {
case 2:
$from = [$cellRange[0], $cellRange[1]];
$to = [$cellRange[0], $cellRange[1]];
break;
case 4:
$from = [$cellRange[0], $cellRange[1]];
$to = [$cellRange[2], $cellRange[3]];
break;
default:
throw new SpreadsheetException('CellRange array length must be 2 or 4');
}
$cellRange = new CellRange(CellAddress::fromColumnRowArray($from), CellAddress::fromColumnRowArray($to));
}
return (string) $cellRange;
}
public static function definedNameToCoordinate(string $coordinate, Worksheet $worksheet): string
{
// Uppercase coordinate
$coordinate = strtoupper($coordinate);
// Eliminate leading equal sign
$testCoordinate = (string) preg_replace('/^=/', '', $coordinate);
$defined = $worksheet->getParent()->getDefinedName($testCoordinate, $worksheet);
if ($defined !== null) {
if ($defined->getWorksheet() === $worksheet && !$defined->isFormula()) {
$coordinate = (string) preg_replace('/^=/', '', $defined->getValue());
}
}
return $coordinate;
}
}

File diff suppressed because it is too large Load Diff