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:
pierre
2025-11-09 18:26:27 +01:00
parent 21657a3820
commit 2f5946a184
812 changed files with 142105 additions and 25992 deletions

View File

@@ -4,17 +4,16 @@ namespace PhpOffice\PhpSpreadsheet;
use JsonSerializable;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Cell\IValueBinder;
use PhpOffice\PhpSpreadsheet\Document\Properties;
use PhpOffice\PhpSpreadsheet\Document\Security;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Shared\File;
use PhpOffice\PhpSpreadsheet\Shared\Font as SharedFont;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
use PhpOffice\PhpSpreadsheet\Style\Style;
use PhpOffice\PhpSpreadsheet\Worksheet\Iterator;
use PhpOffice\PhpSpreadsheet\Worksheet\Table;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
class Spreadsheet implements JsonSerializable
{
@@ -59,7 +58,7 @@ class Spreadsheet implements JsonSerializable
/**
* Calculation Engine.
*/
private ?Calculation $calculationEngine;
private Calculation $calculationEngine;
/**
* Active sheet index.
@@ -117,12 +116,16 @@ class Spreadsheet implements JsonSerializable
/**
* ribbonBinObjects : null if workbook is'nt Excel 2007 or not contain embedded objects (picture(s)) for Ribbon Elements
* ignored if $ribbonXMLData is null.
*
* @var null|mixed[]
*/
private ?array $ribbonBinObjects = null;
/**
* List of unparsed loaded data for export to same format with better compatibility.
* It has to be minimized when the library start to support currently unparsed data.
*
* @var array<array<array<array<string>|string>>>
*/
private array $unparsedLoadedData = [];
@@ -173,6 +176,38 @@ class Spreadsheet implements JsonSerializable
private Theme $theme;
private ?IValueBinder $valueBinder = null;
/** @var array<string, int> */
private array $fontCharsets = [
'B Nazanin' => SharedFont::CHARSET_ANSI_ARABIC,
];
/**
* @param int $charset uses any value from Shared\Font,
* but defaults to ARABIC because that is the only known
* charset for which this declaration might be needed
*/
public function addFontCharset(string $fontName, int $charset = SharedFont::CHARSET_ANSI_ARABIC): void
{
$this->fontCharsets[$fontName] = $charset;
}
public function getFontCharset(string $fontName): int
{
return $this->fontCharsets[$fontName] ?? -1;
}
/**
* Return all fontCharsets.
*
* @return array<string, int>
*/
public function getFontCharsets(): array
{
return $this->fontCharsets;
}
public function getTheme(): Theme
{
return $this->theme;
@@ -198,10 +233,8 @@ class Spreadsheet implements JsonSerializable
/**
* Set the macros code.
*
* @param string $macroCode string|null
*/
public function setMacrosCode(string $macroCode): void
public function setMacrosCode(?string $macroCode): void
{
$this->macrosCode = $macroCode;
$this->setHasMacros($macroCode !== null);
@@ -265,6 +298,8 @@ class Spreadsheet implements JsonSerializable
/**
* retrieve ribbon XML Data.
*
* @return mixed[]
*/
public function getRibbonXMLData(string $what = 'all'): null|array|string //we need some constants here...
{
@@ -304,6 +339,8 @@ class Spreadsheet implements JsonSerializable
* It has to be minimized when the library start to support currently unparsed data.
*
* @internal
*
* @return mixed[]
*/
public function getUnparsedLoadedData(): array
{
@@ -315,6 +352,8 @@ class Spreadsheet implements JsonSerializable
* It has to be minimized when the library start to support currently unparsed data.
*
* @internal
*
* @param array<array<array<array<string>|string>>> $unparsedLoadedData
*/
public function setUnparsedLoadedData(array $unparsedLoadedData): void
{
@@ -323,6 +362,8 @@ class Spreadsheet implements JsonSerializable
/**
* retrieve Binaries Ribbon Objects.
*
* @return mixed[]
*/
public function getRibbonBinObjects(string $what = 'all'): ?array
{
@@ -333,7 +374,7 @@ class Spreadsheet implements JsonSerializable
return $this->ribbonBinObjects;
case 'names':
case 'data':
if (is_array($this->ribbonBinObjects) && isset($this->ribbonBinObjects[$what])) {
if (is_array($this->ribbonBinObjects) && is_array($this->ribbonBinObjects[$what] ?? null)) {
$ReturnData = $this->ribbonBinObjects[$what];
}
@@ -436,7 +477,7 @@ class Spreadsheet implements JsonSerializable
public function __destruct()
{
$this->disconnectWorksheets();
$this->calculationEngine = null;
unset($this->calculationEngine);
$this->cellXfCollection = [];
$this->cellStyleXfCollection = [];
$this->definedNames = [];
@@ -458,11 +499,25 @@ class Spreadsheet implements JsonSerializable
/**
* Return the calculation engine for this worksheet.
*/
public function getCalculationEngine(): ?Calculation
public function getCalculationEngine(): Calculation
{
return $this->calculationEngine;
}
/**
* Intended for use only via a destructor.
*
* @internal
*/
public function getCalculationEngineOrNull(): ?Calculation
{
if (!isset($this->calculationEngine)) { //* @phpstan-ignore-line
return null;
}
return $this->calculationEngine;
}
/**
* Get properties.
*/
@@ -526,6 +581,15 @@ class Spreadsheet implements JsonSerializable
return $this->getSheetByName($worksheetName) !== null;
}
public function duplicateWorksheetByTitle(string $title): Worksheet
{
$original = $this->getSheetByNameOrThrow($title);
$index = $this->getIndex($original) + 1;
$clone = clone $original;
return $this->addSheet($clone, $index, true);
}
/**
* Add sheet.
*
@@ -641,10 +705,10 @@ class Spreadsheet implements JsonSerializable
*/
public function getSheetByName(string $worksheetName): ?Worksheet
{
$worksheetCount = count($this->workSheetCollection);
for ($i = 0; $i < $worksheetCount; ++$i) {
if (strcasecmp($this->workSheetCollection[$i]->getTitle(), trim($worksheetName, "'")) === 0) {
return $this->workSheetCollection[$i];
$trimWorksheetName = StringHelper::strToUpper(trim($worksheetName, "'"));
foreach ($this->workSheetCollection as $worksheet) {
if (StringHelper::strToUpper($worksheet->getTitle()) === $trimWorksheetName) {
return $worksheet;
}
}
@@ -967,13 +1031,34 @@ class Spreadsheet implements JsonSerializable
if ($definedName !== '') {
$definedName = StringHelper::strToUpper($definedName);
// first look for global defined name
if (isset($this->definedNames[$definedName])) {
$returnValue = $this->definedNames[$definedName];
foreach ($this->definedNames as $dn) {
$upper = StringHelper::strToUpper($dn->getName());
if (
!$dn->getLocalOnly()
&& $definedName === $upper
) {
$returnValue = $dn;
break;
}
}
// then look for local defined name (has priority over global defined name if both names exist)
if (($worksheet !== null) && isset($this->definedNames[$worksheet->getTitle() . '!' . $definedName])) {
$returnValue = $this->definedNames[$worksheet->getTitle() . '!' . $definedName];
if ($worksheet !== null) {
$wsTitle = StringHelper::strToUpper($worksheet->getTitle());
$definedName = (string) preg_replace('/^.*!/', '', $definedName);
foreach ($this->definedNames as $dn) {
$sheet = $dn->getScope() ?? $dn->getWorksheet();
$upper = StringHelper::strToUpper($dn->getName());
$upperTitle = StringHelper::strToUpper((string) $sheet?->getTitle());
if (
$dn->getLocalOnly()
&& $upper === $definedName
&& $upperTitle === $wsTitle
) {
return $dn;
}
}
}
}
@@ -1051,24 +1136,89 @@ class Spreadsheet implements JsonSerializable
*/
public function copy(): self
{
$filename = File::temporaryFilename();
$writer = new XlsxWriter($this);
$writer->setIncludeCharts(true);
$writer->save($filename);
$reader = new XlsxReader();
$reader->setIncludeCharts(true);
$reloadedSpreadsheet = $reader->load($filename);
unlink($filename);
return $reloadedSpreadsheet;
return unserialize(serialize($this)); //* @phpstan-ignore-line
}
/**
* Implement PHP __clone to create a deep clone, not just a shallow copy.
*/
public function __clone()
{
throw new Exception(
'Do not use clone on spreadsheet. Use spreadsheet->copy() instead.'
);
$this->uniqueID = uniqid('', true);
$usedKeys = [];
// I don't now why new Style rather than clone.
$this->cellXfSupervisor = new Style(true);
//$this->cellXfSupervisor = clone $this->cellXfSupervisor;
$this->cellXfSupervisor->bindParent($this);
$usedKeys['cellXfSupervisor'] = true;
$oldCalc = $this->calculationEngine;
$this->calculationEngine = new Calculation($this);
$this->calculationEngine
->setSuppressFormulaErrors(
$oldCalc->getSuppressFormulaErrors()
)
->setCalculationCacheEnabled(
$oldCalc->getCalculationCacheEnabled()
)
->setBranchPruningEnabled(
$oldCalc->getBranchPruningEnabled()
)
->setInstanceArrayReturnType(
$oldCalc->getInstanceArrayReturnType()
);
$usedKeys['calculationEngine'] = true;
$currentCollection = $this->cellStyleXfCollection;
$this->cellStyleXfCollection = [];
foreach ($currentCollection as $item) {
$clone = $item->exportArray();
$style = (new Style())->applyFromArray($clone);
$this->addCellStyleXf($style);
}
$usedKeys['cellStyleXfCollection'] = true;
$currentCollection = $this->cellXfCollection;
$this->cellXfCollection = [];
foreach ($currentCollection as $item) {
$clone = $item->exportArray();
$style = (new Style())->applyFromArray($clone);
$this->addCellXf($style);
}
$usedKeys['cellXfCollection'] = true;
$currentCollection = $this->workSheetCollection;
$this->workSheetCollection = [];
foreach ($currentCollection as $item) {
$clone = clone $item;
$clone->setParent($this);
$this->workSheetCollection[] = $clone;
}
$usedKeys['workSheetCollection'] = true;
foreach (get_object_vars($this) as $key => $val) {
if (isset($usedKeys[$key])) {
continue;
}
switch ($key) {
// arrays of objects not covered above
case 'definedNames':
/** @var DefinedName[] */
$currentCollection = $val;
$this->$key = [];
foreach ($currentCollection as $item) {
$clone = clone $item;
$this->{$key}[] = $clone;
}
break;
default:
if (is_object($val)) {
$this->$key = clone $val;
}
}
}
}
/**
@@ -1089,6 +1239,11 @@ class Spreadsheet implements JsonSerializable
return $this->cellXfCollection[$cellStyleIndex];
}
public function getCellXfByIndexOrNull(?int $cellStyleIndex): ?Style
{
return ($cellStyleIndex === null) ? null : ($this->cellXfCollection[$cellStyleIndex] ?? null);
}
/**
* Get cellXf by hash code.
*
@@ -1525,14 +1680,6 @@ class Spreadsheet implements JsonSerializable
}
}
/**
* @throws Exception
*/
public function __serialize(): array
{
throw new Exception('Spreadsheet objects cannot be serialized');
}
/**
* @throws Exception
*/
@@ -1597,4 +1744,108 @@ class Spreadsheet implements JsonSerializable
{
return $this->excelCalendar;
}
public function deleteLegacyDrawing(Worksheet $worksheet): void
{
unset($this->unparsedLoadedData['sheets'][$worksheet->getCodeName()]['legacyDrawing']);
}
public function getLegacyDrawing(Worksheet $worksheet): ?string
{
/** @var ?string */
$temp = $this->unparsedLoadedData['sheets'][$worksheet->getCodeName()]['legacyDrawing'] ?? null;
return $temp;
}
public function getValueBinder(): ?IValueBinder
{
return $this->valueBinder;
}
public function setValueBinder(?IValueBinder $valueBinder): self
{
$this->valueBinder = $valueBinder;
return $this;
}
/**
* All the PDF writers treat charts as if they occupy a single cell.
* This will be better most of the time.
* It is not needed for any other output type.
* It changes the contents of the spreadsheet, so you might
* be better off cloning the spreadsheet and then using
* this method on, and then writing, the clone.
*/
public function mergeChartCellsForPdf(): void
{
foreach ($this->workSheetCollection as $worksheet) {
foreach ($worksheet->getChartCollection() as $chart) {
$br = $chart->getBottomRightCell();
$tl = $chart->getTopLeftCell();
if ($br !== '' && $br !== $tl) {
if (!$worksheet->cellExists($br)) {
$worksheet->getCell($br)->setValue(' ');
}
$worksheet->mergeCells("$tl:$br");
}
}
}
}
/**
* All the PDF writers do better with drawings than charts.
* This will be better some of the time.
* It is not needed for any other output type.
* It changes the contents of the spreadsheet, so you might
* be better off cloning the spreadsheet and then using
* this method on, and then writing, the clone.
*/
public function mergeDrawingCellsForPdf(): void
{
foreach ($this->workSheetCollection as $worksheet) {
foreach ($worksheet->getDrawingCollection() as $drawing) {
$br = $drawing->getCoordinates2();
$tl = $drawing->getCoordinates();
if ($br !== '' && $br !== $tl) {
if (!$worksheet->cellExists($br)) {
$worksheet->getCell($br)->setValue(' ');
}
$worksheet->mergeCells("$tl:$br");
}
}
}
}
/**
* Excel will sometimes replace user's formatting choice
* with a built-in choice that it thinks is equivalent.
* Its choice is often not equivalent after all.
* Such treatment is astonishingly user-hostile.
* This function will undo such changes.
*/
public function replaceBuiltinNumberFormat(int $builtinFormatIndex, string $formatCode): void
{
foreach ($this->cellXfCollection as $style) {
$numberFormat = $style->getNumberFormat();
if ($numberFormat->getBuiltInFormatCode() === $builtinFormatIndex) {
$numberFormat->setFormatCode($formatCode);
}
}
}
public function returnArrayAsArray(): void
{
$this->calculationEngine->setInstanceArrayReturnType(
Calculation::RETURN_ARRAY_AS_ARRAY
);
}
public function returnArrayAsValue(): void
{
$this->calculationEngine->setInstanceArrayReturnType(
Calculation::RETURN_ARRAY_AS_VALUE
);
}
}