Completed
Pull Request — develop (#464)
by
unknown
10:11
created

PptSlides::writeSlideRelationships()   F

Complexity

Conditions 61
Paths 224

Size

Total Lines 290
Code Lines 157

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 103
CRAP Score 180.5449

Importance

Changes 0
Metric Value
dl 0
loc 290
ccs 103
cts 151
cp 0.6821
rs 3.68
c 0
b 0
f 0
cc 61
eloc 157
nc 224
nop 1
crap 180.5449

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\PhpPresentation\Writer\PowerPoint2007;
4
5
use PhpOffice\Common\Drawing as CommonDrawing;
6
use PhpOffice\Common\XMLWriter;
7
use PhpOffice\PhpPresentation\Shape\Chart as ShapeChart;
8
use PhpOffice\PhpPresentation\Shape\Comment;
9
use PhpOffice\PhpPresentation\Shape\Drawing as ShapeDrawing;
10
use PhpOffice\PhpPresentation\Shape\Group;
11
use PhpOffice\PhpPresentation\Shape\Media;
12
use PhpOffice\PhpPresentation\Shape\RichText;
13
use PhpOffice\PhpPresentation\Shape\RichText\Run;
14
use PhpOffice\PhpPresentation\Shape\RichText\TextElement;
15
use PhpOffice\PhpPresentation\Shape\Table as ShapeTable;
16
use PhpOffice\PhpPresentation\Slide;
17
use PhpOffice\PhpPresentation\Slide\Background\Image;
18
use PhpOffice\PhpPresentation\Slide\Note;
19
20
class PptSlides extends AbstractSlide
21
{
22
    /**
23
     * Add slides (drawings, ...) and slide relationships (drawings, ...)
24
     * @return \PhpOffice\Common\Adapter\Zip\ZipInterface
25
     */
26 114
    public function render()
27
    {
28 114
        foreach ($this->oPresentation->getAllSlides() as $idx => $oSlide) {
29 114
            $this->oZip->addFromString('ppt/slides/_rels/slide' . ($idx + 1) . '.xml.rels', $this->writeSlideRelationships($oSlide));
30 114
            $this->oZip->addFromString('ppt/slides/slide' . ($idx + 1) . '.xml', $this->writeSlide($oSlide));
31
32
            // Add note slide
33 114
            if ($oSlide->getNote() instanceof Note) {
34 114
                if ($oSlide->getNote()->getShapeCollection()->count() > 0) {
35 2
                    $this->oZip->addFromString('ppt/notesSlides/notesSlide' . ($idx + 1) . '.xml', $this->writeNote($oSlide->getNote()));
36
                }
37
            }
38
39
            // Add background image slide
40 114
            $oBkgImage = $oSlide->getBackground();
41 114
            if ($oBkgImage instanceof Image) {
42 114
                $this->oZip->addFromString('ppt/media/'.$oBkgImage->getIndexedFilename($idx), file_get_contents($oBkgImage->getPath()));
43
            }
44
        }
45
46 114
        return $this->oZip;
47
    }
48
49
    /**
50
     * Write slide relationships to XML format
51
     *
52
     * @param  \PhpOffice\PhpPresentation\Slide $pSlide
53
     * @return string              XML Output
54
     * @throws \Exception
55
     */
56 114
    protected function writeSlideRelationships(Slide $pSlide)
57
    {
58
        //@todo Group all getShapeCollection()->getIterator
59
60
        // Create XML writer
61 114
        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
62
63
        // XML header
64 114
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
65
66
        // Relationships
67 114
        $objWriter->startElement('Relationships');
68 114
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
69
70
        // Starting relation id
71 114
        $relId = 1;
72 114
        $idxSlide = $pSlide->getParent()->getIndex($pSlide);
73
74
        // Write slideLayout relationship
75 114
        $layoutId = 1;
76 114
        if ($pSlide->getSlideLayout()) {
77 114
            $layoutId = $pSlide->getSlideLayout()->layoutNr;
78
        }
79 114
        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout', '../slideLayouts/slideLayout' . $layoutId . '.xml');
80 114
        ++$relId;
81
82
        // Write drawing relationships?
83 114
        if ($pSlide->getShapeCollection()->count() > 0) {
84
            // Loop trough images and write relationships
85 87
            $iterator = $pSlide->getShapeCollection()->getIterator();
86 87
            while ($iterator->valid()) {
87 87
                if ($iterator->current() instanceof Media) {
88
                    // Write relationship for image drawing
89 1
                    $iterator->current()->relationId = 'rId' . $relId;
90 1
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/video', '../media/' . $iterator->current()->getIndexedFilename());
91 1
                    ++$relId;
92 1
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.microsoft.com/office/2007/relationships/media', '../media/' . $iterator->current()->getIndexedFilename());
93 1
                    ++$relId;
94 86
                } elseif ($iterator->current() instanceof ShapeDrawing\AbstractDrawingAdapter) {
95
                    // Write relationship for image drawing
96 9
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $iterator->current()->getIndexedFilename());
97 9
                    $iterator->current()->relationId = 'rId' . $relId;
98 9
                    ++$relId;
99 78
                } elseif ($iterator->current() instanceof ShapeChart) {
100
                    // Write relationship for chart drawing
101 35
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart', '../charts/' . $iterator->current()->getIndexedFilename());
102
103 35
                    $iterator->current()->relationId = 'rId' . $relId;
104
105 35
                    ++$relId;
106 44
                } elseif ($iterator->current() instanceof Group) {
107 1
                    $iterator2 = $iterator->current()->getShapeCollection()->getIterator();
108 1
                    while ($iterator2->valid()) {
109 1
                        if ($iterator2->current() instanceof Media) {
110
                            // Write relationship for image drawing
111
                            $iterator2->current()->relationId = 'rId' . $relId;
112
                            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/video', '../media/' . $iterator->current()->getIndexedFilename());
113
                            ++$relId;
114
                            $this->writeRelationship($objWriter, $relId, 'http://schemas.microsoft.com/office/2007/relationships/media', '../media/' . $iterator->current()->getIndexedFilename());
115
                            ++$relId;
116 1
                        } elseif ($iterator2->current() instanceof ShapeDrawing\AbstractDrawingAdapter) {
117
                            // Write relationship for image drawing
118
                            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $iterator2->current()->getIndexedFilename());
119
                            $iterator2->current()->relationId = 'rId' . $relId;
120
121
                            ++$relId;
122 1
                        } elseif ($iterator2->current() instanceof ShapeChart) {
123
                            // Write relationship for chart drawing
124
                            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart', '../charts/' . $iterator2->current()->getIndexedFilename());
125
                            $iterator2->current()->relationId = 'rId' . $relId;
126
127
                            ++$relId;
128
                        }
129 1
                        $iterator2->next();
130
                    }
131
                }
132
133 87
                $iterator->next();
134
            }
135
        }
136
137
        // Write background relationships?
138 114
        $oBackground = $pSlide->getBackground();
139 114
        if ($oBackground instanceof Image) {
140
            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $oBackground->getIndexedFilename($idxSlide));
141
            $oBackground->relationId = 'rId' . $relId;
142
            ++$relId;
143
        }
