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}
Zend_Controller_Action_Helper
{zone-data}

{zone-data:proposer-list}
[~ralph]
{zone-data}

{zone-data:revision}
1.1 - 1 March 2007: Updated from community comments.
{zone-data}

{zone-data:overview}

The goal of Zend_Controller_Action_Helper is to supply Action Controllers with runtime/on-demand helper functionality. Currently, the only way to inject functionality into the abstract Action Controller is by extending it with the desired common functionality as methods of the abstract class. Action Helpers aim to minimize the necessity to extend the abstract action controller in order to inject common action controller functionality.

Why not the current Plugin system? The current plugin system is a product of the Front Controller and thusly hooks into the various stages of dispatching from routing,looping,then the superficial dispatching. (I say superficial since it in no way interacts with the Action Controller from the point at which execution is handed off). Currently, Plugins are a one-way street. Beyond being registered, a developer cannot interact with them easily from the Action Controller layer. It could be said that there is ZERO overlap in these two systems. In short, think of it like this: Existing "Plugins" are plugins to the Front Controller as Action Helpers are plugins to the Action Controller.

Action Helpers exist independently of the chosen method of Dispatching (Front Controller or Page Controller), thusly a developers can be certain that all action helpers will work the same way regardless of the method of dispatchment.

Action Helpers (like Zend_View_Helpers) are minimally loaded and called on demand; maximumly can be instantiated at request time (bootstrap) or action controller creation time (init()).

Most immediately, and included in this proposal, candidates for Action Helpers are redirect functionality (which currently exists as Action Controller core functionality.. argument can be made as to wether or not it belongs there), and flash messaging (or FlashMessenger). These are common tasks that the overwhelming majority of developers have used in one form or another.. and have roots in existing frameworks.

IMPACT ON EXISTING FRAMEWORK

Minimal at best.. I counted 5 lines of changes to Action.php, the rest is included and run on demand as noted above. The existing functionality of _redirect can be replaced (to depreciate if desired) with the same code that would be expected from developers from within their own Action Controllers... another few lines at best.

(Future) Many different Action Helpers could potentially become part of the Zend Framework core with zero modifications to core files once the Hooks for Action Helpers are put in place (much the same way Zend_View_Helpers can be introduced into the framework via the proposal process.


{zone-data}

{zone-data:references}
* [see ROR flashmessage|http://api.rubyonrails.org/classes/ActionController/Flash.html]
* Zend_View_Helper
* [Code Branch|http://svn.ralphschindler.com/repo/ZendFrameworkBranches/Zend_Controller_Action_Helper-r3715/]

{zone-data}

{zone-data:requirements}
none
{zone-data}

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

{zone-data:operation}
see usage case 1
{zone-data}

{zone-data:milestones}
to be determined
{zone-data}

{zone-data:class-list}
* Zend_Controller_Action_Exception
* Zend_Controller_Action_HelperBroker
* Zend_Controller_Action_Helper_Abstract
* Zend_Controller_Action_Helper_Redirector
* Zend_Controller_Action_Helper_FlashMessenger
{zone-data}

{zone-data:use-cases}
{code}
<?php

class IndexController extends Zend_Controller_Action
{
/**
* @var Zend_Controller_Action_Helper_Redirector
*/
protected $_redirector = null;

/**
* @var Zend_Controller_Action_Helper_FlashMessenger
*/
protected $_flashmessenger = null;

public function init()
{
// this works
$this->_redirector = $this->_helper->getHelper('Redirector');

// thsi works
$this->_redirector = $this->_helper->redirector;

$this->_flashmessenger = $this->_helper->getHelper('FlashMessenger');

return;
}

public function indexAction()
{
/**
* REDIRECTOR USAGE EXAMPLES
*/

// this api works
$this->_helper->redirector->goto('/my/urlA/');

// this api works
$this->_helper->Redirector->goto('/my/urlA2/');

// this api works
$this->_helper->redirector('/my/urlB/');

// this api works
$this->_redirector->goto('/my/urlC/');

$this->getHelper('Redirector')->goto('/my/urlD');


/**
* FLASHMESSENGER USAGE EXAMPLES
*/

if ($this->_flashmessenger->hasMessages()) {
print_r($this->_flashmessenger->getMessages());
}

$this->_flashmessenger->addMessage('Hello!' . rand(5, 10));

echo "<br> SWITCHING NAMESPACES <br>";
$this->_flashmessenger->setNamespace('index_controller');

if ($this->_flashmessenger->hasMessages()) {
print_r($this->_flashmessenger->getMessages());
}

$this->_helper->FlashMessenger->addMessage('Hello from new namespace!' . rand(5, 10));

echo "<br> ADDING BACK TO ORIGINAL NAMESPACE ";
$this->_flashmessenger->resetNamespace();
$this->_flashmessenger->addMessage('Hello again!' . rand(5, 10));

echo "Current messages: ";
print_r($this->_flashmessenger->getCurrentMessages());


}

}
{code}


{zone-data}

{zone-data:skeletons}

HelperBroker.php
{code}
final class Zend_Controller_Action_HelperBroker
{
static protected $_helpers = array();
static protected $_paths = array(
array('dir' => 'Zend/Controller/Action/Helper/', 'prefix' => 'Zend_Controller_Action_Helper_')
);
protected $_actionController;

static public function addHelper(Zend_Controller_Action_Helper_Abstract $helper)
static public function addPrefix($prefix)
static public function addPath($path, $prefix)
public function __construct(Zend_Controller_Action $actionController)
public function _notifyActionControllerPreDispatch()
public function _notifyActionControllerPostDispatch()
public function getHelper($name)
protected function _loadHelper($name)
public function __call($method, $args)
public function __get($name)

}
{code}

Helper/Abstract.php
{code}

abstract class Zend_Controller_Action_Helper_Abstract
{
protected $_actionController = null;
public function setActionController(Zend_Controller_Action $actionController)
public function actionControllerInit() { }
public function actionControllerPreDispatch() { }
public function actionControllerPostDispatch() { }
public function getRequest()
public function getResponse()
public function getName()
public function simple($args)
{
throw new Zend_Controller_Action_Exception('Calling this helper in this manner \$this->_helper->' . $this->getName()
. '() is not supported in this Action Helper; try: \$this->_helper->' . $this->getName() . '->desiredMethod()');
}

}

{code}

Helper/Redirector.php
{code}

class Zend_Controller_Action_Helper_Redirector extends Zend_Controller_Action_Helper_Abstract
{

protected $_code = 302;
protected $_exit = true;
protected $_prependBase = true;
public function getCode()
protected function _checkCode($code)
public function setCode($code)
public function getExit()
public function setExit($flag)
public function getPrependBase()
public function setPrependBase($flag)
public function goto($url, array $options = null)
public function simple($args)

}
{code}


Helper/FlashMessenger.php
{code}
class Zend_Controller_Action_Helper_FlashMessenger extends Zend_Controller_Action_Helper_Abstract implements IteratorAggregate, Countable
{
static protected $_messages = array();
static protected $_session = null;
static protected $_messageAdded = false;
protected $_namespace = 'default';
public function __construct()
public function actionControllerPostDispatch()
public function setNamespace($namespace = 'default')
public function resetNamespace()
public function addMessage($message)
public function hasMessages()
public function getMessages()
public function hasCurrentMessages()
public function getCurrentMessages()
public function getIterator()
public function count()

}
{code}
{zone-data}

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