1 <?php
2 /**
3 * @package FrameworkOnFramework
4 * @subpackage database
5 * @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
6 * @license GNU General Public License version 2 or later; see LICENSE.txt
7 *
8 * This file is adapted from the Joomla! Platform. It is used to iterate a database cursor returning FOFTable objects
9 * instead of plain stdClass objects
10 */
11
12 // Protect from unauthorized access
13 defined('FOF_INCLUDED') or die;
14
15 /**
16 * Database iterator
17 */
18 abstract class FOFDatabaseIterator implements Iterator
19 {
20 /**
21 * The database cursor.
22 *
23 * @var mixed
24 */
25 protected $cursor;
26
27 /**
28 * The class of object to create.
29 *
30 * @var string
31 */
32 protected $class;
33
34 /**
35 * The name of the column to use for the key of the database record.
36 *
37 * @var mixed
38 */
39 private $_column;
40
41 /**
42 * The current database record.
43 *
44 * @var mixed
45 */
46 private $_current;
47
48 /**
49 * The current database record as a FOFTable object.
50 *
51 * @var FOFTable
52 */
53 private $_currentTable;
54
55 /**
56 * A numeric or string key for the current database record.
57 *
58 * @var scalar
59 */
60 private $_key;
61
62 /**
63 * The number of fetched records.
64 *
65 * @var integer
66 */
67 private $_fetched = 0;
68
69 /**
70 * A FOFTable object created using the class type $class, used by getTable
71 *
72 * @var FOFTable
73 */
74 private $_tableObject = null;
75
76 /**
77 * Returns an iterator object for a specific database type
78 *
79 * @param string $dbName The database type, e.g. mysql, mysqli, sqlazure etc.
80 * @param mixed $cursor The database cursor
81 * @param string $column An option column to use as the iterator key
82 * @param string $class The table class of the returned objects
83 * @param array $config Configuration parameters to push to the table class
84 *
85 * @return FOFDatabaseIterator
86 *
87 * @throws InvalidArgumentException
88 */
89 public static function &getIterator($dbName, $cursor, $column = null, $class, $config = array())
90 {
91 $className = 'FOFDatabaseIterator' . ucfirst($dbName);
92
93 $object = new $className($cursor, $column, $class, $config);
94
95 return $object;
96 }
97
98 /**
99 * Database iterator constructor.
100 *
101 * @param mixed $cursor The database cursor.
102 * @param string $column An option column to use as the iterator key.
103 * @param string $class The table class of the returned objects.
104 * @param array $config Configuration parameters to push to the table class
105 *
106 * @throws InvalidArgumentException
107 */
108 public function __construct($cursor, $column = null, $class, $config = array())
109 {
110 // Figure out the type and prefix of the class by the class name
111 $parts = FOFInflector::explode($class);
112
113 if(count($parts) != 3)
114 {
115 throw new InvalidArgumentException('Invalid table name, expected a pattern like ComponentTableFoobar got '.$class);
116 }
117
118 $this->_tableObject = FOFTable::getInstance($parts[2], ucfirst($parts[0]) . ucfirst($parts[1]))->getClone();
119
120 $this->cursor = $cursor;
121 $this->class = 'stdClass';
122 $this->_column = $column;
123 $this->_fetched = 0;
124
125 $this->next();
126 }
127
128 /**
129 * Database iterator destructor.
130 */
131 public function __destruct()
132 {
133 if ($this->cursor)
134 {
135 $this->freeResult($this->cursor);
136 }
137 }
138
139 /**
140 * The current element in the iterator.
141 *
142 * @return object
143 *
144 * @see Iterator::current()
145 */
146 public function current()
147 {
148 return $this->_currentTable;
149 }
150
151 /**
152 * The key of the current element in the iterator.
153 *
154 * @return scalar
155 *
156 * @see Iterator::key()
157 */
158 public function key()
159 {
160 return $this->_key;
161 }
162
163 /**
164 * Moves forward to the next result from the SQL query.
165 *
166 * @return void
167 *
168 * @see Iterator::next()
169 */
170 public function next()
171 {
172 // Set the default key as being the number of fetched object
173 $this->_key = $this->_fetched;
174
175 // Try to get an object
176 $this->_current = $this->fetchObject();
177
178 // If an object has been found
179 if ($this->_current)
180 {
181 $this->_currentTable = $this->getTable();
182
183 // Set the key as being the indexed column (if it exists)
184 if (isset($this->_current->{$this->_column}))
185 {
186 $this->_key = $this->_current->{$this->_column};
187 }
188
189 // Update the number of fetched object
190 $this->_fetched++;
191 }
192 }
193
194 /**
195 * Rewinds the iterator.
196 *
197 * This iterator cannot be rewound.
198 *
199 * @return void
200 *
201 * @see Iterator::rewind()
202 */
203 public function rewind()
204 {
205 }
206
207 /**
208 * Checks if the current position of the iterator is valid.
209 *
210 * @return boolean
211 *
212 * @see Iterator::valid()
213 */
214 public function valid()
215 {
216 return (boolean) $this->_current;
217 }
218
219 /**
220 * Method to fetch a row from the result set cursor as an object.
221 *
222 * @return mixed Either the next row from the result set or false if there are no more rows.
223 */
224 abstract protected function fetchObject();
225
226 /**
227 * Method to free up the memory used for the result set.
228 *
229 * @return void
230 */
231 abstract protected function freeResult();
232
233 /**
234 * Returns the data in $this->_current as a FOFTable instance
235 *
236 * @return FOFTable
237 *
238 * @throws OutOfBoundsException
239 */
240 protected function getTable()
241 {
242 if (!$this->valid())
243 {
244 throw new OutOfBoundsException('Cannot get item past iterator\'s bounds', 500);
245 }
246
247 $this->_tableObject->bind($this->_current);
248
249 return $this->_tableObject;
250 }
251 }
252