144
145
        // Write hyperlink relationships?
146 114
        if ($pSlide->getShapeCollection()->count() > 0) {
147
            // Loop trough hyperlinks and write relationships
148 87
            $iterator = $pSlide->getShapeCollection()->getIterator();
149 87
            while ($iterator->valid()) {
150
                // Hyperlink on shape
151 87
                if ($iterator->current()->hasHyperlink()) {
152
                    // Write relationship for hyperlink
153 3
                    $hyperlink               = $iterator->current()->getHyperlink();
154 3
                    $hyperlink->relationId = 'rId' . $relId;
155
156 3
                    if (!$hyperlink->isInternal()) {
157 3
                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
158
                    } else {
159
                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
160
                    }
161
162 3
                    ++$relId;
163
                }
164
165
                // Hyperlink on rich text run
166 87
                if ($iterator->current() instanceof RichText) {
167 26
                    foreach ($iterator->current()->getParagraphs() as $paragraph) {
168 26
                        foreach ($paragraph->getRichTextElements() as $element) {
169 21
                            if ($element instanceof Run || $element instanceof TextElement) {
170 20
                                if ($element->hasHyperlink()) {
171
                                    // Write relationship for hyperlink
172 2
                                    $hyperlink               = $element->getHyperlink();
173 2
                                    $hyperlink->relationId = 'rId' . $relId;
174
175 2
                                    if (!$hyperlink->isInternal()) {
176 1
                                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
177
                                    } else {
178 1
                                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
179
                                    }
180
181 26
                                    ++$relId;
182
                                }
183
                            }
184
                        }
185
                    }
186
                }
187
188
                // Hyperlink in table
189 87
                if ($iterator->current() instanceof ShapeTable) {
190
                    // Rows
191 11
                    $countRows = count($iterator->current()->getRows());
192 11
                    for ($row = 0; $row < $countRows; $row++) {
193
                        // Cells in rows
194 11
                        $countCells = count($iterator->current()->getRow($row)->getCells());
195 11
                        for ($cell = 0; $cell < $countCells; $cell++) {
196 11
                            $currentCell = $iterator->current()->getRow($row)->getCell($cell);
197
                            // Paragraphs in cell
198 11
                            foreach ($currentCell->getParagraphs() as $paragraph) {
199
                                // RichText in paragraph
200 11
                                foreach ($paragraph->getRichTextElements() as $element) {
201
                                    // Run or Text in RichText
202 11
                                    if ($element instanceof Run || $element instanceof TextElement) {
203 11
                                        if ($element->hasHyperlink()) {
204
                                            // Write relationship for hyperlink
205 1
                                            $hyperlink               = $element->getHyperlink();
206 1
                                            $hyperlink->relationId = 'rId' . $relId;
207
208 1
                                            if (!$hyperlink->isInternal()) {
209 1
                                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
210
                                            } else {
211
                                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
212
                                            }
213
214 11
                                            ++$relId;
215
                                        }
216
                                    }
217
                                }
218
                            }
219
                        }
220
                    }
221
                }
222
223 87
                if ($iterator->current() instanceof Group) {
224 1
                    $iterator2 = $pSlide->getShapeCollection()->getIterator();
225 1
                    while ($iterator2->valid()) {
226
                        // Hyperlink on shape
227 1
                        if ($iterator2->current()->hasHyperlink()) {
228
                            // Write relationship for hyperlink
229
                            $hyperlink             = $iterator2->current()->getHyperlink();
230
                            $hyperlink->relationId = 'rId' . $relId;
231
232
                            if (!$hyperlink->isInternal()) {
233
                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
234
                            } else {
235
                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
236
                            }
237
238
                            ++$relId;
239
                        }
240
241
                        // Hyperlink on rich text run
242 1
                        if ($iterator2->current() instanceof RichText) {
243
                            foreach ($iterator2->current()->getParagraphs() as $paragraph) {
244
                                foreach ($paragraph->getRichTextElements() as $element) {
245
                                    if ($element instanceof Run || $element instanceof TextElement) {
246
                                        if ($element->hasHyperlink()) {
247
                                            // Write relationship for hyperlink
248
                                            $hyperlink              = $element->getHyperlink();
249
                                            $hyperlink->relationId = 'rId' . $relId;
250
251
                                            if (!$hyperlink->isInternal()) {
252
                                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
253
                                            } else {
254
                                                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
255
                                            }
256
257
                                            ++$relId;
258
                                        }
259
                                    }
260
                                }
261
                            }
262
                        }
263
264
                        // Hyperlink in table
265 1
                        if ($iterator2->current() instanceof ShapeTable) {
266
                            // Rows
267
                            $countRows = count($iterator2->current()->getRows());
268
                            for ($row = 0; $row < $countRows; $row++) {
269
                                // Cells in rows
270
                                $countCells = count($iterator2->current()->getRow($row)->getCells());
271
                                for ($cell = 0; $cell < $countCells; $cell++) {
272
                                    $currentCell = $iterator2->current()->getRow($row)->getCell($cell);
273
                                    // Paragraphs in cell
274
                                    foreach ($currentCell->getParagraphs() as $paragraph) {
275
                                        // RichText in paragraph
276
                                        foreach ($paragraph->getRichTextElements() as $element) {
277
                                            // Run or Text in RichText
278
                                            if ($element instanceof Run || $element instanceof TextElement) {
279
                                                if ($element->hasHyperlink()) {
280
                                                    // Write relationship for hyperlink
281
                                                    $hyperlink               = $element->getHyperlink();
282
                                                    $hyperlink->relationId = 'rId' . $relId;
283
284
                                                    if (!$hyperlink->isInternal()) {
285
                                                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', $hyperlink->getUrl(), 'External');
286
                                                    } else {
287
                                                        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide', 'slide' . $hyperlink->getSlideNumber() . '.xml');
288
                                                    }
289
290
                                                    ++$relId;
291
                                                }
292
                                            }
293
                                        }
294
                                    }
295
                                }
296
                            }
297
                        }
298
299 1
                        $iterator2->next();
300
                    }
301
                }
302
303 87
                $iterator->next();
304
            }
305
        }
