Failed Conditions
Pull Request — master (#3876)
by Abdul Malik
22:45 queued 13:31
created

Rels::writeWorksheetRelationships()   F

Complexity

Conditions 16
Paths 2304

Size

Total Lines 126
Code Lines 80

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 85
CRAP Score 16.0003

Importance

Changes 0
Metric Value
eloc 80
dl 0
loc 126
ccs 85
cts 86
cp 0.9884
rs 1.5563
c 0
b 0
f 0
cc 16
nc 2304
nop 5
crap 16.0003

How to fix   Long Method    Complexity   

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