Rels.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. <?php
  2. namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  3. use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
  4. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  5. use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing;
  6. use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
  7. class Rels extends WriterPart
  8. {
  9. /**
  10. * Write relationships to XML format.
  11. *
  12. * @param Spreadsheet $spreadsheet
  13. *
  14. * @throws WriterException
  15. *
  16. * @return string XML Output
  17. */
  18. public function writeRelationships(Spreadsheet $spreadsheet)
  19. {
  20. // Create XML writer
  21. $objWriter = null;
  22. if ($this->getParentWriter()->getUseDiskCaching()) {
  23. $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
  24. } else {
  25. $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
  26. }
  27. // XML header
  28. $objWriter->startDocument('1.0', 'UTF-8', 'yes');
  29. // Relationships
  30. $objWriter->startElement('Relationships');
  31. $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
  32. $customPropertyList = $spreadsheet->getProperties()->getCustomProperties();
  33. if (!empty($customPropertyList)) {
  34. // Relationship docProps/app.xml
  35. $this->writeRelationship(
  36. $objWriter,
  37. 4,
  38. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties',
  39. 'docProps/custom.xml'
  40. );
  41. }
  42. // Relationship docProps/app.xml
  43. $this->writeRelationship(
  44. $objWriter,
  45. 3,
  46. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties',
  47. 'docProps/app.xml'
  48. );
  49. // Relationship docProps/core.xml
  50. $this->writeRelationship(
  51. $objWriter,
  52. 2,
  53. 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties',
  54. 'docProps/core.xml'
  55. );
  56. // Relationship xl/workbook.xml
  57. $this->writeRelationship(
  58. $objWriter,
  59. 1,
  60. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument',
  61. 'xl/workbook.xml'
  62. );
  63. // a custom UI in workbook ?
  64. if ($spreadsheet->hasRibbon()) {
  65. $this->writeRelationShip(
  66. $objWriter,
  67. 5,
  68. 'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility',
  69. $spreadsheet->getRibbonXMLData('target')
  70. );
  71. }
  72. $objWriter->endElement();
  73. return $objWriter->getData();
  74. }
  75. /**
  76. * Write workbook relationships to XML format.
  77. *
  78. * @param Spreadsheet $spreadsheet
  79. *
  80. * @throws WriterException
  81. *
  82. * @return string XML Output
  83. */
  84. public function writeWorkbookRelationships(Spreadsheet $spreadsheet)
  85. {
  86. // Create XML writer
  87. $objWriter = null;
  88. if ($this->getParentWriter()->getUseDiskCaching()) {
  89. $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
  90. } else {
  91. $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
  92. }
  93. // XML header
  94. $objWriter->startDocument('1.0', 'UTF-8', 'yes');
  95. // Relationships
  96. $objWriter->startElement('Relationships');
  97. $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
  98. // Relationship styles.xml
  99. $this->writeRelationship(
  100. $objWriter,
  101. 1,
  102. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles',
  103. 'styles.xml'
  104. );
  105. // Relationship theme/theme1.xml
  106. $this->writeRelationship(
  107. $objWriter,
  108. 2,
  109. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme',
  110. 'theme/theme1.xml'
  111. );
  112. // Relationship sharedStrings.xml
  113. $this->writeRelationship(
  114. $objWriter,
  115. 3,
  116. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings',
  117. 'sharedStrings.xml'
  118. );
  119. // Relationships with sheets
  120. $sheetCount = $spreadsheet->getSheetCount();
  121. for ($i = 0; $i < $sheetCount; ++$i) {
  122. $this->writeRelationship(
  123. $objWriter,
  124. ($i + 1 + 3),
  125. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet',
  126. 'worksheets/sheet' . ($i + 1) . '.xml'
  127. );
  128. }
  129. // Relationships for vbaProject if needed
  130. // id : just after the last sheet
  131. if ($spreadsheet->hasMacros()) {
  132. $this->writeRelationShip(
  133. $objWriter,
  134. ($i + 1 + 3),
  135. 'http://schemas.microsoft.com/office/2006/relationships/vbaProject',
  136. 'vbaProject.bin'
  137. );
  138. ++$i; //increment i if needed for an another relation
  139. }
  140. $objWriter->endElement();
  141. return $objWriter->getData();
  142. }
  143. /**
  144. * Write worksheet relationships to XML format.
  145. *
  146. * Numbering is as follows:
  147. * rId1 - Drawings
  148. * rId_hyperlink_x - Hyperlinks
  149. *
  150. * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet
  151. * @param int $pWorksheetId
  152. * @param bool $includeCharts Flag indicating if we should write charts
  153. *
  154. * @throws WriterException
  155. *
  156. * @return string XML Output
  157. */
  158. public function writeWorksheetRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet, $pWorksheetId = 1, $includeCharts = false)
  159. {
  160. // Create XML writer
  161. $objWriter = null;
  162. if ($this->getParentWriter()->getUseDiskCaching()) {
  163. $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
  164. } else {
  165. $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
  166. }
  167. // XML header
  168. $objWriter->startDocument('1.0', 'UTF-8', 'yes');
  169. // Relationships
  170. $objWriter->startElement('Relationships');
  171. $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
  172. // Write drawing relationships?
  173. $d = 0;
  174. if ($includeCharts) {
  175. $charts = $pWorksheet->getChartCollection();
  176. } else {
  177. $charts = [];
  178. }
  179. if (($pWorksheet->getDrawingCollection()->count() > 0) ||
  180. (count($charts) > 0)) {
  181. $this->writeRelationship(
  182. $objWriter,
  183. ++$d,
  184. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing',
  185. '../drawings/drawing' . $pWorksheetId . '.xml'
  186. );
  187. }
  188. // Write hyperlink relationships?
  189. $i = 1;
  190. foreach ($pWorksheet->getHyperlinkCollection() as $hyperlink) {
  191. if (!$hyperlink->isInternal()) {
  192. $this->writeRelationship(
  193. $objWriter,
  194. '_hyperlink_' . $i,
  195. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink',
  196. $hyperlink->getUrl(),
  197. 'External'
  198. );
  199. ++$i;
  200. }
  201. }
  202. // Write comments relationship?
  203. $i = 1;
  204. if (count($pWorksheet->getComments()) > 0) {
  205. $this->writeRelationship(
  206. $objWriter,
  207. '_comments_vml' . $i,
  208. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing',
  209. '../drawings/vmlDrawing' . $pWorksheetId . '.vml'
  210. );
  211. $this->writeRelationship(
  212. $objWriter,
  213. '_comments' . $i,
  214. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments',
  215. '../comments' . $pWorksheetId . '.xml'
  216. );
  217. }
  218. // Write header/footer relationship?
  219. $i = 1;
  220. if (count($pWorksheet->getHeaderFooter()->getImages()) > 0) {
  221. $this->writeRelationship(
  222. $objWriter,
  223. '_headerfooter_vml' . $i,
  224. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing',
  225. '../drawings/vmlDrawingHF' . $pWorksheetId . '.vml'
  226. );
  227. }
  228. $objWriter->endElement();
  229. return $objWriter->getData();
  230. }
  231. /**
  232. * Write drawing relationships to XML format.
  233. *
  234. * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet
  235. * @param int &$chartRef Chart ID
  236. * @param bool $includeCharts Flag indicating if we should write charts
  237. *
  238. * @throws WriterException
  239. *
  240. * @return string XML Output
  241. */
  242. public function writeDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet, &$chartRef, $includeCharts = false)
  243. {
  244. // Create XML writer
  245. $objWriter = null;
  246. if ($this->getParentWriter()->getUseDiskCaching()) {
  247. $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
  248. } else {
  249. $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
  250. }
  251. // XML header
  252. $objWriter->startDocument('1.0', 'UTF-8', 'yes');
  253. // Relationships
  254. $objWriter->startElement('Relationships');
  255. $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
  256. // Loop through images and write relationships
  257. $i = 1;
  258. $iterator = $pWorksheet->getDrawingCollection()->getIterator();
  259. while ($iterator->valid()) {
  260. if ($iterator->current() instanceof \PhpOffice\PhpSpreadsheet\Worksheet\Drawing
  261. || $iterator->current() instanceof MemoryDrawing) {
  262. // Write relationship for image drawing
  263. $this->writeRelationship(
  264. $objWriter,
  265. $i,
  266. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
  267. '../media/' . str_replace(' ', '', $iterator->current()->getIndexedFilename())
  268. );
  269. }
  270. $iterator->next();
  271. ++$i;
  272. }
  273. if ($includeCharts) {
  274. // Loop through charts and write relationships
  275. $chartCount = $pWorksheet->getChartCount();
  276. if ($chartCount > 0) {
  277. for ($c = 0; $c < $chartCount; ++$c) {
  278. $this->writeRelationship(
  279. $objWriter,
  280. $i++,
  281. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart',
  282. '../charts/chart' . ++$chartRef . '.xml'
  283. );
  284. }
  285. }
  286. }
  287. $objWriter->endElement();
  288. return $objWriter->getData();
  289. }
  290. /**
  291. * Write header/footer drawing relationships to XML format.
  292. *
  293. * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet
  294. *
  295. * @throws WriterException
  296. *
  297. * @return string XML Output
  298. */
  299. public function writeHeaderFooterDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet)
  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. // XML header
  309. $objWriter->startDocument('1.0', 'UTF-8', 'yes');
  310. // Relationships
  311. $objWriter->startElement('Relationships');
  312. $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
  313. // Loop through images and write relationships
  314. foreach ($pWorksheet->getHeaderFooter()->getImages() as $key => $value) {
  315. // Write relationship for image drawing
  316. $this->writeRelationship(
  317. $objWriter,
  318. $key,
  319. 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
  320. '../media/' . $value->getIndexedFilename()
  321. );
  322. }
  323. $objWriter->endElement();
  324. return $objWriter->getData();
  325. }
  326. /**
  327. * Write Override content type.
  328. *
  329. * @param XMLWriter $objWriter XML Writer
  330. * @param int $pId Relationship ID. rId will be prepended!
  331. * @param string $pType Relationship type
  332. * @param string $pTarget Relationship target
  333. * @param string $pTargetMode Relationship target mode
  334. *
  335. * @throws WriterException
  336. */
  337. private function writeRelationship(XMLWriter $objWriter, $pId, $pType, $pTarget, $pTargetMode = '')
  338. {
  339. if ($pType != '' && $pTarget != '') {
  340. // Write relationship
  341. $objWriter->startElement('Relationship');
  342. $objWriter->writeAttribute('Id', 'rId' . $pId);
  343. $objWriter->writeAttribute('Type', $pType);
  344. $objWriter->writeAttribute('Target', $pTarget);
  345. if ($pTargetMode != '') {
  346. $objWriter->writeAttribute('TargetMode', $pTargetMode);
  347. }
  348. $objWriter->endElement();
  349. } else {
  350. throw new WriterException('Invalid parameters passed.');
  351. }
  352. }
  353. }