Completed
Pull Request — develop (#230)
by Franck
07:45
created

PptSlideMasters::writeSlideMasterRelationships()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 28
ccs 15
cts 15
cp 1
rs 8.8571
cc 2
eloc 14
nc 2
nop 2
crap 2
1
<?php
2
namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007;
3
4
use PhpOffice\Common\Drawing as CommonDrawing;
5
use PhpOffice\Common\XMLWriter;
6
use PhpOffice\PhpPresentation\Shape\AbstractDrawing;
7
use PhpOffice\PhpPresentation\Shape\Chart as ShapeChart;
8
use PhpOffice\PhpPresentation\Shape\Comment;
9
use PhpOffice\PhpPresentation\Shape\Group;
10
use PhpOffice\PhpPresentation\Shape\Line;
11
use PhpOffice\PhpPresentation\Shape\RichText;
12
use PhpOffice\PhpPresentation\Shape\Table as ShapeTable;
13
use PhpOffice\PhpPresentation\Slide;
14
use PhpOffice\PhpPresentation\Slide\SlideMaster;
15
use PhpOffice\PhpPresentation\Style\TextStyle;
16
17
class PptSlideMasters extends AbstractSlide
18
{
19
    /**
20
     * @return \PhpOffice\Common\Adapter\Zip\ZipInterface
21
     */
22 95
    public function render()
23
    {
24 95
        $prevLayouts = 0;
25 95
        foreach ($this->oPresentation->getAllMasterSlides() as $idx => $oSlide) {
26 95
            $oSlide->setRelsIndex($idx + 1);
27
            // Add the relations from the masterSlide to the ZIP file
28 95
            $this->oZip->addFromString('ppt/slideMasters/_rels/slideMaster' . ($idx + 1) . '.xml.rels', $this->writeSlideMasterRelationships($oSlide, $prevLayouts));
29
            // Add the information from the masterSlide to the ZIP file
30 95
            $this->oZip->addFromString('ppt/slideMasters/slideMaster' . ($idx + 1) . '.xml', $this->writeSlideMaster($oSlide));
31 95
            $prevLayouts += count($oSlide->getAllSlideLayouts());
32 95
        }
33
//        // Add layoutpack relations
34
//        $otherRelations = $oLayoutPack->getMasterSlideRelations();
35
//        foreach ($otherRelations as $otherRelation) {
36
//            if (strpos($otherRelation['target'], 'http://') !== 0) {
37
//                $this->oZip->addFromString(
38
//                  $this->absoluteZipPath('ppt/slideMasters/' . $otherRelation['target']),
39
//                  $otherRelation['contents']
40
//              );
41
//            }
42
//        }
43 95
        return $this->oZip;
44
    }
45
46
    /**
47
     * Write slide master relationships to XML format
48
     *
49
     * @param SlideMaster $pSlideMaster
50
     * @param int $layoutNr
51
     * @return string XML Output
52
     * @throws \Exception
53
     * @internal param int $masterId Master slide id
54
     */
55 95
    public function writeSlideMasterRelationships(SlideMaster $pSlideMaster, $layoutNr)
56
    {
57
        // Create XML writer
58 95
        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
59
        // XML header
60 95
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
61
        // Relationships
62 95
        $objWriter->startElement('Relationships');
63 95
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
64
        // Starting relation id
65 95
        $relId = 0;
66
        // Write all the relations to the Layout Slides
67 95
        foreach ($pSlideMaster->getAllSlideLayouts() as $slideLayout) {
68 95
            $this->writeRelationship($objWriter, ++$relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout', '../slideLayouts/slideLayout' . ++$layoutNr . '.xml');
69
            // Save the used relationId & layout number
70 95
            $slideLayout->relationId = 'rId' . $relId;
71 95
            $slideLayout->layoutNr = $layoutNr;
72 95
        }
73
        // Write drawing relationships?
74 95
        $this->writeDrawingRelations($pSlideMaster, $objWriter, $relId);
75
        // TODO: Write hyperlink relationships?
76
        // TODO: Write comment relationships
77
        // Relationship theme/theme1.xml
78 95
        $this->writeRelationship($objWriter, ++$relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme', '../theme/theme' . $pSlideMaster->getRelsIndex() . '.xml');
79 95
        $objWriter->endElement();
80
        // Return
81 95
        return $objWriter->getData();
82
    }
83
84
    /**
85
     * Write slide to XML format
86
     *
87
     * @param  \PhpOffice\PhpPresentation\Slide\SlideMaster $pSlideMaster
0 ignored issues
show
Documentation introduced by
There is no parameter named $pSlideMaster. Did you maybe mean $pSlide?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
88
     * @return string              XML Output
89
     * @throws \Exception
90
     */
91 95
    public function writeSlideMaster(SlideMaster $pSlide)
92
    {
93
        // Create XML writer
94 95
        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
95
        // XML header
96 95
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
97
        // p:sldMaster
98 95
        $objWriter->startElement('p:sldMaster');
99 95
        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
100 95
        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
101 95
        $objWriter->writeAttribute('xmlns:p', 'http://schemas.openxmlformats.org/presentationml/2006/main');
102
        // p:cSld
103 95
        $objWriter->startElement('p:cSld');
104
        // Background
105 95
        if ($pSlide->getBackground() instanceof Slide\AbstractBackground) {
106 95
            $this->writeSlideBackground($pSlide, $objWriter);
107 95
        }
108
        // p:spTree
109 95
        $objWriter->startElement('p:spTree');
110
        // p:nvGrpSpPr
111 95
        $objWriter->startElement('p:nvGrpSpPr');
112
        // p:cNvPr
113 95
        $objWriter->startElement('p:cNvPr');
114 95
        $objWriter->writeAttribute('id', '1');
115 95
        $objWriter->writeAttribute('name', '');
116 95
        $objWriter->endElement();
117
        // p:cNvGrpSpPr
118 95
        $objWriter->writeElement('p:cNvGrpSpPr', null);
119
        // p:nvPr
120 95
        $objWriter->writeElement('p:nvPr', null);
121 95
        $objWriter->endElement();
122
        // p:grpSpPr
123 95
        $objWriter->startElement('p:grpSpPr');
124
        // a:xfrm
125 95
        $objWriter->startElement('a:xfrm');
126
        // a:off
127 95
        $objWriter->startElement('a:off');
128 95
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($pSlide->getOffsetX()));
129 95
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($pSlide->getOffsetY()));
130 95
        $objWriter->endElement(); // a:off
131
        // a:ext
132 95
        $objWriter->startElement('a:ext');
133 95
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($pSlide->getExtentX()));
134 95
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($pSlide->getExtentY()));
135 95
        $objWriter->endElement(); // a:ext
136
        // a:chOff
137 95
        $objWriter->startElement('a:chOff');
138 95
        $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($pSlide->getOffsetX()));
