Completed
Push — master ( 748f90...5c1aea )
by Luke
08:07
created

Flavor::__get()   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
c 0
b 0
f 0
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * CSVelte: Slender, elegant CSV for PHP
4
 *
5
 * Inspired by Python's CSV module and Frictionless Data and the W3C's CSV
6
 * standardization efforts, CSVelte was written in an effort to take all the
7
 * suck out of working with CSV.
8
 *
9
 * @version   v0.2
10
 * @copyright Copyright (c) 2016 Luke Visinoni <[email protected]>
11
 * @author    Luke Visinoni <[email protected]>
12
 * @license   https://github.com/deni-zen/csvelte/blob/master/LICENSE The MIT License (MIT)
13
 */
14
namespace CSVelte;
15
16
use \InvalidArgumentException;
17
use CSVelte\Exception\ImmutableException;
18
19
/**
20
 * CSV Flavor
21
 *
22
 * Represents a particular "flavor"  of CSV. Inspired by python's csv "dialects".
23
 * Also inspired by Frictionless Data's "dialect description" format and the W3C's
24
 * CSV on the Web Working Group and their work on CSV dialects.
25
 *
26
 * @package CSVelte
27
 * @subpackage Flavor
28
 * @since v0.1
29
 * @property-read string $delimiter The delimiter character
30
 * @property-read string $quoteChar The quoting character
31
 * @property-read string $lineTerminator The character sequence used to terminate rows of data
32
 * @property-read string $escapeChar The character used to escape quotes within a quoted string
33
 *     Mutually exclusive to $doubleQuote
34
 * @property-read bool $doubleQuote If true, quote characters will be escaped by preceding them
35
 *     with another quote character. Mutually exclusive to $escapeChar
36
 * @property-read string $quoteStyle One of four class constants that determine which cells are quoted
37
 * @property-read bool $header If true, first row should be treated as a header row
38
 */
