Completed
Pull Request — master (#331)
by Adrien
02:57
created

AbstractReader::isSupportedStreamWrapper()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

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