Completed
Pull Request — develop (#263)
by Franck
09:08
created

PptSlides::writeShapeGroup()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 60
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 60
ccs 33
cts 33
cp 1
rs 9.5555
c 0
b 0
f 0
cc 1
eloc 32
nc 1
nop 3
crap 1

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\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 107
    public function render()
27
    {
28 107
        foreach ($this->oPresentation->getAllSlides() as $idx => $oSlide) {
29 107
            $this->oZip->addFromString('ppt/slides/_rels/slide' . ($idx + 1) . '.xml.rels', $this->writeSlideRelationships($oSlide));
30 107
            $this->oZip->addFromString('ppt/slides/slide' . ($idx + 1) . '.xml', $this->writeSlide($oSlide));
31
32
            // Add note slide
33 107
            if ($oSlide->getNote() instanceof Note) {
34 107
                if ($oSlide->getNote()->getShapeCollection()->count() > 0) {
35 1
                    $this->oZip->addFromString('ppt/notesSlides/notesSlide' . ($idx + 1) . '.xml', $this->writeNote($oSlide->getNote()));
36
                }
37
            }
38
39
            // Add background image slide
40 107
            $oBkgImage = $oSlide->getBackground();
41 107
            if ($oBkgImage instanceof Image) {
42 107
                $this->oZip->addFromString('ppt/media/'.$oBkgImage->getIndexedFilename($idx), file_get_contents($oBkgImage->getPath()));
43
            }
44
        }
45
46 107
        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 107
    protected function writeSlideRelationships(Slide $pSlide)
57
    {
58
        //@todo Group all getShapeCollection()->getIterator
59
60
        // Create XML writer
61 107
        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
62
63
        // XML header
64 107
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
65
66
        // Relationships
67 107
        $objWriter->startElement('Relationships');
68 107
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
69
70
        // Starting relation id
71 107
        $relId = 1;
72 107
        $idxSlide = $pSlide->getParent()->getIndex($pSlide);
73
74
        // Write slideLayout relationship
75 107
        $layoutId = 1;
76 107
        if ($pSlide->getSlideLayout()) {
77 107
            $layoutId = $pSlide->getSlideLayout()->layoutNr;
78
        }
79 107
        $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout', '../slideLayouts/slideLayout' . $layoutId . '.xml');
80 107
        ++$relId;
81
82
        // Write drawing relationships?
83 107
        if ($pSlide->getShapeCollection()->count() > 0) {
84
            // Loop trough images and write relationships
85 80
            $iterator = $pSlide->getShapeCollection()->getIterator();
86 80
            while ($iterator->valid()) {
87 80
                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 79
                } elseif ($iterator->current() instanceof ShapeDrawing\AbstractDrawingAdapter) {
95
                    // Write relationship for image drawing
96 7
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $iterator->current()->getIndexedFilename());
97 7
                    $iterator->current()->relationId = 'rId' . $relId;
98 7
                    ++$relId;
99 72
                } elseif ($iterator->current() instanceof ShapeChart) {
100
                    // Write relationship for chart drawing
101 30
                    $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart', '../charts/' . $iterator->current()->getIndexedFilename());
102
103 30
                    $iterator->current()->relationId = 'rId' . $relId;
104
105 30
                    ++$relId;
106 42
                } 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 80
                $iterator->next();
134
            }
135
        }
136
137
        // Write background relationships?
138 107
        $oBackground = $pSlide->getBackground();
139 107
        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 107
        if ($pSlide->getShapeCollection()->count() > 0) {
147
            // Loop trough hyperlinks and write relationships
148 80
            $iterator = $pSlide->getShapeCollection()->getIterator();
149 80
            while ($iterator->valid()) {
150
                // Hyperlink on shape
151 80
                if ($iterator->current()->hasHyperlink()) {
152
                    // Write relationship for hyperlink
153 2
                    $hyperlink               = $iterator->current()->getHyperlink();
154 2
                    $hyperlink->relationId = 'rId' . $relId;
155
156 2
                    if (!$hyperlink->isInternal()) {
157 2
                        $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 2
                    ++$relId;
163
                }
164
165
                // Hyperlink on rich text run
166 80
                if ($iterator->current() instanceof RichText) {
167 24
                    foreach ($iterator->current()->getParagraphs() as $paragraph) {
168 24
                        foreach ($paragraph->getRichTextElements() as $element) {
169 19
                            if ($element instanceof Run || $element instanceof TextElement) {
170 18
                                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 24
                                    ++$relId;
182
                                }
183
                            }
184
                        }
185
                    }
186
                }
187
188
                // Hyperlink in table
189 80
                if ($iterator->current() instanceof ShapeTable) {
190
                    // Rows
191 10
                    $countRows = count($iterator->current()->getRows());
192 10
                    for ($row = 0; $row < $countRows; $row++) {
193
                        // Cells in rows
194 10
                        $countCells = count($iterator->current()->getRow($row)->getCells());
195 10
                        for ($cell = 0; $cell < $countCells; $cell++) {
196 10
                            $currentCell = $iterator->current()->getRow($row)->getCell($cell);
197
                            // Paragraphs in cell
198 10
                            foreach ($currentCell->getParagraphs() as $paragraph) {
199
                                // RichText in paragraph
200 10
                                foreach ($paragraph->getRichTextElements() as $element) {
201
                                    // Run or Text in RichText
202 10
                                    if ($element instanceof Run || $element instanceof TextElement) {
203 10
                                        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 10
                                            ++$relId;
215
                                        }
216
                                    }
217
                                }
218
                            }
219
                        }
220
                    }
221
                }
222
223 80
                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 80
                $iterator->next();
304
            }
305
        }
