Passed
Push — develop ( b05d07...17d4a5 )
by Adrien
26:16
created

Rels::writeRelationship()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4.016

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 3
nop 5
dl 0
loc 16
ccs 9
cts 10
cp 0.9
crap 4.016
rs 9.9332
c 0
b 0
f 0
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
     * @param Spreadsheet $spreadsheet
16
     *
17
     * @throws WriterException
18
     *
19
     * @return string XML Output
20
     */
21 81
    public function writeRelationships(Spreadsheet $spreadsheet)
22
    {
23
        // Create XML writer
24 81
        $objWriter = null;
25 81
        if ($this->getParentWriter()->getUseDiskCaching()) {
26
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
27
        } else {
28 81
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
29
        }
30
31
        // XML header
32 81
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
33
34
        // Relationships
35 81
        $objWriter->startElement('Relationships');
36 81
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
37
38 81
        $customPropertyList = $spreadsheet->getProperties()->getCustomProperties();
39 81
        if (!empty($customPropertyList)) {
40
            // Relationship docProps/app.xml
41 2
            $this->writeRelationship(
42 2
                $objWriter,
43 2
                4,
44 2
                'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties',
45 2
                'docProps/custom.xml'
46
            );
47
        }
48
49
        // Relationship docProps/app.xml
50 81
        $this->writeRelationship(
51 81
            $objWriter,
52 81
            3,
53 81
            'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties',
54 81
            'docProps/app.xml'
55
        );
56
57
        // Relationship docProps/core.xml
58 81
        $this->writeRelationship(
59 81
            $objWriter,
60 81
            2,
61 81
            'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties',
62 81
            'docProps/core.xml'
63
        );
64
65
        // Relationship xl/workbook.xml
66 81
        $this->writeRelationship(
67 81
            $objWriter,
68 81
            1,
69 81
            'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument',
70 81
            'xl/workbook.xml'
71
        );
72
        // a custom UI in workbook ?
73 81
        if ($spreadsheet->hasRibbon()) {
74
            $this->writeRelationShip(
75
                $objWriter,
76
                5,
77
                'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility',
78
                $spreadsheet->getRibbonXMLData('target')
79
            );
80
        }
81
82 81
        $objWriter->endElement();
83
84 81
        return $objWriter->getData();
85
    }
86
87
    /**
88
     * Write workbook relationships to XML format.
89
     *
90
     * @param Spreadsheet $spreadsheet
91
     *
92
     * @throws WriterException
93
     *
94
     * @return string XML Output
95
     */
96 81
    public function writeWorkbookRelationships(Spreadsheet $spreadsheet)
97
    {
98
        // Create XML writer
99 81
        $objWriter = null;
100 81
        if ($this->getParentWriter()->getUseDiskCaching()) {
101
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
102
        } else {
103 81
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
104
        }
105
106
        // XML header
107 81
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
108
109
        // Relationships
110 81
        $objWriter->startElement('Relationships');
111 81
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
112
113
        // Relationship styles.xml
114 81
        $this->writeRelationship(
115 81
            $objWriter,
116 81
            1,
117 81
            'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles',
118 81
            'styles.xml'
119
        );
120
121
        // Relationship theme/theme1.xml
122 81
        $this->writeRelationship(
123 81
            $objWriter,
124 81
            2,
125 81
            'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme',
126 81
            'theme/theme1.xml'
127
        );
128
129
        // Relationship sharedStrings.xml
130 81
        $this->writeRelationship(
131 81
            $objWriter,
132 81
            3,
133 81
            'http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings',
134 81
            'sharedStrings.xml'
135
        );
136
137
        // Relationships with sheets
138 81
        $sheetCount = $spreadsheet->getSheetCount();
139 81
        for ($i = 0; $i < $sheetCount; ++$i) {
140 81
            $this->writeRelationship(
141 81
                $objWriter,
142 81
                ($i + 1 + 3),
143 81
                'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet',
144 81
                'worksheets/sheet' . ($i + 1) . '.xml'
145
            );
146
        }
147
        // Relationships for vbaProject if needed
148
        // id : just after the last sheet
149 81
        if ($spreadsheet->hasMacros()) {
150 1
            $this->writeRelationShip(
151 1
                $objWriter,
152 1
                ($i + 1 + 3),
153 1
                'http://schemas.microsoft.com/office/2006/relationships/vbaProject',
154 1
                'vbaProject.bin'
155
            );
156 1
            ++$i; //increment i if needed for an another relation
157
        }
158
159 81
        $objWriter->endElement();
160
161 81
        return $objWriter->getData();
162
    }
163
164
    /**
165
     * Write worksheet relationships to XML format.
166
     *
167
     * Numbering is as follows:
168
     *     rId1                 - Drawings
169
     *  rId_hyperlink_x     - Hyperlinks
170
     *
171
     * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet
172
     * @param int $pWorksheetId
173
     * @param bool $includeCharts Flag indicating if we should write charts
174
     *
175
     * @throws WriterException
176
     *
177
     * @return string XML Output
178
     */
