Overview

Packages

  • View
    • Helper

Classes

  • Horde_View
  • Horde_View_Base
  • Horde_View_Json

Interfaces

  • Horde_View_Interface

Exceptions

  • Horde_View_Exception
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * @category Horde
  4:  * @package View
  5:  */
  6: 
  7: /**
  8:  * Abstract base class for Horde_View to get private constructs out of
  9:  * template scope.
 10:  *
 11:  * @category Horde
 12:  * @package View
 13:  */
 14: abstract class Horde_View_Base
 15: {
 16:     /**
 17:      * @var string
 18:      */
 19:     public static $defaultFormBuilder = 'Horde_View_Helper_Form_Builder';
 20: 
 21:     /**
 22:      * Path stack for templates.
 23:      *
 24:      * @var array
 25:      */
 26:     private $_templatePath = array('./');
 27: 
 28:     /**
 29:      * Template to execute.
 30:      *
 31:      * Stored in a private variable to keep it out of the public view scope.
 32:      *
 33:      * @var string
 34:      */
 35:     private $_file = null;
 36: 
 37:     /**
 38:      * Cache of helper objects.
 39:      *
 40:      * @var array
 41:      */
 42:     private $_helpers = array();
 43: 
 44:     /**
 45:      * Encoding to use in escaping mechanisms.
 46:      *
 47:      * @var string
 48:      */
 49:     private $_encoding = 'UTF-8';
 50: 
 51:     /**
 52:      * Should we throw an error if helper methods collide?
 53:      *
 54:      * @var boolean
 55:      */
 56:     private $_throwOnHelperCollision = false;
 57: 
 58:     /**
 59:      * Protected properties.
 60:      *
 61:      * @var array
 62:      */
 63:     private $_protectedProperties;
 64: 
 65:     /**
 66:      * Constructor.
 67:      *
 68:      * @param array $config  Configuration key-value pairs.
 69:      */
 70:     public function __construct($config = array())
 71:     {
 72:         // Encoding.
 73:         if (!empty($config['encoding'])) {
 74:             $this->setEncoding($config['encoding']);
 75:         }
 76: 
 77:         // User-defined template path.
 78:         if (!empty($config['templatePath'])) {
 79:             $this->addTemplatePath($config['templatePath']);
 80:         }
 81: 
 82:         $this->_protectedProperties = get_class_vars(__CLASS__);
 83:     }
 84: 
 85:     /**
 86:      * Undefined variables return null.
 87:      *
 88:      * @return null
 89:      */
 90:     public function __get($name)
 91:     {
 92:         return null;
 93:     }
 94: 
 95:     /**
 96:      * Accesses a helper object from within a template.
 97:      *
 98:      * @param string $method  The helper method.
 99:      * @param array $args     The parameters for the helper.
100:      *
101:      * @return string  The result of the helper method.
102:      * @throws Horde_View_Exception
103:      */
104:     public function __call($method, $args)
105:     {
106:         if (isset($this->_helpers[$method])) {
107:             return call_user_func_array(array($this->_helpers[$method], $method), $args);
108:         }
109: 
110:         throw new Horde_View_Exception('Helper for ' . $method . ' not found.');
111:     }
112: 
113:     /**
114:      * Adds to the stack of template paths in LIFO order.
115:      *
116:      * @param string|array  The directory (-ies) to add.
117:      */
118:     public function addTemplatePath($path)
119:     {
120:         foreach ((array)$path as $dir) {
121:             // Attempt to strip any possible separator and append a
122:             // directory separator.
123:             $dir = rtrim($dir, '\\/' . DIRECTORY_SEPARATOR) . '/';
124: 
125:             // Add to the top of the stack.
126:             array_unshift($this->_templatePath, $dir);
127:         }
128:     }
129: 
130:     /**
131:      * Resets the stack of template paths.
132:      *
133:      * To clear all paths, use Horde_View::setTemplatePath(null).
134:      *
135:      * @param string|array  The directory (-ies) to set as the path.
136:      */
137:     public function setTemplatePath($path)
138:     {
139:         $this->_templatePath = array();
140:         $this->addTemplatePath($path);
141:     }
142: 
143:     /**
144:      * Returns the template paths.
145:      *
146:      * @return array  The stack of current template paths.
147:      */
148:     public function getTemplatePaths()
149:     {
150:         return $this->_templatePath;
151:     }
152: 
153:     /**
154:      * Adds to the stack of helpers in LIFO order.
155:      *
156:      * If the $helper parameter is a string instead of a Helper instance, then
157:      * it will be treated as a class name. Names without "_" and that do not
158:      * have "Helper" in them will be prefixed with Horde_View_Helper_; other
159:      * names will be treated as literal class names. Examples:
160:      *
161:      * <code>
162:      * // Adds a new Horde_View_Helper_Tag to the view:
163:      * $v->addHelper('Tag');
164:      * // Adds a new AppHelper object to the view if it exists, otherwise
165:      * // throws an exception:
166:      * $v->addHelper('AppHelper');
167:      * </code>
168:      *
169:      * @param Horde_View_Helper|string $helper  The helper instance to add.
170:      *
171:      * @return Horde_View_Helper  Returns the helper object that was added.
172:      * @throws Horde_View_Exception
173:      */
174:     public function addHelper($helper)
175:     {
176:         if (is_string($helper)) {
177:             if (strpos($helper, '_') === false &&
178:                 strpos($helper, 'Helper') === false) {
179:                 $class = 'Horde_View_Helper_' . $helper;
180:             } else {
181:                 $class = $helper;
182:             }
183:             if (!class_exists($class)) {
184:                 throw new Horde_View_Exception('Helper class ' . $helper . ' not found');
185:             }
186:             $helper = new $class($this);
187:         }
188: 
189:         foreach (get_class_methods($helper) as $method) {
190:             if (isset($this->_helpers[$method])) {
191:                 $msg = 'Helper method ' . get_class($this->_helpers[$method])
192:                     . '#' . $method . ' overridden by ' . get_class($helper)
193:                     . '#' . $method;
194:                 if ($this->_throwOnHelperCollision) {
195:                     throw new Horde_View_Exception($msg);
196:                 }
197:                 if ($this->logger) {
198:                     $this->logger->warn($msg);
199:                 }
200:             }
201:             $this->_helpers[$method] = $helper;
202:         }
203: 
204:         return $helper;
205:     }
206: 
207:     /**
208:      * Assigns multiple variables to the view.
209:      *
210:      * The array keys are used as names, each assigned their corresponding
211:      * array value.
212:      *
213:      * @param array $array  The array of key/value pairs to assign.
214:      */
215:     public function assign($array)
216:     {
217:         foreach ($array as $key => $val) {
218:             if (isset($this->_protectedProperties[$key])) {
219:                 throw new Horde_View_Exception('Cannott overwrite internal variables in assign()');
220:             }
221:             $this->$key = $val;
222:         }
223:     }
224: 
225:     /**
226:      * Processes a template and returns the output.
227:      *
228:      * @param string $name  The template to process.
229:      *
230:      * @return string  The template output.
231:      */
232:     public function render($name, $locals = array())
233:     {
234:         // Render partial.
235:         if (is_array($name) && $partial = $name['partial']) {
236:             unset($name['partial']);
237:             return $this->renderPartial($partial, $name);
238:         }
239: 
240:         // Find the template file name.
241:         $this->_file = $this->_template($name);
242: 
243:         // Remove $name from local scope.
244:         unset($name);
245: 
246:         ob_start();
247:         $this->_run($this->_file, $locals);
248:         return ob_get_clean();
249:     }
250: 
251:     /**
252:      * Renders a partial template.
253:      *
254:      * Partial template filenames are named with a leading underscore, although
255:      * this underscore is not used when specifying the name of the partial.
256:      *
257:      * We would reference the file /views/shared/_sidebarInfo.html in our
258:      * template using:
259:      *
260:      * <code>
261:      *   <div>
262:      *   <?php echo $this->renderPartial('sidebarInfo') ?>
263:      *   </div>
264:      * </code>
265:      *
266:      * @param string $name
267:      * @param array $options
268:      *
269:      * @return string  The template output.
270:      */
271:     public function renderPartial($name, $options = array())
272:     {
273:         // Pop name off of the path.
274:         $parts = strstr($name, '/') ? explode('/', $name) : array($name);
275:         $name = array_pop($parts);
276:         $path = implode('/', $parts) . '/';
277: 
278:         // Check if they passed in a collection before validating keys.
279:         $useCollection = array_key_exists('collection', $options);
280: 
281:         $valid = array('object' => null,
282:                        'locals' => array(),
283:                        'collection' => array());
284:         $options = array_merge($valid, $options);
285:         $locals = array($name => null);
286: 
287:         // Set the object variable.
288:         if ($options['object']) {
289:             $locals[$name] = $options['object'];
290:         }
291: 
292:         // Set local variables to be used in the partial.
293:         if (isset($options['locals']) &&
294:             (is_array($options['locals']) ||
295:              $options['locals'] instanceof Traversable)) {
296:             foreach ($options['locals'] as $key => $val) {
297:                 $locals[$key] = $val;
298:             }
299:         }
300: 
301:         if ($useCollection) {
302:             // Collection.
303:             $rendered = '';
304:             if (is_array($options['collection'])) {
305:                 $sz = count($options['collection']);
306:                 for ($i = 0; $i < $sz; $i++) {
307:                     $locals["{$name}Counter"] = $i;
308:                     $locals[$name] = $options['collection'][$i];
309:                     $rendered .= $this->render("{$path}_{$name}", $locals);
310:                 }
311:             }
312:         } else {
313:             // Single render.
314:             $rendered = $this->render("{$path}_{$name}", $locals);
315:         }
316: 
317:         return $rendered;
318:     }
319: 
320:     /**
321:      * Sets the output encoding.
322:      *
323:      * @param string $encoding  A character set name.
324:      */
325:     public function setEncoding($encoding)
326:     {
327:         $this->_encoding = $encoding;
328:     }
329: 
330:     /**
331:      * Returns the current output encoding.
332:      *
333:      * @return string  The current character set.
334:      */
335:     public function getEncoding()
336:     {
337:         return $this->_encoding;
338:     }
339: 
340:     /**
341:      * Controls the behavior when a helper method is overridden by another
342:      * helper.
343:      *
344:      * @param boolean $throw  Throw an exception when helper methods collide?
345:      */
346:     public function throwOnHelperCollision($throw = true)
347:     {
348:         $this->_throwOnHelperCollision = $throw;
349:     }
350: 
351:     /**
352:      * Finds a template from the available directories.
353:      *
354:      * @param $name string  The base name of the template.
355:      *
356:      * @return string  The full path to the first matching template.
357:      */
358:     protected function _template($name)
359:     {
360:         // Append missing .html.
361:         if (!strstr($name, '.')) {
362:             $name .= '.html.php';
363:         }
364: 
365:         if (!count($this->_templatePath)) {
366:             throw new Horde_View_Exception('No template directory set; unable to locate ' . $name);
367:         }
368: 
369:         foreach ($this->_templatePath as $dir) {
370:             if (is_readable($dir . $name)) {
371:                 return $dir . $name;
372:             }
373:         }
374: 
375:         throw new Horde_View_Exception("\"$name\" not found in template path (\"" . implode(':', $this->_templatePath) . '")');
376:     }
377: 
378:     /**
379:      * Includes the template in a scope with only public variables.
380:      *
381:      * @param string  The template to execute. Not declared in the function
382:      *                signature so it stays out of the view's public scope.
383:      * @param array   Any local variables to declare.
384:      */
385:     abstract protected function _run();
386: }
387: 
API documentation generated by ApiGen