mirror of
https://github.com/PHPOffice/PhpSpreadsheet.git
synced 2026-09-12 19:16:45 +00:00
Ensure that a basic metadata file containing a cell metadata definition is written and linked; and then tag array formula cells with the cm tag to link them to that cell metadata definition
This commit is contained in:
@@ -327,10 +327,10 @@ class Cell
|
||||
// as well as updating the spillage cells,
|
||||
// so we need to restore this cell to its formula value, attributes, and datatype
|
||||
$worksheet->getCell($coordinate);
|
||||
$this->updateInCollection();
|
||||
$this->value = $value;
|
||||
$this->dataType = $datatype;
|
||||
$this->formulaAttributes = $formulaAttributes;
|
||||
$this->updateInCollection();
|
||||
}
|
||||
|
||||
// Now we just extract the top-left value from the array to get the result for this specific cell
|
||||
|
||||
@@ -20,6 +20,7 @@ use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Comments;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\ContentTypes;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\DocProps;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Drawing;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Metadata;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\Rels;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\RelsRibbon;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx\RelsVBA;
|
||||
@@ -157,6 +158,11 @@ class Xlsx extends BaseWriter
|
||||
*/
|
||||
private $writerPartStringTable;
|
||||
|
||||
/**
|
||||
* @var Metadata
|
||||
*/
|
||||
private $writerPartMetadata;
|
||||
|
||||
/**
|
||||
* @var Style
|
||||
*/
|
||||
@@ -193,6 +199,7 @@ class Xlsx extends BaseWriter
|
||||
$this->writerPartRels = new Rels($this);
|
||||
$this->writerPartRelsRibbon = new RelsRibbon($this);
|
||||
$this->writerPartRelsVBA = new RelsVBA($this);
|
||||
$this->writerPartMetadata = new Metadata($this);
|
||||
$this->writerPartStringTable = new StringTable($this);
|
||||
$this->writerPartStyle = new Style($this);
|
||||
$this->writerPartTheme = new Theme($this);
|
||||
@@ -256,6 +263,11 @@ class Xlsx extends BaseWriter
|
||||
return $this->writerPartRelsVBA;
|
||||
}
|
||||
|
||||
public function getWriterPartMetadata(): Metadata
|
||||
{
|
||||
return $this->writerPartMetadata;
|
||||
}
|
||||
|
||||
public function getWriterPartStringTable(): StringTable
|
||||
{
|
||||
return $this->writerPartStringTable;
|
||||
@@ -364,6 +376,9 @@ class Xlsx extends BaseWriter
|
||||
// Add theme to ZIP file
|
||||
$zipContent['xl/theme/theme1.xml'] = $this->getWriterPartTheme()->writeTheme($this->spreadSheet);
|
||||
|
||||
// Add metadata to ZIP file
|
||||
$zipContent['xl/metadata.xml'] = $this->getWriterPartMetadata()->writeMetadata();
|
||||
|
||||
// Add string table to ZIP file
|
||||
$zipContent['xl/sharedStrings.xml'] = $this->getWriterPartStringTable()->writeStringTable($this->stringTable);
|
||||
|
||||
|
||||
@@ -82,6 +82,9 @@ class ContentTypes extends WriterPart
|
||||
$this->writeOverrideContentType($objWriter, '/xl/worksheets/sheet' . ($i + 1) . '.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml');
|
||||
}
|
||||
|
||||
// Shared strings
|
||||
$this->writeOverrideContentType($objWriter, '/xl/metadata.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml');
|
||||
|
||||
// Shared strings
|
||||
$this->writeOverrideContentType($objWriter, '/xl/sharedStrings.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml');
|
||||
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
|
||||
|
||||
class Metadata extends WriterPart
|
||||
{
|
||||
protected const METADATA_TYPES = [
|
||||
[
|
||||
'cellMeta' => '1',
|
||||
'coerce' => '1',
|
||||
'assign' => '1',
|
||||
'clearComments' => '1',
|
||||
'clearFormats' => '1',
|
||||
'rowColShift' => '1',
|
||||
'splitFirst' => '1',
|
||||
'merge' => '1',
|
||||
'pasteValues' => '1',
|
||||
'pasteAll' => '1',
|
||||
'copy' => '1',
|
||||
'minSupportedVersion' => '120000',
|
||||
'name' => 'XLDAPR',
|
||||
],
|
||||
[
|
||||
'coerce' => '1',
|
||||
'assign' => '1',
|
||||
'clearComments' => '1',
|
||||
'clearFormats' => '1',
|
||||
'rowColShift' => '1',
|
||||
'splitFirst' => '1',
|
||||
'merge' => '1',
|
||||
'pasteValues' => '1',
|
||||
'pasteAll' => '1',
|
||||
'copy' => '1',
|
||||
'minSupportedVersion' => '120000',
|
||||
'name' => 'XLRICHVALUE',
|
||||
],
|
||||
];
|
||||
|
||||
protected const FUTURE_METADATA = [
|
||||
'XLDAPR' => [
|
||||
[
|
||||
'uri' => '{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}',
|
||||
'xda:dynamicArrayProperties' => [
|
||||
'fCollapsed' => '0',
|
||||
'fDynamic' => '1',
|
||||
],
|
||||
],
|
||||
],
|
||||
'XLRICHVALUE' => [
|
||||
[
|
||||
'uri' => '{3e2802c4-a4d2-4d8b-9148-e3be6c30e623}',
|
||||
'xlrd:rvb' => [
|
||||
'i' => '0',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
protected const EXTRA_METADATA = [
|
||||
'cellMetadata' => [
|
||||
[
|
||||
'v' => '0',
|
||||
't' => '1',
|
||||
],
|
||||
],
|
||||
'valueMetadata' => [
|
||||
[
|
||||
'v' => '0',
|
||||
't' => '2',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Write metadata to XML format.
|
||||
*
|
||||
* @return string XML Output
|
||||
*/
|
||||
public function writeMetadata()
|
||||
{
|
||||
// Create XML writer
|
||||
$objWriter = null;
|
||||
if ($this->getParentWriter()->getUseDiskCaching()) {
|
||||
$objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
|
||||
} else {
|
||||
$objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
|
||||
}
|
||||
|
||||
// XML header
|
||||
$objWriter->startDocument('1.0', 'UTF-8', 'yes');
|
||||
|
||||
$objWriter->startElement('metadata');
|
||||
$objWriter->writeAttribute('xmlns:xda', 'http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray');
|
||||
$objWriter->writeAttribute('xmlns:xlrd', 'http://schemas.microsoft.com/office/spreadsheetml/2017/richdata');
|
||||
$objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
|
||||
|
||||
$this->writeMetadataTypes($objWriter);
|
||||
$this->writeFutureMetadata($objWriter);
|
||||
$this->writeExtraMetadata($objWriter);
|
||||
|
||||
$objWriter->endElement(); // metadata
|
||||
|
||||
return $objWriter->getData();
|
||||
}
|
||||
|
||||
private function writeMetadataTypes(XMLWriter $objWriter): void
|
||||
{
|
||||
$objWriter->startElement('metadataTypes');
|
||||
$objWriter->writeAttribute('count', (string) count(self::METADATA_TYPES));
|
||||
|
||||
foreach (self::METADATA_TYPES as $metadataType) {
|
||||
$objWriter->startElement('metadataType');
|
||||
|
||||
foreach ($metadataType as $metadataTypeKey => $metadataTypeValue) {
|
||||
$objWriter->writeAttribute($metadataTypeKey, $metadataTypeValue);
|
||||
}
|
||||
|
||||
$objWriter->endElement(); //metadataType
|
||||
}
|
||||
|
||||
$objWriter->endElement(); //metadataTypes
|
||||
}
|
||||
|
||||
private function writeFutureMetadata(XMLWriter $objWriter): void
|
||||
{
|
||||
foreach (self::FUTURE_METADATA as $name => $futureMetadata) {
|
||||
$objWriter->startElement('futureMetadata');
|
||||
$objWriter->writeAttribute('count', (string) count($futureMetadata));
|
||||
$objWriter->writeAttribute('name', $name);
|
||||
|
||||
foreach ($futureMetadata as $futureMetadatum) {
|
||||
$objWriter->startElement('bk');
|
||||
$objWriter->startElement('extLst');
|
||||
|
||||
$ext = array_shift($futureMetadatum);
|
||||
$objWriter->startElement('ext');
|
||||
$objWriter->writeAttribute('uri', $ext);
|
||||
|
||||
foreach ($futureMetadatum as $extElementName => $extElementProperties) {
|
||||
$objWriter->startElement($extElementName);
|
||||
|
||||
foreach ($extElementProperties as $extElementPropertyName => $extElementPropertyValue) {
|
||||
$objWriter->writeAttribute($extElementPropertyName, $extElementPropertyValue);
|
||||
}
|
||||
|
||||
$objWriter->endElement(); // ext
|
||||
}
|
||||
|
||||
$objWriter->endElement(); // ext
|
||||
$objWriter->endElement(); // extLst
|
||||
$objWriter->endElement(); // bk
|
||||
}
|
||||
|
||||
$objWriter->endElement(); // futureMetadata
|
||||
}
|
||||
}
|
||||
|
||||
private function writeExtraMetadata(XMLWriter $objWriter): void
|
||||
{
|
||||
foreach (self::EXTRA_METADATA as $name => $metadata) {
|
||||
$objWriter->startElement($name);
|
||||
$objWriter->writeAttribute('count', (string) count($metadata));
|
||||
|
||||
foreach ($metadata as $metadatum) {
|
||||
$objWriter->startElement('bk');
|
||||
$objWriter->startElement('rc');
|
||||
|
||||
foreach ($metadatum as $attributeName => $attrbuteValue) {
|
||||
$objWriter->writeAttribute($attributeName, $attrbuteValue);
|
||||
}
|
||||
|
||||
$objWriter->endElement(); // rc
|
||||
$objWriter->endElement(); // bk
|
||||
}
|
||||
|
||||
$objWriter->endElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,6 +137,17 @@ class Rels extends WriterPart
|
||||
'worksheets/sheet' . ($i + 1) . '.xml'
|
||||
);
|
||||
}
|
||||
|
||||
// Relationship sharedStrings.xml
|
||||
// id : just after the last sheet
|
||||
$this->writeRelationship(
|
||||
$objWriter,
|
||||
($i + 1 + 3),
|
||||
'http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata',
|
||||
'metadata.xml'
|
||||
);
|
||||
++$i; //increment i if needed for an another relation
|
||||
|
||||
// Relationships for vbaProject if needed
|
||||
// id : just after the last sheet
|
||||
if ($spreadsheet->hasMacros()) {
|
||||
|
||||
@@ -1265,11 +1265,13 @@ class Worksheet extends WriterPart
|
||||
|
||||
$attributes = $cell->getFormulaAttributes();
|
||||
if (($attributes['t'] ?? null) === 'array') {
|
||||
$objWriter->writeAttribute('cm', '1');
|
||||
|
||||
$objWriter->startElement('f');
|
||||
$objWriter->writeAttribute('t', 'array');
|
||||
$objWriter->writeAttribute('ref', $attributes['ref'] ?? $cell->getCoordinate());
|
||||
$objWriter->writeAttribute('aca', '1');
|
||||
$objWriter->writeAttribute('ca', '1');
|
||||
$objWriter->writeAttribute('aca', '1'); // Always calculate array, true
|
||||
$objWriter->writeAttribute('ca', '1'); // Calculate cell, true
|
||||
$objWriter->text(Xlfn::addXlfnStripEquals($cellValue));
|
||||
$objWriter->endElement();
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user