306
307
        // Write comment relationships
308 107
        if ($pSlide->getShapeCollection()->count() > 0) {
309 80
            $hasSlideComment = false;
310
311
            // Loop trough images and write relationships
312 80
            $iterator = $pSlide->getShapeCollection()->getIterator();
313 80
            while ($iterator->valid()) {
314 80
                if ($iterator->current() instanceof Comment) {
315 6
                    $hasSlideComment = true;
316 6
                    break;
317 74
                } 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 73
                $iterator->next();
329
            }
330
331 80
            if ($hasSlideComment) {
332 7
                $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments', '../comments/comment'.($idxSlide + 1).'.xml');
333 7
                ++$relId;
334
            }
335
        }
336
337 107
        if ($pSlide->getNote()->getShapeCollection()->count() > 0) {
338 1
            $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide', '../notesSlides/notesSlide'.($idxSlide + 1).'.xml');
339
        }
340
341 107
        $objWriter->endElement();
342
343
        // Return
344 107
        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 107
    public function writeSlide(Slide $pSlide)
355
    {
356
        // Create XML writer
357 107
        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
358
359
        // XML header
360 107
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
361
362
        // p:sld
363 107
        $objWriter->startElement('p:sld');
364 107
        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
365 107
        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
366 107
        $objWriter->writeAttribute('xmlns:p', 'http://schemas.openxmlformats.org/presentationml/2006/main');
367 107
        $objWriter->writeAttributeIf(!$pSlide->isVisible(), 'show', 0);
368
369
        // p:sld/p:cSld
370 107
        $objWriter->startElement('p:cSld');
371
372
        // Background
373 107
        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 107
        $objWriter->startElement('p:spTree');
424
425
        // p:nvGrpSpPr
426 107
        $objWriter->startElement('p:nvGrpSpPr');
427
428
        // p:cNvPr
429 107
        $objWriter->startElement('p:cNvPr');
430 107
        $objWriter->writeAttribute('id', '1');
431 107
        $objWriter->writeAttribute('name', '');
432 107
        $objWriter->endElement();
433
434
        // p:cNvGrpSpPr
435 107
        $objWriter->writeElement('p:cNvGrpSpPr', null);
436
437
        // p:nvPr
438 107
        $objWriter->writeElement('p:nvPr', null);
439
440 107
        $objWriter->endElement();
441
442
        // p:grpSpPr
443 107
        $objWriter->startElement('p:grpSpPr');
444
445
        // a:xfrm
446 107
        $objWriter->startElement('a:xfrm');
447
448
        // a:off
449 107
        $objWriter->startElement('a:off');
450 107
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($pSlide->getOffsetX()));
451 107
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($pSlide->getOffsetY()));
452 107
        $objWriter->endElement(); // a:off
453
454
        // a:ext
455 107
        $objWriter->startElement('a:ext');
456 107
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($pSlide->getExtentX()));
457 107
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($pSlide->getExtentY()));
458 107
        $objWriter->endElement(); // a:ext
459
460
        // a:chOff
461 107
        $objWriter->startElement('a:chOff');
