I have a module in my zendframework 2 application which contains two controllers.
I want to set a different layout for one of the controller's actions.
Is there a way to set it inside module config file?
P.s: I just tried to set it inside controller's __CONSTRUCT method using the following commands but it just didnt worked!
$event = $this->getEvent();
$event->getViewModel()->setTemplate('layout/MYLAYOUT');
But if i use the above commands inside each action of my controller it just works fine.
See akrabat's examples for a number of nice ways that layouts, views, etcetera can be tweaked easily.
Specifically what you're looking for can be found on his github here.
Here is a cut-paste of the controller's action method that sets/uses the alternate layout:
public function differentLayoutAction()
{
// Use a different layout
$this->layout('layout/different');
return new ViewModel();
}
Edit: It looks like akrabat has an example that says Change the layout for every action within a module, which might give the best pointers for setting the layout in the config; but I just had a look at the code, and the example is currently unfinished, it's not changing the layout.
I can just point you into the right direction, since currently i'm unable to open a sample project. Evan Coury has posted a method for Module specific layouts. See the following links:
Module Specific Layouts in Zend Framework 2
<?php
namespace MyModule;
use Zend\ModuleManager\ModuleManager;
class Module
{
public function init(ModuleManager $moduleManager)
{
$sharedEvents = $moduleManager->getEventManager()->getSharedManager();
$sharedEvents->attach(__NAMESPACE__, 'dispatch', function($e) {
// This event will only be fired when an ActionController under the MyModule namespace is dispatched.
$controller = $e->getTarget();
$controller->layout('layout/alternativelayout');
}, 100);
}
}
Now how would this help you?: Well, $controller should have both the called controller and action stored. I'm sure you can check the $controller for the called action and then assign the layout accordingly.
I'm sorry i can currently only hint you into the direction, but i'm sure this can get you started.
#Sam's answer pretty much answers the question. As stated it just needs a check on which controller is called, which can be done like this:
<?php
namespace MyModule;
use Zend\ModuleManager\ModuleManager;
class Module
{
public function init(ModuleManager $moduleManager){
$sharedEvents = $moduleManager->getEventManager()->getSharedManager();
$sharedEvents->attach(__NAMESPACE__, 'dispatch', function($e) {
$controller = $e->getTarget();
if ($controller instanceof Controller\AltLayoutController) {
$controller->layout('layout/alternativelayout');
}
}, 100);
}
I
Related
I am new to prestashop, so please bear with me if I am asking a very simple question.
I am into creating module, and in my task I have to extend the cart controller that is being called by the ajaxcart.add() function in the javascript.
I want to know, where is the controller that responds to this ajax request is located, and how can i extend this controller in my module.
Are there any good documentation regarding this?
thanks
I found a way to extending the prestashop default controllers inside a module.
I looked iniside the classes/Dispatcher.php and found this inside the dispatch() method
case self::FC_MODULE :
$module_name = Validate::isModuleName(Tools::getValue('module')) ? Tools::getValue('module') : '';
$module = Module::getInstanceByName($module_name);
$controller_class = 'PageNotFoundController';
if (Validate::isLoadedObject($module) && $module->active) {
$controllers = Dispatcher::getControllers(_PS_MODULE_DIR_.$module_name.'/controllers/front/');
if (isset($controllers[strtolower($this->controller)])) {
include_once(_PS_MODULE_DIR_.$module_name.'/controllers/front/'.$this->controller.'.php');
$controller_class = $module_name.$this->controller.'ModuleFrontController';
}
}
$params_hook_action_dispatcher = array('controller_type' => self::FC_FRONT, 'controller_class' => $controller_class, 'is_module' => 1);
So, The naming convention for the controller is
<modulename><controllername>ModuleFrontController
and the path to the controller should be
module/<module name>/cotrollers/front/<controllername>.php
Example mycart controller inside an areacalc module
class areacalcmycartModuleFrontController extends CartController {
File path to the mycart controller inside an areacalc module
/modules/areacalc/controllers/front/mycart.php
url will be
http://localhost:8080/index.php?fc=module&module=areacalc&controller=mycart
You can override the defaut CartController.php, in the override module folder you add your class code (only the modified method) in this case i suppose you would modify the processChangeProductInCart method, you can see the prestashop override documentation
Apologies if this is a basic question but I have attempted to find an answer in the ZF2 documentation and I can't find a clear answer.
I have a set of Controllers each containing a set of actions. I would like each action to check for a certain parameter being present in the request. What is the best to ensure that this gets done for all actions such that if I add a new action it will automatically be catered for too?
Many thanks for your help.
You could extend the AbstractActionController and add your custom methods or override existing ones to your needs.
use Zend\Mvc\Controller\AbstractActionController;
abstract class AbstractCustomController extends AbstractActionController
{
//custom methods
}
once That is done you then simply access your custom controller trough namespaces and extend it with the new controllers.
<?php
namespace Custom\Controller;
use Zend\View\Model\ViewModel;
use Custom\Controller\AbstractCustomController;
class NewController extends AbstractUserController {
//new controller which has access to methods from extented AbstractController
}
You didnt specify on what exactly you are checking on. But using a MVC Event might be cleaner and easier to implement. You'll simply add some functionality to your module.php for example:
public function onBootstrap(MvcEvent $e) {
//check request
}
This is just an example and may not work though. Depending on the Order of events the request may not be filled at this given point and you'd be forced to use another one.
I once used the onDispatch(\Zend\Mvc\MvcEvent $e) provided by the AbstractActionController for a task that was a little bit similar to yours. But then again if you could be more specific we'd probably could give you a more specific answer.
best regards and good luck!
Edit: Regarding your question in the comment you could listen to the routing event and get your params there.
//Module.php within your onBootstrap Method
$application = $e->getApplication();
$eventManager = $application->getEventManager();
$eventManager->attach('route', function(MvcEvent $mvcEvent) {
$params = $mvcEvent->getRouteMatch()->getParams();
echo '<pre>'; print_r($params); exit;
}
Let's say I got ControllerA and ControllerB which both implement the same layout. Now I want to pass data to layout, for example, a message that should appear in layout no matter which controller implements it. If I had only 1 controller, I would do something like:
class Controller extends \BaseController {
public function setupLayout() {
View::share('message', 'Hello world!');
}
// further methods
}
However, when I want multiple controllers to implement a layout, I have to do this in every controller, which doesn't sound reasonable. So I wanted to ask, is there any native way in Laravel to pass data to layout and not to copy code in every controller.
Thanks in advance!
For those cases I would recommend a view composer, where you can set them for more than one view (or layout) or just all of them:
View::composer(['store.index', 'products.*'], function($view)
{
$view->with('model', 'one');
$view->with('colour', 'black');
});
You can put that in your routes file, filters file or, like, me, create a app/composers.php and load by adding
require app_path().'/composers.php';
To your app/start/global.php.
Take for example the following controller/action:
public function indexAction()
{
return $this->render('TestBundle:TestController:index.html.twig');
}
I would like to write the template expression (or whatever it's name is) this way:
public function indexAction()
{
return $this->render('*:TestController:index.html.twig');
}
So that symfony knows I'm looking for a template in this very bundle. Having to write the whole Owner + Bundle for every template/action/repository I want to refer is very annoying. Even more so considering most of the time I refer to actions and templates in the same bundle.
NOTE: I know templates can be put at the app level and be refernced like this:
'::index.html.twig'
But that is not what I need.
It's possible with a bit of custom code.
Basically, you want to override the controller's render() method and include logic to fetch the name of the current bundle.
Note that instead of my controllers extending Symfony\Bundle\FrameworkBundle\Controller\Controller, they extend a custom controller (which then extends Symfony's controller). This allows you to conveniently give the controller more ability by adding your own methods.
Ex:
MyBundle\Controller\MyController\ extends MyCustomBaseController which extends Symfony\Bundle\FrameworkBundle\Controller\Controller.
So, in my custom controller I have these two methods:
public function render($view, array $parameters = array(), Response $response = null) {
$currentBundle = $this->getCurrentBundle();
$view = str_replace('*', $currentBundle, $view);
return parent::render($view, $parameters, $response);
}
public function getCurrentBundle() {
$controller = $this->getRequest()->attributes->get('_controller');
$splitController = explode('\\', $controller);
return $splitController[1];
}
Take a look at render(). It fetches the current bundle name and uses it to build the $view variable. Then it just calls parent::render() and it's as if you had manually defined the bundle name in the render statement.
The code here is very simple, so you should be able to easily extend it to do other things, such as allow you to also avoid typing the controller name.
Important: If you do use a custom controller, make sure you use Symfony\Component\HttpFoundation\Response, otherwise PHP will complain that the method signatures for render() don't match.
I am new to Zend Framework. 1st things 1st, I want to change that .phtml extention to .php in the views.
After researching, I found that this code works, in the init method of different controllers:
$this->getHelper('viewRenderer')->setViewSuffix('php');
Problem is that I have to repeat that code in every controller, which is something bad and defeats the purpose of using a framework.
I could have subclassed the Zend_Controller_Action into some base controller with all the shared code which all other controllers can inherit from, but as far as I know, it's not the best practice to do.
How can I achieve the shared code without subclassing the Zend_Controller_Action class and without using any plugins or Action helpers
Thanks in advance.
Just figured it out..No need for any base controllers.
In the bootstap, I wrote this code:
protected function _initViewSuffix() {
$this->bootstrap('View');
$view = $this->getResource('View');
$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view);
$viewRenderer->setViewSuffix('php');
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
}
And then in Application.ini, I added this line:
resources.view = []
Now it works.