2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
4 // Copyright (c) 2003 Laurent Bedubourg
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.
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.
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
20 // Authors: Laurent Bedubourg <laurent.bedubourg@free.fr>
23 require_once PT_IP
. "/Types/OArray.php";
24 require_once PT_IP
. "/Types/OHash.php";
25 require_once PT_IP
. "/Types/Iterator.php";
28 * Template loop execution controler.
30 * This object is instantiated by the template on each loop.
32 * LoopControlers accept different types of loop target.
35 * - objects having an getNewIterator() method returning an Iterator object.
36 * - Iterator objects which produce isValid(), next(), key() and index()
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:
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
67 * Controler constructor.
69 * @param PHPTAL_Context $context
70 * The template context.
71 * @param string $data_name
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;
90 // - iteratable implementing getNewIterator() method
91 // - iterator implementing next(), isValid() and index() methods
92 // - db_result produced by PEAR::DB package
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);
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
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();
127 // echo "OHash::iterator", RxObject::ClassName($data), endl;
128 $this->_data
= new OHash($data);
129 $this->_iterator
=& $this->_data
->getNewIterator();
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);
154 * Return current item index.
160 return $this->_iterator
->index();
164 * Return current item key or index for non associative iterators.
170 if (method_exists($this->_iterator
, "key")) {
171 return $this->_iterator
->key();
173 return $this->_iterator
->index();
178 * Index is in range(0, length-1), the number in in range(1, length).
184 return $this->index() +
1;
188 * Return true if index is even.
194 return !$this->odd();
198 * Return true if index is odd.
204 return ($this->index() %
2);
208 * Return true if at the begining of the loop.
214 return ($this->index() == 0);
218 * Return true if at the end of the loop (no more item).
224 return ($this->length() == $this->number());
229 return $this->_iterator
->isValid();
233 * Return the length of the data (total number of iterations).
239 return $this->_data
->size();
243 * Retrieve next iterator value.
249 $temp =& $this->_iterator
->next();
250 if (!$this->_iterator
->isValid()) {
254 // $this->_context->setRef($this->_data_name, $temp);
255 $this->_context
->set($this->_data_name
, $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
277 * Iterator constructor.
279 * @param DB_Result $result
282 function PHPTAL_DBResultIterator(&$result)
284 $this->_src
=& $result;
290 if ($this->size() == 0) {
297 unset($this->_value
);
298 $this->_value
= $this->_src
->fetchRow();
302 * Return the number of rows in this result.
308 if (!isset($this->_size
)) {
309 $this->_size
= $this->_src
->numRows();
315 * Returns true if end of iterator has not been reached yet.
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
333 if ($this->_end || ++
$this->_index
>= $this->size()) {
338 unset($this->_value
);
339 $this->_value
= $this->_src
->fetchRow();
340 return $this->_value
;
344 * Return current row.
350 return $this->_value
;
354 * Return current row index in resultset.
360 return $this->_index
;