462 107
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($pSlide->getOffsetX()));
463 107
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($pSlide->getOffsetY()));
464 107
        $objWriter->endElement(); // a:chOff
465
466
        // a:chExt
467 107
        $objWriter->startElement('a:chExt');
468 107
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($pSlide->getExtentX()));
469 107
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($pSlide->getExtentY()));
470 107
        $objWriter->endElement(); // a:chExt
471
472 107
        $objWriter->endElement();
473
474 107
        $objWriter->endElement();
475
476
        // Loop shapes
477 107
        $this->writeShapeCollection($objWriter, $pSlide->getShapeCollection());
478
479
        // TODO
480 107
        $objWriter->endElement();
481
482 107
        $objWriter->endElement();
483
484
        // p:clrMapOvr
485 107
        $objWriter->startElement('p:clrMapOvr');
486
        // p:clrMapOvr\a:masterClrMapping
487 107
        $objWriter->writeElement('a:masterClrMapping', null);
488
        // ##p:clrMapOvr
489 107
        $objWriter->endElement();
490
491 107
        $this->writeSlideTransition($objWriter, $pSlide->getTransition());
492
493 107
        $this->writeSlideAnimations($objWriter, $pSlide);
494
495 107
        $objWriter->endElement();
496
497
        // Return
498 107
        return $objWriter->getData();
499
    }
500
501
    /**
502
     * @param XMLWriter $objWriter
503
     * @param Slide $oSlide
504
     */
505 107
    protected function writeSlideAnimations(XMLWriter $objWriter, Slide $oSlide)
