Passed
Push — master ( b504ba...c2a964 )
by
unknown
21:09 queued 09:01
created

Rels::writeWorkbookRelationships()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 77
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 51
CRAP Score 5.0001

Importance

Changes 0
Metric Value
eloc 43
c 0
b 0
f 0
dl 0
loc 77
ccs 51
cts 52
cp 0.9808
rs 8.9208
cc 5
nc 16
nop 1
crap 5.0001

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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