feat: Version 3.5.2 - Configuration Stripe et gestion des immeubles
- Configuration complète Stripe pour les 3 environnements (DEV/REC/PROD) * DEV: Clés TEST Pierre (mode test) * REC: Clés TEST Client (mode test) * PROD: Clés LIVE Client (mode live) - Ajout de la gestion des bases de données immeubles/bâtiments * Configuration buildings_database pour DEV/REC/PROD * Service BuildingService pour enrichissement des adresses - Optimisations pages et améliorations ergonomie - Mises à jour des dépendances Composer - Nettoyage des fichiers obsolètes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -50,7 +50,7 @@ class AutoFilter implements Stringable
|
||||
/**
|
||||
* Create a new AutoFilter.
|
||||
*
|
||||
* @param AddressRange<CellAddress>|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: int}|string $range
|
||||
* @param AddressRange<CellAddress>|AddressRange<int>|AddressRange<string>|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: 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.
|
||||
@@ -145,7 +145,7 @@ class AutoFilter implements Stringable
|
||||
$this->evaluated = false;
|
||||
if ($this->workSheet !== null) {
|
||||
$thisrange = $this->range;
|
||||
$range = (string) preg_replace('/\\d+$/', (string) $this->workSheet->getHighestRow(), $thisrange);
|
||||
$range = (string) preg_replace('/\d+$/', (string) $this->workSheet->getHighestRow(), $thisrange);
|
||||
if ($range !== $thisrange) {
|
||||
$this->setRange($range);
|
||||
}
|
||||
@@ -295,7 +295,7 @@ class AutoFilter implements Stringable
|
||||
$fromColumn = strtoupper($fromColumn);
|
||||
$toColumn = strtoupper($toColumn);
|
||||
|
||||
if (($fromColumn !== null) && (isset($this->columns[$fromColumn])) && ($toColumn !== null)) {
|
||||
if (isset($this->columns[$fromColumn])) {
|
||||
$this->columns[$fromColumn]->setParent();
|
||||
$this->columns[$fromColumn]->setColumnIndex($toColumn);
|
||||
$this->columns[$toColumn] = $this->columns[$fromColumn];
|
||||
@@ -317,7 +317,7 @@ class AutoFilter implements Stringable
|
||||
{
|
||||
$dataSetValues = $dataSet['filterValues'];
|
||||
$blanks = $dataSet['blanks'];
|
||||
if (($cellValue == '') || ($cellValue === null)) {
|
||||
if (($cellValue === '') || ($cellValue === null)) {
|
||||
return $blanks;
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ class AutoFilter implements Stringable
|
||||
{
|
||||
$dateSet = $dataSet['filterValues'];
|
||||
$blanks = $dataSet['blanks'];
|
||||
if (($cellValue == '') || ($cellValue === null)) {
|
||||
if (($cellValue === '') || ($cellValue === null)) {
|
||||
return $blanks;
|
||||
}
|
||||
$timeZone = new DateTimeZone('UTC');
|
||||
@@ -368,28 +368,26 @@ class AutoFilter implements Stringable
|
||||
/**
|
||||
* Test if cell value is within a set of values defined by a ruleset.
|
||||
*
|
||||
* @param mixed[] $ruleSet
|
||||
* @param mixed[][] $ruleSet
|
||||
*/
|
||||
protected static function filterTestInCustomDataSet(mixed $cellValue, array $ruleSet): bool
|
||||
{
|
||||
/** @var array[] $dataSet */
|
||||
$dataSet = $ruleSet['filterRules'];
|
||||
$join = $ruleSet['join'];
|
||||
$customRuleForBlanks = $ruleSet['customRuleForBlanks'] ?? false;
|
||||
|
||||
if (!$customRuleForBlanks) {
|
||||
// Blank cells are always ignored, so return a FALSE
|
||||
if (($cellValue == '') || ($cellValue === null)) {
|
||||
if (($cellValue === '') || ($cellValue === null)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$returnVal = ($join == AutoFilter\Column::AUTOFILTER_COLUMN_JOIN_AND);
|
||||
foreach ($dataSet as $rule) {
|
||||
/** @var string $ruleValue */
|
||||
/** @var string[] $rule */
|
||||
$ruleValue = $rule['value'];
|
||||
/** @var string $ruleOperator */
|
||||
$ruleOperator = $rule['operator'];
|
||||
/** @var string $cellValueString */
|
||||
/** @var string */
|
||||
$cellValueString = $cellValue ?? '';
|
||||
$retVal = false;
|
||||
|
||||
@@ -424,8 +422,8 @@ class AutoFilter implements Stringable
|
||||
}
|
||||
} elseif ($ruleValue == '') {
|
||||
$retVal = match ($ruleOperator) {
|
||||
Rule::AUTOFILTER_COLUMN_RULE_EQUAL => ($cellValue == '') || ($cellValue === null),
|
||||
Rule::AUTOFILTER_COLUMN_RULE_NOTEQUAL => ($cellValue != '') && ($cellValue !== null),
|
||||
Rule::AUTOFILTER_COLUMN_RULE_EQUAL => ($cellValue === '') || ($cellValue === null),
|
||||
Rule::AUTOFILTER_COLUMN_RULE_NOTEQUAL => ($cellValue != ''),
|
||||
default => true,
|
||||
};
|
||||
} else {
|
||||
@@ -486,7 +484,7 @@ class AutoFilter implements Stringable
|
||||
protected static function filterTestInPeriodDateSet(mixed $cellValue, array $monthSet): bool
|
||||
{
|
||||
// Blank cells are always ignored, so return a FALSE
|
||||
if (($cellValue == '') || ($cellValue === null)) {
|
||||
if (($cellValue === '') || ($cellValue === null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -529,6 +527,7 @@ class AutoFilter implements Stringable
|
||||
Rule::AUTOFILTER_RULETYPE_DYNAMIC_YESTERDAY => 'dynamicYesterday',
|
||||
];
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicLastMonth(): array
|
||||
{
|
||||
$maxval = new DateTime();
|
||||
@@ -554,6 +553,7 @@ class AutoFilter implements Stringable
|
||||
return $val;
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicLastQuarter(): array
|
||||
{
|
||||
$maxval = self::firstDayOfQuarter();
|
||||
@@ -563,6 +563,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicLastWeek(): array
|
||||
{
|
||||
$val = new DateTime();
|
||||
@@ -576,6 +577,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicLastYear(): array
|
||||
{
|
||||
$val = new DateTime();
|
||||
@@ -586,6 +588,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicNextMonth(): array
|
||||
{
|
||||
$val = new DateTime();
|
||||
@@ -600,6 +603,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicNextQuarter(): array
|
||||
{
|
||||
$val = self::firstDayOfQuarter();
|
||||
@@ -610,6 +614,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicNextWeek(): array
|
||||
{
|
||||
$val = new DateTime();
|
||||
@@ -623,6 +628,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicNextYear(): array
|
||||
{
|
||||
$val = new DateTime();
|
||||
@@ -633,6 +639,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicThisMonth(): array
|
||||
{
|
||||
$baseDate = new DateTime();
|
||||
@@ -646,6 +653,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicThisQuarter(): array
|
||||
{
|
||||
$val = self::firstDayOfQuarter();
|
||||
@@ -655,6 +663,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicThisWeek(): array
|
||||
{
|
||||
$val = new DateTime();
|
||||
@@ -668,6 +677,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicThisYear(): array
|
||||
{
|
||||
$val = new DateTime();
|
||||
@@ -678,6 +688,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicToday(): array
|
||||
{
|
||||
$val = new DateTime();
|
||||
@@ -688,6 +699,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicTomorrow(): array
|
||||
{
|
||||
$val = new DateTime();
|
||||
@@ -699,6 +711,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicYearToDate(): array
|
||||
{
|
||||
$maxval = new DateTime();
|
||||
@@ -709,6 +722,7 @@ class AutoFilter implements Stringable
|
||||
return [$val, $maxval];
|
||||
}
|
||||
|
||||
/** @return array{DateTime, DateTime} */
|
||||
private static function dynamicYesterday(): array
|
||||
{
|
||||
$maxval = new DateTime();
|
||||
@@ -732,7 +746,7 @@ class AutoFilter implements Stringable
|
||||
// Val is lowest permitted value.
|
||||
// Maxval is greater than highest permitted value
|
||||
$val = $maxval = 0;
|
||||
if (is_callable($callBack)) {
|
||||
if (is_callable($callBack)) { //* @phpstan-ignore-line
|
||||
[$val, $maxval] = $callBack();
|
||||
}
|
||||
$val = Date::dateTimeToExcel($val);
|
||||
@@ -941,6 +955,7 @@ class AutoFilter implements Stringable
|
||||
if ($periodType == 'M') {
|
||||
$ruleValues = [$period];
|
||||
} else {
|
||||
/** @var int $period */
|
||||
--$period;
|
||||
$periodEnd = (1 + $period) * 3;
|
||||
$periodStart = 1 + $period * 3;
|
||||
@@ -1071,7 +1086,7 @@ class AutoFilter implements Stringable
|
||||
// The columns array of \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\AutoFilter objects
|
||||
$this->{$key} = [];
|
||||
foreach ($value as $k => $v) {
|
||||
$this->{$key}[$k] = clone $v;
|
||||
$this->{$key}[$k] = clone $v; //* @phpstan-ignore-line
|
||||
// attach the new cloned Column to this new cloned Autofilter object
|
||||
$this->{$key}[$k]->setParent($this);
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ class Column
|
||||
public function __clone()
|
||||
{
|
||||
$vars = get_object_vars($this);
|
||||
/** @var AutoFilter\Column\Rule[] $value */
|
||||
/** @var Column\Rule[] $value */
|
||||
foreach ($vars as $key => $value) {
|
||||
if ($key === 'parent') {
|
||||
// Detach from autofilter parent
|
||||
|
||||
@@ -330,8 +330,7 @@ class Rule
|
||||
{
|
||||
$this->setEvaluatedFalse();
|
||||
if (
|
||||
($grouping !== null)
|
||||
&& (!in_array($grouping, self::DATE_TIME_GROUPS))
|
||||
(!in_array($grouping, self::DATE_TIME_GROUPS))
|
||||
&& (!in_array($grouping, self::DYNAMIC_TYPES))
|
||||
&& (!in_array($grouping, self::TOP_TEN_TYPE))
|
||||
) {
|
||||
|
||||
@@ -15,18 +15,16 @@ class AutoFit
|
||||
$this->worksheet = $worksheet;
|
||||
}
|
||||
|
||||
/** @return mixed[] */
|
||||
public function getAutoFilterIndentRanges(): array
|
||||
{
|
||||
$autoFilterIndentRanges = [];
|
||||
$autoFilterIndentRanges[] = $this->getAutoFilterIndentRange($this->worksheet->getAutoFilter());
|
||||
|
||||
foreach ($this->worksheet->getTableCollection() as $table) {
|
||||
/** @var Table $table */
|
||||
if ($table->getShowHeaderRow() === true && $table->getAllowFilter() === true) {
|
||||
$autoFilter = $table->getAutoFilter();
|
||||
if ($autoFilter !== null) {
|
||||
$autoFilterIndentRanges[] = $this->getAutoFilterIndentRange($autoFilter);
|
||||
}
|
||||
$autoFilterIndentRanges[] = $this->getAutoFilterIndentRange($autoFilter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -131,6 +131,12 @@ class BaseDrawing implements IComparable
|
||||
/** @var null|SimpleXMLElement|string[] */
|
||||
protected $srcRect = [];
|
||||
|
||||
/**
|
||||
* Percentage multiplied by 100,000, e.g. 40% = 40,000.
|
||||
* Opacity=x is the same as transparency=100000-x.
|
||||
*/
|
||||
protected ?int $opacity = null;
|
||||
|
||||
/**
|
||||
* Create a new BaseDrawing.
|
||||
*/
|
||||
@@ -352,9 +358,12 @@ class BaseDrawing implements IComparable
|
||||
*/
|
||||
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 ($this->width === 0 || $this->height === 0 || $width === 0 || $height === 0 || !$this->resizeProportional) {
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
} else {
|
||||
$xratio = $width / $this->width;
|
||||
$yratio = $height / $this->height;
|
||||
if (($xratio * $this->height) < $height) {
|
||||
$this->height = (int) ceil($xratio * $this->height);
|
||||
$this->width = $width;
|
||||
@@ -362,9 +371,6 @@ class BaseDrawing implements IComparable
|
||||
$this->width = (int) ceil($yratio * $this->width);
|
||||
$this->height = $height;
|
||||
}
|
||||
} else {
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -554,4 +560,16 @@ class BaseDrawing implements IComparable
|
||||
{
|
||||
return $this->flipVertical;
|
||||
}
|
||||
|
||||
public function setOpacity(?int $opacity): self
|
||||
{
|
||||
$this->opacity = $opacity;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOpacity(): ?int
|
||||
{
|
||||
return $this->opacity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ use PhpOffice\PhpSpreadsheet\Helper\Dimension as CssDimension;
|
||||
|
||||
class ColumnDimension extends Dimension
|
||||
{
|
||||
public const EXCEL_MAX_WIDTH = 255.0;
|
||||
|
||||
/**
|
||||
* Column index.
|
||||
*/
|
||||
@@ -89,6 +91,11 @@ class ColumnDimension extends Dimension
|
||||
: (new CssDimension((string) $this->width))->toUnit($unitOfMeasure);
|
||||
}
|
||||
|
||||
public function getWidthForOutput(bool $restrictMax): float
|
||||
{
|
||||
return ($restrictMax && $this->width > self::EXCEL_MAX_WIDTH) ? self::EXCEL_MAX_WIDTH : $this->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Width.
|
||||
*
|
||||
|
||||
@@ -92,7 +92,7 @@ class Drawing extends BaseDrawing
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPath(string $path, bool $verifyFile = true, ?ZipArchive $zip = null): static
|
||||
public function setPath(string $path, bool $verifyFile = true, ?ZipArchive $zip = null, bool $allowExternal = true): static
|
||||
{
|
||||
$this->isUrl = false;
|
||||
if (preg_match('~^data:image/[a-z]+;base64,~', $path) === 1) {
|
||||
@@ -103,10 +103,13 @@ class Drawing extends BaseDrawing
|
||||
|
||||
$this->path = '';
|
||||
// Check if a URL has been passed. https://stackoverflow.com/a/2058596/1252979
|
||||
if (filter_var($path, FILTER_VALIDATE_URL) || (preg_match('/^([\\w\\s\\x00-\\x1f]+):/u', $path) && !preg_match('/^([\\w]+):/u', $path))) {
|
||||
if (filter_var($path, FILTER_VALIDATE_URL) || (preg_match('/^([\w\s\x00-\x1f]+):/u', $path) && !preg_match('/^([\w]+):/u', $path))) {
|
||||
if (!preg_match('/^(http|https|file|ftp|s3):/', $path)) {
|
||||
throw new PhpSpreadsheetException('Invalid protocol for linked drawing');
|
||||
}
|
||||
if (!$allowExternal) {
|
||||
return $this;
|
||||
}
|
||||
// Implicit that it is a URL, rather store info than running check above on value in other places.
|
||||
$this->isUrl = true;
|
||||
$ctx = null;
|
||||
@@ -192,20 +195,6 @@ class Drawing extends BaseDrawing
|
||||
return $this->isUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set isURL.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @deprecated 3.7.0 not needed, property is set by setPath
|
||||
*/
|
||||
public function setIsURL(bool $isUrl): self
|
||||
{
|
||||
$this->isUrl = $isUrl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hash code.
|
||||
*
|
||||
|
||||
@@ -67,11 +67,29 @@ class HeaderFooter
|
||||
{
|
||||
// Header/footer image location
|
||||
const IMAGE_HEADER_LEFT = 'LH';
|
||||
const IMAGE_HEADER_LEFT_ODD = 'LH';
|
||||
const IMAGE_HEADER_LEFT_FIRST = 'LHFIRST';
|
||||
const IMAGE_HEADER_LEFT_EVEN = 'LHEVEN';
|
||||
const IMAGE_HEADER_CENTER = 'CH';
|
||||
const IMAGE_HEADER_CENTER_ODD = 'CH';
|
||||
const IMAGE_HEADER_CENTER_FIRST = 'CHFIRST';
|
||||
const IMAGE_HEADER_CENTER_EVEN = 'CHEVEN';
|
||||
const IMAGE_HEADER_RIGHT = 'RH';
|
||||
const IMAGE_HEADER_RIGHT_ODD = 'RH';
|
||||
const IMAGE_HEADER_RIGHT_FIRST = 'RHFIRST';
|
||||
const IMAGE_HEADER_RIGHT_EVEN = 'RHEVEN';
|
||||
const IMAGE_FOOTER_LEFT = 'LF';
|
||||
const IMAGE_FOOTER_LEFT_ODD = 'LF';
|
||||
const IMAGE_FOOTER_LEFT_FIRST = 'LFFIRST';
|
||||
const IMAGE_FOOTER_LEFT_EVEN = 'LFEVEN';
|
||||
const IMAGE_FOOTER_CENTER = 'CF';
|
||||
const IMAGE_FOOTER_CENTER_ODD = 'CF';
|
||||
const IMAGE_FOOTER_CENTER_FIRST = 'CFFIRST';
|
||||
const IMAGE_FOOTER_CENTER_EVEN = 'CFEVEN';
|
||||
const IMAGE_FOOTER_RIGHT = 'RF';
|
||||
const IMAGE_FOOTER_RIGHT_ODD = 'RF';
|
||||
const IMAGE_FOOTER_RIGHT_FIRST = 'RFFIRST';
|
||||
const IMAGE_FOOTER_RIGHT_EVEN = 'RFEVEN';
|
||||
|
||||
/**
|
||||
* OddHeader.
|
||||
@@ -377,6 +395,27 @@ class HeaderFooter
|
||||
return $this;
|
||||
}
|
||||
|
||||
private const IMAGE_SORT_ORDER = [
|
||||
self::IMAGE_HEADER_LEFT,
|
||||
self::IMAGE_HEADER_LEFT_FIRST,
|
||||
self::IMAGE_HEADER_LEFT_EVEN,
|
||||
self::IMAGE_HEADER_CENTER,
|
||||
self::IMAGE_HEADER_CENTER_FIRST,
|
||||
self::IMAGE_HEADER_CENTER_EVEN,
|
||||
self::IMAGE_HEADER_RIGHT,
|
||||
self::IMAGE_HEADER_RIGHT_FIRST,
|
||||
self::IMAGE_HEADER_RIGHT_EVEN,
|
||||
self::IMAGE_FOOTER_LEFT,
|
||||
self::IMAGE_FOOTER_LEFT_FIRST,
|
||||
self::IMAGE_FOOTER_LEFT_EVEN,
|
||||
self::IMAGE_FOOTER_CENTER,
|
||||
self::IMAGE_FOOTER_CENTER_FIRST,
|
||||
self::IMAGE_FOOTER_CENTER_EVEN,
|
||||
self::IMAGE_FOOTER_RIGHT,
|
||||
self::IMAGE_FOOTER_RIGHT_FIRST,
|
||||
self::IMAGE_FOOTER_RIGHT_EVEN,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get header/footer images.
|
||||
*
|
||||
@@ -384,25 +423,12 @@ class HeaderFooter
|
||||
*/
|
||||
public function getImages(): array
|
||||
{
|
||||
// Sort array
|
||||
// Sort array - not sure why needed
|
||||
$images = [];
|
||||
if (isset($this->headerFooterImages[self::IMAGE_HEADER_LEFT])) {
|
||||
$images[self::IMAGE_HEADER_LEFT] = $this->headerFooterImages[self::IMAGE_HEADER_LEFT];
|
||||
}
|
||||
if (isset($this->headerFooterImages[self::IMAGE_HEADER_CENTER])) {
|
||||
$images[self::IMAGE_HEADER_CENTER] = $this->headerFooterImages[self::IMAGE_HEADER_CENTER];
|
||||
}
|
||||
if (isset($this->headerFooterImages[self::IMAGE_HEADER_RIGHT])) {
|
||||
$images[self::IMAGE_HEADER_RIGHT] = $this->headerFooterImages[self::IMAGE_HEADER_RIGHT];
|
||||
}
|
||||
if (isset($this->headerFooterImages[self::IMAGE_FOOTER_LEFT])) {
|
||||
$images[self::IMAGE_FOOTER_LEFT] = $this->headerFooterImages[self::IMAGE_FOOTER_LEFT];
|
||||
}
|
||||
if (isset($this->headerFooterImages[self::IMAGE_FOOTER_CENTER])) {
|
||||
$images[self::IMAGE_FOOTER_CENTER] = $this->headerFooterImages[self::IMAGE_FOOTER_CENTER];
|
||||
}
|
||||
if (isset($this->headerFooterImages[self::IMAGE_FOOTER_RIGHT])) {
|
||||
$images[self::IMAGE_FOOTER_RIGHT] = $this->headerFooterImages[self::IMAGE_FOOTER_RIGHT];
|
||||
foreach (self::IMAGE_SORT_ORDER as $key) {
|
||||
if (isset($this->headerFooterImages[$key])) {
|
||||
$images[$key] = $this->headerFooterImages[$key];
|
||||
}
|
||||
}
|
||||
$this->headerFooterImages = $images;
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ class MemoryDrawing extends BaseDrawing
|
||||
|
||||
/**
|
||||
* Rendering function.
|
||||
*
|
||||
* @var callable-string
|
||||
*/
|
||||
private string $renderingFunction;
|
||||
|
||||
@@ -62,10 +64,7 @@ class MemoryDrawing extends BaseDrawing
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->imageResource) {
|
||||
@imagedestroy($this->imageResource);
|
||||
$this->imageResource = null;
|
||||
}
|
||||
$this->imageResource = null;
|
||||
$this->worksheet = null;
|
||||
}
|
||||
|
||||
@@ -128,9 +127,6 @@ class MemoryDrawing extends BaseDrawing
|
||||
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);
|
||||
}
|
||||
@@ -161,6 +157,7 @@ class MemoryDrawing extends BaseDrawing
|
||||
return $drawing;
|
||||
}
|
||||
|
||||
/** @return callable-string */
|
||||
private static function identifyRenderingFunction(string $mimeType): string
|
||||
{
|
||||
return match ($mimeType) {
|
||||
@@ -261,6 +258,8 @@ class MemoryDrawing extends BaseDrawing
|
||||
|
||||
/**
|
||||
* Get rendering function.
|
||||
*
|
||||
* @return callable-string
|
||||
*/
|
||||
public function getRenderingFunction(): string
|
||||
{
|
||||
@@ -270,7 +269,7 @@ class MemoryDrawing extends BaseDrawing
|
||||
/**
|
||||
* Set rendering function.
|
||||
*
|
||||
* @param string $value see self::RENDERING_*
|
||||
* @param callable-string $value see self::RENDERING_*
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
@@ -208,14 +208,14 @@ class PageSetup
|
||||
/**
|
||||
* Columns to repeat at left.
|
||||
*
|
||||
* @var array Containing start column and end column, empty array if option unset
|
||||
* @var array{string, string} Containing start column and end column, empty array if option unset
|
||||
*/
|
||||
private array $columnsToRepeatAtLeft = ['', ''];
|
||||
|
||||
/**
|
||||
* Rows to repeat at top.
|
||||
*
|
||||
* @var array Containing start row number and end row number, empty array if option unset
|
||||
* @var int[] Containing start row number and end row number, empty array if option unset
|
||||
*/
|
||||
private array $rowsToRepeatAtTop = [0, 0];
|
||||
|
||||
@@ -443,7 +443,7 @@ class PageSetup
|
||||
/**
|
||||
* Get Columns to repeat at left.
|
||||
*
|
||||
* @return array Containing start column and end column, empty array if option unset
|
||||
* @return array{string, string} Containing start column and end column, empty array if option unset
|
||||
*/
|
||||
public function getColumnsToRepeatAtLeft(): array
|
||||
{
|
||||
@@ -453,7 +453,7 @@ class PageSetup
|
||||
/**
|
||||
* Set Columns to repeat at left.
|
||||
*
|
||||
* @param array $columnsToRepeatAtLeft Containing start column and end column, empty array if option unset
|
||||
* @param array{string, string} $columnsToRepeatAtLeft Containing start column and end column, empty array if option unset
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
@@ -496,7 +496,7 @@ class PageSetup
|
||||
/**
|
||||
* Get Rows to repeat at top.
|
||||
*
|
||||
* @return array Containing start column and end column, empty array if option unset
|
||||
* @return int[] Containing start column and end column, empty array if option unset
|
||||
*/
|
||||
public function getRowsToRepeatAtTop(): array
|
||||
{
|
||||
@@ -506,7 +506,7 @@ class PageSetup
|
||||
/**
|
||||
* Set Rows to repeat at top.
|
||||
*
|
||||
* @param array $rowsToRepeatAtTop Containing start column and end column, empty array if option unset
|
||||
* @param int[] $rowsToRepeatAtTop Containing start column and end column, empty array if option unset
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Worksheet;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||
|
||||
class ProtectedRange
|
||||
{
|
||||
private string $name = '';
|
||||
@@ -42,4 +44,16 @@ class ProtectedRange
|
||||
{
|
||||
return $this->securityDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split range into coordinate strings.
|
||||
*
|
||||
* @return array<array<string>> Array containing one or more arrays containing one or two coordinate strings
|
||||
* e.g. ['B4','D9'] or [['B4','D9'], ['H2','O11']]
|
||||
* or ['B4']
|
||||
*/
|
||||
public function allRanges(): array
|
||||
{
|
||||
return Coordinate::allRanges($this->sqref, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class Table implements Stringable
|
||||
/**
|
||||
* Create a new Table.
|
||||
*
|
||||
* @param AddressRange<CellAddress>|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: int}|string $range
|
||||
* @param AddressRange<CellAddress>|AddressRange<int>|AddressRange<string>|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: 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.
|
||||
@@ -117,10 +117,10 @@ class Table implements Stringable
|
||||
) {
|
||||
throw new PhpSpreadsheetException('The table name can\'t be the same as a cell reference');
|
||||
}
|
||||
if (!preg_match('/^[\p{L}_\\\\]/iu', $name)) {
|
||||
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)) {
|
||||
if (!preg_match('/^[\p{L}_\\\][\p{L}\p{M}0-9\._]+$/iu', $name)) {
|
||||
throw new PhpSpreadsheetException('The table name contains invalid characters');
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ class Table implements Stringable
|
||||
/**
|
||||
* Set Table Cell Range.
|
||||
*
|
||||
* @param AddressRange<CellAddress>|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: int}|string $range
|
||||
* @param AddressRange<CellAddress>|AddressRange<int>|AddressRange<string>|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: 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.
|
||||
@@ -318,7 +318,7 @@ class Table implements Stringable
|
||||
{
|
||||
if ($this->workSheet !== null) {
|
||||
$thisrange = $this->range;
|
||||
$range = (string) preg_replace('/\\d+$/', (string) $this->workSheet->getHighestRow(), $thisrange);
|
||||
$range = (string) preg_replace('/\d+$/', (string) $this->workSheet->getHighestRow(), $thisrange);
|
||||
if ($range !== $thisrange) {
|
||||
$this->setRange($range);
|
||||
}
|
||||
@@ -442,7 +442,7 @@ class Table implements Stringable
|
||||
{
|
||||
if ((is_string($columnObjectOrString)) && (!empty($columnObjectOrString))) {
|
||||
$column = $columnObjectOrString;
|
||||
} elseif (is_object($columnObjectOrString) && ($columnObjectOrString instanceof Table\Column)) {
|
||||
} elseif ($columnObjectOrString instanceof Table\Column) {
|
||||
$column = $columnObjectOrString->getColumnIndex();
|
||||
} else {
|
||||
throw new PhpSpreadsheetException('Column is not within the table range.');
|
||||
@@ -491,7 +491,7 @@ class Table implements Stringable
|
||||
$fromColumn = strtoupper($fromColumn);
|
||||
$toColumn = strtoupper($toColumn);
|
||||
|
||||
if (($fromColumn !== null) && (isset($this->columns[$fromColumn])) && ($toColumn !== null)) {
|
||||
if (isset($this->columns[$fromColumn])) {
|
||||
$this->columns[$fromColumn]->setTable();
|
||||
$this->columns[$fromColumn]->setColumnIndex($toColumn);
|
||||
$this->columns[$toColumn] = $this->columns[$fromColumn];
|
||||
@@ -540,6 +540,19 @@ class Table implements Stringable
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the row number on this table for given coordinates.
|
||||
*/
|
||||
public function getRowNumber(string $coordinate): int
|
||||
{
|
||||
$range = $this->getRange();
|
||||
$coords = Coordinate::splitRange($range);
|
||||
$firstCell = Coordinate::coordinateFromString($coords[0][0]);
|
||||
$thisCell = Coordinate::coordinateFromString($coordinate);
|
||||
|
||||
return (int) $thisCell[1] - (int) $firstCell[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement PHP __clone to create a deep clone, not just a shallow copy.
|
||||
*/
|
||||
@@ -558,6 +571,7 @@ class Table implements Stringable
|
||||
// The columns array of \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\Table objects
|
||||
$this->{$key} = [];
|
||||
foreach ($value as $k => $v) {
|
||||
/** @var Table\Column $v */
|
||||
$this->{$key}[$k] = clone $v;
|
||||
// attach the new cloned Column to this new cloned Table object
|
||||
$this->{$key}[$k]->setTable($this);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Worksheet\Table;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Style\Style;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Table;
|
||||
|
||||
class TableStyle
|
||||
@@ -93,6 +94,11 @@ class TableStyle
|
||||
*/
|
||||
private bool $showColumnStripes = false;
|
||||
|
||||
/**
|
||||
* TableDxfsStyle.
|
||||
*/
|
||||
private ?TableDxfsStyle $tableStyle = null;
|
||||
|
||||
/**
|
||||
* Table.
|
||||
*/
|
||||
@@ -198,6 +204,36 @@ class TableStyle
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this Style's Dxfs TableStyle.
|
||||
*/
|
||||
public function getTableDxfsStyle(): ?TableDxfsStyle
|
||||
{
|
||||
return $this->tableStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this Style's Dxfs TableStyle.
|
||||
*
|
||||
* @param Style[] $dxfs
|
||||
*/
|
||||
public function setTableDxfsStyle(TableDxfsStyle $tableStyle, array $dxfs): self
|
||||
{
|
||||
$this->tableStyle = $tableStyle;
|
||||
|
||||
if ($this->tableStyle->getHeaderRow() !== null && isset($dxfs[$this->tableStyle->getHeaderRow()])) {
|
||||
$this->tableStyle->setHeaderRowStyle($dxfs[$this->tableStyle->getHeaderRow()]);
|
||||
}
|
||||
if ($this->tableStyle->getFirstRowStripe() !== null && isset($dxfs[$this->tableStyle->getFirstRowStripe()])) {
|
||||
$this->tableStyle->setFirstRowStripeStyle($dxfs[$this->tableStyle->getFirstRowStripe()]);
|
||||
}
|
||||
if ($this->tableStyle->getSecondRowStripe() !== null && isset($dxfs[$this->tableStyle->getSecondRowStripe()])) {
|
||||
$this->tableStyle->setSecondRowStripeStyle($dxfs[$this->tableStyle->getSecondRowStripe()]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this Style's Table.
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Worksheet;
|
||||
|
||||
use Composer\Pcre\Preg;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\AddressRange;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\CellRange;
|
||||
@@ -36,7 +37,7 @@ class Validations
|
||||
/**
|
||||
* Validate a cell address or cell range.
|
||||
*
|
||||
* @param AddressRange<CellAddress>|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: int}|CellAddress|int|string $cellRange Coordinate of the cells as a string, eg: 'C5:F12';
|
||||
* @param AddressRange<CellAddress>|AddressRange<int>|AddressRange<string>|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: 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.
|
||||
*/
|
||||
@@ -45,7 +46,7 @@ class Validations
|
||||
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);
|
||||
$cellRange = Preg::replace('/^([A-Z]+|\d+)$/', '${1}:${1}', (string) $cellRange);
|
||||
} elseif (is_object($cellRange) && $cellRange instanceof CellAddress) {
|
||||
$cellRange = new CellRange($cellRange, $cellRange);
|
||||
}
|
||||
@@ -56,10 +57,23 @@ class Validations
|
||||
private const SETMAXROW = '${1}1:${2}' . AddressRange::MAX_ROW;
|
||||
private const SETMAXCOL = 'A${1}:' . AddressRange::MAX_COLUMN . '${2}';
|
||||
|
||||
/**
|
||||
* Convert Column ranges like 'A:C' to 'A1:C1048576'
|
||||
* or Row ranges like '1:3' to 'A1:XFD3'.
|
||||
*/
|
||||
public static function convertWholeRowColumn(?string $addressRange): string
|
||||
{
|
||||
return Preg::replace(
|
||||
['/^([A-Z]+):([A-Z]+)$/i', '/^(\d+):(\d+)$/'],
|
||||
[self::SETMAXROW, self::SETMAXCOL],
|
||||
$addressRange ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a cell range.
|
||||
*
|
||||
* @param AddressRange<CellAddress>|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: int}|string $cellRange Coordinate of the cells as a string, eg: 'C5:F12';
|
||||
* @param AddressRange<CellAddress>|AddressRange<int>|AddressRange<string>|array{0: int, 1: int, 2: int, 3: int}|array{0: int, 1: 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.
|
||||
*/
|
||||
@@ -70,11 +84,7 @@ class Validations
|
||||
|
||||
// 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+)$/'],
|
||||
[self::SETMAXROW, self::SETMAXCOL],
|
||||
$addressRange ?? ''
|
||||
);
|
||||
$addressRange = self::convertWholeRowColumn($addressRange);
|
||||
|
||||
return empty($worksheet) ? strtoupper($addressRange) : $worksheet . '!' . strtoupper($addressRange);
|
||||
}
|
||||
@@ -105,11 +115,11 @@ class Validations
|
||||
// Uppercase coordinate
|
||||
$coordinate = strtoupper($coordinate);
|
||||
// Eliminate leading equal sign
|
||||
$testCoordinate = (string) preg_replace('/^=/', '', $coordinate);
|
||||
$testCoordinate = Preg::replace('/^=/', '', $coordinate);
|
||||
$defined = $worksheet->getParentOrThrow()->getDefinedName($testCoordinate, $worksheet);
|
||||
if ($defined !== null) {
|
||||
if ($defined->getWorksheet() === $worksheet && !$defined->isFormula()) {
|
||||
$coordinate = (string) preg_replace('/^=/', '', $defined->getValue());
|
||||
$coordinate = Preg::replace('/^=/', '', $defined->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user