quickfix for bug that caused
[mediawiki.git] / PHPTAL-NP-0.7.0 / libs / PHPTAL / Context.php
blobb41201fc9ea4639d10c312d0ab3ff53742a1e1a1
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 //
24 // What are Context and Resolvers
25 // ==============================
27 // In phptal, variables and methods are referenced by path without distinction,
28 // also, arrays and hashtable elements are accessed using a path like
29 // myarray/10 to reach the 11's element of myarray or myhash/mykey to
30 // reach the value of mykey in myhash.
32 // This allow things like 'myobject/mymethod/10/othermethod' which is usefull
33 // in templates.
34 //
35 // The Context is an array containing all template variables.
36 // When asked to reach a path, it look for the variable type of the first path
37 // element and generate a resolver matching the variable type.
38 // Then this resolver is asked to resolve the rest of the path, etc... up to
39 // the final path element.
41 // Resolver knows how to handle a given path relatively to the object they
42 // handle.
44 // For instance, an array resolver can handle access to its array elements
45 // given a key (string) or the element id (int).
47 // The array resolver also bring an array method : count which return the
48 // number of elements in the array.
50 // Note
51 // ----
52 //
53 // If a name conflict occurs between an object's variable and one of its
54 // methods, the variable is return in stead of the method.
55 //
57 /**
58 * Template context handler.
60 * This object produce a translation between variables passed to the template
61 * and regular template pathes.
63 * @author Laurent Bedubourg <laurent.bedubourg@free.fr>
65 class PHPTAL_Context
67 var $_array = array();
68 var $_errorRaised = false;
70 /**
71 * Context constructor.
73 * @param hashtable $hash (opt)
75 function PHPTAL_Context($hash=array())
77 $this->_array = $hash;
80 /**
81 * Set a value by reference.
83 * @param string $path -- Variable path
84 * @param mixed $value -- Reference to variable.
86 function setRef($path, &$value)
88 $this->remove($path);
89 $this->_array[$path] =& $value;
92 /**
93 * Set a context variable.
95 * @param string $path -- Variable path
96 * @param mixed $value -- Value
98 function set($path, $value)
100 $this->remove($path);
101 $this->_array[$path] = $value;
105 * Remove a context variable.
107 * @param string $path -- Context path
109 function remove($path)
111 if (array_key_exists($path, $this->_array)) {
112 unset($this->_array[$path]);
117 * Test if the context can resolve specified path.
119 * @param string $path
120 * Path to a context resource.
122 * @return boolean
124 function has($path)
126 if (array_key_exists($path, $this->_array)) {
127 return true;
129 $resp =& PHPTAL_ArrayResolver::get($this->_array, $path);
130 if (PEAR::isError($resp)) {
131 return false;
132 } else if ($resp === null) {
133 return false;
135 return true;
139 * Return the context associative object.
141 function &getHash()
143 return $this->_array;
147 * Retrieve specified context resource.
149 * @param string $path
150 * Path to a context resource.
152 * @return mixed
153 * @throws NameError
155 function &get($path)
157 if (array_key_exists($path, $this->_array)) {
158 return $this->_array[$path];
160 $resp =& PHPTAL_ArrayResolver::get($this->_array, $path);
161 if (PEAR::isError($resp)) {
162 $this->_errorRaised = $resp;
163 } else if ($resp === null) {
164 $this->_errorRaised = true;
166 return $resp;
170 * Retrieve specified context resouce as a string object
172 * @param string $path
173 * Path to a context resource.
175 * @return string
177 function &getToString($path)
179 $o = $this->get($path);
180 if (is_object($o) && method_exists($o, "toString")) {
181 return $o->toString();
183 if (is_object($o) || is_array($o)) {
184 ob_start();
185 print_r($o); // var_dump($o);
186 $res = ob_get_contents();
187 ob_end_clean();
188 return $res;
190 return $o;
194 * Tells if an error was raised by this context accessing an unknown path.
196 * @return boolean
198 function errorRaised()
200 $r = $this->_errorRaised;
201 $this->_errorRaised = false;
202 return $r;
206 * Clean error handler.
208 function cleanError()
210 $this->_errorRaised = false;
215 * Object resolver.
217 * Resolver pathes relatives to object.
219 * @access private
220 * @author Laurent Bedubourg <laurent.bedubourg@free.fr>
222 class PHPTAL_ObjectResolver
224 function &get(&$obj, $subpath)
226 list($first, $next) = PHPTAL_path_explode($subpath);
228 if (method_exists($obj, $first)) {
229 // reference to a variable of the handled object
230 $value =& $obj->$first();
231 } elseif (array_key_exists($first, $obj)) {
232 // reference to an object variable
233 $value =& $obj->$first;
234 } elseif (is_a($obj, 'OHash') && $obj->containsKey($first)) {
235 return $obj->get($first);
236 } elseif (is_a($obj, 'OArray') && preg_match('/^[0-9]+$/', $first)) {
237 return $obj->get((int)$first);
238 } else {
239 $err = new NameError($subpath . " not found");
240 return $err;
242 // more to resolve in value
243 if ($next) {
244 return PHPTAL_resolve($next, $value, $obj);
246 return $value;
252 * Array resolver.
254 * Resolve pathes relative to arrays and hashtables.
256 * @author Laurent Bedubourg <laurent.bedubourg@free.fr>
258 class PHPTAL_ArrayResolver
260 function &get(&$array, $subpath)
262 list($first, $next) = PHPTAL_path_explode($subpath);
264 if ($first == "length" && !$next && !array_key_exists("length", $array)) {
265 return count($array);
268 if ($next === false) {
269 if ($first == 'count') { return count($array); }
270 if ($first == 'keys') { return array_keys($array); }
271 if ($first == 'values'){ return array_values($array); }
272 if (!array_key_exists($first, $array)) {
273 $err = new NameError("(ArrayResolver) Context does not contains key '$first'");
274 return $err;
276 return $array[$first];
279 if (!array_key_exists($first, $array)) {
280 $err = new NameError("(ArrayResolver) Context does not contains key '$first'");
281 return $err;
283 $temp =& $array[$first];
284 if ($temp) {
285 return PHPTAL_resolve($next, $temp, $array);
292 * String resolver.
294 * Add method to string type.
296 class PHPTAL_StringResolver
298 function get(&$str, $subpath)
300 list($first, $next) = PHPTAL_path_explode($subpath);
301 if ($next) {
302 $err = new TypeError("string methods have no sub path (string.$subpath)");
303 return $err;
305 if ($first == "len") {
306 return strlen($str);
308 $err = new NameError("string type has no method named '$first'");
309 return $err;
314 * Retrieve a resolver given a value and a parent.
316 function &PHPTAL_resolve($path, &$value, &$parent)
318 if (is_array($value)) return PHPTAL_ArrayResolver::get($value, $path);
319 if (is_object($value)) return PHPTAL_ObjectResolver::get($value, $path);
320 if (is_string($value)) return PHPTAL_StringResolver::get($value, $path);
321 $err = new TypeError("unable to find adequate resolver for '".gettype($value)."' remaining path is '$path'");
322 return $err;
326 * Shift the first elemetn of a phptal path.
328 * Returns an array containing the first element of the path and the rest of
329 * the path.
331 function PHPTAL_path_explode($path)
333 if (preg_match('|^(.*?)\/(.*?)$|', $path, $match)) {
334 array_shift($match);
335 return $match;
336 } else {
337 return array($path, false);
340 $pos = strpos($path,".");
341 if ($pos !== false) {
342 $first = substr($path, 0, $pos);
343 $next = substr($path, $pos+1);
344 return array($first, $next);
346 return array($path, false);