Failed Conditions
Push — develop ( a6bb49...7a4cbd )
by Adrien
36:15
created

ContentTypes::writeDefaultContentType()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.0261

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 3
dl 0
loc 10
ccs 6
cts 7
cp 0.8571
crap 3.0261
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx;
4
5
use PhpOffice\PhpSpreadsheet\Shared\File;
6
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
7
use PhpOffice\PhpSpreadsheet\Spreadsheet;
8
use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing;
9
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
10
11
class ContentTypes extends WriterPart
12
{
13
    /**
14
     * Write content types to XML format.
15
     *
16
     * @param Spreadsheet $spreadsheet
17
     * @param bool $includeCharts Flag indicating if we should include drawing details for charts
18
     *
19
     * @throws WriterException
20
     *
21
     * @return string XML Output
22
     */
23 78
    public function writeContentTypes(Spreadsheet $spreadsheet, $includeCharts = false)
24
    {
25
        // Create XML writer
26 78
        $objWriter = null;
27 78
        if ($this->getParentWriter()->getUseDiskCaching()) {
28
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
29
        } else {
30 78
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
31
        }
32
33
        // XML header
34 78
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
35
36
        // Types
37 78
        $objWriter->startElement('Types');
38 78
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/content-types');
39
40
        // Theme
41 78
        $this->writeOverrideContentType($objWriter, '/xl/theme/theme1.xml', 'application/vnd.openxmlformats-officedocument.theme+xml');
42
43
        // Styles
44 78
        $this->writeOverrideContentType($objWriter, '/xl/styles.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml');
45
46
        // Rels
47 78
        $this->writeDefaultContentType($objWriter, 'rels', 'application/vnd.openxmlformats-package.relationships+xml');
48
49
        // XML
50 78
        $this->writeDefaultContentType($objWriter, 'xml', 'application/xml');
51
52
        // VML
53 78
        $this->writeDefaultContentType($objWriter, 'vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing');
54
55
        // Workbook
56 78
        if ($spreadsheet->hasMacros()) { //Macros in workbook ?
57
            // Yes : not standard content but "macroEnabled"
58 1
            $this->writeOverrideContentType($objWriter, '/xl/workbook.xml', 'application/vnd.ms-excel.sheet.macroEnabled.main+xml');
59
            //... and define a new type for the VBA project
60
            // Better use Override, because we can use 'bin' also for xl\printerSettings\printerSettings1.bin
61 1
            $this->writeOverrideContentType($objWriter, '/xl/vbaProject.bin', 'application/vnd.ms-office.vbaProject');
62 1
            if ($spreadsheet->hasMacrosCertificate()) {
63
                // signed macros ?
64
                // Yes : add needed information
65 1
                $this->writeOverrideContentType($objWriter, '/xl/vbaProjectSignature.bin', 'application/vnd.ms-office.vbaProjectSignature');
66
            }
67
        } else {
68
            // no macros in workbook, so standard type
69 77
            $this->writeOverrideContentType($objWriter, '/xl/workbook.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml');
70
        }
71
72
        // DocProps
73 78
        $this->writeOverrideContentType($objWriter, '/docProps/app.xml', 'application/vnd.openxmlformats-officedocument.extended-properties+xml');
74
75 78
        $this->writeOverrideContentType($objWriter, '/docProps/core.xml', 'application/vnd.openxmlformats-package.core-properties+xml');
76
77 78
        $customPropertyList = $spreadsheet->getProperties()->getCustomProperties();
78 78
        if (!empty($customPropertyList)) {
79 2
            $this->writeOverrideContentType($objWriter, '/docProps/custom.xml', 'application/vnd.openxmlformats-officedocument.custom-properties+xml');
80
        }
81
82
        // Worksheets
83 78
        $sheetCount = $spreadsheet->getSheetCount();
84 78
        for ($i = 0; $i < $sheetCount; ++$i) {
85 78
            $this->writeOverrideContentType($objWriter, '/xl/worksheets/sheet' . ($i + 1) . '.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml');
86
        }
87
88
        // Shared strings
89 78
        $this->writeOverrideContentType($objWriter, '/xl/sharedStrings.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml');
90
91
        // Add worksheet relationship content types
92 78
        $unparsedLoadedData = $spreadsheet->getUnparsedLoadedData();
93 78
        $chart = 1;
94 78
        for ($i = 0; $i < $sheetCount; ++$i) {
95 78
            $drawings = $spreadsheet->getSheet($i)->getDrawingCollection();
96 78
            $drawingCount = count($drawings);
97 78
            $chartCount = ($includeCharts) ? $spreadsheet->getSheet($i)->getChartCount() : 0;
98 78
            $hasUnparsedDrawing = isset($unparsedLoadedData['sheets'][$spreadsheet->getSheet($i)->getCodeName()]['drawingOriginalIds']);
99
100
            //    We need a drawing relationship for the worksheet if we have either drawings or charts
101 78
            if (($drawingCount > 0) || ($chartCount > 0) || $hasUnparsedDrawing) {
102 23
                $this->writeOverrideContentType($objWriter, '/xl/drawings/drawing' . ($i + 1) . '.xml', 'application/vnd.openxmlformats-officedocument.drawing+xml');
103
            }
104
105
            //    If we have charts, then we need a chart relationship for every individual chart
106 78
            if ($chartCount > 0) {
107 13
                for ($c = 0; $c < $chartCount; ++$c) {
108 13
                    $this->writeOverrideContentType($objWriter, '/xl/charts/chart' . $chart++ . '.xml', 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml');
109
                }
110
            }
111
        }
112
113
        // Comments
114 78
        for ($i = 0; $i < $sheetCount; ++$i) {
115 78
            if (count($spreadsheet->getSheet($i)->getComments()) > 0) {
116 10
                $this->writeOverrideContentType($objWriter, '/xl/comments' . ($i + 1) . '.xml', 'application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml');
117
            }
118
        }
119
120
        // Add media content-types
121 78
        $aMediaContentTypes = [];
122 78
        $mediaCount = $this->getParentWriter()->getDrawingHashTable()->count();
123 78
        for ($i = 0; $i < $mediaCount; ++$i) {
124 10
            $extension = '';
125 10
            $mimeType = '';
126
127 10
            if ($this->getParentWriter()->getDrawingHashTable()->getByIndex($i) instanceof \PhpOffice\PhpSpreadsheet\Worksheet\Drawing) {
128 6
                $extension = strtolower($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getExtension());
0 ignored issues
show
Bug introduced by
The method getExtension() does not exist on PhpOffice\PhpSpreadsheet\IComparable. It seems like you code against a sub-type of PhpOffice\PhpSpreadsheet\IComparable such as PhpOffice\PhpSpreadsheet\Worksheet\Drawing. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

128
                $extension = strtolower($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->/** @scrutinizer ignore-call */ getExtension());
Loading history...
129 6
                $mimeType = $this->getImageMimeType($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getPath());
0 ignored issues
show
Bug introduced by
The method getPath() does not exist on PhpOffice\PhpSpreadsheet\IComparable. It seems like you code against a sub-type of PhpOffice\PhpSpreadsheet\IComparable such as PhpOffice\PhpSpreadsheet\Worksheet\Drawing. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

129
                $mimeType = $this->getImageMimeType($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->/** @scrutinizer ignore-call */ getPath());
Loading history...
130 4
            } elseif ($this->getParentWriter()->getDrawingHashTable()->getByIndex($i) instanceof MemoryDrawing) {
131 4
                $extension = strtolower($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getMimeType());
0 ignored issues
show
Bug introduced by
The method getMimeType() does not exist on PhpOffice\PhpSpreadsheet\IComparable. It seems like you code against a sub-type of PhpOffice\PhpSpreadsheet\IComparable such as PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

131
                $extension = strtolower($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->/** @scrutinizer ignore-call */ getMimeType());
Loading history...
132 4
                $extension = explode('/', $extension);
133 4
                $extension = $extension[1];
134
135 4
                $mimeType = $this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getMimeType();
136
            }
137
138 10
            if (!isset($aMediaContentTypes[$extension])) {
139 10
                $aMediaContentTypes[$extension] = $mimeType;
140
141 10
                $this->writeDefaultContentType($objWriter, $extension, $mimeType);
142
            }
143
        }
144 78
        if ($spreadsheet->hasRibbonBinObjects()) {
145
            // Some additional objects in the ribbon ?
146
            // we need to write "Extension" but not already write for media content
147
            $tabRibbonTypes = array_diff($spreadsheet->getRibbonBinObjects('types'), array_keys($aMediaContentTypes));
148
            foreach ($tabRibbonTypes as $aRibbonType) {
149
                $mimeType = 'image/.' . $aRibbonType; //we wrote $mimeType like customUI Editor
150
                $this->writeDefaultContentType($objWriter, $aRibbonType, $mimeType);
151
            }
152
        }
153 78
        $sheetCount = $spreadsheet->getSheetCount();
154 78
        for ($i = 0; $i < $sheetCount; ++$i) {
155 78
            if (count($spreadsheet->getSheet($i)->getHeaderFooter()->getImages()) > 0) {
156 1
                foreach ($spreadsheet->getSheet($i)->getHeaderFooter()->getImages() as $image) {
157 1
                    if (!isset($aMediaContentTypes[strtolower($image->getExtension())])) {
158 1
                        $aMediaContentTypes[strtolower($image->getExtension())] = $this->getImageMimeType($image->getPath());
159
160 1
                        $this->writeDefaultContentType($objWriter, strtolower($image->getExtension()), $aMediaContentTypes[strtolower($image->getExtension())]);
161
                    }
162
                }
163
            }
164
        }
165
166
        // unparsed defaults
167 78
        if (isset($unparsedLoadedData['default_content_types'])) {
168 4
            foreach ($unparsedLoadedData['default_content_types'] as $extName => $contentType) {
169 4
                $this->writeDefaultContentType($objWriter, $extName, $contentType);
170
            }
171
        }
172
173
        // unparsed overrides
174 78
        if (isset($unparsedLoadedData['override_content_types'])) {
175 1
            foreach ($unparsedLoadedData['override_content_types'] as $partName => $overrideType) {
176 1
                $this->writeOverrideContentType($objWriter, $partName, $overrideType);
177
            }
178
        }
179
180 78
        $objWriter->endElement();
181
182
        // Return
183 78
        return $objWriter->getData();
184
    }
185
186
    /**
187
     * Get image mime type.
188
     *
189
     * @param string $pFile Filename
190
     *
191
     * @throws WriterException
192
     *
193
     * @return string Mime Type
194
     */
195 7
    private function getImageMimeType($pFile)
196
    {
197 7
        if (File::fileExists($pFile)) {
198 7
            $image = getimagesize($pFile);
199
200 7
            return image_type_to_mime_type($image[2]);
201
        }
202
203
        throw new WriterException("File $pFile does not exist");
204
    }
205
206
    /**
207
     * Write Default content type.
208
     *
209
     * @param XMLWriter $objWriter XML Writer
210
     * @param string $pPartname Part name
211
     * @param string $pContentType Content type
212
     *
213
     * @throws WriterException
214
     */
215 78
    private function writeDefaultContentType(XMLWriter $objWriter, $pPartname, $pContentType)
216
    {
217 78
        if ($pPartname != '' && $pContentType != '') {
218
            // Write content type
219 78
            $objWriter->startElement('Default');
220 78
            $objWriter->writeAttribute('Extension', $pPartname);
221 78
            $objWriter->writeAttribute('ContentType', $pContentType);
222 78
            $objWriter->endElement();
223
        } else {
224
            throw new WriterException('Invalid parameters passed.');
225
        }
226 78
    }
227
228
    /**
229
     * Write Override content type.
230
     *
231
     * @param XMLWriter $objWriter XML Writer
232
     * @param string $pPartname Part name
233
     * @param string $pContentType Content type
234
     *
235
     * @throws WriterException
236
     */
237 78
    private function writeOverrideContentType(XMLWriter $objWriter, $pPartname, $pContentType)
238
    {
239 78
        if ($pPartname != '' && $pContentType != '') {
240
            // Write content type
241 78
            $objWriter->startElement('Override');
242 78
            $objWriter->writeAttribute('PartName', $pPartname);
243 78
            $objWriter->writeAttribute('ContentType', $pContentType);
244 78
            $objWriter->endElement();
245
        } else {
246
            throw new WriterException('Invalid parameters passed.');
247
        }
248 78
    }
249
}
250