Completed
Pull Request — develop_3.0 (#568)
by Hura
08:27
created

ReaderAbstract::setStartColumnIndex()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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