506
    {
507 107
        $arrayAnimations = $oSlide->getAnimations();
508 107
        if (empty($arrayAnimations)) {
509 106
            return;
510
        }
511
512
        // Variables
513 1
        $shapeId = 1;
514 1
        $idCount = 1;
515 1
        $hashToIdMap = array();
516 1
        $arrayAnimationIds = array();
517
518 1
        foreach ($oSlide->getShapeCollection() as $shape) {
519 1
            $hashToIdMap[$shape->getHashCode()] = ++$shapeId;
520
        }
521 1
        foreach ($arrayAnimations as $oAnimation) {
522 1
            foreach ($oAnimation->getShapeCollection() as $oShape) {
523 1
                $arrayAnimationIds[] = $hashToIdMap[$oShape->getHashCode()];
524
            }
525
        }
526
527
        // p:timing
528 1
        $objWriter->startElement('p:timing');
529
        // p:timing/p:tnLst
530 1
        $objWriter->startElement('p:tnLst');
531
        // p:timing/p:tnLst/p:par
532 1
        $objWriter->startElement('p:par');
533
        // p:timing/p:tnLst/p:par/p:cTn
534 1
        $objWriter->startElement('p:cTn');
535 1
        $objWriter->writeAttribute('id', $idCount++);
536 1
        $objWriter->writeAttribute('dur', 'indefinite');
537 1
        $objWriter->writeAttribute('restart', 'never');
538 1
        $objWriter->writeAttribute('nodeType', 'tmRoot');
539
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst
540 1
        $objWriter->startElement('p:childTnLst');
541
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq
542 1
        $objWriter->startElement('p:seq');
543 1
        $objWriter->writeAttribute('concurrent', '1');
544 1
        $objWriter->writeAttribute('nextAc', 'seek');
545
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn
546 1
        $objWriter->startElement('p:cTn');
547 1
        $objWriter->writeAttribute('id', $idCount++);
548 1
        $objWriter->writeAttribute('dur', 'indefinite');
549 1
        $objWriter->writeAttribute('nodeType', 'mainSeq');
550
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst
551 1
        $objWriter->startElement('p:childTnLst');
552
553
        // Each animation has multiple shapes
554 1
        foreach ($arrayAnimations as $oAnimation) {
555
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par
556 1
            $objWriter->startElement('p:par');
557
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn
558 1
            $objWriter->startElement('p:cTn');
559 1
            $objWriter->writeAttribute('id', $idCount++);
560 1
            $objWriter->writeAttribute('fill', 'hold');
561
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:stCondLst
562 1
            $objWriter->startElement('p:stCondLst');
563
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:stCondLst/p:cond
564 1
            $objWriter->startElement('p:cond');
565 1
            $objWriter->writeAttribute('delay', 'indefinite');
566 1
            $objWriter->endElement();
567
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn\##p:stCondLst
568 1
            $objWriter->endElement();
569
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst
570 1
            $objWriter->startElement('p:childTnLst');
571
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par
572 1
            $objWriter->startElement('p:par');
573
            // 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
574 1
            $objWriter->startElement('p:cTn');
575 1
            $objWriter->writeAttribute('id', $idCount++);
576 1
            $objWriter->writeAttribute('fill', 'hold');
577
            // 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
578 1
            $objWriter->startElement('p:stCondLst');
579
            // 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
580 1
            $objWriter->startElement('p:cond');
581 1
            $objWriter->writeAttribute('delay', '0');
582 1
            $objWriter->endElement();
583
            // 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
584 1
            $objWriter->endElement();
585
            // 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
586 1
            $objWriter->startElement('p:childTnLst');
587
588 1
            $firstAnimation = true;
589 1
            foreach ($oAnimation->getShapeCollection() as $oShape) {
590 1
                $nodeType = $firstAnimation ? 'clickEffect' : 'withEffect';
591 1
                $shapeId = $hashToIdMap[$oShape->getHashCode()];
592
593
                // p:par
594 1
                $objWriter->startElement('p:par');
595
                // p:par/p:cTn
596 1
                $objWriter->startElement('p:cTn');
597 1
                $objWriter->writeAttribute('id', $idCount++);
598 1
                $objWriter->writeAttribute('presetID', '1');
599 1
                $objWriter->writeAttribute('presetClass', 'entr');
600 1
                $objWriter->writeAttribute('fill', 'hold');
601 1
                $objWriter->writeAttribute('presetSubtype', '0');
602 1
                $objWriter->writeAttribute('grpId', '0');
603 1
                $objWriter->writeAttribute('nodeType', $nodeType);
604
                // p:par/p:cTn/p:stCondLst
605 1
                $objWriter->startElement('p:stCondLst');
606
                // p:par/p:cTn/p:stCondLst/p:cond
607 1
                $objWriter->startElement('p:cond');
608 1
                $objWriter->writeAttribute('delay', '0');
609 1
                $objWriter->endElement();
610
                // p:par/p:cTn\##p:stCondLst
611 1
                $objWriter->endElement();
612
                // p:par/p:cTn/p:childTnLst
613 1
                $objWriter->startElement('p:childTnLst');
614
                // p:par/p:cTn/p:childTnLst/p:set
615 1
                $objWriter->startElement('p:set');
616
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr
617 1
                $objWriter->startElement('p:cBhvr');
618
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn
619 1
                $objWriter->startElement('p:cTn');
620 1
                $objWriter->writeAttribute('id', $idCount++);
621 1
                $objWriter->writeAttribute('dur', '1');
622 1
                $objWriter->writeAttribute('fill', 'hold');
623
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn/p:stCondLst
624 1
                $objWriter->startElement('p:stCondLst');
625
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn/p:stCondLst/p:cond
626 1
                $objWriter->startElement('p:cond');
627 1
                $objWriter->writeAttribute('delay', '0');
628 1
                $objWriter->endElement();
629
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:cTn\##p:stCondLst
630 1
                $objWriter->endElement();
631
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr\##p:cTn
632 1
                $objWriter->endElement();
633
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:tgtEl
634 1
                $objWriter->startElement('p:tgtEl');
635
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:tgtEl/p:spTgt
636 1
                $objWriter->startElement('p:spTgt');
637 1
                $objWriter->writeAttribute('spid', $shapeId);
638 1
                $objWriter->endElement();
639
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr\##p:tgtEl
640 1
                $objWriter->endElement();
641
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:attrNameLst
642 1
                $objWriter->startElement('p:attrNameLst');
643
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr/p:attrNameLst/p:attrName
644 1
                $objWriter->writeElement('p:attrName', 'style.visibility');
645
                // p:par/p:cTn/p:childTnLst/p:set/p:cBhvr\##p:attrNameLst
646 1
                $objWriter->endElement();
647
                // p:par/p:cTn/p:childTnLst/p:set\##p:cBhvr
648 1
                $objWriter->endElement();
649
                // p:par/p:cTn/p:childTnLst/p:set/p:to
650 1
                $objWriter->startElement('p:to');
651
                // p:par/p:cTn/p:childTnLst/p:set/p:to/p:strVal
652 1
                $objWriter->startElement('p:strVal');
653 1
                $objWriter->writeAttribute('val', 'visible');
654 1
                $objWriter->endElement();
655
                // p:par/p:cTn/p:childTnLst/p:set\##p:to
656 1
                $objWriter->endElement();
657
                // p:par/p:cTn/p:childTnLst\##p:set
658 1
                $objWriter->endElement();
659
                // p:par/p:cTn\##p:childTnLst
660 1
                $objWriter->endElement();
661
                // p:par\##p:cTn
662 1
                $objWriter->endElement();
663
                // ##p:par
664 1
                $objWriter->endElement();
665
666 1
                $firstAnimation = false;
667
            }
668
669
            // 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
670 1
            $objWriter->endElement();
671
            // 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
672 1
            $objWriter->endElement();
673
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst\##p:par
674 1
            $objWriter->endElement();
675
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn\##p:childTnLst
676 1
            $objWriter->endElement();
677
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par\##p:cTn
678 1
            $objWriter->endElement();
679
            // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst\##p:par
680 1
            $objWriter->endElement();
681
        }
682
683
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn\##p:childTnLst
684 1
        $objWriter->endElement();
685
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq\##p:cTn
686 1
        $objWriter->endElement();
687
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst
688 1
        $objWriter->startElement('p:prevCondLst');
689
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond
690 1
        $objWriter->startElement('p:cond');
691 1
        $objWriter->writeAttribute('evt', 'onPrev');
692 1
        $objWriter->writeAttribute('delay', '0');
693
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond/p:tgtEl
694 1
        $objWriter->startElement('p:tgtEl');
695
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond/p:tgtEl/p:sldTgt
696 1
        $objWriter->writeElement('p:sldTgt', null);
697
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst/p:cond\##p:tgtEl
698 1
        $objWriter->endElement();
699
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:prevCondLst\##p:cond
700 1
        $objWriter->endElement();
701
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq\##p:prevCondLst
702 1
        $objWriter->endElement();
703
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst
704 1
        $objWriter->startElement('p:nextCondLst');
705
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond
706 1
        $objWriter->startElement('p:cond');
707 1
        $objWriter->writeAttribute('evt', 'onNext');
708 1
        $objWriter->writeAttribute('delay', '0');
709
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond/p:tgtEl
710 1
        $objWriter->startElement('p:tgtEl');
711
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond/p:tgtEl/p:sldTgt
712 1
        $objWriter->writeElement('p:sldTgt', null);
713
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst/p:cond\##p:tgtEl
714 1
        $objWriter->endElement();
715
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:nextCondLst\##p:cond
716 1
        $objWriter->endElement();
717
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq\##p:nextCondLst
718 1
        $objWriter->endElement();
719
        // p:timing/p:tnLst/p:par/p:cTn/p:childTnLst\##p:seq
720 1
        $objWriter->endElement();
721
        // p:timing/p:tnLst/p:par/p:cTn\##p:childTnLst
722 1
        $objWriter->endElement();
723
        // p:timing/p:tnLst/p:par\##p:cTn
724 1
        $objWriter->endElement();
725
        // p:timing/p:tnLst\##p:par
726 1
        $objWriter->endElement();
727
        // p:timing\##p:tnLst
728 1
        $objWriter->endElement();
729
730
        // p:timing/p:bldLst
731 1
        $objWriter->startElement('p:bldLst');
732
733
        // Add in ids of all shapes in this slides animations
734 1
        foreach ($arrayAnimationIds as $id) {
735
            // p:timing/p:bldLst/p:bldP
736 1
            $objWriter->startElement('p:bldP');
737 1
            $objWriter->writeAttribute('spid', $id);
738 1
            $objWriter->writeAttribute('grpId', 0);
739 1
            $objWriter->endELement();
740
        }
741
742
        // p:timing\##p:bldLst
743 1
        $objWriter->endElement();
744
745
        // ##p:timing
746 1
        $objWriter->endElement();
747 1
    }