306
307
        // Write comment relationships
308 114
        if ($pSlide->getShapeCollection()->count() > 0) {
309 87
            $hasSlideComment = false;
310
311
            // Loop trough images and write relationships
312 87
            $iterator = $pSlide->getShapeCollection()->getIterator();
313 87
            while ($iterator->valid()) {
314 87
                if ($iterator->current() instanceof Comment) {
315 7
                    $hasSlideComment = true;
316 7
                    break;
317 81
                } elseif ($iterator->current() instanceof Group) {
318 1
                    $iterator2 = $iterator->current()->getShapeCollection()->getIterator();
319 1
                    while ($iterator2->valid()) {
320 1
                        if ($iterator2->current() instanceof Comment) {
321 1
                            $hasSlideComment = true;
322 1
                            break 2;
323
                        }
324
                        $iterator2->next();
325
                    }
326
                }
327
328 80
                $iterator->next();
329
            }
330
331 87
            if ($hasSlideComment) {
332 8
                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments', '../comments/comment'.($idxSlide + 1).'.xml');
333 8
                ++$relId;
334
            }
335
        }
336
337 114
        if ($pSlide->getNote()->getShapeCollection()->count() > 0) {
338 2
            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide', '../notesSlides/notesSlide'.($idxSlide + 1).'.xml');
339
        }