39
class Flavor
40
{
41
    /**
42
     * Quote all cells.
43
     * Set Flavor::$quoteStyle to this to quote all cells, regardless of data type
44
     * @var string
45
     */
46
    const QUOTE_ALL = 'quote_all';
47
48
    /**
49
     * Quote no cells.
50
     * Set Flavor::$quoteStyle to this to quote no columns, regardless of data type
51
     * @var string
52
     */
53
    const QUOTE_NONE = 'quote_none';
54
55
    /**
56
     * Quote minimal columns.
57
     * Set Flavor::$quoteStyle to this to quote only cells that contain special
58
     * characters such as newlines or the delimiter character
59
     * @var string
60
     */
61
    const QUOTE_MINIMAL = 'quote_minimal';
62
63
    /**
64
     * Quote non-numeric cells.
65
     * Set Flavor::$quoteStyle to this to quote only cells that contain
66
     * non-numeric data
67
     * @var string
68
     */
69
    const QUOTE_NONNUMERIC = 'quote_nonnumeric';
70
71
    /**
72
     * Delimiter character.
73
     * This is the character that will be used to separate data cells within a
74
     * row of CSV data. Usually a comma.
75
     * @var string
76
     */
77
    protected $delimiter = ",";
78
79
    /**
80
     * Quote character.
81
     * This is the character that will be used to enclose (quote) data cells. It
82
     * is usually a double quote character but single quote is allowed.
83
     * @var string
84
     */
85
    protected $quoteChar = '"';
86
87
    /**
88
     * Escape character.
89
     * This character will be used to escape quotes within quoted text. It is
90
     * mutually exclusive to the doubleQuote attribute. Usually a backspace.
91
     * @var string
92
     */
93
    protected $escapeChar = '\\';
94
95
    /**
96
     * Double quote escape mode.
97
     * If set to true, quote characters within quoted text will be escaped by
98
     * preceding them with the same quote character.
99
     * @var boolean
100
     */
101
    protected $doubleQuote = true;
102
103
    /**
104
     * Not yet implemented
105
     * @ignore
106
     */
107
    // protected $skipInitialSpace = false;
1 ignored issue
show
Unused Code Comprehensibility introduced by
45% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
108
109
    /**
110
     * Quoting style.
111
     * This may be set to one of four values:
112
     *     * *Flavor::QUOTE_NONE* - To never quote data cells
113
     *     * *Flavor::QUOTE_ALL* - To always quote data cells
114
     *     * *Flavor::QUOTE_MINIMAL* - To only quote data cells that contain special characters such as quote character or delimiter character
115
     *     * *Flavor::QUOTE_NONNUMERIC* - To quote data cells that contain non-numeric data
116
     * @var string
117
     */
118
    protected $quoteStyle = self::QUOTE_MINIMAL;
119
120
    /**
121
     * Line terminator string sequence.
122
     * This is a character or sequence of characters that will be used to denote
123
     * the end of a row within the data
124
     * @var string
125
     */
126
    protected $lineTerminator = "\r\n";
127
128
    /**
129
     * Header.
130
     * If set to true, this means the first line of the CSV data is to be treated
131
     * as the column headers.
132
     * @var boolean
133
     */
134
    protected $header;
135
136
    /**
137
     * Class constructor
138
     *
139
     * The attributes that make up a flavor object can only be specified by
140
     * passing them in an array as key => value pairs to the constructor. Once
141
     * the flavor object is created, its attributes cannot be changed.
142
     *
143
     * @param array The attributes that define this particular flavor. These
144
     *     attributes are immutable. They can only be set here.
145
     */
146 45
    public function __construct($attributes = null)
147
    {
148 45
        if (!is_null($attributes)) {
149 33
            if (!is_array($attributes)) {
150
                // @todo throw exception?
151 1
                return;
152
            }
153 32
            foreach ($attributes as $attr => $val) {
154 32
                $this->assertValidAttribute($attr);
155 32
                $this->$attr = $val;
156 32
            }
157 32
        }
158 45
    }
159
160
    /**
161
     * Does this flavor of CSV have a header row?
162
     *
163
     * The difference between $flavor->header and $flavor->hasHeader() is that
164
     * hasHeader() is always going to give you a boolean value, whereas
165
     * $flavor->header may be null. A null value for header could mean that the
166
     * taster class could not reliably determine whether or not there was a
167
     * header row or it could simply mean that the flavor was instantiated with
168
     * no value for the header property.
169
     *
170
     * @param void
171
     * @return boolean
172
     * @access public
173
     */
174 1
    public function hasHeader()
175
    {
176 1
        return (bool) $this->header;
177
    }
178
179
    /**
180
     * Assert valid attribute name.
181
     * Assert that a particular attribute is valid (basically just that it exists)
182
     * and throw an exception otherwise
183
     *
184
     * @param string The attribute to check validity of
185
     * @return void
186
     * @access protected
187
     * @throws InvalidArgumentException
188
     * @internal
189
     * @todo This should accept a second parameter for value that asserts the value
190
     *     is a valid value
191
     */
192 41
    protected function assertValidAttribute($attr)
193
    {
194 41
        if (!property_exists(self::class, $attr))
195 41
            throw new InvalidArgumentException("Unknown attribute: " . $attr);
196 40
    }
197
198
    /**
199
     * Copy this flavor object
200
     *
201
     * Because flavor attributes are immutable, it is implossible to change their
202
     * attributes. If you need to change a flavor's attributes, call this method
203
     * instead, specifying which attributes are to be changed.
204
     *
205
     * @param array An array of attribute name/values to change in the copied flavor
206
     * @return CSVelte\Flavor A flavor object with your new attributes
207
     * @access public
208
     * @todo I may want to remove the array type-hint so that this can accept
209
     *     array-like objects and iterables as well. Not sure...
210
     */
211 6
    public function copy(array $attribs = array())
212
    {
213 6
        return new Flavor(array_merge($this->toArray(), $attribs));
214
    }
215
216
    /**
217
     * Attribute accessor magic method
218
     *
219
     * @param string The attribute to "get"
220
     * @return string The attribute value
221
     * @access public
222
     * @internal
223
     * @throws InvalidArgumentException
224
     */
225 35
    public function __get($attr)
226
    {
227 35
        $this->assertValidAttribute($attr);
228 34
        return $this->$attr;
229
    }
230
231
    /**
232
     * Attribute accessor (setter) magic method.
233
     * Disabled because attributes are immutable (read-only)
234
     *
235
     * @param string The attribute to "set"
236
     * @param string The attribute value
237
     * @return void
238
     * @access public
239
     * @internal
240
     * @throws CSVelte\Exception\ImmutableException
241
     */
242 1
    public function __set($attr, $val)
243
    {
244 1
        throw new ImmutableException("Cannot change attributes on an immutable object: " . self::class . "::\$" . $attr);
245
    }
246
247 9
    public function toArray()
248
    {
249 9
        return get_object_vars($this);
250
    }
251
252
}
253