Key
This line was removed.
This word was removed. This word was added.
This line was added.

Changes (172)

View Page History
Wherever possible, View Helpers are preferred in place of adding code directly to Zend_View_Abstract. A number of these View Helpers have been proposed which capture the above four concepts, and add specialised variants to simplify template authoring. These expand the reach of View Helpers primarily to the <head> section of a HTML document where a lot of activity around Javascript, CSS, meta tags, etc. may be controlled outside a Layout within the actual sub-templates (a common requirement of any nested View design).

The proposed additions maintain Zend_View's decoupling from Zend_Controller. They should (as a requirement) have no conflict with Controller integrated strategies for similar features. There are therefore no conflicts with the addition of Controller based variants for Layouts such as the introduction of a Two-Step View implementation. It is noted that
The proposed additions maintain Zend_View's decoupling from Zend_Controller. They should (as a requirement) have no conflict with Controller integrated strategies for similar features. -There are therefore no conflicts with the addition of Controller based variants for Layouts such as the introduction of a Two-Step View implementation.- However, layouts will be dealt with under a separate proposal.

The additions are therefore quite straight forward, easy to implement, and pose no threat to backwards compatibility.

{zone-data:requirements}
* *Must* implement the 4 view construction strategies (Layout, Partial, Controller, Placeholder)
* *Must* implement the -4-3 view construction strategies (-Layout,- Partial, Controller, Placeholder) _(Note: Layouts will be dealt with in a separate proposal)_
* *Must* implement several specialised View Helpers for controlling Element additions to the <head>
* *Must* maintain backwards compatibility with Zend_View and Zend_Controller_Action_Helper_ViewRenderer

{zone-data:operation}
Zend_View Enhanced advocates a template driven approach to output generation. As templates are rendered by Zend_View, the templates themselves may invoke Partials and Controllers, as well as set Placeholder content (template specific or default) which is centrally stored for higher level and subsequent templates (such as Layouts) to utilise. -Layouts are applied at the end of any Zend_View instance's rendering process to take advantage of Placeholders, and their specialised variants.-

Partials: Partials simply render a specified template within it's own separate variable scope. This is useful for reusable template fragments, avoids variable name clashes, and allows configuration of Partials to include from independent Modules (i.e. using that Module's helpers/filters/paths). At a higher level, Partials implement the Composite View design pattern allowing for the generation of a tree of View objects for even more flexibility.
Controllers: Dispatches a request to the Controller which returns output for embedding in a template. This must be compatible with ViewRenderer. May be used for querying the Model, but it's generally recommended to use a View Helper where possible. Most likely useful where authentication or authorisation must also be queried before Model access, or where existing Controllers can be reused as an alternative to implementing more View Helpers.

-Layouts: Decorates the main output of a Zend_View instance with a Layout template composed of common page elements and Placeholders for context specific additions which are defined by templates prior to the Layout rendering. Layouts in Zend_View are implemented in a simple manner - they are the only feature requiring editing of Zend_View_Abstract.-

Placeholders: Allows templates to set centrally registered content for inclusion in any subsequently rendered template or Layout. Placeholders are sufficiently decoupled from templates so that templates from different variable scopes can still communicate data to each other. Set Placeholders are only ever available to templates rendered after the Placeholder is set. Placeholders may be used for HTML elements which require a strict order of addition (e.g. Javascript <script> tags), or alternatively a specialised HTML generating Helper (e.g. Zend_View_Helper_HeadScript) can be used instead. See next.
||UC-03||

*Layout Use Case*

Layouts are templates which decorate the rendered output of a View. The decoration is handled internally by Zend_View_Abstract::render() by allowing Layouts to define an insertion point for the main output to be placed. Layouts are quite flexible, the primary insertion point for the main rendered output is just a typical Placeholder proxied by the getContentLayout() method.

*./src/bootstrap.php*
{code:php}
$view = new Zend_View;
$view->setBasePath(APPLICATION_PATH . DIRECTORY_SEPARATOR . 'default/views');
$view->setLayout('layout.phtml'); // manually handled, could be automated by ViewRenderer
$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer;
$viewRenderer->setView($view);
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
{code}

