}
/**
+ * Return the template paths
+ *
+ * @return array
+ */
+ public function getTemplatePaths()
+ {
+ return $this->_templatePath;
+ }
+
+ /**
* Adds to the stack of helpers in LIFO order.
*
* @param Horde_View_Helper $helper The helper instance to add. If this is a
*
* @return string The template output.
*/
- public function render($name)
+ public function render($name, $locals = array())
{
+ // render partial
+ if (is_array($name) && $partial = $name['partial']) {
+ unset($name['partial']);
+ return $this->renderPartial($partial, $name);
+ }
+
// Find the template file name.
$this->_file = $this->_template($name);
unset($name);
ob_start();
- $this->_run($this->_file);
+ $this->_run($this->_file, $locals);
return ob_get_clean();
}
/**
+ * Render a partial template. Partial template filenames are named with a
+ * leading underscore, although this underscore is not used when specifying
+ * the name of the partial.
+ *
+ * we would reference the file /views/shared/_sidebarInfo.html in our
+ * template using:
+ *
+ * <code>
+ * <div>
+ * <?= $this->renderPartial('sidebarInfo') ?>
+ * </div>
+ * </code>
+ *
+ * @param string $name
+ * @param array $options
+ *
+ * @return string The template output
+ */
+ public function renderPartial($name, $options = array())
+ {
+ // pop name off of the path
+ $parts = strstr($name, '/') ? explode('/', $name) : array($name);
+ $name = array_pop($parts);
+ $path = implode('/', $parts)."/";
+
+ // check if they passed in a collection before validating keys
+ $useCollection = array_key_exists('collection', $options);
+
+ $valid = array('object' => null, 'locals' => array(), 'collection' => array());
+ $options = array_merge($valid, $options);
+ $locals = array($name => null);
+
+ // set the object variable
+ if ($options['object']) {
+ $locals[$name] = $options['object'];
+ }
+
+ // set local variables to be used in the partial
+ foreach ($options['locals'] as $key => $val) {
+ $locals[$key] = $val;
+ }
+
+ // collection
+ if ($useCollection) {
+ $rendered = '';
+ if (is_array($options['collection'])) {
+ $sz = count($options['collection']);
+ for ($i = 0; $i < $sz; $i++) {
+ $locals["{$name}Counter"] = $i;
+ $locals[$name] = $options['collection'][$i];
+ $rendered .= $this->render("{$path}_{$name}", $locals);
+ }
+ }
+
+ // single render
+ } else {
+ $rendered = $this->render("{$path}_{$name}", $locals);
+ }
+ return $rendered;
+ }
+
+ /**
* Escapes a value for output in a template.
*
* If escaping mechanism is one of htmlspecialchars or htmlentities, uses
*/
protected function _template($name)
{
+ // append missing html
+ if (!strstr($name, '.')) { $name .= '.html'; }
+
if (!count($this->_templatePath)) {
throw new Horde_View_Exception('No template directory set; unable to locate ' . $name);
}
* Use to include the template in a scope that only allows public
* members.
*
- * @return mixed
+ * @param string The template to execute. Not declared in the
+ * function signature so it stays out of the view's public scope.
+ *
+ * @param array Any local variables to declare.
*/
abstract protected function _run();
--- /dev/null
+<?php
+/**
+ * Copyright 2007-2008 Maintainable Software, LLC
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_View
+ * @subpackage UnitTests
+ */
+
+/**
+ * @group view
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @author Derek DeVries <derek@maintainable.com>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @category Horde
+ * @package Horde_View
+ * @subpackage UnitTests
+ */
+class Horde_View_BaseTest extends Horde_Test_Case
+{
+ protected $_view = null;
+
+ public function setUp()
+ {
+ $this->_view = new Horde_View();
+ $this->_view->addTemplatePath(dirname(__FILE__) . '/fixtures/');
+ }
+
+ /*##########################################################################
+ # Assignment
+ ##########################################################################*/
+
+ // test setting/getting dynamic properties
+ public function testSet()
+ {
+ $this->_view->publicVar = 'test';
+ $this->assertEquals('test', $this->_view->publicVar);
+ }
+
+ // test accessing variable
+ public function testAccessVar()
+ {
+ $this->_view->testVar = 'test';
+ $this->assertTrue(!empty($this->_view->testVar));
+
+ $this->_view->testVar2 = '';
+ $this->assertTrue(empty($this->_view->testVar2));
+
+ $this->assertTrue(isset($this->_view->testVar2));
+ $this->assertTrue(!isset($this->_view->testVar3));
+ }
+
+ // test adding a template path
+ public function testAddTemplatePath()
+ {
+ $this->_view->addTemplatePath('app/views/shared/');
+
+ $expected = array('app/views/shared/',
+ dirname(__FILE__) . '/fixtures/',
+ './');
+ $this->assertEquals($expected, $this->_view->getTemplatePaths());
+ }
+
+ // test adding a template path
+ public function testAddTemplatePathAddSlash()
+ {
+ $this->_view->addTemplatePath('app/views/shared');
+ $expected = array('app/views/shared/',
+ dirname(__FILE__) . '/fixtures/',
+ './');
+ $this->assertEquals($expected, $this->_view->getTemplatePaths());
+ }
+
+
+ /*##########################################################################
+ # Rendering
+ ##########################################################################*/
+
+ // test rendering
+ public function testRender()
+ {
+ $this->_view->myVar = 'test';
+
+ $expected = "<div>test</div>";
+ $this->assertEquals($expected, $this->_view->render('testRender.html'));
+ }
+
+ // test rendering
+ public function testRenderNoExtension()
+ {
+ $this->_view->myVar = 'test';
+
+ $expected = "<div>test</div>";
+ $this->assertEquals($expected, $this->_view->render('testRender'));
+ }
+
+ // test that the
+ public function testRenderPathOrder()
+ {
+ $this->_view->myVar = 'test';
+
+ // we should be rendering the testRender.html in fixtures/
+ $expected = "<div>test</div>";
+ $this->assertEquals($expected, $this->_view->render('testRender'));
+
+ // after we specify the 'subdir' path, it should read from subdir path first
+ $this->_view->addTemplatePath(dirname(__FILE__) . '/fixtures/subdir/');
+ $expected = "<div>subdir test</div>";
+ $this->assertEquals($expected, $this->_view->render('testRender'));
+ }
+
+
+ /*##########################################################################
+ # Partials
+ ##########################################################################*/
+
+ // test rendering partial
+ public function testRenderPartial()
+ {
+ $this->_view->myVar1 = 'main';
+ $this->_view->myVar2 = 'partial';
+
+ $expected = '<div>main<p>partial</p></div>';
+ $this->assertEquals($expected, $this->_view->render('testPartial'));
+ }
+
+ // test rendering partial with object passed in
+ public function testRenderPartialObject()
+ {
+ $this->_view->myObject = (object)array('string_value' => 'hello world');
+ $expected = '<div><p>hello world</p></div>';
+ $this->assertEquals($expected, $this->_view->render('testPartialObject'));
+ }
+
+ // test rendering partial with locals passed in
+ public function testRenderPartialLocals()
+ {
+ $expected = '<div><p>hello world</p></div>';
+ $this->assertEquals($expected, $this->_view->render('testPartialLocals'));
+ }
+
+ // test rendering partial with collection passed in
+ public function testRenderPartialCollection()
+ {
+ $this->_view->myObjects = array((object)array('string_value' => 'hello'),
+ (object)array('string_value' => 'world'));
+ $expected = '<div><p>hello</p><p>world</p></div>';
+ $this->assertEquals($expected, $this->_view->render('testPartialCollection'));
+ }
+
+ // test rendering partial with empty set as collection
+ public function testRenderPartialCollectionEmpty()
+ {
+ $this->_view->myObjects = null;
+
+ $expected = '<div></div>';
+ $this->assertEquals($expected, $this->_view->render('testPartialCollection'));
+ }
+
+ // test rendering partial with empty array as collection
+ public function testRenderPartialCollectionEmptyArray()
+ {
+ $this->_view->myObjects = array();
+
+ $expected = '<div></div>';
+ $this->assertEquals($expected, $this->_view->render('testPartialCollection'));
+ }
+
+ // partial collection is a model collection
+ public function testRenderPartialModelCollection()
+ {
+ $this->_view->myObjects = array((object)array('string_value' => 'name a'), (object)array('string_value' => 'name b'));
+
+ $expected = '<div><p>name a</p><p>name b</p></div>';
+ $this->assertEquals($expected, $this->_view->render('testPartialCollection'));
+ }
+
+
+ /*##########################################################################
+ # Escape output
+ ##########################################################################*/
+
+ public function testEscapeTemplate()
+ {
+ $this->_view->myVar = '"escaping"';
+ $this->_view->addHelper(new Horde_View_Helper_Text($this->_view));
+
+ $expected = "<div>test "escaping" quotes</div>";
+ $this->assertEquals($expected, $this->_view->render('testEscape'));
+ }
+
+ // test adding a helper
+ public function testAddHorde_View_Helper_Text()
+ {
+ $str = 'The quick brown fox jumps over the lazy dog tomorrow morning.';
+
+ // helper doesn't exist
+ try {
+ $this->_view->truncateMiddle($str, 40);
+ } catch (Exception $e) {}
+ $this->assertTrue($e instanceof Horde_View_Exception);
+
+ // add text helper
+ $this->_view->addHelper(new Horde_View_Helper_Text($this->_view));
+ $expected = 'The quick brown fox... tomorrow morning.';
+ $this->assertEquals($expected, $this->_view->truncateMiddle($str, 40));
+ }
+
+ // test adding a helper where methods conflict
+ public function testAddHorde_View_Helper_TextMethodOverwrite()
+ {
+ // add text helper
+ $this->_view->addHelper(new Horde_View_Helper_Text($this->_view));
+
+ // sucessfull when trying to add it again
+ $this->_view->addHelper(new Horde_View_Helper_Text($this->_view));
+ }
+
+}