179 81
    public function writeWorksheetRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet, $pWorksheetId = 1, $includeCharts = false)
180
    {
181
        // Create XML writer
182 81
        $objWriter = null;
183 81
        if ($this->getParentWriter()->getUseDiskCaching()) {
184
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
185
        } else {
186 81
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
187
        }
188
189
        // XML header
190 81
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
191
192
        // Relationships
193 81
        $objWriter->startElement('Relationships');
194 81
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
195
196
        // Write drawing relationships?
197 81
        $d = 0;
198 81
        $drawingOriginalIds = [];
199 81
        $unparsedLoadedData = $pWorksheet->getParent()->getUnparsedLoadedData();
200 81
        if (isset($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()]['drawingOriginalIds'])) {
201 3
            $drawingOriginalIds = $unparsedLoadedData['sheets'][$pWorksheet->getCodeName()]['drawingOriginalIds'];
202
        }
203
204 81
        if ($includeCharts) {
205 14
            $charts = $pWorksheet->getChartCollection();
206
        } else {
207 68
            $charts = [];
208
        }
209
210 81
        if (($pWorksheet->getDrawingCollection()->count() > 0) || (count($charts) > 0) || $drawingOriginalIds) {
211 25
            $relPath = '../drawings/drawing' . $pWorksheetId . '.xml';
212 25
            $rId = ++$d;
213
214 25
            if (isset($drawingOriginalIds[$relPath])) {
215 3
                $rId = (int) (substr($drawingOriginalIds[$relPath], 3));
216
            }
217
218 25
            $this->writeRelationship(
219 25
                $objWriter,
220 25
                $rId,
221 25
                'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing',
222 25
                $relPath
223
            );
224
        }
225
226
        // Write hyperlink relationships?
227 81
        $i = 1;
228 81
        foreach ($pWorksheet->getHyperlinkCollection() as $hyperlink) {
229 10
            if (!$hyperlink->isInternal()) {
230 10
                $this->writeRelationship(
231 10
                    $objWriter,
232 10
                    '_hyperlink_' . $i,
0 ignored issues
show
Bug introduced by
'_hyperlink_' . $i of type string is incompatible with the type integer expected by parameter $pId of PhpOffice\PhpSpreadsheet...ls::writeRelationship(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

232
                    /** @scrutinizer ignore-type */ '_hyperlink_' . $i,
Loading history...
233 10
                    'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink',
234 10
                    $hyperlink->getUrl(),
235 10
                    'External'
236
                );
237
238 10
                ++$i;
239
            }
240
        }
241
242
        // Write comments relationship?
243 81
        $i = 1;
244 81
        if (count($pWorksheet->getComments()) > 0) {
245 10
            $this->writeRelationship(
246 10
                $objWriter,
247 10
                '_comments_vml' . $i,
248 10
                'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing',
249 10
                '../drawings/vmlDrawing' . $pWorksheetId . '.vml'
250
            );
251
252 10
            $this->writeRelationship(
253 10
                $objWriter,
254 10
                '_comments' . $i,
255 10
                'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments',
256 10
                '../comments' . $pWorksheetId . '.xml'
257
            );
258
        }
259
260
        // Write header/footer relationship?
261 81
        $i = 1;
262 81
        if (count($pWorksheet->getHeaderFooter()->getImages()) > 0) {
263 1
            $this->writeRelationship(
264 1
                $objWriter,
265 1
                '_headerfooter_vml' . $i,
266 1
                'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing',
267 1
                '../drawings/vmlDrawingHF' . $pWorksheetId . '.vml'
268
            );
269
        }
270
271 81
        $this->writeUnparsedRelationship($pWorksheet, $objWriter, 'ctrlProps', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp');
272 81
        $this->writeUnparsedRelationship($pWorksheet, $objWriter, 'vmlDrawings', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing');
273 81
        $this->writeUnparsedRelationship($pWorksheet, $objWriter, 'printerSettings', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings');
274
275 81
        $objWriter->endElement();
276
277 81
        return $objWriter->getData();
278
    }
279
280 81
    private function writeUnparsedRelationship(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet, XMLWriter $objWriter, $relationship, $type)
281
    {
282 81
        $unparsedLoadedData = $pWorksheet->getParent()->getUnparsedLoadedData();
283 81
        if (!isset($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()][$relationship])) {
284 81
            return;
285
        }
286
287 4
        foreach ($unparsedLoadedData['sheets'][$pWorksheet->getCodeName()][$relationship] as $rId => $value) {
288 4
            $this->writeRelationship(
289 4
                $objWriter,
290 4
                $rId,
291 4
                $type,
292 4
                $value['relFilePath']
293
            );
294
        }
295 4
    }
296
297
    /**
298
     * Write drawing relationships to XML format.
299
     *
300
     * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet
301
     * @param int &$chartRef Chart ID
302
     * @param bool $includeCharts Flag indicating if we should write charts
303
     *
304
     * @throws WriterException
305
     *
306
     * @return string XML Output
307
     */
308 24
    public function writeDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet, &$chartRef, $includeCharts = false)
309
    {
310
        // Create XML writer
311 24
        $objWriter = null;
312 24
        if ($this->getParentWriter()->getUseDiskCaching()) {
313
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
314
        } else {
315 24
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
316
        }
317
318
        // XML header
319 24
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
320
321
        // Relationships
322 24
        $objWriter->startElement('Relationships');
323 24
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
324
325
        // Loop through images and write relationships
326 24
        $i = 1;
327 24
        $iterator = $pWorksheet->getDrawingCollection()->getIterator();
328 24
        while ($iterator->valid()) {
329 12
            if ($iterator->current() instanceof \PhpOffice\PhpSpreadsheet\Worksheet\Drawing
330 12
                || $iterator->current() instanceof MemoryDrawing) {
331
                // Write relationship for image drawing
332
                /** @var \PhpOffice\PhpSpreadsheet\Worksheet\Drawing $drawing */
333 12
                $drawing = $iterator->current();
334 12
                $this->writeRelationship(
335 12
                    $objWriter,
336 12
                    $i,
337 12
                    'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
338 12
                    '../media/' . str_replace(' ', '', $drawing->getIndexedFilename())
339
                );
340
341 12
                $i = $this->writeDrawingHyperLink($objWriter, $drawing, $i);
342
            }
343
344 12
            $iterator->next();
345 12
            ++$i;
346
        }
347
348 24
        if ($includeCharts) {
349
            // Loop through charts and write relationships
350 13
            $chartCount = $pWorksheet->getChartCount();
351 13
            if ($chartCount > 0) {
352 13
                for ($c = 0; $c < $chartCount; ++$c) {
353 13
                    $this->writeRelationship(
354 13
                        $objWriter,
355 13
                        $i++,
356 13
                        'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart',
357 13
                        '../charts/chart' . ++$chartRef . '.xml'
358
                    );
359
                }
360
            }
361
        }
362
363 24
        $objWriter->endElement();
364
365 24
        return $objWriter->getData();
366
    }
367
368
    /**
369
     * Write header/footer drawing relationships to XML format.
370
     *
371
     * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet
372
     *
373
     * @throws WriterException
374
     *
375
     * @return string XML Output
376
     */
377 1
    public function writeHeaderFooterDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $pWorksheet)