*./src/default/view/scripts/layout.phtml*
{code:php}
<?php echo $this->doctype('XHTML 1.0 Strict') ?>
<html>
<head>
<title>My Application</title>
<link rel="stylesheet" type="text/css" href="styles/base.css" media="screen">
</head>
<body>
<div id="main">
<?php echo $this->getContentLayout(); ?>
</div>
<div id="footer">
<p><small>Copyright &copy; 2007 Pádraic Brady</small></p>
</div>
</body>
</html>
{code}


||UC-04||

*Placeholder Use Case*

Placeholders are centrally registered pieces of content which all subsequently rendered templates may access. Since Layouts are always rendered last - they may access all set Placeholders. Placeholders may be set with a specific order attached. This is beyond the scope of the the following Use Case which does not differentiate between <head> descendant elements.

*./src/bootstrap.php*
{code:php}
$view = new Zend_View;
$view->setBasePath(APPLICATION_PATH . DIRECTORY_SEPARATOR . 'default/views');
$view->setLayout('layout.phtml'); // manually handled, could be automated by ViewRenderer
$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer;
$viewRenderer->setView($view);
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
{code}
Placeholders can either hold scalars or collections. In the case of collections, placeholders provide a mechanism for ordering and sorting. In either case, a placeholder would allow specifying content with which to either prefix or postfix the placeholder content, and in the case of collections, separator content. They will implement __toString(), allowing them to be echo'd directly. Finally, they will also allow capturing template content into a placeholder.

