Completed
Push — develop ( 069c66...25ff91 )
by Adrien
23:18
created

IOFactory::createReaderForFile()   C

Complexity

Conditions 7
Paths 9

Size

Total Lines 29
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 11.8162

Importance

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