Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 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
    public function writeRelationships(Spreadsheet $spreadsheet): string
20
    {
21
        // Create XML writer
22
        $objWriter = null;
23
        if ($this->getParentWriter()->getUseDiskCaching()) {
24
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
25
        } else {
26
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
27
        }
28
 
29
        // XML header
30
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
31
 
32
        // Relationships
33
        $objWriter->startElement('Relationships');
34
        $objWriter->writeAttribute('xmlns', Namespaces::RELATIONSHIPS);
35
 
36
        $customPropertyList = $spreadsheet->getProperties()->getCustomProperties();
37
        if (!empty($customPropertyList)) {
38
            // Relationship docProps/app.xml
39
            $this->writeRelationship(
40
                $objWriter,
41
                4,
42
                Namespaces::RELATIONSHIPS_CUSTOM_PROPERTIES,
43
                'docProps/custom.xml'
44
            );
45
        }
46
 
47
        // Relationship docProps/app.xml
48
        $this->writeRelationship(
49
            $objWriter,
50
            3,
51
            Namespaces::RELATIONSHIPS_EXTENDED_PROPERTIES,
52
            'docProps/app.xml'
53
        );
54
 
55
        // Relationship docProps/core.xml
56
        $this->writeRelationship(
57
            $objWriter,
58
            2,
59
            Namespaces::CORE_PROPERTIES,
60
            'docProps/core.xml'
61
        );
62
 
63
        // Relationship xl/workbook.xml
64
        $this->writeRelationship(
65
            $objWriter,
66
            1,
67
            Namespaces::OFFICE_DOCUMENT,
68
            'xl/workbook.xml'
69
        );
70
        // a custom UI in workbook ?
71
        $target = $spreadsheet->getRibbonXMLData('target');
72
        if ($spreadsheet->hasRibbon()) {
73
            $this->writeRelationShip(
74
                $objWriter,
75
                5,
76
                Namespaces::EXTENSIBILITY,
77
                is_string($target) ? $target : ''
78
            );
79
        }
80
 
81
        $objWriter->endElement();
82
 
83
        return $objWriter->getData();
84
    }
85
 
86
    /**
87
     * Write workbook relationships to XML format.
88
     *
89
     * @return string XML Output
90
     */
91
    public function writeWorkbookRelationships(Spreadsheet $spreadsheet): string
