AbstractRow   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 227
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 0
loc 227
rs 10
c 0
b 0
f 0
wmc 23
lcom 1
cbo 2

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A __toString() 0 4 1
A join() 0 4 1
A toArray() 0 4 1
A count() 0 4 1
A current() 0 4 1
A key() 0 4 1
A next() 0 7 2
A rewind() 0 7 2
A valid() 0 4 1
A offsetExists() 0 4 1
A offsetGet() 0 4 1
A offsetSet() 0 5 1
A offsetUnset() 0 4 1
A setFields() 0 15 5
A raiseImmutableException() 0 5 2
1
<?php
2
3
/*
4
 * CSVelte: Slender, elegant CSV for PHP
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   {version}
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\Table;
15
16
use ArrayAccess;
17
use Countable;
18
use CSVelte\Collection\AbstractCollection;
19
use CSVelte\Exception\ImmutableException;
20
21
use InvalidArgumentException;
22
use Iterator;
23
24
use function CSVelte\collect;
25
26
/**
27
 * Table row abstract base class
28
 * Represents a row of tabular data (represented by CSVelte\Table\Data objects).
29
 *
30
 * @package CSVelte
31
 * @subpackage CSVelte\Table
32
 *
33
 * @since v0.1
34
 *
35
 * @todo On all of the ArrayAccess methods, the docblocks say that $offset can be
36
 *     either an integer offset or a string index, but that isn't true, they must
37
 *     be an integer offset. Fix docblocks.
38
 */
39
abstract class AbstractRow implements Iterator, Countable, ArrayAccess
40
{
41
    /**
42
     * An collection of fields for this row.
43
     *
44
     * @var AbstractCollection
45
     */
46
    protected $fields;
47
48
    /**
49
     * Iterator position.
50
     *
51
     * @var int
52
     */
53
    protected $position;
54
55
    /**
56
     * Class constructor.
57
     *
58
     * @param array|Iterator An array (or anything that looks like one) of data (fields)
59
     * @param mixed $fields
60
     */
61
    public function __construct($fields)
62
    {
63
        $this->setFields($fields)
64
             ->rewind();
65
    }
66
67
    /**
68
     * Return a string representation of this object.
69
     *
70
     * @return string
71
     */
72
    public function __toString()
73
    {
74
        return $this->join();
75
    }
76
77
    /**
78
     * Join fields together using specified delimiter.
79
     *
80
     * @param string The delimiter character
81
     * @param mixed $delimiter
82
     *
83
     * @return string
84
     */
85
    public function join($delimiter = ',')
86
    {
87
        return $this->fields->join($delimiter);
88
    }
89
90
    /**
91
     * Convert object to an array.
92
     *
93
     * @return array representation of the object
94
     */
95
    public function toArray()
96
    {
97
        return $this->fields->toArray();
98
    }
99
100
    // Begin SPL Countable Interface Method
101
102
    /**
103
     * Count fields within the row.
104
     *
105
     * @return int The amount of fields
106
     */
107
    public function count()
108
    {
109
        return count($this->fields);
110
    }
111
112
    // Begin SPL Iterator Interface Methods
113
114
    /**
115
     * Get the current column's data object.
116
     *
117
     * @return string
118
     */
119
    public function current()
120
    {
121
        return $this->fields->getValueAtPosition($this->position);
122
    }
123
124
    /**
125
     * Get the current key (column number or header, if available).
126
     *
127
     * @return string The "current" key
128
     *
129
     * @todo Figure out if this can return a CSVelte\Table\HeaderData object so long as it
130
     *     has a __toString() method that generated the right key...
131
     */
132
    public function key()
133
    {
134
        return $this->fields->getKeyAtPosition($this->position);
135
    }
136
137
    /**
138
     * Advance the internal pointer to the next column's data object
139
     * Also returns the next column's data object if there is one.
140
     *
141
     * @return mixed The "next" column's data
142
     */
143
    public function next()
144
    {
145
        $this->position++;
146
        if ($this->valid()) {
147
            return $this->current();
148
        }
149
    }
150
151
    /**
152
     * Return the internal pointer to the first column and return that object.
153
     *
154
     * @return null|mixed|AbstractRow
155
     */
156
    public function rewind()
157
    {
158
        $this->position = 0;
159
        if ($this->valid()) {
160
            return $this->current();
161
        }
162
    }
163
164
    /**
165
     * Is the current position within the row's data fields valid?
166
     *
167
     * @return bool
168
     */
169
    public function valid()
170
    {
171
        return $this->fields->hasPosition($this->position);
172
    }
173
174
    // Begin SPL ArrayAccess Methods
175
176
    /**
177
     * Is there an offset at specified position.
178
     *
179
     * @param mixed $offset The offset to check existence of
180
     *
181
     * @return bool
182
     */
183
    public function offsetExists($offset)
184
    {
185
        return $this->fields->offsetExists($offset);
186
    }
187
188
    /**
189
     * Retrieve offset at specified position or by header name.
190
     *
191
     * @param mixed $offset The offset to get
192
     *
193
     * @return mixed The data at the specified position
194
     */
195
    public function offsetGet($offset)
196
    {
197
        return $this->fields->offsetGet($offset);
198
    }
199
200
    /**
201
     * Set offset at specified position.
202
     *
203
     * @param mixed $offset The array offset to set
204
     * @param mixed $value  The value to set $offset to
205
     *
206
     * @throws ImmutableException
207
     */
208
    public function offsetSet($offset, $value)
209
    {
210
        // fields are immutable, cannot be set
211
        $this->raiseImmutableException();
212
    }
213
214
    /**
215
     * Unset offset at specified position/index.
216
     *
217
     * @param mixed $offset The offset to unset
218
     *
219
     * @throws ImmutableException
220
     *
221
     * @todo I'm not sure if these objects will stay immutable or not yet...
222
     */
223
    public function offsetUnset($offset)
224
    {
225
        $this->raiseImmutableException();
226
    }
227
228
    /**
229
     * Set the row fields.
230
     *
231
     * Using either an array or iterator, set the fields for this row.
232
     *
233
     * @param array|Iterator $fields An array or iterator with the row's fields
234
     *
235
     * @return $this
236
     */
237
    protected function setFields($fields)
238
    {
239
        if (!is_array($fields)) {
240
            if (is_object($fields) && method_exists($fields, 'toArray')) {
241
                $fields = $fields->toArray();
242
            } elseif ($fields instanceof Iterator) {
243
                $fields = iterator_to_array($fields);
244
            } else {
245
                throw new InvalidArgumentException(__CLASS__ . ' requires an array, got: ' . gettype($fields));
246
            }
247
        }
248
        $this->fields = collect($fields)->values();
249
250
        return $this;
251
    }
252
253
    /**
254
     * Raise (throw) immutable exception.
255
     *
256
     * @param string $msg The message to pass to the exception
257
     *
258
     * @throws ImmutableException
259
     */
260
    protected function raiseImmutableException($msg = null)
261
    {
262
        // fields are immutable, cannot be set
263
        throw new ImmutableException($msg ?: 'Cannot change immutable column data');
264
    }
265
}
266