*./src/default/view/scripts/layout.phtml*
</head>
<body>
<div id="nav">
<?php echo $this->placeholder('subnav') ?>
</div>
<div id="main">
<?php echo $this->getLayoutContent(); $this->layout_content; ?>
</div>
<div id="footer">
<p>
<?php if($this->placeholder()->has('license')): if (count($this->placeholder('license')): ?>
<?php echo $this->placeholder->get('LICENSE'); $this->placeholder('license'); ?>
<?php else: ?>
Licensed under the <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation License</a>.
{code:php}
<?php $this->headLink(array('rel'=>'alternate', 'type'=>'application/rss+xml', 'title'=>'RSS', 'href'=>'http://www.planet-php.org/rss/')); ?>
<?php $this->headLink(array('rel'=>'stylesheet', 'type'=>'text/css', 'href'=>'/style/extras.css')); ?>
<?php $this->placeholder->set('license', 'Licensed $this->placeholder('license')->set('Licensed under a <a href="http://creativecommons.org/licenses/by/1.0/">Creative Commons License</a>.'); ?>

<div class="blog content">
<?php endforeach; ?>
</div>

<?php $this->placeholder('subnav')->captureStart(); ?>
<ul id="subnav">
<li><a href="/blog/tags">Tags</a></li>
<li><a href="/blog/authors">Authors</a></li>
</ul>
<?php $this->placeholder('subnav')->captureEnd(); ?>
{code}


{zone-data:skeletons}
*Zend_View_Abstract: Extract showing additional public methods proposed*
{code:php}
/**
* Abstract class for Zend_View to help enforce private constructs.
*
* @category Zend
* @package Zend_View
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_View_Abstract implements Zend_View_Interface
{

/**
* Stores a Factory instance for creating Zend_View objects
*
* @var Zend_View_Factory
*/
private static $_factory = null;

/**
* The Layout template for this View if enabled
*
* @var string
*/
protected $_layoutFile = null;

/**
* The main template being rendered by this View, ignoring other secondary
* templates rendered by subsequent Zend_View::render() calls.
*
* @var string
*/
protected $_fileToRender = null;

/**
* Constructor.
*
* @param array $config Configuration key-value pairs.
*/
public function __construct($config = array())
{}

/**
* Processes a view script and returns the output. If enabled it will also
* decorate the output with a rendered Layout file.
*
* @see Zend_View_Abstract::contentForLayout()
* @param string $name The script script name to process.
* @return string The script output.
*/
public function render($name)
{}

/**
* Set the filename of a Layout template to be used. The existence of a
* Layout filename will cause the final rendered View to be stored until
* the rendered Layout includes it by calling Zend_View::content().
*
* @param $file string
* @return void
*/
public function setLayout($name)
{}

/**
* Return the filename of the Layout.
*
* @return string
*/
public function getLayout()
{}

/**
* Returns true if a Layout has been set for this View.
*
* @return bool
*/
public function hasLayout()
{}

/**
* Simple accessor to return pre-rendered content of the main template
*
* @return string
*/
public function getLayoutContent()
{}

/**
* Set an instance of Zend_View_Factory as a singleton Factory instance
*
* @param Zend_View_Factory
* @return void
*/
public static function setFactory(Zend_View_Factory_Interface $factory)
{}

/**
* Return the static singleton Factory instance
*
* @return Zend_View_Factory
*/
public static function getFactory()
{}

/**
* Use to include the view script in a scope that only allows public
* members.
*
* @return mixed
*/
abstract protected function _run();
}
{code}

*Zend_View_Helper_Partial*
{code:php}
By allowing templates within the Composite View tree (i.e. nested render() calls, partials etc.) access a central object which all View objects may access as a central Registry, it becomes possible for nested templates, irrespective of nest depth, to influence their top-level decorating Layout, or subsequently rendered templates, by setting values these may later refer to.

All values are stored in arrays. This enables Placeholders to maintain an indexed set of values, where the order of inclusion at a rendering point is determined by this indexation, or a user defined ordering function. At present the ordering defaults to ksort() but can be expanded to allow user defined callback functions to manage such ordering in an easy to modify manner.
All values are stored in array objects. This enables Placeholders to maintain an indexed set of values, where the order of inclusion at a rendering point is determined by this index. Because it implements ArrayObject, any PHP array sorting function may be used to sort the placeholder values.

This strategy is built into a set of a pre-defined Placeholders for the <head> element of HTML documents in the proposed Zend_View_Helper_Head* helpers. More similar helpers may be proposed if their utility proves valuable. Their purpose is primarily to offer specialised usage of the basic Placeholder class using Proxies which are capable of outputting valid XHTML/HTML using the values set by the template authors, and optionally specific to a defined Doctype.
{code:php}
/**
* Helper for passing data between otherwise segregated Views. It's called Placeholder to
* make its typical usage obvious, but can be used just as easily for non-Placeholder
* things. That said, the support for this is only guaranteed to effect subsequently rendered
* templates, and of course Layouts.
* This class is utilised by a number of specialised helpers such as Zend_View_Helper_HeadTitle
* Container for placeholder values
* @package Zend_View
* @subpackage Helpers
* @copyright Copyright (c) 2007 Pádraic Brady (http://blog.astrumfutura.com)
* @license New BSD
*/
class Zend_View_Helper_Placeholder {
class Zend_View_Helper_Placeholder_Container extends ArrayObject
{
const SET = 'set';
const APPEND = 'append';

protected $_prefix = '';
protected $_postfix = '';
protected $_separator = '';

protected $_captureLock = false;
protected $_captureType;

/**
* Registry array to store Placeholder values for later queries from layouts or
* Set a single value
* templates.
* @param mixed $value
* @return void
* */
public function set($value) * @var array
{ */
protected static $_registry = array(); $this->exchangeArray(array($value));
}

/**
* Potential function for custom ordering of Placeholder key arrays prior to rendering
* Retrieve container value
*
* If single element registered, returns that element; otherwise,
* serializes to array.
*
* @var @return mixed
*/
protected $_callback = null; public function getValue()
{
if (1 == count($this)) {
return $this[0];
}

return $this->getArrayCopy();
}

/**
* Set prefix for __toString() serialization
* Return the current object
* @param string $prefix
* @return Zend_View_Helper_Placeholder_Container
* */
public function setPrefix($prefix) * @return Zend_View_Helper_Placeholder
{} */
public function placeholder()
{}

/**
* Check for the existence of the named Placeholder key Retrieve prefix
*
* @return string
* */
public function getPrefix() * @param string $key
{} * @param mixed $index
* @return bool
*/
public function has($key, $index = null, $value = null)
{}

/**
* Append a value string to an existing Placeholder key Set postfix for __toString() serialization
* without any overwriting or index value
* @param string $postfix
* @return Zend_View_Helper_Placeholder_Container
* */
public function setPostfix($postfix) * @param string $key
{} * @param mixed $value
* @return void
*/
public function append($key, $value)
{}

/**
* Sets the value for a Placeholder key, or sets the value for a specific index
* on this key (e.g. to set a rendering order). If an index is not defined, it
* is assumed a single value per key is to be set and any pre-existing array
* will be replaced with this single value. Retrieve postfix
*
* @return string
* */
* If you want to set multiple values where ordering isn't necessary, use the
* Zend_View_Helper_Placeholder::append() method instead. This will append
* values using the default array indexation.
public function getPostfix()
{} *
* @param string $key
* @param mixed $value
* @param mixed $index
* @return void
*/
public function set($key, $value, $index = null)
{}

/**
* Return the value of a Placeholder key Set separator for __toString() serialization
*
* Used to implode elements in container
*
* @param string $key $separator
* @param mixed $index @return Zend_View_Helper_Placeholder_Container
*/ @return mixed
public function setSeparator($separator)
{} */
public function get($key, $index = null)
{}

/**
* Unset the value of a Placeholder key Retrieve separator
*
* @return string
* */
public function getSeparator()
{}

/**
* Start capturing content to push into placeholder
* @param string $key
* @param mixed $index
* @param string $value
* @param int $type How to capture content into placeholder; append or set
* @return void
* @throws Zend_View_Helper_Placeholder_Exception if nested captures detected
*/
public function remove($key, $index = null, $value = null)
public function captureStart($type = Zend_View_Helper_Placeholder_Container::APPEND)
{}
if ($this->_captureLock) {
throw new Zend_View_Helper_Placeholder_Exception('Cannot nest placeholder captures for the same placeholder');
}

$this->_captureLock = true;
$this->_captureType = $type;
ob_start();
}

/**
* Register a callback function which is passed the Placeholder array
* for a given key, along with the key name. This callback function may
* then proceed to order the array in such a way as to determine the
* sorting order by which element values are rendered into the Placeholder
* injection point in any calling template. End content capture
*
* @param string $function
* @param object $object
* @return void
*/
public function registerCallback($function, $object = null) captureEnd()
{}
$data = ob_get_flush();
$this->_captureLock = false;
switch ($this->_captureType) {
case self::SET:
$this->exchangeArray(array($data));
break;
case self::APPEND:
default:
$this[] = $data;
break;
}
}

/**
* Flatten the array of indexed values for output and return as
* Serialize object to string
* a string after the value array has been sorted.
*
* @param array $array
* @return string
*/
protected function _toString($array, $key = null)
public function __toString()
{}
$items = $this->getArrayCopy();
$return = $this->getPrefix()
. implode($this->getSeparator(), $items)
. $this->getPostfix();
return $return;
}
}
{code}

