AbstractCsv::getDialect()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace CSanquer\ColibriCsv;
4
5
use CSanquer\ColibriCsv\Utility\Transcoder;
6
7
/**
8
 * Common Abstract Csv
9
 *
10
 * @author Charles SANQUER - <[email protected]>
11
 */
12
abstract class AbstractCsv
13
{
14
    const MODE_READING = 'reading';
15
    const MODE_WRITING = 'writing';
16
    /**
17
     *
18
     * @var Dialect
19
     */
20
    protected $dialect;
21
22
    /**
23
     * @var Transcoder
24
     */
25
    protected $transcoder;
26
27
    /**
28
     *
29
     * @var string
30
     */
31
    protected $filename;
32
33
    /**
34
     *
35
     * @var string
36
     */
37
    protected $fileHandlerMode;
38
39
    /**
40
     *
41
     * @var string
42
     */
43
    protected $mode;
44
45
    /**
46
     *
47
     * @var resource
48
     */
49
    protected $fileHandler;
50
51
    /**
52
     * CSV Header row
53
     * 
54
     * @var array
55
     */
56
    protected $headers = [];
57
    
58
    /**
59
     *
60
     * Default Excel configuration
61
     *
62
     * @param Dialect|array $options default = []
63
     */
64 62
    public function __construct($options = [])
65
    {
66 62
        $this->dialect = $options instanceof Dialect ? $options : new Dialect($options);
67 62
        $this->transcoder = new Transcoder($this->dialect->getEncoding());
68 62
    }
69
70 41
    public function __destruct()
71
    {
72 41
        $this->closeFile();
73 41
    }
74
75
    /**
76
     * @return array compatible file handler modes
77
     */
78
    abstract protected function getCompatibleFileHanderModes();
79
80
    /**
81
     * get CSV first row header if enabled
82
     * 
83
     * @return array
84
     */
85 13
    public function getHeaders()
86
    {
87 13
        return $this->headers;
88
    }
89
90
    /**
91
     *
92
     * check if a file handle mode is allowed
93
     *
94
     * @param string $mode
95
     *
96
     * @throws \InvalidArgumentException
97
     */
98 6
    protected function checkFileHandleMode($mode)
99
    {
100 6
        if (!in_array($mode, $this->getCompatibleFileHanderModes())) {
101 1
            throw new \InvalidArgumentException(
102 1
                'The file handler mode "'.$mode.'" is not valid. Allowed modes : "'.
103 1
                implode('", "', $this->getCompatibleFileHanderModes()).'".'
104 1
            );
105
        }
106 5
    }
107
108
    /**
109
     *
110
     * @return Dialect
111
     */
112 1
    public function getDialect()
113
    {
114 1
        return $this->dialect;
115
    }
116
117 1
    public function setDialect(Dialect $dialect)
118
    {
119 1
        $this->dialect = $dialect;
120
121 1
        return $this;
122
    }
123
124
    /**
125
     *
126
     * @deprecated since version 1.0.2 use setFile instead
127
     *
128
     * @param  string|resource $filename filename or stream resource
129
     * @return AbstractCsv
130
     */
131
    public function setFilename($filename)
132
    {
133
        return $this->setFile($filename);
134
    }
135
136
    /**
137
     *
138
     * @param  string|resource $file filename or stream resource
139
     * @return AbstractCsv
140
     */
141 52
    public function setFile($file)
142
    {
143 52
        if (is_resource($file)) {
144 7
            if (get_resource_type($file) !== 'stream') {
145 1
                throw new \InvalidArgumentException('The file resource must be valid stream resource.');
146
            }
147
148 6
            $streamMeta = stream_get_meta_data($file);
149 6
            $mode = $streamMeta['mode'];
150 6
            $this->checkFileHandleMode($mode);
151 5
            $this->fileHandler = $file;
152 5
            $this->fileHandlerMode = $mode;
153 5
            $file = $streamMeta['uri'];
154 5
        } else {
155 45
            if ($this->mode == self::MODE_READING && !file_exists($file)) {
156 1
                throw new \InvalidArgumentException('The file "'.$file.'" does not exists.');
157
            }
158
159 44
            if ($this->isFileOpened() && $file != $this->filename) {
160 1
                $this->closeFile();
161 1
            }
162
        }
163
164 49
        $this->filename = $file;
165
166 49
        return $this;
167
    }
168
169
    /**
170
     *
171
     * @return string
172
     */
173 5
    public function getFilename()
174
    {
175 5
        return $this->filename;
176
    }
177
178
    /**
179
     *
180
     * @return resource stream
181
     */
182 43
    public function getFileHandler()
183
    {
184 43
        return $this->fileHandler;
185
    }
186
187
    /**
188
     * Write UTF-8 BOM code if encoding is UTF-8 and useBom is set to true
189
     *
190
     * @return AbstractCsv
191
     */
192 12
    protected function writeBom()
193
    {
194 12
        if ($this->dialect->getUseBom()) {
195 2
            $bom = $this->transcoder->getBOM($this->dialect->getEncoding());
196
            // Write the unicode BOM code
197 2
            if (!empty($bom) && $this->isFileOpened()) {
198 1
                fwrite($this->fileHandler, is_array($bom) ? $bom[0] : $bom);
199 1
            }
200 2
        }
201
202 12
        return $this;
203
    }
204
205
    /**
206
     * Remove BOM in the provided string
207
     *
208
     * @param  string $str
209
     * @return string
210
     */
211 15
    protected function removeBom($str)
212
    {
213 15
        return $str !== false && $this->dialect->getUseBom() ? str_replace($this->transcoder->getBOM($this->dialect->getEncoding()), '', $str) : $str;
214
    }
215
216
    /**
217
     *
218
     * @param  string $str
219
     * @param  string $from
220
     * @param  string $to
221
     * @return string
222
     */
223 13
    protected function convertEncoding($str, $from, $to)
224
    {
225 13
        return $str !== false ? $this->transcoder->transcode($str, $from, $to, $this->dialect->getTranslit()) : $str;
226
    }
227
228
    /**
229
     *
230
     * @param  string   $mode file handler open mode, default = rb
231
     * @return resource file handler
232
     *
233
     * @throws \InvalidArgumentException
234
     */
235 48
    protected function openFile($mode = 'rb')
236
    {
237 48
        if (!$this->isFileOpened()) {
238 43
            $mode = empty($mode) ? 'rb' : $mode;
239 43
            $this->fileHandler = @fopen($this->filename, $mode);
240 43
            if (!$this->isFileOpened()) {
241 4
                $modeLabel = $this instanceof CsvReader ? self::MODE_READING : self::MODE_WRITING;
242 4
                throw new \InvalidArgumentException('Could not open file "'.$this->filename.'" for '.$modeLabel.'.');
243
            }
244 39
        }
245
246 44
        return $this->fileHandler;
247
    }
248
249
    /**
250
     *
251
     * @return boolean
252
     */
253 43
    protected function closeFile()
254
    {
255 43
        if ($this->isFileOpened()) {
256 33
            $ret = @fclose($this->fileHandler);
257 33
            $this->fileHandler = null;
258
259 33
            return $ret;
260
        }
261
262 39
        return false;
263
    }
264
265
    /**
266
     *
267
     * check if a file is already opened and is a stream
268
     *
269
     * @return boolean
270
     */
271 54
    public function isFileOpened()
272
    {
273 54
        return is_resource($this->fileHandler) && get_resource_type($this->fileHandler) == 'stream';
274
    }
275
276
    /**
277
     * open a csv file to read or write
278
     *
279
     * @param  string|resource $file filename or stream resource, default = null
280
     * @return AbstractCsv
281
     *
282
     * @throws \InvalidArgumentException
283
     */
284 34
    public function open($file = null)
285
    {
286 34
        if (!is_null($file)) {
287 32
            $this->setFile($file);
288 30
        }
289 32
        $this->openFile($this->fileHandlerMode);
290
291 30
        return $this;
292
    }
293
294
    /**
295
     * Open a temp php stream for reading from a CSV string or Writing CSV to a PHP string
296
     *
297
     * @param  string                           $csvContent
298
     * @return \CSanquer\ColibriCsv\AbstractCsv
299
     */
300 2
    public function createTempStream($csvContent = null)
301
    {
302 2
        $this->closeFile();
303
304 2
        $stream = fopen('php://temp', $this->mode == self::MODE_WRITING ? 'wb' : 'r+b');
305 2
        if ($this->mode == self::MODE_READING && $csvContent !== null && $csvContent !== '') {
306 1
            fwrite($stream, $csvContent);
307 1
            rewind($stream);
308 1
        }
309
310 2
        $this->open($stream);
311
312 2
        return $this;
313
    }
314
315
    /**
316
     * get the current stream resource (or file) content
317
     *
318
     * @return string
319
     */
320 1
    public function getFileContent()
321
    {
322 1
        $this->openFile();
323 1
        $content = '';
324
325 1
        if ($this->isFileOpened()) {
326 1
            $current = ftell($this->fileHandler);
327 1
            rewind($this->fileHandler);
328 1
            $content = stream_get_contents($this->fileHandler);
329 1
            fseek($this->fileHandler, $current);
330 1
        }
331
332 1
        return $content;
333
    }
334
335
    /**
336
     * close the current csv file
337
     *
338
     * @return AbstractCsv
339
     */
340 30
    public function close()
341
    {
342 30
        $this->closeFile();
343
344 30
        return $this;
345
    }
346
}
347