748
749
    /**
750
     * Write pic
751
     *
752
     * @param  \PhpOffice\Common\XMLWriter  $objWriter XML Writer
753
     * @param  \PhpOffice\PhpPresentation\Shape\Drawing\AbstractDrawingAdapter $shape
754
     * @param  int $shapeId
755
     * @throws \Exception
756
     */
757
    protected function writeShapeDrawing(XMLWriter $objWriter, ShapeDrawing\AbstractDrawingAdapter $shape, $shapeId)
758
    {
759
        // p:pic
760
        $objWriter->startElement('p:pic');
761
762
        // p:nvPicPr
763
        $objWriter->startElement('p:nvPicPr');
764
765
        // p:cNvPr
766
        $objWriter->startElement('p:cNvPr');
767
        $objWriter->writeAttribute('id', $shapeId);
768
        $objWriter->writeAttribute('name', $shape->getName());
769
        $objWriter->writeAttribute('descr', $shape->getDescription());
770
771
        // a:hlinkClick
772
        if ($shape->hasHyperlink()) {
773
            $this->writeHyperlink($objWriter, $shape);
774
        }
775
776
        $objWriter->endElement();
777
778
        // p:cNvPicPr
779
        $objWriter->startElement('p:cNvPicPr');
780
781
        // a:picLocks
782
        $objWriter->startElement('a:picLocks');
783
        $objWriter->writeAttribute('noChangeAspect', '1');
784
        $objWriter->endElement();
785
786
        $objWriter->endElement();
787
788
        // p:nvPr
789
        $objWriter->startElement('p:nvPr');
790
        // PlaceHolder
791
        if ($shape->isPlaceholder()) {
792
            $objWriter->startElement('p:ph');
793
            $objWriter->writeAttribute('type', $shape->getPlaceholder()->getType());
794
            $objWriter->endElement();
795
        }
796
        /**
797
         * @link : https://github.com/stefslon/exportToPPTX/blob/master/exportToPPTX.m#L2128
798
         */
799
        if ($shape instanceof Media) {
800
            // p:nvPr > a:videoFile
801
            $objWriter->startElement('a:videoFile');
802
            $objWriter->writeAttribute('r:link', $shape->relationId);
803
            $objWriter->endElement();
804
            // p:nvPr > p:extLst
805
            $objWriter->startElement('p:extLst');
806
            // p:nvPr > p:extLst > p:ext
807
            $objWriter->startElement('p:ext');
808
            $objWriter->writeAttribute('uri', '{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}');
809
            // p:nvPr > p:extLst > p:ext > p14:media
810
            $objWriter->startElement('p14:media');
811
            $objWriter->writeAttribute('r:embed', ($shape->relationId + 1));
812
            $objWriter->writeAttribute('xmlns:p14', 'http://schemas.microsoft.com/office/powerpoint/2010/main');
813
            // p:nvPr > p:extLst > p:ext > ##p14:media
814
            $objWriter->endElement();
815
            // p:nvPr > p:extLst > ##p:ext
816
            $objWriter->endElement();
817
            // p:nvPr > ##p:extLst
818
            $objWriter->endElement();
819
        }
820
        // ##p:nvPr
821
        $objWriter->endElement();
822
        $objWriter->endElement();
823
824
        // p:blipFill
825
        $objWriter->startElement('p:blipFill');
826
827
        // a:blip
828
        $objWriter->startElement('a:blip');
829
        $objWriter->writeAttribute('r:embed', $shape->relationId);
830
        $objWriter->endElement();
831
832
        // a:stretch
833
        $objWriter->startElement('a:stretch');
834
        $objWriter->writeElement('a:fillRect', null);
835
        $objWriter->endElement();
836
837
        $objWriter->endElement();
838
839
        // p:spPr
840
        $objWriter->startElement('p:spPr');
841
        // a:xfrm
842
        $objWriter->startElement('a:xfrm');
843
        $objWriter->writeAttributeIf($shape->getRotation() != 0, 'rot', CommonDrawing::degreesToAngle($shape->getRotation()));
844
845
        // a:off
846
        $objWriter->startElement('a:off');
847
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX()));
848
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY()));
849
        $objWriter->endElement();
850
851
        // a:ext
852
        $objWriter->startElement('a:ext');
853
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($shape->getWidth()));
854
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($shape->getHeight()));
855
        $objWriter->endElement();
856
857
        $objWriter->endElement();
858
859
        // a:prstGeom
860
        $objWriter->startElement('a:prstGeom');
861
        $objWriter->writeAttribute('prst', 'rect');
862
863
        // a:avLst
864
        $objWriter->writeElement('a:avLst', null);
865
866
        $objWriter->endElement();
867
868
        $this->writeBorder($objWriter, $shape->getBorder(), '');
869
870
        $this->writeShadow($objWriter, $shape->getShadow());
871
872
        $objWriter->endElement();
873
874
        $objWriter->endElement();
875
    }
876
}
877