| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- <?php
- namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx;
- use PhpOffice\PhpSpreadsheet\Reader\Xlsx\Namespaces;
- use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
- use PhpOffice\PhpSpreadsheet\Spreadsheet;
- use PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing;
- use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing;
- use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
- class Rels extends WriterPart
- {
- /**
- * Write relationships to XML format.
- *
- * @return string XML Output
- */
- public function writeRelationships(Spreadsheet $spreadsheet)
- {
- // 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');
- // Relationships
- $objWriter->startElement('Relationships');
- $objWriter->writeAttribute('xmlns', Namespaces::RELATIONSHIPS);
- $customPropertyList = $spreadsheet->getProperties()->getCustomProperties();
- if (!empty($customPropertyList)) {
- // Relationship docProps/app.xml
- $this->writeRelationship(
- $objWriter,
- 4,
- Namespaces::RELATIONSHIPS_CUSTOM_PROPERTIES,
- 'docProps/custom.xml'
- );
- }
- // Relationship docProps/app.xml
- $this->writeRelationship(
- $objWriter,
- 3,
- Namespaces::RELATIONSHIPS_EXTENDED_PROPERTIES,
- 'docProps/app.xml'
- );
- // Relationship docProps/core.xml
- $this->writeRelationship(
- $objWriter,
- 2,
- Namespaces::CORE_PROPERTIES,
- 'docProps/core.xml'
- );
- // Relationship xl/workbook.xml
- $this->writeRelationship(
- $objWriter,
- 1,
- Namespaces::OFFICE_DOCUMENT,
- 'xl/workbook.xml'
- );
- // a custom UI in workbook ?
- $target = $spreadsheet->getRibbonXMLData('target');
- if ($spreadsheet->hasRibbon()) {
- $this->writeRelationShip(
- $objWriter,
- 5,
- Namespaces::EXTENSIBILITY,
- is_string($target) ? $target : ''
- );
- }
- $objWriter->endElement();
- return $objWriter->getData();
- }
- /**
- * Write workbook relationships to XML format.
- *
- * @return string XML Output
- */
- public function writeWorkbookRelationships(Spreadsheet $spreadsheet)
- {
- // 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');
- // Relationships
- $objWriter->startElement('Relationships');
- $objWriter->writeAttribute('xmlns', Namespaces::RELATIONSHIPS);
- // Relationship styles.xml
- $this->writeRelationship(
- $objWriter,
- 1,
- Namespaces::STYLES,
- 'styles.xml'
- );
- // Relationship theme/theme1.xml
- $this->writeRelationship(
- $objWriter,
- 2,
- Namespaces::THEME2,
- 'theme/theme1.xml'
- );
- // Relationship sharedStrings.xml
- $this->writeRelationship(
- $objWriter,
- 3,
- Namespaces::SHARED_STRINGS,
- 'sharedStrings.xml'
- );
- // Relationships with sheets
- $sheetCount = $spreadsheet->getSheetCount();
- for ($i = 0; $i < $sheetCount; ++$i) {
- $this->writeRelationship(
- $objWriter,
- ($i + 1 + 3),
- Namespaces::WORKSHEET,
- 'worksheets/sheet' . ($i + 1) . '.xml'
- );
- }
- // Relationships for vbaProject if needed
- // id : just after the last sheet
- if ($spreadsheet->hasMacros()) {
- $this->writeRelationShip(
- $objWriter,
- ($i + 1 + 3),
- Namespaces::VBA,
- 'vbaProject.bin'
- );
- ++$i; //increment i if needed for an another relation
- }
- $objWriter->endElement();
- return $objWriter->getData();
- }
- /**
- * Write worksheet relationships to XML format.
- *
- * Numbering is as follows:
- * rId1 - Drawings
- * rId_hyperlink_x - Hyperlinks
- *
- * @param int $worksheetId
- * @param bool $includeCharts Flag indicating if we should write charts
- * @param int $tableRef Table ID
- *
- * @return string XML Output
- */
- public function writeWorksheetRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet, $worksheetId = 1, $includeCharts = false, $tableRef = 1)
- {
- // 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');
- // Relationships
- $objWriter->startElement('Relationships');
- $objWriter->writeAttribute('xmlns', Namespaces::RELATIONSHIPS);
- // Write drawing relationships?
- $drawingOriginalIds = [];
- $unparsedLoadedData = $worksheet->getParentOrThrow()->getUnparsedLoadedData();
- if (isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds'])) {
- $drawingOriginalIds = $unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds'];
- }
- if ($includeCharts) {
- $charts = $worksheet->getChartCollection();
- } else {
- $charts = [];
- }
- if (($worksheet->getDrawingCollection()->count() > 0) || (count($charts) > 0) || $drawingOriginalIds) {
- $rId = 1;
- // Use original $relPath to get original $rId.
- // Take first. In future can be overwritten.
- // (! synchronize with \PhpOffice\PhpSpreadsheet\Writer\Xlsx\Worksheet::writeDrawings)
- reset($drawingOriginalIds);
- $relPath = key($drawingOriginalIds);
- if (isset($drawingOriginalIds[$relPath])) {
- $rId = (int) (substr($drawingOriginalIds[$relPath], 3));
- }
- // Generate new $relPath to write drawing relationship
- $relPath = '../drawings/drawing' . $worksheetId . '.xml';
- $this->writeRelationship(
- $objWriter,
- $rId,
- Namespaces::RELATIONSHIPS_DRAWING,
- $relPath
- );
- }
- // Write hyperlink relationships?
- $i = 1;
- foreach ($worksheet->getHyperlinkCollection() as $hyperlink) {
- if (!$hyperlink->isInternal()) {
- $this->writeRelationship(
- $objWriter,
- '_hyperlink_' . $i,
- Namespaces::HYPERLINK,
- $hyperlink->getUrl(),
- 'External'
- );
- ++$i;
- }
- }
- // Write comments relationship?
- $i = 1;
- if (count($worksheet->getComments()) > 0 || isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['legacyDrawing'])) {
- $this->writeRelationship(
- $objWriter,
- '_comments_vml' . $i,
- Namespaces::VML,
- '../drawings/vmlDrawing' . $worksheetId . '.vml'
- );
- }
- if (count($worksheet->getComments()) > 0) {
- $this->writeRelationship(
- $objWriter,
- '_comments' . $i,
- Namespaces::COMMENTS,
- '../comments' . $worksheetId . '.xml'
- );
- }
- // Write Table
- $tableCount = $worksheet->getTableCollection()->count();
- for ($i = 1; $i <= $tableCount; ++$i) {
- $this->writeRelationship(
- $objWriter,
- '_table_' . $i,
- Namespaces::RELATIONSHIPS_TABLE,
- '../tables/table' . $tableRef++ . '.xml'
- );
- }
- // Write header/footer relationship?
- $i = 1;
- if (count($worksheet->getHeaderFooter()->getImages()) > 0) {
- $this->writeRelationship(
- $objWriter,
- '_headerfooter_vml' . $i,
- Namespaces::VML,
- '../drawings/vmlDrawingHF' . $worksheetId . '.vml'
- );
- }
- $this->writeUnparsedRelationship($worksheet, $objWriter, 'ctrlProps', Namespaces::RELATIONSHIPS_CTRLPROP);
- $this->writeUnparsedRelationship($worksheet, $objWriter, 'vmlDrawings', Namespaces::VML);
- $this->writeUnparsedRelationship($worksheet, $objWriter, 'printerSettings', Namespaces::RELATIONSHIPS_PRINTER_SETTINGS);
- $objWriter->endElement();
- return $objWriter->getData();
- }
- private function writeUnparsedRelationship(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet, XMLWriter $objWriter, string $relationship, string $type): void
- {
- $unparsedLoadedData = $worksheet->getParentOrThrow()->getUnparsedLoadedData();
- if (!isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()][$relationship])) {
- return;
- }
- foreach ($unparsedLoadedData['sheets'][$worksheet->getCodeName()][$relationship] as $rId => $value) {
- if (substr($rId, 0, 17) !== '_headerfooter_vml') {
- $this->writeRelationship(
- $objWriter,
- $rId,
- $type,
- $value['relFilePath']
- );
- }
- }
- }
- /**
- * Write drawing relationships to XML format.
- *
- * @param int $chartRef Chart ID
- * @param bool $includeCharts Flag indicating if we should write charts
- *
- * @return string XML Output
- */
- public function writeDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet, &$chartRef, $includeCharts = false)
- {
- // 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');
- // Relationships
- $objWriter->startElement('Relationships');
- $objWriter->writeAttribute('xmlns', Namespaces::RELATIONSHIPS);
- // Loop through images and write relationships
- $i = 1;
- $iterator = $worksheet->getDrawingCollection()->getIterator();
- while ($iterator->valid()) {
- $drawing = $iterator->current();
- if (
- $drawing instanceof \PhpOffice\PhpSpreadsheet\Worksheet\Drawing
- || $drawing instanceof MemoryDrawing
- ) {
- // Write relationship for image drawing
- $this->writeRelationship(
- $objWriter,
- $i,
- Namespaces::IMAGE,
- '../media/' . $drawing->getIndexedFilename()
- );
- $i = $this->writeDrawingHyperLink($objWriter, $drawing, $i);
- }
- $iterator->next();
- ++$i;
- }
- if ($includeCharts) {
- // Loop through charts and write relationships
- $chartCount = $worksheet->getChartCount();
- if ($chartCount > 0) {
- for ($c = 0; $c < $chartCount; ++$c) {
- $this->writeRelationship(
- $objWriter,
- $i++,
- Namespaces::RELATIONSHIPS_CHART,
- '../charts/chart' . ++$chartRef . '.xml'
- );
- }
- }
- }
- $objWriter->endElement();
- return $objWriter->getData();
- }
- /**
- * Write header/footer drawing relationships to XML format.
- *
- * @return string XML Output
- */
- public function writeHeaderFooterDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet)
- {
- // 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');
- // Relationships
- $objWriter->startElement('Relationships');
- $objWriter->writeAttribute('xmlns', Namespaces::RELATIONSHIPS);
- // Loop through images and write relationships
- foreach ($worksheet->getHeaderFooter()->getImages() as $key => $value) {
- // Write relationship for image drawing
- $this->writeRelationship(
- $objWriter,
- $key,
- Namespaces::IMAGE,
- '../media/' . $value->getIndexedFilename()
- );
- }
- $objWriter->endElement();
- return $objWriter->getData();
- }
- public function writeVMLDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet): string
- {
- // 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');
- // Relationships
- $objWriter->startElement('Relationships');
- $objWriter->writeAttribute('xmlns', Namespaces::RELATIONSHIPS);
- // Loop through images and write relationships
- foreach ($worksheet->getComments() as $comment) {
- if (!$comment->hasBackgroundImage()) {
- continue;
- }
- $bgImage = $comment->getBackgroundImage();
- $this->writeRelationship(
- $objWriter,
- $bgImage->getImageIndex(),
- Namespaces::IMAGE,
- '../media/' . $bgImage->getMediaFilename()
- );
- }
- $objWriter->endElement();
- return $objWriter->getData();
- }
- /**
- * Write Override content type.
- *
- * @param int|string $id Relationship ID. rId will be prepended!
- * @param string $type Relationship type
- * @param string $target Relationship target
- * @param string $targetMode Relationship target mode
- */
- private function writeRelationship(XMLWriter $objWriter, $id, $type, $target, $targetMode = ''): void
- {
- if ($type != '' && $target != '') {
- // Write relationship
- $objWriter->startElement('Relationship');
- $objWriter->writeAttribute('Id', 'rId' . $id);
- $objWriter->writeAttribute('Type', $type);
- $objWriter->writeAttribute('Target', $target);
- if ($targetMode != '') {
- $objWriter->writeAttribute('TargetMode', $targetMode);
- }
- $objWriter->endElement();
- } else {
- throw new WriterException('Invalid parameters passed.');
- }
- }
- private function writeDrawingHyperLink(XMLWriter $objWriter, BaseDrawing $drawing, int $i): int
- {
- if ($drawing->getHyperlink() === null) {
- return $i;
- }
- ++$i;
- $this->writeRelationship(
- $objWriter,
- $i,
- Namespaces::HYPERLINK,
- $drawing->getHyperlink()->getUrl(),
- $drawing->getHyperlink()->getTypeHyperlink()
- );
- return $i;
- }
- }
|