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