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