1: <?php
2: /**
3: * Zend Framework
4: *
5: * LICENSE
6: *
7: * This source file is subject to the new BSD license that is bundled
8: * with this package in the file LICENSE.txt.
9: * It is also available through the world-wide-web at this URL:
10: * http://framework.zend.com/license/new-bsd
11: * If you did not receive a copy of the license and are unable to
12: * obtain it through the world-wide-web, please send an email
13: * to license@zend.com so we can send you a copy immediately.
14: *
15: * @category Zend
16: * @package Zend_Db
17: * @subpackage Table
18: * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
19: * @license http://framework.zend.com/license/new-bsd New BSD License
20: * @version $Id: Abstract.php 23484 2010-12-10 03:57:59Z mjh_ca $
21: */
22:
23: /**
24: * @category Zend
25: * @package Zend_Db
26: * @subpackage Table
27: * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
28: * @license http://framework.zend.com/license/new-bsd New BSD License
29: */
30: abstract class Zend_Db_Table_Rowset_Abstract implements SeekableIterator, Countable, ArrayAccess
31: {
32: /**
33: * The original data for each row.
34: *
35: * @var array
36: */
37: protected $_data = array();
38:
39: /**
40: * Zend_Db_Table_Abstract object.
41: *
42: * @var Zend_Db_Table_Abstract
43: */
44: protected $_table;
45:
46: /**
47: * Connected is true if we have a reference to a live
48: * Zend_Db_Table_Abstract object.
49: * This is false after the Rowset has been deserialized.
50: *
51: * @var boolean
52: */
53: protected $_connected = true;
54:
55: /**
56: * Zend_Db_Table_Abstract class name.
57: *
58: * @var string
59: */
60: protected $_tableClass;
61:
62: /**
63: * Zend_Db_Table_Row_Abstract class name.
64: *
65: * @var string
66: */
67: protected $_rowClass = 'Zend_Db_Table_Row';
68:
69: /**
70: * Iterator pointer.
71: *
72: * @var integer
73: */
74: protected $_pointer = 0;
75:
76: /**
77: * How many data rows there are.
78: *
79: * @var integer
80: */
81: protected $_count;
82:
83: /**
84: * Collection of instantiated Zend_Db_Table_Row objects.
85: *
86: * @var array
87: */
88: protected $_rows = array();
89:
90: /**
91: * @var boolean
92: */
93: protected $_stored = false;
94:
95: /**
96: * @var boolean
97: */
98: protected $_readOnly = false;
99:
100: /**
101: * Constructor.
102: *
103: * @param array $config
104: */
105: public function __construct(array $config)
106: {
107: if (isset($config['table'])) {
108: $this->_table = $config['table'];
109: $this->_tableClass = get_class($this->_table);
110: }
111: if (isset($config['rowClass'])) {
112: $this->_rowClass = $config['rowClass'];
113: }
114: if (!class_exists($this->_rowClass)) {
115: require_once 'Zend/Loader.php';
116: Zend_Loader::loadClass($this->_rowClass);
117: }
118: if (isset($config['data'])) {
119: $this->_data = $config['data'];
120: }
121: if (isset($config['readOnly'])) {
122: $this->_readOnly = $config['readOnly'];
123: }
124: if (isset($config['stored'])) {
125: $this->_stored = $config['stored'];
126: }
127:
128: // set the count of rows
129: $this->_count = count($this->_data);
130:
131: $this->init();
132: }
133:
134: /**
135: * Store data, class names, and state in serialized object
136: *
137: * @return array
138: */
139: public function __sleep()
140: {
141: return array('_data', '_tableClass', '_rowClass', '_pointer', '_count', '_rows', '_stored',
142: '_readOnly');
143: }
144:
145: /**
146: * Setup to do on wakeup.
147: * A de-serialized Rowset should not be assumed to have access to a live
148: * database connection, so set _connected = false.
149: *
150: * @return void
151: */
152: public function __wakeup()
153: {
154: $this->_connected = false;
155: }
156:
157: /**
158: * Initialize object
159: *
160: * Called from {@link __construct()} as final step of object instantiation.
161: *
162: * @return void
163: */
164: public function init()
165: {
166: }
167:
168: /**
169: * Return the connected state of the rowset.
170: *
171: * @return boolean
172: */
173: public function isConnected()
174: {
175: return $this->_connected;
176: }
177:
178: /**
179: * Returns the table object, or null if this is disconnected rowset
180: *
181: * @return Zend_Db_Table_Abstract
182: */
183: public function getTable()
184: {
185: return $this->_table;
186: }
187:
188: /**
189: * Set the table object, to re-establish a live connection
190: * to the database for a Rowset that has been de-serialized.
191: *
192: * @param Zend_Db_Table_Abstract $table
193: * @return boolean
194: * @throws Zend_Db_Table_Row_Exception
195: */
196: public function setTable(Zend_Db_Table_Abstract $table)
197: {
198: $this->_table = $table;
199: $this->_connected = false;
200: // @todo This works only if we have iterated through
201: // the result set once to instantiate the rows.
202: foreach ($this as $row) {
203: $connected = $row->setTable($table);
204: if ($connected == true) {
205: $this->_connected = true;
206: }
207: }
208: return $this->_connected;
209: }
210:
211: /**
212: * Query the class name of the Table object for which this
213: * Rowset was created.
214: *
215: * @return string
216: */
217: public function getTableClass()
218: {
219: return $this->_tableClass;
220: }
221:
222: /**
223: * Rewind the Iterator to the first element.
224: * Similar to the reset() function for arrays in PHP.
225: * Required by interface Iterator.
226: *
227: * @return Zend_Db_Table_Rowset_Abstract Fluent interface.
228: */
229: public function rewind()
230: {
231: $this->_pointer = 0;
232: return $this;
233: }
234:
235: /**
236: * Return the current element.
237: * Similar to the current() function for arrays in PHP
238: * Required by interface Iterator.
239: *
240: * @return Zend_Db_Table_Row_Abstract current element from the collection
241: */
242: public function current()
243: {
244: if ($this->valid() === false) {
245: return null;
246: }
247:
248: // return the row object
249: return $this->_loadAndReturnRow($this->_pointer);
250: }
251:
252: /**
253: * Return the identifying key of the current element.
254: * Similar to the key() function for arrays in PHP.
255: * Required by interface Iterator.
256: *
257: * @return int
258: */
259: public function key()
260: {
261: return $this->_pointer;
262: }
263:
264: /**
265: * Move forward to next element.
266: * Similar to the next() function for arrays in PHP.
267: * Required by interface Iterator.
268: *
269: * @return void
270: */
271: public function next()
272: {
273: ++$this->_pointer;
274: }
275:
276: /**
277: * Check if there is a current element after calls to rewind() or next().
278: * Used to check if we've iterated to the end of the collection.
279: * Required by interface Iterator.
280: *
281: * @return bool False if there's nothing more to iterate over
282: */
283: public function valid()
284: {
285: return $this->_pointer >= 0 && $this->_pointer < $this->_count;
286: }
287:
288: /**
289: * Returns the number of elements in the collection.
290: *
291: * Implements Countable::count()
292: *
293: * @return int
294: */
295: public function count()
296: {
297: return $this->_count;
298: }
299:
300: /**
301: * Take the Iterator to position $position
302: * Required by interface SeekableIterator.
303: *
304: * @param int $position the position to seek to
305: * @return Zend_Db_Table_Rowset_Abstract
306: * @throws Zend_Db_Table_Rowset_Exception
307: */
308: public function seek($position)
309: {
310: $position = (int) $position;
311: if ($position < 0 || $position >= $this->_count) {
312: require_once 'Zend/Db/Table/Rowset/Exception.php';
313: throw new Zend_Db_Table_Rowset_Exception("Illegal index $position");
314: }
315: $this->_pointer = $position;
316: return $this;
317: }
318:
319: /**
320: * Check if an offset exists
321: * Required by the ArrayAccess implementation
322: *
323: * @param string $offset
324: * @return boolean
325: */
326: public function offsetExists($offset)
327: {
328: return isset($this->_data[(int) $offset]);
329: }
330:
331: /**
332: * Get the row for the given offset
333: * Required by the ArrayAccess implementation
334: *
335: * @param string $offset
336: * @return Zend_Db_Table_Row_Abstract
337: */
338: public function offsetGet($offset)
339: {
340: $offset = (int) $offset;
341: if ($offset < 0 || $offset >= $this->_count) {
342: require_once 'Zend/Db/Table/Rowset/Exception.php';
343: throw new Zend_Db_Table_Rowset_Exception("Illegal index $offset");
344: }
345: $this->_pointer = $offset;
346:
347: return $this->current();
348: }
349:
350: /**
351: * Does nothing
352: * Required by the ArrayAccess implementation
353: *
354: * @param string $offset
355: * @param mixed $value
356: */
357: public function offsetSet($offset, $value)
358: {
359: }
360:
361: /**
362: * Does nothing
363: * Required by the ArrayAccess implementation
364: *
365: * @param string $offset
366: */
367: public function offsetUnset($offset)
368: {
369: }
370:
371: /**
372: * Returns a Zend_Db_Table_Row from a known position into the Iterator
373: *
374: * @param int $position the position of the row expected
375: * @param bool $seek wether or not seek the iterator to that position after
376: * @return Zend_Db_Table_Row
377: * @throws Zend_Db_Table_Rowset_Exception
378: */
379: public function getRow($position, $seek = false)
380: {
381: try {
382: $row = $this->_loadAndReturnRow($position);
383: } catch (Zend_Db_Table_Rowset_Exception $e) {
384: require_once 'Zend/Db/Table/Rowset/Exception.php';
385: throw new Zend_Db_Table_Rowset_Exception('No row could be found at position ' . (int) $position, 0, $e);
386: }
387:
388: if ($seek == true) {
389: $this->seek($position);
390: }
391:
392: return $row;
393: }
394:
395: /**
396: * Returns all data as an array.
397: *
398: * Updates the $_data property with current row object values.
399: *
400: * @return array
401: */
402: public function toArray()
403: {
404: // @todo This works only if we have iterated through
405: // the result set once to instantiate the rows.
406: foreach ($this->_rows as $i => $row) {
407: $this->_data[$i] = $row->toArray();
408: }
409: return $this->_data;
410: }
411:
412: protected function _loadAndReturnRow($position)
413: {
414: if (!isset($this->_data[$position])) {
415: require_once 'Zend/Db/Table/Rowset/Exception.php';
416: throw new Zend_Db_Table_Rowset_Exception("Data for provided position does not exist");
417: }
418:
419: // do we already have a row object for this position?
420: if (empty($this->_rows[$position])) {
421: $this->_rows[$position] = new $this->_rowClass(
422: array(
423: 'table' => $this->_table,
424: 'data' => $this->_data[$position],
425: 'stored' => $this->_stored,
426: 'readOnly' => $this->_readOnly
427: )
428: );
429: }
430:
431: // return the row object
432: return $this->_rows[$position];
433: }
434:
435: }
436: