rm trailing white space
[mediawiki.git] / PHPTAL-NP-0.7.0 / libs / PHPTAL / LoopControler.php
blob9ff38bd79dae180042167f88d6e6636417660be8
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
3 //
4 // Copyright (c) 2003 Laurent Bedubourg
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 //
20 // Authors: Laurent Bedubourg <laurent.bedubourg@free.fr>
21 //
23 require_once PT_IP . "/Types/OArray.php";
24 require_once PT_IP . "/Types/OHash.php";
25 require_once PT_IP . "/Types/Iterator.php";
27 /**
28 * Template loop execution controler.
30 * This object is instantiated by the template on each loop.
32 * LoopControlers accept different types of loop target.
34 * - array
35 * - objects having an getNewIterator() method returning an Iterator object.
36 * - Iterator objects which produce isValid(), next(), key() and index()
37 * methods.
38 * please note that key() return index() for non associative data.
40 * Other types are rejected by the loop controler on runtime producing
41 * a TypeError exception.
43 * The loop controler install its iterator under the path "repeat/item"
44 * where "item" is the name of the output var (defined in the template).
46 * Thus, the template can access differents methods of the iterator:
47 * repeat/someitem/key
48 * repeat/someitem/index
49 * repeat/someitem/next
50 * repeat/someitem/last
52 * If not all of these methods are implemented in iterators, ask
53 * iterator maintainers.
55 * @author Laurent Bedubourg <laurent.bedubourg@free.fr>
58 class PHPTAL_LoopControler
60 var $_context;
61 var $_data;
62 var $_data_name;
63 var $_iterator;
64 var $_error;
66 /**
67 * Controler constructor.
69 * @param PHPTAL_Context $context
70 * The template context.
71 * @param string $data_name
72 * The item data name.
73 * @param mixed $data
74 * Loop resource.
76 function PHPTAL_LoopControler(&$context, $data_name, $data)
78 $this->_context =& $context;
79 $this->_data =& $data;
80 $this->_data_name = $data_name;
82 // ensure that data is not an error
83 if (PEAR::isError($data)) {
84 $this->_error =& $data;
85 return $data;
88 // accepted objects
89 //
90 // - iteratable implementing getNewIterator() method
91 // - iterator implementing next(), isValid() and index() methods
92 // - db_result produced by PEAR::DB package
93 //
94 if (is_object($data)) {
95 if (method_exists($data, "getNewIterator")) {
97 $this->_iterator =& $data->getNewIterator();
99 } elseif (is_a("iterator", $data)
100 || (method_exists($data, 'next')
101 && method_exists($data, 'isValid')
102 && method_exists($data, 'index'))) {
104 $this->_iterator =& $data;
106 } elseif (get_class($data) == 'db_result') {
108 $this->_iterator = new PHPTAL_DBResultIterator($data);
110 } else {
112 $err = new TypeError("PHPTAL loop controler received a non Iterable object ("
113 . get_class($data) . ")");
114 $this->_error =& $err;
115 return PEAR::raiseError($err);
117 } elseif (is_array($data)) {
119 // array are accepted thanks to OArrayIterator
121 reset($data);
122 if (count($data) > 0 && array_key_exists(0, $data)) {
123 // echo "OArray::iterator", RxObject::ClassName($data), endl;
124 $this->_data = new OArray($data);
125 $this->_iterator =& $this->_data->getNewIterator();
126 } else {
127 // echo "OHash::iterator", RxObject::ClassName($data), endl;
128 $this->_data = new OHash($data);
129 $this->_iterator =& $this->_data->getNewIterator();
131 } else {
132 $err = new TypeError("phptal loop controler received a non Iterable value ("
133 . gettype($data) . ")");
134 $this->_error =& $err;
135 return PEAR::raiseError($err);
139 // install loop in repeat context array
141 $repeat =& $this->_context->get("repeat");
142 if (array_key_exists($this->_data_name, $repeat)) {
143 unset($repeat[$this->_data_name]);
145 $repeat[$this->_data_name] =& $this;
147 // $this->_context->setRef($this->_data_name, $temp);
148 $temp =& $this->_iterator->value();
149 $this->_context->set($this->_data_name, $temp);
150 return $temp;
154 * Return current item index.
156 * @return int
158 function index()
160 return $this->_iterator->index();
164 * Return current item key or index for non associative iterators.
166 * @return mixed
168 function key()
170 if (method_exists($this->_iterator, "key")) {
171 return $this->_iterator->key();
172 } else {
173 return $this->_iterator->index();
178 * Index is in range(0, length-1), the number in in range(1, length).
180 * @return int
182 function number()
184 return $this->index() + 1;
188 * Return true if index is even.
190 * @return boolean
192 function even()
194 return !$this->odd();
198 * Return true if index is odd.
200 * @return boolean
202 function odd()
204 return ($this->index() % 2);
208 * Return true if at the begining of the loop.
210 * @return boolean
212 function start()
214 return ($this->index() == 0);
218 * Return true if at the end of the loop (no more item).
220 * @return boolean
222 function end()
224 return ($this->length() == $this->number());
227 function isValid()
229 return $this->_iterator->isValid();
233 * Return the length of the data (total number of iterations).
235 * @return int
237 function length()
239 return $this->_data->size();
243 * Retrieve next iterator value.
245 * @return mixed
247 function &next()
249 $temp =& $this->_iterator->next();
250 if (!$this->_iterator->isValid()) {
251 return false;
254 // $this->_context->setRef($this->_data_name, $temp);
255 $this->_context->set($this->_data_name, $temp);
256 return $temp;
262 * Iterator for DB_Result PEAR object.
264 * This class is an implementation of the Iterator Interface
265 * for DB_Result objects produced by the usage of PEAR::DB package.
267 * @author Laurent Bedubourg <laurent.bedubourg@free.fr>
269 class PHPTAL_DBResultIterator extends Iterator
271 var $_src;
272 var $_index = -1;
273 var $_end = false;
274 var $_value;
277 * Iterator constructor.
279 * @param DB_Result $result
280 * The query result.
282 function PHPTAL_DBResultIterator(&$result)
284 $this->_src =& $result;
285 $this->reset();
288 function reset()
290 if ($this->size() == 0) {
291 $this->_end = true;
292 return;
295 $this->_index = 0;
296 $this->_end = false;
297 unset($this->_value);
298 $this->_value = $this->_src->fetchRow();
302 * Return the number of rows in this result.
304 * @return int
306 function size()
308 if (!isset($this->_size)) {
309 $this->_size = $this->_src->numRows();
311 return $this->_size;
315 * Returns true if end of iterator has not been reached yet.
317 function isValid()
319 return !$this->_end;
323 * Return the next row in this result.
325 * This method calls fetchRow() on the DB_Result, the return type depends
326 * of the DB_result->fetchmod. Please specify it before executing the
327 * template.
329 * @return mixed
331 function &next()
333 if ($this->_end || ++ $this->_index >= $this->size()) {
334 $this->_end = true;
335 return false;
338 unset($this->_value);
339 $this->_value = $this->_src->fetchRow();
340 return $this->_value;
344 * Return current row.
346 * @return mixed
348 function &value()
350 return $this->_value;
354 * Return current row index in resultset.
356 * @return int
358 function index()
360 return $this->_index;