Failed Conditions
Push — master ( a2bb82...a189d9 )
by Adrien
10:27 queued 01:00
created

IOFactory::createWriter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 10
ccs 5
cts 5
cp 1
crap 2
rs 10
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet;
4
5
use PhpOffice\PhpSpreadsheet\Shared\File;
6
7
/**
8
 * Factory to create readers and writers easily.
9
 *
10
 * It is not required to use this class, but it should make it easier to read and write files.
11
 * Especially for reading files with an unknown format.
12
 */
13
abstract class IOFactory
14
{
15
    private static $readers = [
16
        'Xlsx' => Reader\Xlsx::class,
17
        'Xls' => Reader\Xls::class,
18
        'Xml' => Reader\Xml::class,
19
        'Ods' => Reader\Ods::class,
20
        'Slk' => Reader\Slk::class,
21
        'Gnumeric' => Reader\Gnumeric::class,
22
        'Html' => Reader\Html::class,
23
        'Csv' => Reader\Csv::class,
24
    ];
25
26
    private static $writers = [
27
        'Xls' => Writer\Xls::class,
28
        'Xlsx' => Writer\Xlsx::class,
29
        'Ods' => Writer\Ods::class,
30
        'Csv' => Writer\Csv::class,
31
        'Html' => Writer\Html::class,
32
        'Tcpdf' => Writer\Pdf\Tcpdf::class,
33
        'Dompdf' => Writer\Pdf\Dompdf::class,
34
        'Mpdf' => Writer\Pdf\Mpdf::class,
35
    ];
36
37
    /**
38
     * Create Writer\IWriter.
39
     *
40
     * @param string $writerType Example: Xlsx
41
     *
42
     * @return Writer\IWriter
43
     */
44 290
    public static function createWriter(Spreadsheet $spreadsheet, $writerType)
45
    {
46 290
        if (!isset(self::$writers[$writerType])) {
47 1
            throw new Writer\Exception("No writer found for type $writerType");
48
        }
49
50
        // Instantiate writer
51 289
        $className = self::$writers[$writerType];
52
53 289
        return new $className($spreadsheet);
54
    }
55
56
    /**
57
     * Create Reader\IReader.
58
     *
59
     * @param string $readerType Example: Xlsx
60
     *
61
     * @return Reader\IReader
62
     */
63 300
    public static function createReader($readerType)
64
    {
65 300
        if (!isset(self::$readers[$readerType])) {
66 1
            throw new Reader\Exception("No reader found for type $readerType");
67
        }
68
69
        // Instantiate reader
70 299
        $className = self::$readers[$readerType];
71
72 299
        return new $className();
73
    }
74
75
    /**
76
     * Loads Spreadsheet from file using automatic Reader\IReader resolution.
77
     *
78
     * @param string $pFilename The name of the spreadsheet file
79
     *
80
     * @return Spreadsheet
81
     */
82 19
    public static function load($pFilename)
83
    {
84 19
        $reader = self::createReaderForFile($pFilename);
85
86 18
        return $reader->load($pFilename);
87
    }
88
89
    /**
90
     * Identify file type using automatic Reader\IReader resolution.
91
     *
92
     * @param string $pFilename The name of the spreadsheet file to identify
93
     *
94
     * @return string
95
     */
96 12
    public static function identify($pFilename)
97
    {
98 12
        $reader = self::createReaderForFile($pFilename);
99 10
        $className = get_class($reader);
100 10
        $classType = explode('\\', $className);
101 10
        unset($reader);
102
103 10
        return array_pop($classType);
104
    }
105
106
    /**
107
     * Create Reader\IReader for file using automatic Reader\IReader resolution.
108
     *
109
     * @param string $filename The name of the spreadsheet file
110
     *
111
     * @return Reader\IReader
112
     */
113 43
    public static function createReaderForFile($filename)
114
    {
115 43
        File::assertFile($filename);
116
117
        // First, lucky guess by inspecting file extension
118 40
        $guessedReader = self::getReaderTypeFromExtension($filename);
119 40
        if ($guessedReader !== null) {
120 36
            $reader = self::createReader($guessedReader);
121
122
            // Let's see if we are lucky
123 36
            if ($reader->canRead($filename)) {
124 36
                return $reader;
125
            }
126
        }
127
128
        // If we reach here then "lucky guess" didn't give any result
129
        // Try walking through all the options in self::$autoResolveClasses
130 4
        foreach (self::$readers as $type => $class) {
131
            //    Ignore our original guess, we know that won't work
132 4
            if ($type !== $guessedReader) {
133 4
                $reader = self::createReader($type);
134 4
                if ($reader->canRead($filename)) {
135 3
                    return $reader;
136
                }
137
            }
138
        }
139
140 1
        throw new Reader\Exception('Unable to identify a reader for this file');
141
    }
142
143
    /**
144
     * Guess a reader type from the file extension, if any.
145
     *
146
     * @param string $filename
147
     *
148
     * @return null|string
149
     */
150 40
    private static function getReaderTypeFromExtension($filename)
151
    {
152 40
        $pathinfo = pathinfo($filename);
153 40
        if (!isset($pathinfo['extension'])) {
154 1
            return null;
155
        }
156
157 39
        switch (strtolower($pathinfo['extension'])) {
158 39
            case 'xlsx': // Excel (OfficeOpenXML) Spreadsheet
159 32
            case 'xlsm': // Excel (OfficeOpenXML) Macro Spreadsheet (macros will be discarded)
160 32
            case 'xltx': // Excel (OfficeOpenXML) Template
161 32
            case 'xltm': // Excel (OfficeOpenXML) Macro Template (macros will be discarded)
162 7
                return 'Xlsx';
163 32
            case 'xls': // Excel (BIFF) Spreadsheet
164 25
            case 'xlt': // Excel (BIFF) Template
165 7
                return 'Xls';
166 25
            case 'ods': // Open/Libre Offic Calc
167 21
            case 'ots': // Open/Libre Offic Calc Template
168 4
                return 'Ods';
169 21
            case 'slk':
170 4
                return 'Slk';
171 17
            case 'xml': // Excel 2003 SpreadSheetML
172 4
                return 'Xml';
173 13
            case 'gnumeric':
174 7
                return 'Gnumeric';
175 6
            case 'htm':
176 6
            case 'html':
177 3
                return 'Html';
178 3
            case 'csv':
179
                // Do nothing
180
                // We must not try to use CSV reader since it loads
181
                // all files including Excel files etc.
182 1
                return null;
183
            default:
184 2
                return null;
185
        }
186
    }
187
188
    /**
189
     * Register a writer with its type and class name.
190
     *
191
     * @param string $writerType
192
     * @param string $writerClass
193
     */
194 6
    public static function registerWriter($writerType, $writerClass): void
195
    {
196 6
        if (!is_a($writerClass, Writer\IWriter::class, true)) {
197 1
            throw new Writer\Exception('Registered writers must implement ' . Writer\IWriter::class);
198
        }
199
200 5
        self::$writers[$writerType] = $writerClass;
201 5
    }
202
203
    /**
204
     * Register a reader with its type and class name.
205
     *
206
     * @param string $readerType
207
     * @param string $readerClass
208
     */
209 2
    public static function registerReader($readerType, $readerClass): void
210
    {
211 2
        if (!is_a($readerClass, Reader\IReader::class, true)) {
212 1
            throw new Reader\Exception('Registered readers must implement ' . Reader\IReader::class);
213
        }
214
215 1
        self::$readers[$readerType] = $readerClass;
216 1
    }
217
}
218