340
341 114
        $objWriter->endElement();
342
343
        // Return
344 114
        return $objWriter->getData();
345
    }
346
347
    /**
348
     * Write slide to XML format
349
     *
350
     * @param  \PhpOffice\PhpPresentation\Slide $pSlide
351
     * @return string              XML Output
352
     * @throws \Exception
353
     */
354 114
    public function writeSlide(Slide $pSlide)
355
    {
356
        // Create XML writer
357 114
        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
358
359
        // XML header
360 114
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
361
362
        // p:sld
363 114
        $objWriter->startElement('p:sld');
364 114
        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
365 114
        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
366 114
        $objWriter->writeAttribute('xmlns:p', 'http://schemas.openxmlformats.org/presentationml/2006/main');
367 114
        $objWriter->writeAttributeIf(!$pSlide->isVisible(), 'show', 0);
368
369
        // p:sld/p:cSld
370 114
        $objWriter->startElement('p:cSld');
371
372
        // Background
373 114
        if ($pSlide->getBackground() instanceof Slide\AbstractBackground) {
374
            $oBackground = $pSlide->getBackground();
375
            // p:bg
376
            $objWriter->startElement('p:bg');
377
378
            // p:bgPr
379
            $objWriter->startElement('p:bgPr');
380
381
            if ($oBackground instanceof Slide\Background\Color) {
382
                // a:solidFill
383
                $objWriter->startElement('a:solidFill');
384
385
                $this->writeColor($objWriter, $oBackground->getColor());
386
387
                // > a:solidFill
388
                $objWriter->endElement();
389
            }
390
391
            if ($oBackground instanceof Slide\Background\Image) {
392
                // a:blipFill
393
                $objWriter->startElement('a:blipFill');
394
395
                // a:blip
396
                $objWriter->startElement('a:blip');
397
                $objWriter->writeAttribute('r:embed', $oBackground->relationId);
398
399
                // > a:blipFill
400
                $objWriter->endElement();
401
402
                // a:stretch
403
                $objWriter->startElement('a:stretch');
404
405
                // a:fillRect
406
                $objWriter->writeElement('a:fillRect');
407
408
                // > a:stretch
409
                $objWriter->endElement();
410
411
                // > a:blipFill
412
                $objWriter->endElement();
413
            }
414
415
            // > p:bgPr
416
            $objWriter->endElement();
417
418
            // > p:bg
419
            $objWriter->endElement();
420
        }
421
422
        // p:spTree
423 114
        $objWriter->startElement('p:spTree');
424
425
        // p:nvGrpSpPr
426 114
        $objWriter->startElement('p:nvGrpSpPr');
427
428
        // p:cNvPr
429 114
        $objWriter->startElement('p:cNvPr');
430 114
        $objWriter->writeAttribute('id', '1');
431 114
        $objWriter->writeAttribute('name', '');
432 114
        $objWriter->endElement();
433
434
        // p:cNvGrpSpPr
435 114
        $objWriter->writeElement('p:cNvGrpSpPr', null);
436
437
        // p:nvPr
438 114
        $objWriter->writeElement('p:nvPr', null);
439
440 114
        $objWriter->endElement();
441
442
        // p:grpSpPr
443 114
        $objWriter->startElement('p:grpSpPr');
444
445
        // a:xfrm
446 114
        $objWriter->startElement('a:xfrm');
447
448
        // a:off
449 114
        $objWriter->startElement('a:off');
450 114
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($pSlide->getOffsetX()));
451 114
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($pSlide->getOffsetY()));
452 114
        $objWriter->endElement(); // a:off