*Zend_View_Factory* /**
* Helper for passing data between otherwise segregated Views. It's called
Zend_View_Factory is a debatable implementation. How does one manage the instantiation and configuration of a View object without Controller access? The ViewRenderer object is very close to being a View Factory, so this class may simply act as a configurable Facade to that class. In either case it must allow for non-conventional directory layouts and thus should be configurable from an application's bootstrap to enable maximum flexibility in how a user may organise View paths.
* Placeholder to make its typical usage obvious, but can be used just as easily
* for non-Placeholder things. That said, the support for this is only
* guaranteed to effect subsequently rendered templates, and of course Layouts.
* This class is utilised by a number of specialised helpers such as
* Zend_View_Helper_HeadTitle
*/
class Zend_View_Helper_Placeholder
{code:php} {
class Zend_View_Factory
{
/**
* Constructor; optionally set options.
*
* @param array|Zend_Config $options
* @return void
*/
public function __construct($options = null)
{}

/**
* Create a Zend_View instance following the same conventions as ViewRenderer
* which can be amended by declaring a set of options when creating the
* Factory instance. @var Zend_View_Interface
* */
* @param string|array $module
public $view; * @param array $model
* @param Zend_View_Abstract
* @return void
*/
public function createInstance($module = null, array $model = null, Zend_View_Abstract $parentView = null)
{}

/**
* Placeholder items
* @var array
*/
protected $_items = array();

/**
* Set view basePath specification
*
* Specification can contain one or more of the following:
* - :moduleDir - parent directory of all modules
* - :module - name of current module in the request
*
* @param string $path Zend_View_Interface $view
* @return Zend_View_Factory void
*/
public function setViewBasePathSpec($path) setView(Zend_View_Interface $view)
{}
$this->view = $view;
}

/**
* Retrieve the current view basePath specification string Placeholder helper
*
* @param string $name
* @return string Zend_View_Helper_Placeholder_Container
*/
public function getViewBasePathSpec() placeholder($name)
{}
$name = (string) $name;
if (!isset($this->_items[$name])) {
$this->_items[$name] = new Zend_View_Helper_Placeholder_Container(array());
}

return $this->_items[$name];
}
}
{code}
/**
* Helper to insert or append <title> tags to the ZEND_HEAD Placeholder
*
* @category Zend
* @package Zend_View
* @subpackage Helper
* @copyright Copyright (c) 2007 Pádraic Brady
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_View_Helper_HeadTitle
{

/**
* Instance of parent Zend_View object
* Return self for further in-object calls
*
* @return Zend_View_Helper_HeadTitle Zend_View_Helper_Placeholder_Container
*/
public function headTitle($value = null)
{}

