View Source

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[{zone-template-instance:ZFDEV:Zend Proposal Zone Template}

{zone-data:component-name}
MVC View Integration
{zone-data}

{zone-data:proposer-list}
[Matthew Weier O'Phinney|mailto:matthew@zend.com]
{zone-data}

{zone-data:revision}
1.0 - 7 March 2007: Original proposal creation
{zone-data}

{zone-data:overview}
The MVC components consist of the Zend_Controller and Zend_View families (and, nominally, Zend_Db_Table). However, there is no current integration of these components; a simple patch would enable this.
{zone-data}

{zone-data:references}
* [Ruby on Rails|http://www.onlamp.com/pub/a/onlamp/2007/01/05/revisiting-ruby-on-rails-revisited-2.html]
{zone-data}

{zone-data:requirements}
* View instantation *will* be lazy-loaded and optional
* View instantation *will* be overrideable to allow for custom view objects or loading view objects from alternate sources (e.g. registry)
* View script suffixes *will* be configurable via a controller property
* View rendering *will not* require an argument, and *will* use the controller and action to determine the view script by default
* View rendering *will* accept an optional view script name
{zone-data}

{zone-data:dependencies}
* Zend_Exception
* Zend_View_Interface
* Zend_Controller_Action
{zone-data}

{zone-data:operation}
Two new methods will be added to Zend_Controller_Action, initView() and render(), and two new properties, $view and $viewSuffix. When called the first time, render() will check to see if $view has been populated, and if not, call initView() to initialize the property.

render() will by default render the script <controller>/<action>.$viewSuffix in the view object's script path. If an argument is passed in, it will render $action.$viewSuffix. All rendered views are appended to the response object.

The default implementation of initView() will instantiate a Zend_View object and set the script, filter, and helper paths based on the following directory structure:
{code}
application/
controllers/
IndexController.php
ErrorController.php
views/
scripts/
index/
error/
filters/
helpers/
modules/
app/
controllers/
IndexController.php
ListController.php
FormController.php
views/
scripts/
index/
list/
form/
filters/
helpers/
{code}
Thus, the script path will be set to ../views/scripts, helpers to ../views/helpers, etc, relative to the controller class file.
{zone-data}

{zone-data:milestones}
* Milestone 1: initial proposal accepted
* Milestone 2: working and tested code checked into core
* Milestone 3: documentation exists
{zone-data}

{zone-data:class-list}
* Zend_Controller_Action
{zone-data}

{zone-data:use-cases}
||UC-01||
This example illustrates the default usage.
{code:php}
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
// Renders views/scripts/index/index.phtml
$this->render();
}

public function listAction()
{
// Initialize view so we can assign data to it
$this->initView();
$results = $this->model->fetchAll();
$this->view->results = $results;

// Renders views/scripts/index/list.phtml
$this->render();
}
}
{code}

||UC-02||
The following example illustrates two concepts:
* Initializing the view to allow assigning data to it
* Rendering an alternate view script (i.e., something other than controller/action.phtml)

{code:php}
class CrudController extends Zend_Controller_Action
{
public function createAction()
{
if ('post' != strtolower($_SERVER['REQUEST_METHOD'])) {
// Renders views/scripts/crud/form.phtml
return $this->render('form');
}

// process form...
}

public function updateAction()
{
if ('post' != strtolower($_SERVER['REQUEST_METHOD'])) {
// Initialize view and assign user details to it
$this->initView();
$this->view->user = $this->model->find($this->_getParam('id', 1));

// Renders views/scripts/crud/form.phtml
return $this->render('form');
}

// process form...
}

public function readAction()
{
// Initialize view and populate with user
$this->initView();
$this->view->user = $this->model->find($this->_getParam('id', 1));

// Renders views/scripts/crud/read.phtml
return $this->render();
}
}
{code}
||UC-03||
This example illustrates using a different suffix
{code:php}
class IndexController extends Zend_Controller_Action
{
public function init()
{
// set a different suffix
$this->viewSuffix = 'php';
}

public function indexAction()
{
// Renders views/scripts/index/index.php
$this->render();
}
}
{code}

||UC-04||
This example illustrates overriding initView() and render().
{code:php}
class IndexController extends Zend_Controller_Action
{
public function initView()
{
if (null !== $this->view) {
return;
}

require_once 'My/View/Adapter.php';
$this->view = new My_View_Adapter();
}

public function render($action = null)
{
if ( null === $action) {
throw new Exception('No template specified');
}
if (!Zend::isReadable($action, true)) {
throw new Exception('Template does not exist or is not readable');
}
$this->_response->appendBody($this->view->fetch($action));
}
}
{code}
{zone-data}

{zone-data:skeletons}
{code:php}
abstract class Zend_Controller_Action
{
/**
* @var Zend_View_Interface
*/
public $view;

/**
* @var string
*/
public $viewSuffix = 'phtml';

/**
* Initialize view object
*
* @return void
*/
public function initView()
{
if (null !== $this->view) {
return;
}

require_once 'Zend/View.php';
$basePath = dirname(__FILE__) . DIRECTORY_SEPARATOR . '..'
. DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR;

$this->view = new Zend_View(array(
'scriptPath' => $basePath . 'scripts',
'helperPath' => $basePath . 'helpers',
'filterPath' => $basePath . 'filters'
));
}

/**
* Render a view
*
* By default, renders controller/action.phtml in the current script path.
* If $action is provided, controller/$action.phtml will be rendered.
*
* The view script suffix may be changed by modifying the value of
* {@link $viewSuffix}.
*
* Rendered views are appended to the response object.
*
* @param null|string $action
* @return void
*/
public function render($action = null)
{
if (null === $this->view) {
$this->initView();
}

$controller = $this->_request->getControllerName();

if (null === $action) {
$action = $this->_request->getActionName();
}

$script = $controller . DIRECTORY_SEPARATOR . $action . '.' . $this->viewSuffix;

$this->_response->appendBody($this->view->render($script));
}
}
{code}
{zone-data}

{zone-template-instance}]]></ac:plain-text-body></ac:macro>