453
454
        // a:ext
455 114
        $objWriter->startElement('a:ext');
456 114
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($pSlide->getExtentX()));
457 114
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($pSlide->getExtentY()));
458 114
        $objWriter->endElement(); // a:ext
459
460
        // a:chOff
461 114
        $objWriter->startElement('a:chOff');
462 114
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($pSlide->getOffsetX()));
463 114
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($pSlide->getOffsetY()));
464 114
        $objWriter->endElement(); // a:chOff
465
466
        // a:chExt
467 114
        $objWriter->startElement('a:chExt');
468 114
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($pSlide->getExtentX()));
469 114
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($pSlide->getExtentY()));
470 114
        $objWriter->endElement(); // a:chExt
471
472 114
        $objWriter->endElement();
473
474 114
        $objWriter->endElement();
475
476
        // Loop shapes
477 114
        $shapId = 1;
478 114
        $this->writeShapeCollection($objWriter, $pSlide->getShapeCollection(), $shapId);
479
480
        // TODO
481 114
        $objWriter->endElement();
482
483 114
        $objWriter->endElement();
484
485
        // p:clrMapOvr
486 114
        $objWriter->startElement('p:clrMapOvr');
487
        // p:clrMapOvr\a:masterClrMapping
488 114
        $objWriter->writeElement('a:masterClrMapping', null);
489
        // ##p:clrMapOvr
490 114
        $objWriter->endElement();
491
492 114
        $this->writeSlideTransition($objWriter, $pSlide->getTransition());
493
494 114
        $this->writeSlideAnimations($objWriter, $pSlide);
495
496 114
        $objWriter->endElement();
497
498
        // Return
499 114
        return $objWriter->getData();
500
    }
501
502
    /**
503
     * @param XMLWriter $objWriter
504
     * @param Slide $oSlide
505
     */
506 114
    protected function writeSlideAnimations(XMLWriter $objWriter, Slide $oSlide)
