Using Action Helpers in Zend Framework
When you have some functionality that needs to be shared across multiple controllers, one method is to use action helpers. Action helpers are very powerful and contain hooks to automatically run when you need them too, but you can ignore all that if you don’t need it.
The first thing you need to do is decide where to put them. The latest default project structure document recommends using a sub folder from your controllers directory. That is: application/controllers/helpers, and it’s as good a place as any.
Firstly, you need to tell the helper broker where your action helpers are. I usually do this in the bootstrap, but it could equally be done in a front controller plug-in:
Zend_Controller_Action_HelperBroker::addPath(
APPLICATION_PATH .'/controllers/helpers');
You then need to create your action helper, we’ll call it Multiples in this example and so
the filename is application/controllers/helpers/Multiples.php:
<?php
class Zend_Controller_Action_Helper_Multiples extends
Zend_Controller_Action_Helper_Abstract
{
function direct($a)
{
return $a * 2;
}
}
Note that there is a prefix to the action helper name of Zend_Controller_Action_Helper. You can change this by passing a different prefix as the second parameter to the Zend_Controller_Action_HelperBroker::addPath() call in your bootstrap.
Finally, usage within a controller action:
<?php
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$this->view->headTitle('Home');
$this->view->title = 'Test of the Multiples action helper';
$number = 30;
$twice = $this->_helper->multiples($number);
$this->view->number = $number;
$this->view-twice = $twice;
}
}
Note that we call the action helper’s name as a function of the _helper class. This maps to the direct() call within the helper.
You can put also multiple functions within the action helper:
class Zend_Controller_Action_Helper_Multiples extends
Zend_Controller_Action_Helper_Abstract
{
function direct($a)
{
return $a * 2;
}
function thrice($a)
{
return $a * 3;
}
}
To call the thrice() function within a controller action you use:
$thrice = $this->_helper->multiples->thrice($number);
As you can see if you use the action helper’s name as a property of _helper, then you can call any function within the helper.
This is just a summary to get you going. Full details are in the manual.
Have fun and avoid copy and paste with your common functionality!
Zip Files:
I’ve created an example project so you can see it in context.
- ZF_Action_Helper_example.zip – 9.7kB
- ZF_Action_Helper_example_with_zf.zip (including ZF 1.6) – 3.5MB
Just great!!
The diference between Action Helpers and Plugin is that plugin can deal with the behave of the request.
That's right?
F@bio,
The happen at different points. Action helpers have pre and post hooks too.
Regards,
Rob…
$thrice = $this->_helper->multiples->thrice($number);
Nice! Didn't see that the first time.
Great stuff! Thanks for clearing that up.
One question, how can I use helpers in the view script? Currently I just put them in a random directory and use partial() when I need them, e.g.
partial('../whatever/foo.phtml', array('foo' => 'bar')) ?>
Is there a more preferred method?
It looks like in a modular structure you could have helper name conflicts. If I have several modules that each provide action helpers I might have
Zend_Controller_Action_Helper_Test in
/modules/blog/controllers/helpers
and
Zend_Controller_Action_Helper_Test in /modules/support/controllers/helpers
The helpers are in different directories and are both named test so when you call $this->_helper->test() which one gets called? Or will an exception be thrown somewhere?
I can see a situation where several developers individually create modules (think Drupal) and provide their own action helpers, but how can you avoid the conflict of naming when regardless of classname prefix, you still have to call $this->_helper->helperName()?
Hi Dan,
If you have multiple helper paths added to the helper broker, then the last path added is searched first.
Regards,
Rob…
That makes sense. Classname prefixing like this wouldn't help:
Blog_Controller_Action_Helper_Test
Support_Controller_Action_Helper_Test
because you still have to call $this->_helper->test().
So I guess to avoid getting intercepted, helpers in my previous example should be named:
Zend_Controller_Action_Helper_BlogTest
Zend_Controller_Action_Helper_SupportTest.
Feels awkward but a small price to pay for the functionality you gain.
Thanks for the tutorials!
Like F@bio I'm a little confused about the difference between plugins and action helpers. As I understand it, action helpers are for more on demand functionality, while plugins are for things that you'd want to use on every single page, such as authentication for a private system, or some view initialisation code. Is that the case?
I've got this working for using helpers in the action. But when I try to use a helper straight from the view script I get "Fatal error: Call to a member function formatDate() on a non-object"
I've tried (in the view script)…
$this->view->formatDate();
and
$this->_helper->formatDate();
What am I missing? I have my helper path saved in the bootstrap like explained above and have the correct case for classes etc….? :/
I think you need to assign the helper to the view first, e.g.
In your controller, $this->view-> multiples = $this->_helper->multiples;
That sounds reasonable – The view doesn't know anything about action helpers otherwise.
Regards,
Rob…
hello Rob
I'm thinking about directory structure and name conventions, and i have problem.
From one side:
you suggest to name helpers Zend_Controller_Action_Helper_Multiples and put them into application/helpers
From other side:
Manual http://framework.zend.com/manual/en/coding-standard.naming-conventions.html#coding-standard.naming-conventions.classes
IMPORTANT: Code that must be deployed alongside ZF libraries but is not part of the standard or extras libraries (e.g. application code or libraries that are not distributed by Zend) must never start with "Zend_" or "ZendX_"
That mean that Zend_Controller_Action… doesn't allowed
And from third side, in Matthew Weier O'Phinney pastebin application
http://weierophinney.net/matthew/archives/189-Pastebin-app-and-conference-updates.html
another variant, My_View_Helper_SimpleTextarea for example in directory library/My/View/Helper. It's not an action helper, but idea the same.
I'm confused, what the best way?
P.S. Sorry for my english
Hi,
For action and view helpers, the default prefix is "Zend_Controller_Action" or "Zend_View_Helper", so I would argue that these particular cases are different. It would be helpful if the defaults were App_View_Helper or My_View_Helper though as it would establish the convention for the name of the folder that lives in library that is used for ZF overrides.
There are two places to put the action helper files: within the library/ folder as per Matthew's pastebin or in the controllers/helpers/ folder as per the official Quickstart. The choice is yours :)
Regards,
Rob…
Is it ok accessing action helpers from within models?
Jonathan.
Jonathan,
I wouldn't. Models should be self-contained.
Regards,
Rob…
What would you suggest for a function that needs to be executed across multiple models? surely copying and pasting it across multiple models isn't the right way of going about it?
Thanks!
Jonathan,
I would write the functionality into a separate model class and use it in the other models.
Regards,
Rob…
ok that makes sense, thanks rob!
Jonno.
Hi,
am facing a small problem; am trying to create a view helper with more than just one method.
for one method it works perfectly, i just call it from the view using $this->MyViewHelperName();
but, i created another method in the class and when i try to call it.. it fails
$this->MyViewHelperName()->MethodTwo();
Any idea how can i make it work?
Thanks,
Mo,
Return $this from the function MyViewHelperName::myViewHelperName()
Regards,
Rob…
Hi,
I have a doubt about handling some jobs that needs to be executed across multiple controllers. To be more precise, here are things that need to be done:
//Setting compile dir for every module, because I use Smarty
$compile_dir = $this->view->getCompileDir();
$this->view->setCompileDir($compile_dir . '/' . $this->_request->getModuleName());
//Getting template dir that user has selected in admin panel.
$settings = Zend_Registry::get('settings');
$this->view->theme = $settings['theme_dir'];
Currently, I keep that code in init() method of every controller. Is there any better solution, maybe with those action helpers?
Thanks.
Nikola,
I would use the preDispatch() hook of an action controller to do that.
Regards,
Rob…
So you mean just to put those lines from init() to preDispatch()?
Ok, but there's still a problem of copy/paste that code in every controller, or maybe I misunderstood something? :)
Hi Rob,
I am using a modular directory structure for my zend app. Here is the structure:
Appname
– frontend
-modules
-module1
-controller
-models
-views
-module2
-controller
-models
-views
-layouts
-helpers
I need to have an action helper for my controllers
The helpers directory is where my action helper files will reside. In the bootstrap, I have done this:
$view->addHelperPath(FRONT_APPLICATION_PATH.'/helpers');
This is the code that I have written for my new helper
class Zend_Controller_Action_Helper_Cim extends Zend_Controller_Action_Helper_Abstract
{
function direct($a) {
return $a.'from Helper';
}
function other($a) {
echo $a.'from Helper other';
}
}
And this is how I am calling in the controller:
$leadHelper = $this->_helper->getHelper('cim');
echo $leadHelper->direct('asdasd');
I cannot see any error but also I do not see any output. Am I doing something wrong here.
Thanks,
Vibhor
Hi,
Sorry for the formatting!
I am using a modular directory structure for my zend app. Here is the structure:
I need to have an action helper for my controllers
The helpers directory is where my action helper files will reside. In the bootstrap, I have done this:
$view->addHelperPath(FRONT_APPLICATION_PATH.'/helpers');
This is the code that I have written for my new helper
class Zend_Controller_Action_Helper_Cim extends Zend_Controller_Action_Helper_Abstract
{
function direct($a) {
return $a.'from Helper';
}
function other($a) {
echo $a.'from Helper other';
}
}
And this is how I am calling in the controller:
$leadHelper = $this->_helper->getHelper('cim');
echo $leadHelper->direct('asdasd');
I cannot see any error but also I do not see any output. Am I doing something wrong here.
Any help will be appreciated.
Thanks,
Vibhor
Hi Rob
I'am beginner in zf 1.9 where do i write this code
[code]
Zend_Controller_Action_HelperBroker::addPath(
APPLICATION_PATH .'/controllers/helpers');
[/code]
with my version(zf 1.9)
Thanks
ok found it
[code]
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
public function run()
{
$config = new Zend_Config_Ini(APPLICATION_PATH.'/configs/application.ini');
// On met notre fichier de config dans un registre.
Zend_Registry::set('config', $config);
Zend_Controller_Action_HelperBroker::addPath(
APPLICATION_PATH .'/controllers/helpers');
parent::run();
}
[/code]
In ZF 1.10 we can use like this
Zend_Controller_Action_HelperBroker::addHelper(new Zend_Controller_Action_Helper_Multiples());