Completed
Pull Request — develop_3.0 (#457)
by Adrien
02:34
created

ReaderAbstract::setShouldFormatDates()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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