507
    {
508 114
        $arrayAnimations = $oSlide->getAnimations();
509 114
        if (empty($arrayAnimations)) {
510 113
            return;
511
        }
512
513
        // Variables
514 2
        $shapeId = 1;
515 2
        $idCount = 1;
516 2
        $hashToIdMap = array();
517 2
        $arrayAnimationIds = array();
518
519 2
        foreach ($oSlide->getShapeCollection() as $shape) {
520 2
            $hashToIdMap[$shape->getHashCode()] = ++$shapeId;
521
        }
522 2
        foreach ($arrayAnimations as $oAnimation) {
523 2
            foreach ($oAnimation->getShapeCollection() as $oShape) {
524 2
                $arrayAnimationIds[] = $hashToIdMap[$oShape->getHashCode()];
525
            }
526
        }
527
528
        // p:timing
529 2
        $objWriter->startElement('p:timing');
530
        // p:timing/p:tnLst
531 2
        $objWriter->startElement('p:tnLst');
532
        // p:timing/p:tnLst/p:par
533 2
        $objWriter->startElement('p:par');
534
        // p:timing/p:tnLst/p:par/p:cTn
535 2
        $objWriter->startElement('p:cTn');
536 2
        $objWriter->writeAttribute('id', $idCount++);
537 2
        $objWriter->writeAttribute('dur', 'indefinite');
538 2
        $objWriter->writeAttribute('restart', 'never');
539 2
        $objWriter->writeAttribute('nodeType', 'tmRoot');
540
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst
541 2
        $objWriter->startElement('p:childTnLst');
542
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq
543 2
        $objWriter->startElement('p:seq');
544 2
        $objWriter->writeAttribute('concurrent', '1');
545 2
        $objWriter->writeAttribute('nextAc', 'seek');
546
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn
547 2
        $objWriter->startElement('p:cTn');
548 2
        $objWriter->writeAttribute('id', $idCount++);
549 2
        $objWriter->writeAttribute('dur', 'indefinite');
550 2
        $objWriter->writeAttribute('nodeType', 'mainSeq');
551
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst
552 2
        $objWriter->startElement('p:childTnLst');
553
554
        // Each animation has multiple shapes
555 2
        foreach ($arrayAnimations as $oAnimation) {
556
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par
557 2
            $objWriter->startElement('p:par');
558
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn
559 2
            $objWriter->startElement('p:cTn');
560 2
            $objWriter->writeAttribute('id', $idCount++);
561 2
            $objWriter->writeAttribute('fill', 'hold');
562
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:stCondLst
563 2
            $objWriter->startElement('p:stCondLst');
564
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:stCondLst/p:cond
565 2
            $objWriter->startElement('p:cond');
566 2
            $objWriter->writeAttribute('delay', 'indefinite');
567 2
            $objWriter->endElement();
568
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn\##p:stCondLst
569 2
            $objWriter->endElement();
570
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst
571 2
            $objWriter->startElement('p:childTnLst');
572
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par
573 2
            $objWriter->startElement('p:par');
574
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn
575 2
            $objWriter->startElement('p:cTn');
576 2
            $objWriter->writeAttribute('id', $idCount++);
577 2
            $objWriter->writeAttribute('fill', 'hold');
578
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn/p:stCondLst
579 2
            $objWriter->startElement('p:stCondLst');
580
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn/p:stCondLst/p:cond
581 2
            $objWriter->startElement('p:cond');
582 2
            $objWriter->writeAttribute('delay', '0');
583 2
            $objWriter->endElement();
584
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn\##p:stCondLst
585 2
            $objWriter->endElement();
586
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst
587 2
            $objWriter->startElement('p:childTnLst');
588
589 2
            $firstAnimation = true;
590 2
            foreach ($oAnimation->getShapeCollection() as $oShape) {
591 2
                $nodeType = $firstAnimation ? 'clickEffect' : 'withEffect';
592 2
                $shapeId = $hashToIdMap[$oShape->getHashCode()];
593
594
                // p:par
595 2
                $objWriter->startElement('p:par');
596
                // p:par/p:cTn
597 2
                $objWriter->startElement('p:cTn');
598 2
                $objWriter->writeAttribute('id', $idCount++);
599 2
                $objWriter->writeAttribute('presetID', '1');
600 2
                $objWriter->writeAttribute('presetClass', 'entr');
601 2
                $objWriter->writeAttribute('fill', 'hold');
602 2
                $objWriter->writeAttribute('presetSubtype', '0');
603 2
                $objWriter->writeAttribute('grpId', '0');
604 2
                $objWriter->writeAttribute('nodeType', $nodeType);
605
                // p:par/p:cTn/p:stCondLst
606 2
                $objWriter->startElement('p:stCondLst');
607
                // p:par/p:cTn/p:stCondLst/p:cond
608 2
                $objWriter->startElement('p:cond');
609 2
                $objWriter->writeAttribute('delay', '0');
610 2
                $objWriter->endElement();
611
                // p:par/p:cTn\##p:stCondLst
612 2
                $objWriter->endElement();
613
                // p:par/p:cTn/p:childTnLst
614 2
                $objWriter->startElement('p:childTnLst');
615
                // p:par/p:cTn/p:childTnLst/p:set
616 2
                $objWriter->startElement('p:set');
617
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr
618 2
                $objWriter->startElement('p:cBhvr');
619
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn
620 2
                $objWriter->startElement('p:cTn');
621 2
                $objWriter->writeAttribute('id', $idCount++);
622 2
                $objWriter->writeAttribute('dur', '1');
623 2
                $objWriter->writeAttribute('fill', 'hold');
624
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn/p:stCondLst
625 2
                $objWriter->startElement('p:stCondLst');
626
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn/p:stCondLst/p:cond
627 2
                $objWriter->startElement('p:cond');
628 2
                $objWriter->writeAttribute('delay', '0');
629 2
                $objWriter->endElement();
630
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn\##p:stCondLst
631 2
                $objWriter->endElement();
632
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr\##p:cTn
633 2
                $objWriter->endElement();
634
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:tgtEl
635 2
                $objWriter->startElement('p:tgtEl');
636
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:tgtEl/p:spTgt
637 2
                $objWriter->startElement('p:spTgt');
638 2
                $objWriter->writeAttribute('spid', $shapeId);
639 2
                $objWriter->endElement();
640
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr\##p:tgtEl
641 2
                $objWriter->endElement();
642
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:attrNameLst
643 2
                $objWriter->startElement('p:attrNameLst');
644
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:attrNameLst/p:attrName
645 2
                $objWriter->writeElement('p:attrName', 'style.visibility');
646
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr\##p:attrNameLst
647 2
                $objWriter->endElement();
648
                // p:par/p:cTn/p:childTnLst/p:set\##p:cBhvr
649 2
                $objWriter->endElement();
650
                // p:par/p:cTn/p:childTnLst/p:set/p:to
651 2
                $objWriter->startElement('p:to');
652
                // p:par/p:cTn/p:childTnLst/p:set/p:to/p:strVal
653 2
                $objWriter->startElement('p:strVal');
654 2
                $objWriter->writeAttribute('val', 'visible');
655 2
                $objWriter->endElement();
656
                // p:par/p:cTn/p:childTnLst/p:set\##p:to
657 2
                $objWriter->endElement();
658
                // p:par/p:cTn/p:childTnLst\##p:set
659 2
                $objWriter->endElement();
660
                // p:par/p:cTn\##p:childTnLst
661 2
                $objWriter->endElement();
662
                // p:par\##p:cTn
663 2
                $objWriter->endElement();
664
                // ##p:par
665 2
                $objWriter->endElement();
666
667 2
                $firstAnimation = false;
668
            }
669
670
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn\##p:childTnLst
671 2
            $objWriter->endElement();
672
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par\##p:cTn
673 2
            $objWriter->endElement();
674
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst\##p:par
675 2
            $objWriter->endElement();
676
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn\##p:childTnLst
677 2
            $objWriter->endElement();
678
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par\##p:cTn
679 2
            $objWriter->endElement();
680
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst\##p:par
681 2
            $objWriter->endElement();
682
        }
683
684
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn\##p:childTnLst
685 2
        $objWriter->endElement();
686
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq\##p:cTn
687 2
        $objWriter->endElement();
688
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst
689 2
        $objWriter->startElement('p:prevCondLst');
690
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond
691 2
        $objWriter->startElement('p:cond');
692 2
        $objWriter->writeAttribute('evt', 'onPrev');
693 2
        $objWriter->writeAttribute('delay', '0');
694
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond/p:tgtEl
695 2
        $objWriter->startElement('p:tgtEl');
696
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond/p:tgtEl/p:sldTgt
697 2
        $objWriter->writeElement('p:sldTgt', null);
698
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond\##p:tgtEl
699 2
        $objWriter->endElement();
700
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst\##p:cond
701 2
        $objWriter->endElement();
702
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq\##p:prevCondLst
703 2
        $objWriter->endElement();
704
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst
705 2
        $objWriter->startElement('p:nextCondLst');
706
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond
707 2
        $objWriter->startElement('p:cond');
708 2
        $objWriter->writeAttribute('evt', 'onNext');
709 2
        $objWriter->writeAttribute('delay', '0');
710
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond/p:tgtEl
711 2
        $objWriter->startElement('p:tgtEl');
712
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond/p:tgtEl/p:sldTgt
713 2
        $objWriter->writeElement('p:sldTgt', null);
714
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond\##p:tgtEl
715 2
        $objWriter->endElement();
716
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst\##p:cond
717 2
        $objWriter->endElement();
718
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq\##p:nextCondLst
719 2
        $objWriter->endElement();
720
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst\##p:seq
721 2
        $objWriter->endElement();
722
        // p:timing/p:tnLst/p:par/p:cTn\##p:childTnLst
723 2
        $objWriter->endElement();
724
        // p:timing/p:tnLst/p:par\##p:cTn
725 2
        $objWriter->endElement();
726
        // p:timing/p:tnLst\##p:par
727 2
        $objWriter->endElement();
728
        // p:timing\##p:tnLst
729 2
        $objWriter->endElement();
730
731
        // p:timing/p:bldLst
732 2
        $objWriter->startElement('p:bldLst');
733
734
        // Add in ids of all shapes in this slides animations
735 2
        foreach ($arrayAnimationIds as $id) {
736
            // p:timing/p:bldLst/p:bldP
737 2
            $objWriter->startElement('p:bldP');
738 2
            $objWriter->writeAttribute('spid', $id);
739 2
            $objWriter->writeAttribute('grpId', 0);
740 2
            $objWriter->endELement();
741
        }
742
743
        // p:timing\##p:bldLst
744 2
        $objWriter->endElement();
745
746
        // ##p:timing
747 2
        $objWriter->endElement();
748 2
    }