139 95
        $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($pSlide->getOffsetY()));
140 95
        $objWriter->endElement(); // a:chOff
141
        // a:chExt
142 95
        $objWriter->startElement('a:chExt');
143 95
        $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($pSlide->getExtentX()));
144 95
        $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($pSlide->getExtentY()));
145 95
        $objWriter->endElement(); // a:chExt
146 95
        $objWriter->endElement();
147 95
        $objWriter->endElement();
148
        // Loop shapes
149 95
        $shapeId = 0;
150 95
        $shapes = $pSlide->getShapeCollection();
151 95
        foreach ($shapes as $shape) {
152
            // Increment $shapeId
153
            ++$shapeId;
154
            // Check type
155
            if ($shape instanceof RichText) {
156
                $this->writeShapeText($objWriter, $shape, $shapeId);
157
            } elseif ($shape instanceof ShapeTable) {
158
                $this->writeShapeTable($objWriter, $shape, $shapeId);
159
            } elseif ($shape instanceof Line) {
160
                $this->writeShapeLine($objWriter, $shape, $shapeId);
161
            } elseif ($shape instanceof ShapeChart) {
162
                $this->writeShapeChart($objWriter, $shape, $shapeId);
163
            } elseif ($shape instanceof AbstractDrawing) {
0 ignored issues
show
Bug introduced by
The class PhpOffice\PhpPresentation\Shape\AbstractDrawing does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
164
                $this->writeShapePic($objWriter, $shape, $shapeId);
165
            } elseif ($shape instanceof Group) {
166
                $this->writeShapeGroup($objWriter, $shape, $shapeId);
167
            }
168 95
        }
