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