749
750
    /**
751
     * Write pic
752
     *
753
     * @param  \PhpOffice\Common\XMLWriter  $objWriter XML Writer
754
     * @param  \PhpOffice\PhpPresentation\Shape\Drawing\AbstractDrawingAdapter $shape
755
     * @param  int $shapeId
756
     * @throws \Exception
757
     */
758
    protected function writeShapeDrawing(XMLWriter $objWriter, ShapeDrawing\AbstractDrawingAdapter $shape, $shapeId)
759
    {
760
        // p:pic
761
        $objWriter->startElement('p:pic');
762
763
        // p:nvPicPr
764
        $objWriter->startElement('p:nvPicPr');
765
766
        // p:cNvPr
767
        $objWriter->startElement('p:cNvPr');
768
        $objWriter->writeAttribute('id', $shapeId);
769
        $objWriter->writeAttribute('name', $shape->getName());
770
        $objWriter->writeAttribute('descr', $shape->getDescription());
771
772
        // a:hlinkClick
773
        if ($shape->hasHyperlink()) {
774
            $this->writeHyperlink($objWriter, $shape);
775
        }
776
777
        $objWriter->endElement();
778
779
        // p:cNvPicPr
780
        $objWriter->startElement('p:cNvPicPr');
781
782
        // a:picLocks
783
        $objWriter->startElement('a:picLocks');
784
        $objWriter->writeAttribute('noChangeAspect', '1');
785
        $objWriter->endElement();
786
787
        $objWriter->endElement();
788
789
        // p:nvPr
790
        $objWriter->startElement('p:nvPr');
791
        // PlaceHolder
792
        if ($shape->isPlaceholder()) {
793
            $objWriter->startElement('p:ph');
794
            $objWriter->writeAttribute('type', $shape->getPlaceholder()->getType());
795
            $objWriter->endElement();
796
        }
797
        /**
798
         * @link : https://github.com/stefslon/exportToPPTX/blob/master/exportToPPTX.m#L2128
799
         */
800
        if ($shape instanceof Media) {
801
            // p:nvPr > a:videoFile
802
            $objWriter->startElement('a:videoFile');
803
            $objWriter->writeAttribute('r:link', $shape->relationId);
804
            $objWriter->endElement();
805
            // p:nvPr > p:extLst
806
            $objWriter->startElement('p:extLst');
807
            // p:nvPr > p:extLst > p:ext
808
            $objWriter->startElement('p:ext');
809
            $objWriter->writeAttribute('uri', '{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}');
810
            // p:nvPr > p:extLst > p:ext > p14:media
811
            $objWriter->startElement('p14:media');
812
            $objWriter->writeAttribute('r:embed', ($shape->relationId + 1));
813
            $objWriter->writeAttribute('xmlns:p14', 'http://schemas.microsoft.com/office/powerpoint/2010/main');
814
            // p:nvPr > p:extLst > p:ext > ##p14:media
815
            $objWriter->endElement();
816
            // p:nvPr > p:extLst > ##p:ext
817
            $objWriter->endElement();
818
            // p:nvPr > ##p:extLst
819
            $objWriter->endElement();
820
        }
821
        // ##p:nvPr
822
        $objWriter->endElement();
823
        $objWriter->endElement();
824
825
        // p:blipFill
826
        $objWriter->startElement('p:blipFill');
827
828
        // a:blip
829
        $objWriter->startElement('a:blip');
830
        $objWriter->writeAttribute('r:embed', $shape->relationId);
831
        $objWriter->endElement();
832
833
        // a:stretch
834
        $objWriter->startElement('a:stretch');
835
        $objWriter->writeElement('a:fillRect');
836
        $objWriter->endElement();
837
838
        $objWriter->endElement();
839
840
        // p:spPr
841
        $objWriter->startElement('p:spPr');
842
        // a:xfrm
843
        $objWriter->startElement('a:xfrm');
844
        $objWriter->writeAttributeIf($shape->getRotation() != 0, 'rot', CommonDrawing::degreesToAngle($shape->getRotation()));
845
846
        // a:off
847
        $objWriter->startElement('a:off');
848
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX()));
849
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY()));
850
        $objWriter->endElement();
851
852
        // a:ext
853
        $objWriter->startElement('a:ext');
854
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($shape->getWidth()));
855
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($shape->getHeight()));
856
        $objWriter->endElement();
857
858
        $objWriter->endElement();
859
860
        // a:prstGeom
861
        $objWriter->startElement('a:prstGeom');
862
        $objWriter->writeAttribute('prst', 'rect');
863
        // // a:prstGeom/a:avLst
864
        $objWriter->writeElement('a:avLst', null);
865
        // ##a:prstGeom
866
        $objWriter->endElement();
867
868
        $objWriter->endElement();
869
870
        $objWriter->endElement();
871
    }
872
}
873