Completed
Pull Request — master (#366)
by Alexander
02:25
created

AbstractReader   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 225
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 98.31%

Importance

Changes 0
Metric Value
wmc 24
lcom 1
cbo 2
dl 0
loc 225
ccs 58
cts 59
cp 0.9831
rs 10
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
getOptions() 0 1 ?
doesSupportStreamWrapper() 0 1 ?
openReader() 0 1 ?
getConcreteSheetIterator() 0 1 ?
closeReader() 0 1 ?
A setGlobalFunctionsHelper() 0 5 1
A setShouldFormatDates() 0 5 1
A setShouldPreserveEmptyRows() 0 5 1
A getFileRealPath() 0 9 2
A getStreamWrapperScheme() 0 8 2
A isStreamWrapper() 0 4 1
A isSupportedStreamWrapper() 0 7 2
A isPhpStream() 0 5 1
A getSheetIterator() 0 8 2
A close() 0 13 3
C open() 0 23 8
1
<?php
2
3
namespace Box\Spout\Reader;
4
5
use Box\Spout\Common\Exception\IOException;
6
use Box\Spout\Reader\Exception\ReaderNotOpenedException;
7
8
/**
9
 * Class AbstractReader
10
 *
11
 * @package Box\Spout\Reader
12
 * @abstract
13
 */
14
abstract class AbstractReader implements ReaderInterface
15
{
16
    /** @var bool Indicates whether the stream is currently open */
17
    protected $isStreamOpened = false;
18
19
    /** @var \Box\Spout\Common\Helper\GlobalFunctionsHelper Helper to work with global functions */
20
    protected $globalFunctionsHelper;
21
22
    /** @var \Box\Spout\Reader\Common\ReaderOptions Reader's customized options */
23
    protected $options;
24
25
    /**
26
     * Returns the reader's current options
27
     *
28
     * @return \Box\Spout\Reader\Common\ReaderOptions
29
     */
30
    abstract protected function getOptions();
31
32
    /**
33
     * Returns whether stream wrappers are supported
34
     *
35
     * @return bool
36
     */
37
    abstract protected function doesSupportStreamWrapper();
38
39
    /**
40
     * Opens the file at the given file path to make it ready to be read
41
     *
42
     * @param  string $filePath Path of the file to be read
43
     * @return void
44
     */
45
    abstract protected function openReader($filePath);
46
47
    /**
48
     * Returns an iterator to iterate over sheets.
49
     *
50
     * @return \Iterator To iterate over sheets
51
     */
52
    abstract protected function getConcreteSheetIterator();
53
54
    /**
55
     * Closes the reader. To be used after reading the file.
56
     *
57
     * @return AbstractReader
58
     */
59
    abstract protected function closeReader();
60
61
    /**
62
     * @param \Box\Spout\Common\Helper\GlobalFunctionsHelper $globalFunctionsHelper
63
     * @return AbstractReader
64
     */
65 306
    public function setGlobalFunctionsHelper($globalFunctionsHelper)
66
    {
67 306
        $this->globalFunctionsHelper = $globalFunctionsHelper;
68 306
        return $this;
69
    }
70
71
    /**
72
     * Sets whether date/time values should be returned as PHP objects or be formatted as strings.
73
     *
74
     * @api
75
     * @param bool $shouldFormatDates
76
     * @return AbstractReader
77
     */
78 186
    public function setShouldFormatDates($shouldFormatDates)
79
    {
80 186
        $this->getOptions()->setShouldFormatDates($shouldFormatDates);
81 186
        return $this;
82 3
    }
83
84
    /**
85
     * Sets whether empty rows should be returned or skipped.
86
     *
87
     * @api
88
     * @param bool $shouldPreserveEmptyRows
89
     * @return AbstractReader
90
     */
91 249
    public function setShouldPreserveEmptyRows($shouldPreserveEmptyRows)
92
    {
93 249
        $this->getOptions()->setShouldPreserveEmptyRows($shouldPreserveEmptyRows);
94 249
        return $this;
95
    }
96
97
    /**
98
     * Prepares the reader to read the given file. It also makes sure
99
     * that the file exists and is readable.
100
     *
101
     * @api
102
     * @param  string $filePath Path of the file to be read
103
     * @return void
104
     * @throws \Box\Spout\Common\Exception\IOException If the file at the given path does not exist, is not readable or is corrupted
105
     */
106 303
    public function open($filePath)
107
    {
108 303
        if ($this->isStreamWrapper($filePath) && (!$this->doesSupportStreamWrapper() || !$this->isSupportedStreamWrapper($filePath))) {
109 15
            throw new IOException("Could not open $filePath for reading! Stream wrapper used is not supported for this type of file.");
110
        }
111
112 288
        if (!$this->isPhpStream($filePath)) {
113
            // we skip the checks if the provided file path points to a PHP stream
114 288
            if (!$this->globalFunctionsHelper->file_exists($filePath)) {
115 9
                throw new IOException("Could not open $filePath for reading! File does not exist.");
116 279
            } else if (!$this->globalFunctionsHelper->is_readable($filePath)) {
117 3
                throw new IOException("Could not open $filePath for reading! File is not readable.");
118
            }
119 276
        }
120
121
        try {
122 276
            $fileRealPath = $this->getFileRealPath($filePath);
123 276
            $this->openReader($fileRealPath);
124 261
            $this->isStreamOpened = true;
125 276
        } catch (\Exception $exception) {
126 15
            throw new IOException("Could not open $filePath for reading! ({$exception->getMessage()})");
127
        }
128 261
    }
129
130
    /**
131
     * Returns the real path of the given path.
132
     * If the given path is a valid stream wrapper, returns the path unchanged.
133
     *
134
     * @param string $filePath
135
     * @return string
136
     */
137 276
    protected function getFileRealPath($filePath)
138
    {
139 276
        if ($this->isSupportedStreamWrapper($filePath)) {
140 276
            return $filePath;
141
        }
142
143
        // Need to use realpath to fix "Can't open file" on some Windows setup
144
        return realpath($filePath);
145
    }
146
147
    /**
148
     * Returns the scheme of the custom stream wrapper, if the path indicates a stream wrapper is used.
149
     * For example, php://temp => php, s3://path/to/file => s3...
150
     *
151
     * @param string $filePath Path of the file to be read
152
     * @return string|null The stream wrapper scheme or NULL if not a stream wrapper
153
     */
154 303
    protected function getStreamWrapperScheme($filePath)
155
    {
156 303
        $streamScheme = null;
157 303
        if (preg_match('/^(\w+):\/\//', $filePath, $matches)) {
158 18
            $streamScheme = $matches[1];
159 18
        }
160 303
        return $streamScheme;
161
    }
162
163
    /**
164
     * Checks if the given path is an unsupported stream wrapper
165
     * (like local path, php://temp, mystream://foo/bar...).
166
     *
167
     * @param string $filePath Path of the file to be read
168
     * @return bool Whether the given path is an unsupported stream wrapper
169
     */
170 303
    protected function isStreamWrapper($filePath)
171
    {
172 303
        return ($this->getStreamWrapperScheme($filePath) !== null);
173
    }
174
175
    /**
176
     * Checks if the given path is an supported stream wrapper
177
     * (like php://temp, mystream://foo/bar...).
178
     * If the given path is a local path, returns true.
179
     *
180
     * @param string $filePath Path of the file to be read
181
     * @return bool Whether the given path is an supported stream wrapper
182
     */
183 279
    protected function isSupportedStreamWrapper($filePath)
184
    {
185 279
        $streamScheme = $this->getStreamWrapperScheme($filePath);
186 279
        return ($streamScheme !== null) ?
187 279
            in_array($streamScheme, $this->globalFunctionsHelper->stream_get_wrappers()) :
188 279
            true;
189
    }
190
191
    /**
192
     * Checks if a path is a PHP stream (like php://output, php://memory, ...)
193
     *
194
     * @param string $filePath Path of the file to be read
195
     * @return bool Whether the given path maps to a PHP stream
196
     */
197 288
    protected function isPhpStream($filePath)
198
    {
199 288
        $streamScheme = $this->getStreamWrapperScheme($filePath);
200 288
        return ($streamScheme === 'php');
201
    }
202
203
    /**
204
     * Returns an iterator to iterate over sheets.
205
     *
206
     * @api
207
     * @return \Iterator To iterate over sheets
208
     * @throws \Box\Spout\Reader\Exception\ReaderNotOpenedException If called before opening the reader
209
     */
210 264
    public function getSheetIterator()
211
    {
212 264
        if (!$this->isStreamOpened) {
213 3
            throw new ReaderNotOpenedException('Reader should be opened first.');
214
        }
215
216 261
        return $this->getConcreteSheetIterator();
217
    }
218
219
    /**
220
     * Closes the reader, preventing any additional reading
221
     *
222
     * @api
223
     * @return void
224
     */
225 249
    public function close()
226
    {
227 249
        if ($this->isStreamOpened) {
228 249
            $this->closeReader();
229
230 249
            $sheetIterator = $this->getConcreteSheetIterator();
231 249
            if ($sheetIterator) {
232 249
                $sheetIterator->end();
233 249
            }
234
235 249
            $this->isStreamOpened = false;
236 249
        }
237 249
    }
238
}
239