public function setView(Zend_View_Interface $view)
{}

/**
* Check for the existence of the ZEND_TITLE Placeholder key
*
* @return bool
*/
public function has()
{}

/**
* Set the value for a Placeholder ZEND_TITLE key.
* Overwrites existing value.
*
* @param mixed $value
* @return void
*/
public function set($value)
{}

/**
* Return the value of a Placeholder ZEND_TITLE key
*
* @return mixed
*/
public function get()
{}

/**
* Unset the value of a Placeholder ZEND_TITLE key
*
* @param string $index
* @return void
*/
public function remove($index = null)
{}

}
{code}
* return self for further in-object calls
*
* @return Zend_View_Helper_HeadMeta Zend_View_Helper_Placeholder_Container
*/
public function headMeta($value = null)
public function setView(Zend_View_Interface $view)
{}

/**
* Check for the existence of the self::HEADMETA_NAMESPACE Placeholder key
*
* @return bool
*/
public function has($index = null, $value = null)
{}

/**
* Append a value for a Placeholder self::HEADMETA_NAMESPACE key.
*
* @param mixed $value
* @return void
*/
public function append($value)
{}

/**
* Return the value of a Placeholder self::HEADMETA_NAMESPACE key
*
* @return mixed
*/
public function get($index = null)
{}

/**
* Unset the value of a Placeholder self::HEADMETA_NAMESPACE key
*
* @param string $index
* @return void
*/
public function remove($index = null, $value = null)
{}

/**
* toString function for this class
*
* @return string
*/
public function __toString() {
return $this->get();
}

}
{code}
/**
* Helper to add a <style> tag value to a head->style Placeholder
*
* @category Zend
* @package Zend_View
* @subpackage Helper
* @copyright Copyright (c) 2007 Pádraic Brady
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_View_Helper_HeadStyle
* return self for further in-object calls
*
* @return Zend_View_Helper_HeadStyle Zend_View_Helper_Placeholder_Container
*/
public function headStyle($value = null)
public function setView(Zend_View_Interface $view)
{}

/**
* Check for the existence of the self::HEADSTYLE_NAMESPACE Placeholder key
*
* @return bool
*/
public function has($index = null, $value = null)
{}

/**
* Append a value for a Placeholder self::HEADSTYLE_NAMESPACE key.
*
* @param mixed $value
* @return void
*/
public function append($value)
{}

/**
* Return the value of a Placeholder self::HEADSTYLE_NAMESPACE key
*
* @return mixed
*/
public function get($index = null)
{}