378
    {
379
        // Create XML writer
380 1
        $objWriter = null;
381 1
        if ($this->getParentWriter()->getUseDiskCaching()) {
382
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
383
        } else {
384 1
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
385
        }
386
387
        // XML header
388 1
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
389
390
        // Relationships
391 1
        $objWriter->startElement('Relationships');
392 1
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
393
394
        // Loop through images and write relationships
395 1
        foreach ($pWorksheet->getHeaderFooter()->getImages() as $key => $value) {
396
            // Write relationship for image drawing
397 1
            $this->writeRelationship(
398 1
                $objWriter,
399 1
                $key,
400 1
                'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
401 1
                '../media/' . $value->getIndexedFilename()
402
            );
403
        }
404
405 1
        $objWriter->endElement();
406
407 1
        return $objWriter->getData();
408
    }
409
410
    /**
411
     * Write Override content type.
412
     *
413
     * @param XMLWriter $objWriter XML Writer
414
     * @param int $pId Relationship ID. rId will be prepended!
415
     * @param string $pType Relationship type
416
     * @param string $pTarget Relationship target
417
     * @param string $pTargetMode Relationship target mode
418
     *
419
     * @throws WriterException
420
     */
421 81
    private function writeRelationship(XMLWriter $objWriter, $pId, $pType, $pTarget, $pTargetMode = '')
422
    {
423 81
        if ($pType != '' && $pTarget != '') {
424
            // Write relationship
425 81
            $objWriter->startElement('Relationship');
426 81
            $objWriter->writeAttribute('Id', 'rId' . $pId);
427 81
            $objWriter->writeAttribute('Type', $pType);
428 81
            $objWriter->writeAttribute('Target', $pTarget);
429
430 81
            if ($pTargetMode != '') {
431 12
                $objWriter->writeAttribute('TargetMode', $pTargetMode);
432
            }
433
434 81
            $objWriter->endElement();
435
        } else {
436
            throw new WriterException('Invalid parameters passed.');
437
        }
438 81
    }
439
440
    /**
441
     * @param $objWriter
442
     * @param \PhpOffice\PhpSpreadsheet\Worksheet\Drawing $drawing
443
     * @param $i
444
     *
445
     * @throws WriterException
446
     *
447
     * @return int
448
     */
449 12
    private function writeDrawingHyperLink($objWriter, $drawing, $i)
450
    {
451 12
        if ($drawing->getHyperlink() === null) {
452 10
            return $i;
453
        }
454
455 2
        ++$i;
456 2
        $this->writeRelationship(
457 2
            $objWriter,
458 2
            $i,
459 2
            'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink',
460 2
            $drawing->getHyperlink()->getUrl(),
461 2
            $drawing->getHyperlink()->getTypeHyperlink()
462
        );
463
464 2
        return $i;
465
    }
466
}
467