I have set the variable in module.php which i can get in the layout.
now i want this variable in my controller also.
public function onBootstrap(MvcEvent $e) {
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
// $this->initAcl($e);
$e->attach(MvcEvent::EVENT_RENDER, array($this, 'setVariableToLayout'), 100);
}
public function setVariableToLayout(MvcEvent $event) {
$viewModel = $event->getViewModel();
$viewModel->setVariables(array(
'controller' => $event->getRouteMatch()->getParam('controller'),
));
}
How can i get that variable in all my controller.
if i try to get the variable in controller like print_r($controller) or print_r($this->controller) it gives undefined error.
This is module.php file and i have set controller as which controller is requested., function called from onBootstrap
I do not understand the need for the controller name in the view. The view should only care about the parameters it requires to render correctly; not which controller was dispatched.
I'm assuming you are doing some kind of conditional view logic if ($controller == 'foo') then this should be shouting very loudly that you need a different ViewModel for each 'state'. If they are shared view scripts then take a look into view helpers or view partials.
With the above said; The only error I can see is:
$e->attach(MvcEvent::EVENT_RENDER, ....
Should be:
$eventManager->attach(MvcEvent::EVENT_RENDER, ....
Perhaps this was a typo, however to clarify:
The EventManager manages references to registered event listeners.
The Event is a container that provides metadata regarding the event (which is then injected into the event listener when trigger() is called)
Related
I have installed the skelleton app from ZF3 'zend-expressive'. In the routing config I have configured a few routes. Some of these routes should return a response without the layout. In ZF2 I simply used the ViewModel on which you could call "setTerminal". But now the ViewModel is not directy available in the Action, as it is nested as private property of the ZendViewRenderer. I cannot figure out how I can set the terminal, so the output is rendered without layout.
I have tried various options in the routing configuration, such as adding keys 'terminal', 'terminate' and 'may_terminate' with value true. Also have tried to make a seperate Factory, but ended up with the same problem that I cannot reach the ViewModel.. It also did not work to make a seperate ViewModel in the Action, when I setTerminal on true, and pass the object as 2nd parameter in the 'render' method of the ZendViewRenderer object, it fails when passing 'renderModal' of the same object: "Cannot render; encountered a child marked terminal"..
There must be a simple configuration that I am overlooking, so my question is. Does anyone know how I can set the view on terminal?
Hope that I explained my problem well. Many thanks in advance.
My solution!
Yes! I found a "solution". Instead of pushing into terminal setting of the ViewModal, I have implemented a new layout called "layout/terminal". This layout only outputs the variable $content. Reference: https://github.com/zendframework/zend-expressive/issues/360
To use this layout you should add a new Factory into the configuration.
<?php
namespace Factory;
use Interop\Container\ContainerInterface;
use Zend\Expressive\Template\TemplateRendererInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
use Zend\View\Model\ViewModel;
class RenderWithoutTemplate implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$template = $container->has(TemplateRendererInterface::class)
? $container->get(TemplateRendererInterface::class)
: null;
$r = new \ReflectionClass($template);
$view = new ViewModel();
$view->setTerminal(true); // Does not affect any render behaviour (?)
$view->setTemplate('layout/terminal');
$prop = $r->getProperty('layout');
$prop->setAccessible(true);
$prop->setValue($template, $view);
return $template;
}
}
public function indexAction(){
return $this->getResponse();
}
I have a controller action helper where i save a user object into the view (in an init function) like this:
Zend_Layout::getMvcInstance()->getView()->user = $user;
I'd like to access the object in a preDispatch method of a controller plugin so I don't have to look up the user in the database. I tried doing so like this:
$user = Zend_Layout::getMvcInstance()->getView()->user;
But it's returning a null object. I'm hoping its because I'm doing this wrong and not because I've programmed a catch 22 inside my login logic. Is there another way to access the object?
I think putting the following methods into your action helper may help you here.
private $user
public function init()
{
$this->user = new user();
}
public function preDispatch()
{
$user = $this->user;
//Do whatever you wish with the user object.
// although you probably don't need to do anything.
}
public function direct()
{
Zend_Layout::getMvcInstance()->getView()->user = $this->user;
//alternatively just return the user object or whatever you want to do
}
Then once your helper is registered you can simply do $this->_helper->helperName() in your controller to put the user object into the view.
Mathew WeirO'Phiney has a good explanation of action helpers on devzone. Especially the purpose of the direct() method.
Yes, good approach is to have a singleton class for current logged in user; in such a case it will be accessible anywhere - plugins, views, forms.
I try this codes, but not works:
$this->getView()->translate("Name"); //not work
$this->_view->translate("Name"); //not work
$this->view->translate("Name"); //not work
First of all, Zend_View is not injected into Zend_Form. So when you call $this->view or $this->_view it wont work, because there is nothing to return. Why getHelper() works? Because it fetches view via helper broker (and if your are using viewRenderer). Look below at the code:
// Zend/Form.php
public function getView()
{
if (null === $this->_view) {
require_once 'Zend/Controller/Action/HelperBroker.php';
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$this->setView($viewRenderer->view);
}
return $this->_view;
}
This is reason why $this->_view->translate() works if you call getView() before, because it's stored as protected property.
According to this, that code should work perfectly and works for me:
class My_Form extends Zend_Form
{
public function init()
{
echo $this->getView()->translate('name'); //fires 'translate' view helper and translating value
//below will also work, because you have view now in _view: getView() fetched it.
echo $this->_view->translate("another thing");
}
}
BTW. If your using translate helper to translate labels or names of fields, you don't have to. Will be enough, if you set translator object as a static property of Zend_Form, best in your bootstrap:
Zend_Form::setDefaultTranslator($translator);
And from that moment all fields names and labels will be translated automatically.
I don't no why, but when I add this function to my form, it work:
public function init() {
$this->getView();
}
this line works:
$this->_view->translate("Name");
View is not injected into Zend_Form (don't ask me why, when it's required for rendering). You have to extend Zend_Form and inject view inside yourself. Other option is using FrontController->getInstance() > getStaticHelper > viewRenderer and recieve view from it.
I would like to have some input on the following:
I would like some views to be systematically rendered (I can call $this->render from
my layout for these views) regardless of which controller/action is executed.
However the content used in these views is based on the same dynamically generated data and the code behind it is quite complex so I can't put the logic inside the views for obvious optimization/performance issues.
I could use $this->_helper->actionStack in each controller to call another controller in which data for the views would be prepared however I would like to do without modifying the existing controllers
I would be tempted to put something in the bootstrap since what I want is common to my application however I just don't know what to do.
That's what View Helpers are for.
In the View Helper you can fetch your data (through models or service layer) and prepare it for output.
<?php
class View_Helper_Foobar extends Zend_View_Helper_Abstract
{
protected $_data;
public function foobar()
{
if (null !== $this->_data) {
$this->_data = some_expensive_data_getter();
}
return $this;
}
public function __toString()
{
return $this->view->partial('foobar.phtml', array('data' => $this->_data));
}
}
I want to display a page that has 2 forms. The top form is unique to this page, but the bottom form can already be rendered from a different controller. I'm using the following code to call the action of the other form but keep getting this error:
"Message: id is not specified"
#0 .../library/Zend/Controller/Router/Rewrite.php(441): Zend_Controller_Router_Route->assemble(Array, true, true)
My code:
First controller:
abc_Controller
public function someAction()
{
$this->_helper->actionStack('other','xyz');
}
Second controller:
xyz_Controller
public function otherAction()
{
// code
}
Desired results:
When calling /abc/some, i want to render the "some" content along with the xyz/other content. I think I followed the doc correctly (http://framework.zend.com/manual/en/zend.controller.actionhelpers.html) but can't find any help on why that error occurs. When I trace the code (using XDebug), the xyz/other action completes ok but when the abc/some action reaches the end, the error is thrown somewhere during the dispatch or the routing.
Any help is greatly appreciated.
You can accomplish this in your phtml for your someAction. So in some.phtml put <?php echo $this->action('other','xyz');?> this will render the form found in the otherAction of XyzController
The urge to do something like this is an indication you're going about it in totally the wrong way. If you have the urge to re-use content, it should likely belong in the model. If it is truly controller code it should be encapsulated by an action controller plugin
In phtml file u can use the $this->action() ; to render the page and that response would be added to current response ..
The syntax for action is as follows::
public function action($action, $controller, $module = null, array $params = array())
You can create new object with second controller and call its method (but it`s not the best way).
You can extend your first controller with the second one and call $this->methodFromSecond(); - it will render second form too with its template.
BTW - what type of code you want to execute in both controllers ?
Just an update. The error had absolutely nothing to do with how the action was being called from the second controller. It turns out that in the layout of the second controller, there was a separate phtml call that was throwing the error (layout/abc.phtml):
<?php echo $this->render('userNavigation.phtml') ?>
line of error:
echo $this->navigation()->menu()->renderMenu(...)
I'll be debugging this separately as not to muddy this thread.
Thanks to Akeem and hsz for the prompt response. I learned from your responses.
To summarize, there were 3 different ways to call an action from an external controller:
Instantiate the second controller from the first controller and call the action.
Use $this->_helper->actionStack
In the phtml of the first controller, action('other','xyz');?> (as Akeem pointed out above)
Hope this helps other Zend noobs out there.
Hm I can't find and idea why you need to use diffrent Controlers for one view. Better practise is to have all in one Controller. I using this like in this example
DemoController extends My_Controller_Action() {
....
public function indexAction() {
$this->view->oForm = new Form_Registration();
}
}
My_Controller_Action extends Zend_Controller_Action() {
public function init() {
parent::init();
$this->setGeneralStuf();
}
public function setGeneralStuf() {
$this->view->oLoginForm = new Form_Login();
}
}
This kind of route definition:
routes.abc.route = "abc/buy/:id/*"
routes.abc.defaults.controller = "deal"
routes.abc.defaults.action = "buy"
routes.abc.reqs.id = "\d+"
requires a parameter in order to function. You can do this with actionStack but you can also specify a default id in case that none is provided:
$this->_helper->actionStack('Action',
'Controller',
'Route',
array('param' => 'value')
);
routes.abc.defaults.id = "1"
For Me this worked like a charm
class abcController extends Zend_Controller_Action
{
public function dashBoardAction()
{
$this->_helper->actionStack('list-User-Data', 'xyz');
}
}
class XyzController extends Zend_Controller_Action {
public function listUserDataAction()
{
$data = array('red','green','blue','yellow');
return $data;
}
}