1
|
|
|
<?php defined('SYSPATH') OR die('No direct script access.'); |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* A base iterator class, execute _load_contnet on any interaction with the array. Can be serialized properly |
5
|
|
|
* |
6
|
|
|
* @package Jam |
7
|
|
|
* @category Associations |
8
|
|
|
* @author Ivan Kerin |
9
|
|
|
* @copyright (c) 2011-2012 Despark Ltd. |
10
|
|
|
* @license http://www.opensource.org/licenses/isc-license.txt |
11
|
|
|
*/ |
12
|
|
|
abstract class Kohana_Jam_Array implements Countable, ArrayAccess, Iterator, Serializable { |
13
|
|
|
|
14
|
|
|
public static function factory() |
15
|
|
|
{ |
16
|
|
|
return new Jam_Array(); |
17
|
|
|
} |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* An array of booleans that flags which entries have been changed |
21
|
|
|
* @var array |
22
|
|
|
*/ |
23
|
|
|
protected $_changed = array(); |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* This is set to true when any entries are removed |
27
|
|
|
* @var boolean |
28
|
|
|
*/ |
29
|
|
|
protected $_removed = FALSE; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* The content loaded with _load_content. The main store of this iterator |
33
|
|
|
* @var array |
34
|
|
|
*/ |
35
|
|
|
protected $_content = NULL; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* Iterator implementation |
39
|
|
|
* @var integer |
40
|
|
|
*/ |
41
|
|
|
protected $_current = 0; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Load the _content variable. This is used to lazy load the content of this iterator |
45
|
|
|
*/ |
46
|
5 |
|
protected function _load_content() |
47
|
|
|
{ |
48
|
5 |
|
if ( ! $this->_content) |
|
|
|
|
49
|
1 |
|
throw new Kohana_Exception('Content has not been loaded'); |
50
|
4 |
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Load each of the entries of this iterator. Called everytime an entry is requested. Use it to lazy load each item |
54
|
|
|
* @param mixed $value |
55
|
|
|
* @param boolean $is_changed |
56
|
|
|
* @param int $offset |
57
|
|
|
* @return mixed |
58
|
|
|
*/ |
59
|
2 |
|
protected function _load_item($value, $is_changed, $offset) |
60
|
|
|
{ |
61
|
2 |
|
return $value; |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Getter / Setter of the content. Lazy loads with _load_content(); |
66
|
|
|
* @param array $content |
67
|
|
|
* @return array |
68
|
|
|
*/ |
69
|
9 |
|
public function content(array $content = NULL) |
70
|
|
|
{ |
71
|
9 |
|
if ($content !== NULL) |
72
|
|
|
{ |
73
|
4 |
|
$this->_content = $content; |
74
|
4 |
|
return $this; |
75
|
|
|
} |
76
|
|
|
|
77
|
7 |
|
$this->_load_content(); |
78
|
|
|
|
79
|
6 |
|
return $this->_content; |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* Getter for the changed array - check if any or a particular item has been changed |
84
|
|
|
* @param int $offset |
85
|
|
|
* @return bool |
86
|
|
|
*/ |
87
|
8 |
|
public function changed($offset = NULL) |
88
|
|
|
{ |
89
|
8 |
|
if ($offset !== NULL) |
90
|
4 |
|
return isset($this->_changed[$offset]); |
91
|
|
|
|
92
|
7 |
|
return ( (bool) $this->_changed OR $this->_removed); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* Reset the content so it can be loaded again |
97
|
|
|
* @return Jam_Array |
98
|
|
|
*/ |
99
|
|
|
public function reload() |
100
|
|
|
{ |
101
|
|
|
$this->_changed = array(); |
102
|
|
|
$this->_removed = FALSE; |
103
|
|
|
$this->_current = 0; |
104
|
|
|
$this->_content = NULL; |
|
|
|
|
105
|
|
|
|
106
|
|
|
return $this; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* Implement Countable |
111
|
|
|
* @return int |
112
|
|
|
*/ |
113
|
5 |
|
public function count() |
114
|
|
|
{ |
115
|
5 |
|
$this->_load_content(); |
116
|
|
|
|
117
|
5 |
|
if ($this->_content === NULL) |
118
|
|
|
return 0; |
119
|
|
|
|
120
|
5 |
|
return count($this->_content); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* Implement ArrayAccess. Lazy load with _load_content, and the item with _load_item |
125
|
|
|
* |
126
|
|
|
* @param int $offset |
127
|
|
|
* @return Jam_Model |
128
|
|
|
*/ |
129
|
14 |
|
public function offsetGet($offset) |
130
|
|
|
{ |
131
|
14 |
|
$this->_load_content(); |
132
|
|
|
|
133
|
14 |
|
if (is_array($this->_content) AND ! array_key_exists($offset, $this->_content)) |
134
|
1 |
|
return NULL; |
135
|
|
|
|
136
|
14 |
|
return $this->_load_item($this->_content[$offset] ?? null, isset($this->_changed[$offset]), $offset); |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Implement ArrayAccess. Lazy load with _load_content |
141
|
|
|
* |
142
|
|
|
* @param int $offset |
143
|
|
|
* @return boolean |
144
|
|
|
*/ |
145
|
|
|
public function offsetExists($offset) |
146
|
|
|
{ |
147
|
|
|
$this->_load_content(); |
148
|
|
|
|
149
|
|
|
return isset($this->_content[$offset]); |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Implement ArrayAccess. Lazy load with _load_content |
154
|
|
|
*/ |
155
|
13 |
|
public function offsetSet($offset, $value) |
156
|
|
|
{ |
157
|
13 |
|
$this->_load_content(); |
158
|
|
|
|
159
|
13 |
|
if ($offset === NULL) |
160
|
|
|
{ |
161
|
12 |
|
$this->_content[] = $value; |
162
|
12 |
|
$this->_changed[count($this->_content) - 1] = TRUE; |
163
|
|
|
} |
164
|
5 |
|
elseif ($this->_content !== NULL) |
165
|
|
|
{ |
166
|
5 |
|
$this->_content[$offset] = $value; |
167
|
5 |
|
$this->_changed[$offset] = TRUE; |
168
|
|
|
} |
169
|
13 |
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Implement ArrayAccess. Lazy load with _load_content |
173
|
|
|
*/ |
174
|
6 |
|
public function offsetUnset($offset) |
175
|
|
|
{ |
176
|
6 |
|
$this->_load_content(); |
177
|
6 |
|
if ($this->_content) |
|
|
|
|
178
|
|
|
{ |
179
|
6 |
|
array_splice($this->_content, $offset, 1); |
180
|
6 |
|
array_splice($this->_changed, $offset, 1); |
181
|
|
|
|
182
|
6 |
|
$this->_removed = TRUE; |
183
|
|
|
} |
184
|
|
|
|
185
|
6 |
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* Implement Iterator |
189
|
|
|
*/ |
190
|
16 |
|
public function rewind() |
191
|
|
|
{ |
192
|
16 |
|
$this->_current = 0; |
193
|
16 |
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* Implement Iterator. Lazy load with _load_content and the item with _load_item |
197
|
|
|
* @return Jam_Model |
198
|
|
|
*/ |
199
|
11 |
|
public function current() |
200
|
|
|
{ |
201
|
11 |
|
$this->_load_content(); |
202
|
11 |
|
if ( ! $this->valid()) |
203
|
|
|
return NULL; |
204
|
|
|
|
205
|
11 |
|
return $this->_load_item($this->_content[$this->_current] ?? null, isset($this->_changed[$this->_current]), $this->_current); |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* Implement Iterator |
210
|
|
|
* @return int |
211
|
|
|
*/ |
212
|
11 |
|
public function key() |
213
|
|
|
{ |
214
|
11 |
|
return $this->_current; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* Implement Iterator |
219
|
|
|
*/ |
220
|
12 |
|
public function next() |
221
|
|
|
{ |
222
|
12 |
|
$this->_current ++; |
223
|
12 |
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* Implement Iterator. Lazy load with _load_content |
227
|
|
|
* @return bool |
228
|
|
|
*/ |
229
|
15 |
|
public function valid() |
230
|
|
|
{ |
231
|
15 |
|
$this->_load_content(); |
232
|
15 |
|
return is_array($this->_content) AND array_key_exists($this->_current, $this->_content); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* Implement Serializable. Lazy load with _load_content |
237
|
|
|
* @return string |
238
|
|
|
*/ |
239
|
1 |
|
public function serialize() |
240
|
|
|
{ |
241
|
1 |
|
$this->_load_content(); |
242
|
|
|
|
243
|
1 |
|
return serialize(array( |
244
|
1 |
|
'changed' => $this->_changed, |
245
|
1 |
|
'content' => $this->_content, |
246
|
1 |
|
'removed' => $this->_removed, |
247
|
1 |
|
'current' => $this->_current, |
248
|
|
|
)); |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* Implement Serializable. |
253
|
|
|
* @param string $data [description] |
254
|
|
|
*/ |
255
|
1 |
|
public function unserialize($data) |
256
|
|
|
{ |
257
|
1 |
|
$data = unserialize($data); |
258
|
|
|
|
259
|
1 |
|
$this->_changed = $data['changed']; |
260
|
1 |
|
$this->_content = $data['content']; |
261
|
1 |
|
$this->_removed = $data['removed']; |
262
|
1 |
|
$this->_current = $data['current']; |
263
|
1 |
|
} |
264
|
|
|
} |
265
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.