I have an upload form, which is displayed on overlay/lightbox/toplayer. It's available only for several actions in several controllers.
Creating this form needs ~6 lines of code and needs access to REQUEST object to grab params from it.
Where should I put this code, so I could easily create my form in actions I need.
I'd put this functionality in an Action Helper. An action helper can be called directly from any controller action (and is lazy loaded) and action helpers have access to everything the controller action does including the request object and view.
Example:
<?php
class My_Action_Helper_FormCreator extends Zend_Controller_Action_Helper_Abstract {
public function direct($options = null)
{
$request = $this->getRequest();
$view = $this->getActionController()->view;
$form = new Application_Form_SomeForm();
// set form options here...
$view->form = $form; // optional - assign form directly to the view
return $form;
}
}
Place that code in library/My/Action/Helper/FormCreator.php (or where desired and change the class name).
Then, in your actions, call it like this:
$form = $this->_helper->FormCreator();
Lastly, we need to tell the helper broker where to find this action helper. To do so, add this to your bootstrap:
protected function _initActionHelpers() {
Zend_Controller_Action_HelperBroker::addPrefix('My_Action_Helper');
}
Hope that helps.
Related
I have a custom module with a controller action which performs a certain function,
class Company_CustomModule_ActionController extends Mage_Core_Controller_Front_Action
{
public function doAction()
{
// do something
}
}
I have another controller in the same module (lets say "test"). I would like to call an action within this "test" controller in the above mentioned controller and pass it a parameter like,
class Company_CustomModule_ActionController extends Mage_Core_Controller_Front_Action
{
public function doAction()
{
// do something
// call the index in the "Test" controller
Mage::app()->getFrontController()->getResponse($data)
->setRedirect(Mage::getUrl('company/test'))
->sendResponse();
}
}
My goal is to pass some data from the Action controller to the Test Controller and execute the index action in the Test Controller from within the Action Controller.
Note: in essence, I would like to pass on the POST data received by the Action Controller to the Test Controller.
How would I go about doing this? any guidance would he helpful.
I'm not overly familiar with Magento, but since it's built on the Zend Framework you should be able to use the forward helper and pass your data in the params parameter:
return $this->_forward('test', 'company', $module, $params);
I'm little bit new to Zend, I want to use a controller action through out the entire application automatically, I don't have a clear idea to how to use it, thought about init() method, action helpers, etc.
Then instead of simply creating controller action create controllerAction Helper . Here you can find more about it
http://framework.zend.com/manual/en/zend.controller.actionhelpers.html
My_Helper_Magic extends Zend_Controller_Action_Helper_Abstract
{
public function preDispach()
{
//code inside here will run for entire application automatically
}
}
In your bootstrap do
Zend_Controller_Action_HelperBroker::addHelper(new My_Helper_Magic());
In Response to comment .
It depends upon your 'code fragment' , If your code fragment does not required to know nothing about module , controller, action , base url then you can use Bootstrap init function
like
public function _initAlways()
{
//see how this function name is prefixed with _init hence it will be called by ZF //everytime. You can put your code fragment here
//If your code fragment depends upon some stuff like baseurl then do action controller
// registration here instead
Zend_Controller_Action_HelperBroker::addHelper(new My_Helper_Magic());
}
In Response To comment
You can save any instance of your object inside Zend_Registy and retrieve it whereever you like
Inside Bootstrap.php
public function _initSetup()
{
$object = new My_Custom_Object();
Zend_Registry::set('my_custom_object',$object);
}
Later in your view or controller do
$myObject = Zend_Registry::get('my_custom_object'); //to access it
I currently have a zend framework application with multiple modules. Each module should be using the same Zend_Form_Decorator_ViewScript, located in the default modules /views/scripts folder.
Without any changes, modules by default only look for form decorator viewscripts in their own /views/scripts folder located under each module, so to get them to load them from default modules folder, I first need to apply this within the form:
$view = new Zend_View();
$view->setScriptPath(APPLICATION_PATH . '/views/scripts');
$this->setView($view);
Within that same form, I create multiple Zend_Form_SubForms, for which I need to apply that same code again. If that isn't enough, I need to apply that path to each individual element in each SubForm as well as the parent form. Additionally, each element has to have its ViewScript defined each time like:
$username->setDecorators(array(array('ViewScript', array('viewScript' => '/formScripts/wizardElement.phtml'))));
Now, it all works if I define all of that for each element/subform/form within the same file, but it just seems so much unnecessary work/code.
Can the process be simplified firstly
by just having the parent form define
the scriptPath for itself, its
elements, its subforms, and the
subforms elements?
Can new elements created automatically have specific ViewScripts defined for them, based on what type of element it is (i.e. input box, checkbox, selectbox, textarea, button etc)?
I am currently extending my form directly from the default Zend_Form, I won't have a problem of creating an own abstract form to extend my forms from, but especially with the scriptPath problems, I am not entirely sure how I should approach this whole problem.
Applying:
$this->setSubFormDecorators(array(
'Form',
array('ViewScript', array('viewScript' => '/formScripts/wizardSubForm.phtml'))
));
overwrites all the element specific decorators I've applied before it.
Suggestions?
May be I didn't get your case in details but I would suggest you create base form, then base form classes for each module then your specific forms extend the respective module form
My_Base_Form extends Zend_Form
{
public function init()
{
//if you need to init something for all forms
parent::init();
}
public function _createSelect($name)
{
$element=new Zend_Form_Element_Select($name);
$element->setDecorators(
//decorators for select
)
$element->viewScript='select.phtml';
return $element;
}
}
My_Default_Form extends My_Base_Form
{
public function init()
{
//what you do to init dirs for this module
$view = new Zend_View();
$view->setScriptPath(APPLICATION_PATH . '/views/scripts');
$this->setView($view);
parent::init();
}
//called automatically by Zend_Form
public function loadDefaultDecorators()
{
parent::loadDefaultDecorators();
$this->setDefaultFormDecorators($this);
$this->setButtonDecorators($this);
}
}
My_Admin_Form extends My_Base_From{}
To not repeat setting element decorators you may create helper methods that do that for you
and put it in the base form class or in the module form class
Default_Form_Register extends My_Default_Form
{
public function init()
{
$el=$this->_createSelect($name);
$el->setLabel('Select');
$this->addElement($el);
parent::init();
}
}
you may need to use the same approach for subforms, then put the base classes in your library and you should be ok.
You are will be free to make common changes based on module or element type.
PROBLEM: I can't pass my variables to my custom layout from action helper's init method.
I have this action helper "My_Action_Helper_Initializer":
class My_Action_Helper_Initializer extends Zend_Controller_Action_Helper_Abstract
{
public function init()
{
$controller=$this->getActionController();
//variable passed to controller's view
$controller->view->flop="FLOOP!!";
//variable passed to controller
$controller->boom="BOOM!!";
}
}
In my controller "IndexController":
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
//print the variable passed from action helper
echo $this->boom;
}
}
then in my "layout.phtml":
//print variable passed from action helper
echo $this->flop;
So the "boom" variable echoed out by controller action is shown correctly.
The "flop" variable (passed to my layout) is not shown.
QUESTION: Why the variable passed to controller action is correctly output while the other one passed to the layout view is not?
Thanks
Luca
When your helper's init() called, ViewRenderer's init() wasn't yet. This is because of order in helpers stack.
If you enable strict standards error reporting, you should see something like this in your helper "Creating default object from empty value in ..."
You should consider moving your code to preDispatch() hook as init() method should be used for helper initialization.
To get view instance for controller:
function getView()
{
$controller = $this->getActionController();
if($view = $controller->view) {
return $view;
}
if($this->getFrontController()->getParam('noViewRenderer') {
return $controller->initView();//this view instance will not be used in Zend_Layout!
}
$vr = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
return $vr->initView();
}
if you want to pass parameter to layout, then use
$view = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->initView();
Action helpers are called so because they are a way to avoid code duplication in actions. Everything you do in an action helper is available to the actions but not to the view. That's the normal behaviour of actions, as long as you don't pass something to the view, the view doesn't know it. If you want to avoid code duplication in your views, create view helpers.
Sometimes it can make sense to create an action helper and a corresponding view helper.
--
preDispatch works() while init() doesn't because with init you're not actually hooking into the dispatch process.
How do I get the request object from inside the bootstrap file?
I can try this methods but not work.
$request= new Zend_Controller_Request_Http();
$request = Zend_Controller_FrontController::getInstance()->getRequest();
If you really want to, you may achieve this calling:
public function _initRequest()
{
$this->bootstrap('frontController');
$front = $this->getResource('frontController');
$front->setRequest(new Zend_Controller_Request_Http());
$request = $front->getRequest();
}
However, this should be avoided, because the most data you need from the Response object will be available after the front controller is dispatched (eg. module, controller or action name).
The other variables stored in the Response object are extracted from global arrays such as $_SERVER, $_POST or $_GET which you may exceptionally read directly in bootstrap.
But most likely, you want to use Response object in front controller plugin:
class Your_Controller_Plugin_PluginName extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
// do anything with the $request here
}
}
You shouldn't get the request objet, since if you see the dispatch loop, the idea is that the bootstrap are actions prior to execute in a request.
If you need to alter someway of the application use a Controller Plugin to do that.
You need to bootstrap the frontController first, try something like:
function initFoo()
{
$this->bootstrap('frontController');
$req = $this->frontController->getRequest();
}