Failed Conditions
Pull Request — master (#3962)
by Owen
11:35
created

Rels::writeWorkbookRelationships()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 77
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 5.0002

Importance

Changes 0
Metric Value
eloc 43
c 0
b 0
f 0
dl 0
loc 77
rs 8.9208
ccs 43
cts 44
cp 0.9773
cc 5
nc 16
nop 1
crap 5.0002

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