Completed
Pull Request — master (#203)
by ignace nyamagana
02:06
created

AbstractCsv::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 0
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 2
crap 2
1
<?php
2
/**
3
* This file is part of the League.csv library
4
*
5
* @license http://opensource.org/licenses/MIT
6
* @link https://github.com/thephpleague/csv/
7
* @version 8.1.1
8
* @package League.csv
9
*
10
* For the full copyright and license information, please view the LICENSE
11
* file that was distributed with this source code.
12
*/
13
namespace League\Csv;
14
15
use InvalidArgumentException;
16
use IteratorAggregate;
17
use JsonSerializable;
18
use League\Csv\Config\Controls;
19
use League\Csv\Config\Output;
20
use League\Csv\Modifier\QueryFilter;
21
use League\Csv\Modifier\StreamFilter;
22
use League\Csv\Modifier\StreamIterator;
23
use SplFileInfo;
24
use SplFileObject;
25
use SplTempFileObject;
26
27
/**
28
 *  An abstract class to enable basic CSV manipulation
29
 *
30
 * @package League.csv
31
 * @since  4.0.0
32
 *
33
 */
34
abstract class AbstractCsv implements JsonSerializable, IteratorAggregate
35
{
36
    use Controls;
37
38
    use Output;
39
40
    use QueryFilter;
41
42
    use StreamFilter;
43
44
    /**
45
     *  UTF-8 BOM sequence
46
     */
47
    const BOM_UTF8 = "\xEF\xBB\xBF";
48
49
    /**
50
     * UTF-16 BE BOM sequence
51
     */
52
    const BOM_UTF16_BE = "\xFE\xFF";
53
54
    /**
55
     * UTF-16 LE BOM sequence
56
     */
57
    const BOM_UTF16_LE = "\xFF\xFE";
58
59
    /**
60
     * UTF-32 BE BOM sequence
61
     */
62
    const BOM_UTF32_BE = "\x00\x00\xFE\xFF";
63
64
    /**
65
     * UTF-32 LE BOM sequence
66
     */
67
    const BOM_UTF32_LE = "\xFF\xFE\x00\x00";
68
69
    /**
70
     * The constructor path
71
     *
72
     * can be a SplFileInfo object or the string path to a file
73
     *
74
     * @var SplFileObject|string
75
     */
76
    protected $path;
77
78
    /**
79
     * The file open mode flag
80
     *
81
     * @var string
82
     */
83
    protected $open_mode;
84
85
    /**
86
     * Creates a new instance
87
     *
88
     * The path must be an SplFileInfo object
89
     * an object that implements the `__toString` method
90
     * a path to a file
91
     *
92
     * @param StreamIterator|SplFileObject|string $path      The file path
93
     * @param string                              $open_mode The file open mode flag
94
     */
95
    protected function __construct($path, $open_mode = 'r+')
96
    {
97
        $this->open_mode = strtolower($open_mode);
98
        $this->path = $path;
0 ignored issues
show
Documentation Bug introduced by
It seems like $path can also be of type object<League\Csv\Modifier\StreamIterator>. However, the property $path is declared as type object<SplFileObject>|string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
99
        $this->initStreamFilter($this->path);
0 ignored issues
show
Bug introduced by
It seems like $this->path can also be of type object<League\Csv\Modifier\StreamIterator>; however, League\Csv\Modifier\Stre...ter::initStreamFilter() does only seem to accept object<SplFileObject>|string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
100
    }
101
102
    /**
103
     * The destructor
104
     */
105 357
    public function __destruct()
106
    {
107 357
        $this->path = null;
108 357
    }
109 357
110 357
    /**
111
     * Return a new {@link AbstractCsv} from a SplFileObject
112
     *
113
     * @param SplFileObject $file
114
     *
115 240
     * @return static
116
     */
117 240
    public static function createFromFileObject(SplFileObject $file)
118 240
    {
119
        $csv = new static($file);
120
        $controls = $file->getCsvControl();
121
        $csv->setDelimiter($controls[0]);
122
        $csv->setEnclosure($controls[1]);
123
        if (isset($controls[2])) {
124
            $csv->setEscape($controls[2]);
125
        }
126
127 312
        return $csv;
128
    }
129 312
130
    /**
131
     * Return a new {@link AbstractCsv} from a PHP resource stream or a StreamIterator
132
     *
133
     * @param StreamIterator|resource $stream
134
     *
135
     * @return static
136
     */
137
    public static function createFromStream($stream)
138
    {
139
        if (!$stream instanceof StreamIterator) {
140
            $stream = new StreamIterator($stream);
141
        }
142 27
143
        $csv = new static($stream);
144 27
        $controls = $stream->getCsvControl();
145 27
        $csv->setDelimiter($controls[0]);
146
        $csv->setEnclosure($controls[1]);
147 27
        $csv->setEscape($controls[2]);
148
149
        return $csv;
150
    }
151
152
    /**
153
     * Return a new {@link AbstractCsv} from a string
154
     *
155
     * The string must be an object that implements the `__toString` method,
156
     * or a string
157
     *
158
     * @param string|object $str the string
159 90
     *
160
     * @return static
161 90
     */
162 87
    public static function createFromString($str)
163
    {
164 3
        $file = new SplTempFileObject();
165
        $file->fwrite(static::validateString($str));
166
167
        return new static($file);
168
    }
169
170
    /**
171
     * validate a string
172
     *
173
     * @param mixed $str the value to evaluate as a string
174
     *
175
     * @throws InvalidArgumentException if the submitted data can not be converted to string
176
     *
177 54
     * @return string
178
     */
179 54
    protected static function validateString($str)
180 3
    {
181
        if (is_string($str) || (is_object($str) && method_exists($str, '__toString'))) {
182
            return (string) $str;
183 51
        }
184 3
        throw new InvalidArgumentException('Expected data must be a string or stringable');
185 2
    }
186
187 51
    /**
188
     * Return a new {@link AbstractCsv} from a file path
189
     *
190
     * @param mixed  $path      file path
191
     * @param string $open_mode the file open mode flag
192
     *
193
     * @throws InvalidArgumentException If $path is a SplTempFileObject object
194
     *
195
     * @return static
196
     */
197
    public static function createFromPath($path, $open_mode = 'r+')
198 6
    {
199
        if ($path instanceof SplTempFileObject) {
200 6
            throw new InvalidArgumentException('an `SplTempFileObject` object does not contain a valid path');
201 6
        }
202 6
203 6
        if ($path instanceof SplFileInfo) {
204 6
            $path = $path->getPath().'/'.$path->getBasename();
205 6
        }
206 6
207 6
        return new static(static::validateString($path), $open_mode);
208
    }
209 6
210
    /**
211
     * Return a new {@link AbstractCsv} instance from another {@link AbstractCsv} object
212
     *
213
     * @param string $class     the class to be instantiated
214
     * @param string $open_mode the file open mode flag
215
     *
216
     * @return static
217
     */
218
    protected function newInstance($class, $open_mode)
219 3
    {
220
        $csv = new $class($this->path, $open_mode);
221 3
        $csv->delimiter = $this->delimiter;
222
        $csv->enclosure = $this->enclosure;
223
        $csv->escape = $this->escape;
224
        $csv->input_encoding = $this->input_encoding;
225
        $csv->input_bom = $this->input_bom;
226
        $csv->output_bom = $this->output_bom;
227
        $csv->newline = $this->newline;
228
229
        return $csv;
230
    }
231 3
232
    /**
233 3
     * Return a new {@link Writer} instance from a {@link AbstractCsv} object
234
     *
235
     * @param string $open_mode the file open mode flag
236
     *
237
     * @return Writer
238
     */
239
    public function newWriter($open_mode = 'r+')
240
    {
241 267
        return $this->newInstance(Writer::class, $open_mode);
242
    }
243 267
244 267
    /**
245 33
     * Return a new {@link Reader} instance from a {@link AbstractCsv} object
246 22
     *
247 267
     * @param string $open_mode the file open mode flag
248 267
     *
249
     * @return Reader
250 267
     */
251
    public function newReader($open_mode = 'r+')
252
    {
253
        return $this->newInstance(Reader::class, $open_mode);
254
    }
255
256
    /**
257
     * Returns the inner SplFileObject
258
     *
259
     * @return StreamIterator|SplFileObject
260
     */
261
    public function getIterator()
262
    {
263
        $iterator = $this->setIterator();
264
        $iterator->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
265
        $iterator->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY);
266
267
        return $iterator;
268
    }
269
270
    /**
271
     * Set the Inner Iterator
272
     *
273
     * @return StreamIterator|SplFileObject
274
     */
275
    protected function setIterator()
276
    {
277
        if ($this->path instanceof StreamIterator || $this->path instanceof SplFileObject) {
278
            return $this->path;
279
        }
280
281
        return new SplFileObject($this->getStreamFilterPath(), $this->open_mode);
282
    }
283
}
284