92
    {
93
        // Create XML writer
94
        $objWriter = null;
95
        if ($this->getParentWriter()->getUseDiskCaching()) {
96
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
97
        } else {
98
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
99
        }
100
 
101
        // XML header
102
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
103
 
104
        // Relationships
105
        $objWriter->startElement('Relationships');
106
        $objWriter->writeAttribute('xmlns', Namespaces::RELATIONSHIPS);
107
 
108
        // Relationship styles.xml
109
        $this->writeRelationship(
110
            $objWriter,
111
            1,
112
            Namespaces::STYLES,
113
            'styles.xml'
114
        );
115
 
116
        // Relationship theme/theme1.xml
117
        $this->writeRelationship(
118
            $objWriter,
119
            2,
120
            Namespaces::THEME2,
121
            'theme/theme1.xml'
122
        );
123
 
124
        // Relationship sharedStrings.xml
125
        $this->writeRelationship(
126
            $objWriter,
127
            3,
128
            Namespaces::SHARED_STRINGS,
129
            'sharedStrings.xml'
130
        );
131
 
132
        // Relationships with sheets
133
        $sheetCount = $spreadsheet->getSheetCount();
134
        for ($i = 0; $i < $sheetCount; ++$i) {
135
            $this->writeRelationship(
136
                $objWriter,
137
                ($i + 1 + 3),
138
                Namespaces::WORKSHEET,
139
                'worksheets/sheet' . ($i + 1) . '.xml'
140
            );
141
        }
142
        // Relationships for vbaProject if needed
143
        // id : just after the last sheet
144
        if ($spreadsheet->hasMacros()) {
145
            $this->writeRelationShip(
146
                $objWriter,
147
                ($i + 1 + 3),
148
                Namespaces::VBA,
149
                'vbaProject.bin'
150
            );
151
            ++$i; //increment i if needed for an another relation
152
        }
153
 
154
        // Metadata needed for Dynamic Arrays
155
        if ($this->getParentWriter()->useDynamicArrays()) {
156
            $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
     * 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
    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
        $objWriter = null;
186
        if ($this->getParentWriter()->getUseDiskCaching()) {
187
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
188
        } else {
189
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
190
        }
191
 
192
        // XML header
193
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
194
 
195
        // Relationships
196
        $objWriter->startElement('Relationships');
197
        $objWriter->writeAttribute('xmlns', Namespaces::RELATIONSHIPS);
198
 
199
        // Write drawing relationships?
200
        $drawingOriginalIds = [];
201
        $unparsedLoadedData = $worksheet->getParentOrThrow()->getUnparsedLoadedData();
202
        if (isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds'])) {
203
            $drawingOriginalIds = $unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds'];
204
        }
205
 
206
        if ($includeCharts) {
207
            $charts = $worksheet->getChartCollection();
208
        } else {
209
            $charts = [];
210
        }
211
 
212
        if (($worksheet->getDrawingCollection()->count() > 0) || (count($charts) > 0) || $drawingOriginalIds) {
213
            $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
            reset($drawingOriginalIds);
219
            $relPath = key($drawingOriginalIds);
220
            if (isset($drawingOriginalIds[$relPath])) {
221
                $rId = (int) (substr($drawingOriginalIds[$relPath], 3));
222
            }
223
 
224
            // Generate new $relPath to write drawing relationship
225
            $relPath = '../drawings/drawing' . $worksheetId . '.xml';
226
            $this->writeRelationship(
227
                $objWriter,
228
                $rId,
229
                Namespaces::RELATIONSHIPS_DRAWING,
230
                $relPath
231
            );
232
        }
233
 
234
        $backgroundImage = $worksheet->getBackgroundImage();
235
        if ($backgroundImage !== '') {
236
            $rId = 'Bg';
237
            $uniqueName = md5(mt_rand(0, 9999) . time() . mt_rand(0, 9999));
238
            $relPath = "../media/$uniqueName." . $worksheet->getBackgroundExtension();
239
            $this->writeRelationship(
240
                $objWriter,
241
                $rId,
242
                Namespaces::IMAGE,
243
                $relPath
244
            );
245
            $zipContent["xl/media/$uniqueName." . $worksheet->getBackgroundExtension()] = $backgroundImage;
246
        }
247
 
248
        // Write hyperlink relationships?
249
        $i = 1;
250
        foreach ($worksheet->getHyperlinkCollection() as $hyperlink) {
251
            if (!$hyperlink->isInternal()) {
252
                $this->writeRelationship(
253
                    $objWriter,
254
                    '_hyperlink_' . $i,
255
                    Namespaces::HYPERLINK,
256
                    $hyperlink->getUrl(),
257
                    'External'
258
                );
259
 
260
                ++$i;
261
            }
262
        }
263
 
264
        // Write comments relationship?
265
        $i = 1;
266
        if (count($worksheet->getComments()) > 0 || isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['legacyDrawing'])) {
267
            $this->writeRelationship(
268
                $objWriter,
269
                '_comments_vml' . $i,
270
                Namespaces::VML,
271
                '../drawings/vmlDrawing' . $worksheetId . '.vml'
272
            );
273
        }
274
 
275
        if (count($worksheet->getComments()) > 0) {
276
            $this->writeRelationship(
277
                $objWriter,
278
                '_comments' . $i,
279
                Namespaces::COMMENTS,
280
                '../comments' . $worksheetId . '.xml'
281
            );
282
        }
283
 
284
        // Write Table
285
        $tableCount = $worksheet->getTableCollection()->count();
286
        for ($i = 1; $i <= $tableCount; ++$i) {
287
            $this->writeRelationship(
288
                $objWriter,
289
                '_table_' . $i,
290
                Namespaces::RELATIONSHIPS_TABLE,
291
                '../tables/table' . $tableRef++ . '.xml'
292
            );
293
        }
294
 
295
        // Write header/footer relationship?
296
        $i = 1;
297
        if (count($worksheet->getHeaderFooter()->getImages()) > 0) {
298
            $this->writeRelationship(
299
                $objWriter,
300
                '_headerfooter_vml' . $i,
301
                Namespaces::VML,
302
                '../drawings/vmlDrawingHF' . $worksheetId . '.vml'
303
            );
304
        }
305
 
306
        $this->writeUnparsedRelationship($worksheet, $objWriter, 'ctrlProps', Namespaces::RELATIONSHIPS_CTRLPROP);
307
        $this->writeUnparsedRelationship($worksheet, $objWriter, 'vmlDrawings', Namespaces::VML);
308
        $this->writeUnparsedRelationship($worksheet, $objWriter, 'printerSettings', Namespaces::RELATIONSHIPS_PRINTER_SETTINGS);
309
 
310
        $objWriter->endElement();
311
 
312
        return $objWriter->getData();
313
    }
314
 
