Passed
Push — master ( 75dfcb...5ec0e3 )
by Adrien
27:56
created

IOFactory::identify()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

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