169
        // TODO
170 95
        $objWriter->endElement();
171 95
        $objWriter->endElement();
172
        // < p:clrMap
173 95
        $objWriter->startElement('p:clrMap');
174 95
        foreach ($pSlide->colorMap->getMapping() as $n => $v) {
175 95
            $objWriter->writeAttribute($n, $v);
176 95
        }
177 95
        $objWriter->endElement();
178
        // < p:clrMap
179
        // < p:sldLayoutIdLst
180 95
        $objWriter->startElement('p:sldLayoutIdLst');
181 95
        $sldLayoutId = time() + 689016272; // requires minimum value of 2147483648
182 95
        foreach ($pSlide->getAllSlideLayouts() as $layout) {
183
            /* @var $layout Slide\SlideLayout */
184 95
            $objWriter->startElement('p:sldLayoutId');
185 95
            $objWriter->writeAttribute('id', $sldLayoutId++);
186 95
            $objWriter->writeAttribute('r:id', $layout->relationId);
187 95
            $objWriter->endElement();
188 95
        }
189 95
        $objWriter->endElement();
190
        // > p:sldLayoutIdLst
191
        // p:txStyles
192 95
        $objWriter->startElement('p:txStyles');
193 95
        foreach (array("p:titleStyle" => $pSlide->getTextStyles()->getTitleStyle(),
194 95
                     "p:bodyStyle" => $pSlide->getTextStyles()->getBodyStyle(),
195 95
                     "p:otherStyle" => $pSlide->getTextStyles()->getOtherStyle()) as $startElement => $stylesArray) {
196
            // titleStyle
197 95
            $objWriter->startElement($startElement);
198 95
            foreach ($stylesArray as $lvl => $oParagraph) {
199
                /** @var RichText\Paragraph $oParagraph */
200 95
                $elementName = ($lvl == 0 ? "a:defRPr" : "a:lvl" . $lvl . "pPr");
201 95
                $objWriter->startElement($elementName);
202 95
                $objWriter->writeAttribute('algn', $oParagraph->getAlignment()->getHorizontal());
203 95
                $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($oParagraph->getAlignment()->getMarginLeft()));
204 95
                $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($oParagraph->getAlignment()->getMarginRight()));
205 95
                $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($oParagraph->getAlignment()->getIndent()));
206 95
                $objWriter->startElement('a:defRPr');
207 95
                $objWriter->writeAttribute('sz', $oParagraph->getFont()->getSize() * 100);
208 95
                $objWriter->writeAttribute('kern', '1200');
209 95
                $objWriter->startElement('a:solidFill');
210 95
                $objWriter->startElement('a:schemeClr');
211 95
                $objWriter->writeAttribute('val', $oParagraph->getFont()->getColor()->getValue());
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class PhpOffice\PhpPresentation\Style\Color as the method getValue() does only exist in the following sub-classes of PhpOffice\PhpPresentation\Style\Color: PhpOffice\PhpPresentation\Style\SchemeColor. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
212 95
                $objWriter->endElement();
213 95
                $objWriter->endElement();
214 95
                $objWriter->endElement();
215 95
                $objWriter->endElement();
216 95
            }
217 95
            $objWriter->endElement();
218 95
        }
219 95
        $objWriter->endElement();
220
        // > p:txStyles
221 95
        if (!is_null($pSlide->getTransition())) {
222
            $this->writeTransition($objWriter, $pSlide->getTransition());
0 ignored issues
show
Bug introduced by
The method writeTransition() does not seem to exist on object<PhpOffice\PhpPres...nt2007\PptSlideMasters>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
223
        }
224 95
        $objWriter->endElement();
225
        // Return
226 95
        return $objWriter->getData();
227
    }
228
}
229