315
    private function writeUnparsedRelationship(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet, XMLWriter $objWriter, string $relationship, string $type): void
316
    {
317
        $unparsedLoadedData = $worksheet->getParentOrThrow()->getUnparsedLoadedData();
318
        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
        }
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
    public function writeDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet, int &$chartRef, bool $includeCharts = false): string
343
    {
344
        // Create XML writer
345
        $objWriter = null;
346
        if ($this->getParentWriter()->getUseDiskCaching()) {
347
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
348
        } else {
349
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
350
        }
351
 
352
        // XML header
353
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
354
 
355
        // Relationships
356
        $objWriter->startElement('Relationships');
357
        $objWriter->writeAttribute('xmlns', Namespaces::RELATIONSHIPS);
358
 
359
        // Loop through images and write relationships
360
        $i = 1;
361
        $iterator = $worksheet->getDrawingCollection()->getIterator();
362
        while ($iterator->valid()) {
363
            $drawing = $iterator->current();
364
            if (
365
                $drawing instanceof \PhpOffice\PhpSpreadsheet\Worksheet\Drawing
366
                || $drawing instanceof MemoryDrawing
367
            ) {
368
                // Write relationship for image drawing
369
                $this->writeRelationship(
370
                    $objWriter,
371
                    $i,
372
                    Namespaces::IMAGE,
373
                    '../media/' . $drawing->getIndexedFilename()
374
                );
375
 
376
                $i = $this->writeDrawingHyperLink($objWriter, $drawing, $i);
377
            }
378
 
379
            $iterator->next();
380
            ++$i;
381
        }
382
 
383
        if ($includeCharts) {
384
            // Loop through charts and write relationships
385
            $chartCount = $worksheet->getChartCount();
386
            if ($chartCount > 0) {
387
                for ($c = 0; $c < $chartCount; ++$c) {
388
                    $this->writeRelationship(
389
                        $objWriter,
390
                        $i++,
391
                        Namespaces::RELATIONSHIPS_CHART,
392
                        '../charts/chart' . ++$chartRef . '.xml'
393
                    );
394
                }
395
            }
396
        }
397
 
398
        $objWriter->endElement();
399
 
400
        return $objWriter->getData();
401
    }
402
 
403
    /**
404
     * Write header/footer drawing relationships to XML format.
405
     *
406
     * @return string XML Output
407
     */
408
    public function writeHeaderFooterDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet): string
409
    {
410
        // Create XML writer
411
        $objWriter = null;
412
        if ($this->getParentWriter()->getUseDiskCaching()) {
413
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
414
        } else {
415
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
416
        }
417
 
418
        // XML header
419
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
420
 
421
        // Relationships
422
        $objWriter->startElement('Relationships');
423
        $objWriter->writeAttribute('xmlns', Namespaces::RELATIONSHIPS);
424
 
425
        // Loop through images and write relationships
426
        foreach ($worksheet->getHeaderFooter()->getImages() as $key => $value) {
427
            // Write relationship for image drawing
428
            $this->writeRelationship(
429
                $objWriter,
430
                $key,
431
                Namespaces::IMAGE,
432
                '../media/' . $value->getIndexedFilename()
433
            );
434
        }
435
 
436
        $objWriter->endElement();
437
 
438
        return $objWriter->getData();
439
    }
440
 
441
    public function writeVMLDrawingRelationships(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet): string
442
    {
443
        // Create XML writer
444
        $objWriter = null;
445
        if ($this->getParentWriter()->getUseDiskCaching()) {
446
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
447
        } else {
448
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
449
        }
450
 
451
        // XML header
452
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
453
 
454
        // Relationships
455
        $objWriter->startElement('Relationships');
456
        $objWriter->writeAttribute('xmlns', Namespaces::RELATIONSHIPS);
457
 
458
        // Loop through images and write relationships
459
        foreach ($worksheet->getComments() as $comment) {
460
            if (!$comment->hasBackgroundImage()) {
461
                continue;
462
            }
463
 
464
            $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
        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
    private function writeRelationship(XMLWriter $objWriter, $id, string $type, string $target, string $targetMode = ''): void
487
    {
488
        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
 
495
            if ($targetMode != '') {
496
                $objWriter->writeAttribute('TargetMode', $targetMode);
497
            }
498
 
499
            $objWriter->endElement();
500
        } else {
501
            throw new WriterException('Invalid parameters passed.');
502
        }
503
    }
504
 
505
    private function writeDrawingHyperLink(XMLWriter $objWriter, BaseDrawing $drawing, int $i): int
506
    {
507
        if ($drawing->getHyperlink() === null) {
508
            return $i;
509
        }
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
}