/**
* Unset the value of a Placeholder self::HEADSTYLE_NAMESPACE key
*
* @param string $index
* @return void
*/
public function remove($index = null, $value = null)
{}

/**
* toString function for this class
*
* @return string
*/
public function __toString() {
return $this->get();
}

}
{code}
/**
* Helper to insert or append <script> tags to the head->script Placeholder
*
* @category Zend
* @package Zend_View
* @subpackage Helper
* @copyright Copyright (c) 2007 Pádraic Brady
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_View_Helper_HeadScript
* Return self for further in-object calls
*
* @return Zend_View_Helper_HeadScript Zend_View_Helper_Placeholder_Container
*/
public function headScript($file = null, $type = null, $index = null)
{}

/**
* Check for the existence of the self::HEADSCRIPT_NAMESPACE Placeholder key
*
* @return bool
*/
public function has($index = null, $file = null, $type = 'javascript')
{}

/**
* Append a value for a Placeholder self::HEADSCRIPT_NAMESPACE key.
*
* @param mixed $value
* @return void
*/
public function append($file, $type = null, $index = null)
{}

/**
* Append a script-block value for a Placeholder self::HEADSCRIPT_NAMESPACE key.
*
* @param mixed $value
* @return void
*/
public function appendScript($code, $type = null, $index = null)
{}

/**
* Return the value of a Placeholder self::HEADSCRIPT_NAMESPACE key
*
* @return mixed
*/
public function get($index = null)
{}

/**
* Unset the value of a Placeholder self::HEADSCRIPT_NAMESPACE key
*
* @param string $index
* @return void
*/
public function remove($index = null, $file = null, $type = 'javascript')
{}

/**
* Alias to toString for public API
*
* @return string
*/
public function toString($index = null)
{}

/**
* toString function for this class
*
* @return string
*/
public function __toString($index = null)
{
}

/**
* Set view object
*
public function setView(Zend_View_Interface $view)
{}

/**
* Return a type attribute value for the <script> element
*
* @param string $type
* @return string
*/
protected function _getType($type)
{}

}
{code}
/**
* Helper to add a <link> tag value to a head->link Placeholder
*
* @category Zend
* @package Zend_View
* @subpackage Helper
* @copyright Copyright (c) 2007 Pádraic Brady
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_View_Helper_HeadLink
{

/**
* Instance of parent Zend_View object
*
* @param array $attributes
* @return Zend_View_Helper_HeadLink Zend_View_Helper_Placeholder_Container
*/
public function headLink(array $attributes = null)
public function setView(Zend_View_Interface $view)
{}

/**
* Check for the existence of the self::HEADLINK_NAMESPACE Placeholder key
*
* @return bool
*/
public function has($index = null, array $attributes = null)
{}

/**
* Set the value for a Placeholder self::HEADLINK_NAMESPACE key.
* Overwrites existing value.
*
* @param array $attributes
* @param int $index
* @return Zend_View_Helper_HeadLink
*/
public function append(array $attributes, $index = null)
{}

/**
* Return the value of a Placeholder self::HEADLINK_NAMESPACE key
*
* @return mixed
*/
public function get($index = null)
{}

/**
* Unset the value of a Placeholder self::HEADLINK_NAMESPACE key
*
* @param int $index
* @return Zend_View_Helper_HeadLink
*/
public function remove($index, array $attributes = null)
{}

/**
* Alias to toString for public API
*
* @param int $index
* @return string
*/
public function toString($index = null)
{}

/**
* __toString function for this class
*
* @param int $index
* @return string
*/
public function __toString($index = null)
{}

/**
* Merges key=>value pairs into a form suitable for insertion into
* a <link> string.
*
* @param array $attributes
* @return string
*/
protected function _merge(array $attributes)
{}

}

* Helper to obtain a doctype declaration based on the $standard parameter
* which reflects the full name of the standard including version and context
*
* @category Zend
* @package Zend_View
* @subpackage Helper
* @copyright Copyright (c) 2007 Pádraic Brady
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_View_Helper_Doctype