Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx; 4 5 use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; 6 use PhpOffice\PhpSpreadsheet\Spreadsheet; 7 use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing; 8 use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException; 9 10 class Rels extends WriterPart 11 { 12 /** 13 * Write relationships to XML format. 14 * 15 * @return string XML Output 16 */ 17 public function writeRelationships(Spreadsheet $spreadsheet) 18 { 19 // Create XML writer 20 $objWriter = null; 21 if ($this->getParentWriter()->getUseDiskCaching()) { 22 $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); 23 } else { 24 $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); 25 } 26 27 // XML header 28 $objWriter->startDocument('1.0', 'UTF-8', 'yes'); 29 30 // Relationships 31 $objWriter->startElement('Relationships'); 32 $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); 33 34 $customPropertyList = $spreadsheet->getProperties()->getCustomProperties(); 35 if (!empty($customPropertyList)) { 36 // Relationship docProps/app.xml 37 $this->writeRelationship( 38 $objWriter, 39 4, 40 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties', 41 'docProps/custom.xml' 42 ); 43 } 44 45 // Relationship docProps/app.xml 46 $this->writeRelationship( 47 $objWriter, 48 3, 49 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties', 50 'docProps/app.xml' 51 ); 52 53 // Relationship docProps/core.xml 54 $this->writeRelationship( 55 $objWriter, 56 2, 57 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties', 58 'docProps/core.xml' 59 ); 60 61 // Relationship xl/workbook.xml 62 $this->writeRelationship( 63 $objWriter, 64 1, 65 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument', 66 'xl/workbook.xml' 67 ); 68 // a custom UI in workbook ? 69 if ($spreadsheet->hasRibbon()) { 70 $this->writeRelationShip( 71 $objWriter, 72 5, 73 'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility', 74 $spreadsheet->getRibbonXMLData('target') 75 ); 76 } 77 78 $objWriter->endElement(); 79 80 return $objWriter->getData(); 81 } 82 83 /** 84 * Write workbook relationships to XML format. 85 * 86 * @return string XML Output 87 */ 88 public function writeWorkbookRelationships(Spreadsheet $spreadsheet) 89 { 90 // Create XML writer 91 $objWriter = null; 92 if ($this->getParentWriter()->getUseDiskCaching()) { 93 $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); 94 } else { 95 $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); 96 } 97 98 // XML header 99 $objWriter->startDocument('1.0', 'UTF-8', 'yes'); 100 101 // Relationships 102 $objWriter->startElement('Relationships'); 103 $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); 104 105 // Relationship styles.xml 106 $this->writeRelationship( 107 $objWriter, 108 1, 109 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles', 110 'styles.xml' 111 ); 112 113 // Relationship theme/theme1.xml 114 $this->writeRelationship( 115 $objWriter, 116 2, 117 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme', 118 'theme/theme1.xml' 119 ); 120 121 // Relationship sharedStrings.xml 122 $this->writeRelationship( 123 $objWriter, 124 3, 125 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings', 126 'sharedStrings.xml' 127 ); 128 129 // Relationships with sheets 130 $sheetCount = $spreadsheet->getSheetCount(); 131 for ($i = 0; $i < $sheetCount; ++$i) { 132 $this->writeRelationship( 133 $objWriter, 134 ($i + 1 + 3), 135 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet', 136 'worksheets/sheet' . ($i + 1) . '.xml' 137 ); 138 } 139 // Relationships for vbaProject if needed 140 // id : just after the last sheet 141 if ($spreadsheet->hasMacros()) { 142 $this->writeRelationShip( 143 $objWriter, 144 ($i + 1 + 3), 145 'http://schemas.microsoft.com/office/2006/relationships/vbaProject', 146 'vbaProject.bin' 147 ); 148 ++$i; //increment i if needed for an another relation 149 } 150 151 $objWriter->endElement(); 152 153 return $objWriter->getData(); 154 } 155 156 /** 157 * Write worksheet relationships to XML format. 158 * 159 * Numbering is as follows: 160 * rId1 - Drawings 161 * rId_hyperlink_x - Hyperlinks 162 * 163 * @param int $pWorksheetId 164 * @param bool $includeCharts Flag indicating if we should write charts 165 * 166 * @return string XML Output 167 */ 168 public function writeWorksheetRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet, $pWorksheetId = 1, $includeCharts = false) 169 { 170 // Create XML writer 171 $objWriter = null; 172 if ($this->getParentWriter()->getUseDiskCaching()) { 173 $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); 174 } else { 175 $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); 176 } 177 178 // XML header 179 $objWriter->startDocument('1.0', 'UTF-8', 'yes'); 180 181 // Relationships 182 $objWriter->startElement('Relationships'); 183 $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); 184 185 // Write drawing relationships? 186 $drawingOriginalIds = []; 187 $unparsedLoadedData = $pWorksheet->getParent()->getUnparsedLoadedData(); 188 if (isset($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()]['drawingOriginalIds'])) { 189 $drawingOriginalIds = $unparsedLoadedData['sheets'][$pWorksheet->getCodeName()]['drawingOriginalIds']; 190 } 191 192 if ($includeCharts) { 193 $charts = $pWorksheet->getChartCollection(); 194 } else { 195 $charts = []; 196 } 197 198 if (($pWorksheet->getDrawingCollection()->count() > 0) || (count($charts) > 0) || $drawingOriginalIds) { 199 $rId = 1; 200 201 // Use original $relPath to get original $rId. 202 // Take first. In future can be overwritten. 203 // (! synchronize with \PhpOffice\PhpSpreadsheet\Writer\Xlsx\Worksheet::writeDrawings) 204 reset($drawingOriginalIds); 205 $relPath = key($drawingOriginalIds); 206 if (isset($drawingOriginalIds[$relPath])) { 207 $rId = (int) (substr($drawingOriginalIds[$relPath], 3)); 208 } 209 210 // Generate new $relPath to write drawing relationship 211 $relPath = '../drawings/drawing' . $pWorksheetId . '.xml'; 212 $this->writeRelationship( 213 $objWriter, 214 $rId, 215 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing', 216 $relPath 217 ); 218 } 219 220 // Write hyperlink relationships? 221 $i = 1; 222 foreach ($pWorksheet->getHyperlinkCollection() as $hyperlink) { 223 if (!$hyperlink->isInternal()) { 224 $this->writeRelationship( 225 $objWriter, 226 '_hyperlink_' . $i, 227 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', 228 $hyperlink->getUrl(), 229 'External' 230 ); 231 232 ++$i; 233 } 234 } 235 236 // Write comments relationship? 237 $i = 1; 238 if (count($pWorksheet->getComments()) > 0) { 239 $this->writeRelationship( 240 $objWriter, 241 '_comments_vml' . $i, 242 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing', 243 '../drawings/vmlDrawing' . $pWorksheetId . '.vml' 244 ); 245 246 $this->writeRelationship( 247 $objWriter, 248 '_comments' . $i, 249 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments', 250 '../comments' . $pWorksheetId . '.xml' 251 ); 252 } 253 254 // Write header/footer relationship? 255 $i = 1; 256 if (count($pWorksheet->getHeaderFooter()->getImages()) > 0) { 257 $this->writeRelationship( 258 $objWriter, 259 '_headerfooter_vml' . $i, 260 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing', 261 '../drawings/vmlDrawingHF' . $pWorksheetId . '.vml' 262 ); 263 } 264 265 $this->writeUnparsedRelationship($pWorksheet, $objWriter, 'ctrlProps', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp'); 266 $this->writeUnparsedRelationship($pWorksheet, $objWriter, 'vmlDrawings', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing'); 267 $this->writeUnparsedRelationship($pWorksheet, $objWriter, 'printerSettings', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings'); 268 269 $objWriter->endElement(); 270 271 return $objWriter->getData(); 272 } 273 274 private function writeUnparsedRelationship(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet, XMLWriter $objWriter, $relationship, $type): void 275 { 276 $unparsedLoadedData = $pWorksheet->getParent()->getUnparsedLoadedData(); 277 if (!isset($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()][$relationship])) { 278 return; 279 } 280 281 foreach ($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()][$relationship] as $rId => $value) { 282 $this->writeRelationship( 283 $objWriter, 284 $rId, 285 $type, 286 $value['relFilePath'] 287 ); 288 } 289 } 290 291 /** 292 * Write drawing relationships to XML format. 293 * 294 * @param int &$chartRef Chart ID 295 * @param bool $includeCharts Flag indicating if we should write charts 296 * 297 * @return string XML Output 298 */ 299 public function writeDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet, &$chartRef, $includeCharts = false) 300 { 301 // Create XML writer 302 $objWriter = null; 303 if ($this->getParentWriter()->getUseDiskCaching()) { 304 $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); 305 } else { 306 $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); 307 } 308 309 // XML header 310 $objWriter->startDocument('1.0', 'UTF-8', 'yes'); 311 312 // Relationships 313 $objWriter->startElement('Relationships'); 314 $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); 315 316 // Loop through images and write relationships 317 $i = 1; 318 $iterator = $pWorksheet->getDrawingCollection()->getIterator(); 319 while ($iterator->valid()) { 320 if ( 321 $iterator->current() instanceof \PhpOffice\PhpSpreadsheet\Worksheet\Drawing 322 || $iterator->current() instanceof MemoryDrawing 323 ) { 324 // Write relationship for image drawing 325 /** @var \PhpOffice\PhpSpreadsheet\Worksheet\Drawing $drawing */ 326 $drawing = $iterator->current(); 327 $this->writeRelationship( 328 $objWriter, 329 $i, 330 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', 331 '../media/' . str_replace(' ', '', $drawing->getIndexedFilename()) 332 ); 333 334 $i = $this->writeDrawingHyperLink($objWriter, $drawing, $i); 335 } 336 337 $iterator->next(); 338 ++$i; 339 } 340 341 if ($includeCharts) { 342 // Loop through charts and write relationships 343 $chartCount = $pWorksheet->getChartCount(); 344 if ($chartCount > 0) { 345 for ($c = 0; $c < $chartCount; ++$c) { 346 $this->writeRelationship( 347 $objWriter, 348 $i++, 349 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart', 350 '../charts/chart' . ++$chartRef . '.xml' 351 ); 352 } 353 } 354 } 355 356 $objWriter->endElement(); 357 358 return $objWriter->getData(); 359 } 360 361 /** 362 * Write header/footer drawing relationships to XML format. 363 * 364 * @return string XML Output 365 */ 366 public function writeHeaderFooterDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet) 367 { 368 // Create XML writer 369 $objWriter = null; 370 if ($this->getParentWriter()->getUseDiskCaching()) { 371 $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); 372 } else { 373 $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); 374 } 375 376 // XML header 377 $objWriter->startDocument('1.0', 'UTF-8', 'yes'); 378 379 // Relationships 380 $objWriter->startElement('Relationships'); 381 $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); 382 383 // Loop through images and write relationships 384 foreach ($pWorksheet->getHeaderFooter()->getImages() as $key => $value) { 385 // Write relationship for image drawing 386 $this->writeRelationship( 387 $objWriter, 388 $key, 389 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', 390 '../media/' . $value->getIndexedFilename() 391 ); 392 } 393 394 $objWriter->endElement(); 395 396 return $objWriter->getData(); 397 } 398 399 /** 400 * Write Override content type. 401 * 402 * @param XMLWriter $objWriter XML Writer 403 * @param int $pId Relationship ID. rId will be prepended! 404 * @param string $pType Relationship type 405 * @param string $pTarget Relationship target 406 * @param string $pTargetMode Relationship target mode 407 */ 408 private function writeRelationship(XMLWriter $objWriter, $pId, $pType, $pTarget, $pTargetMode = ''): void 409 { 410 if ($pType != '' && $pTarget != '') { 411 // Write relationship 412 $objWriter->startElement('Relationship'); 413 $objWriter->writeAttribute('Id', 'rId' . $pId); 414 $objWriter->writeAttribute('Type', $pType); 415 $objWriter->writeAttribute('Target', $pTarget); 416 417 if ($pTargetMode != '') { 418 $objWriter->writeAttribute('TargetMode', $pTargetMode); 419 } 420 421 $objWriter->endElement(); 422 } else { 423 throw new WriterException('Invalid parameters passed.'); 424 } 425 } 426 427 /** 428 * @param $objWriter 429 * @param \PhpOffice\PhpSpreadsheet\Worksheet\Drawing $drawing 430 * @param $i 431 * 432 * @return int 433 */ 434 private function writeDrawingHyperLink($objWriter, $drawing, $i) 435 { 436 if ($drawing->getHyperlink() === null) { 437 return $i; 438 } 439 440 ++$i; 441 $this->writeRelationship( 442 $objWriter, 443 $i, 444 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', 445 $drawing->getHyperlink()->getUrl(), 446 $drawing->getHyperlink()->getTypeHyperlink() 447 ); 448 449 return $i; 450 } 451 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body