Yii module layout - php

I am trying to get work layout in a module. So I created a layout in view folder of module called 'adminLayout'
Assuming a layout in AdminModule.php in init() method.
So now it looks like this:
public function init()
{
$this->layoutPath = Yii::getPathOfAlias('application.modules.admin.views.layouts');
$this->layout = 'adminLayout';
// this method is called when the module is being created
// you may place code here to customize the module or the application
// import the module-level models and components
$this->setImport(array(
'admin.models.*',
'admin.components.*',
));
}
But for some reason layout didn't apply to module. I tried to add "public $layout" to controller and it works.
Can't figure out what problem is.
Also I tried to add layout settings to main.php in config folder, but still no action. Will be grateful if someone could help.

The solution is set the layout on beforeControllerAction in your module. It should work.
public function beforeControllerAction($controller, $action)
{
if(parent::beforeControllerAction($controller, $action))
{
$controller->layout = 'adminLayout';
return true;
}
else
return false;
}

There are many posts on this subject and the answer is in the Yii docs:
layout property
public mixed $layout;
the layout that is shared by the controllers inside this module. If a controller has explicitly declared its own layout, this property will be ignored. If this is null (default), the application's layout or the parent module's layout (if available) will be used. If this is false, then no layout will be used.
Simply detect the module from within your controller and set the layout accordingly:
class Controller extends CController
{
public function init(){
//Set layout
$this->layout = ($this->module->id=='admin') ? '//layouts/column2' : '//layouts/column1';
.........
}

Create assets folder in your module. Add the following code for assetsURL:
private $_assetsUrl;
public function getAssetsUrl()
{
if ($this->_assetsUrl === null)
$this->_assetsUrl = Yii::app()->getAssetManager()->publish(
Yii::getPathOfAlias('admin.assets') );
return $this->_assetsUrl;
}
Create a beforeControllerAction function, and add $controller->layout:
public function beforeControllerAction($controller, $action)
{
if(parent::beforeControllerAction($controller, $action))
{
// this overwrites everything in the controller
$controller->layout = 'adminLayout';
// this method is called before any module controller action is performed
return true;
}
else
return false;
}
Import all your CSS and JS files like:
<link rel="stylesheet" type="text/css" href="<?php echo $this->module->assetsUrl; ?>/css/style.default.css" media="screen, projection" />

Related

Silverstripe: Not able to access Page fields in controller with custom route

I'm using SilverStripe 3.3.1 and have a custom route set up to handle urls with many parameters. That works.
However, the routing rule causes Page fields and functions to be inaccessible in the Page_Controller and templates. Any ideas how to fix this?
//MyPage class
class MyPage extends Page {
//Not accessible if route to controller specified in config.yml
private static $db = array(
'MyPageVar' => 'Int',
);
//Not accessible if route to controller specified in config.yml
public function getMySpecialVar() {
return $this->MyPageVar;
}
}
//MyPage_Controller class
class MyPage_Controller extends Page_Controller {
private static $allowed_actions = array(
'index',
'detailsearch',
);
private static $url_handlers = array (
'detailsearch/$Key1/$Value1/$Key2/$Value2/$Key3/$Value3/$Key4/$Value4/$Key5/$Value5' => 'detailsearch',
);
/**
* UseMyPageVar()
*
* #return Boolean
*/
public function UseMyPageVar() {
//Empty if route to controller specified in config.yml
Debug::show($this->MyPageVar);
Debug::show($this->Title);
Debug::show($this->Content);
//Error if route to controller specified in config.yml
Debug::show($this->getMySpecialVar());
return true;
}
}
MyPage.ss
<!-- This work as expected if no route is specified. -->
<!-- But all vars are empty if route is specified in config.yml -->
<p>MyVar: $MyPageVar</p>
<p>Title: $Title</p>
<p>Content: $Content</p>
Routing rule in config.yml
Director:
rules:
'mypage': 'MyPage_Controller'
This question is also posted on the Silverstripe forum:
http://www.silverstripe.org/community/forums/general-questions/editpost/413506
It's not pretty, but for now I've solved the problem by using a private var in the Controller class to hold a reference to the page.
//MyPage_Controller class
class MyPage_Controller extends Page_Controller {
private $_page; //reference to page that's lost with custom routing
//ContentController uses route, which has been changed to
// 'MyPage_Controller' by routing rule, to initialize
// page reference. Can't find anything so reference
// not set. (set to -1)
public function init() {
parent::init();
//Initialize using default route overwritten in routing rule
// This will break if URL segment changed in CMS
$route = array_search($this->URLSegment,
Config::inst()->get('Director', 'rules'));
$link = str_replace($this->URLSegment, $route, $this->Link());
$this->_page = $this->Page($link);
}
//Use private var to access page fields
public function MyPageVar() {
Debug::show($this->_page->MyPageVar);
}
//expose $Content to templates
public function Content() {
return $this->_page->Content;
}
//Can't use Title() so expose Page Title as $PageTitle
public function PageTitle() {
return $this->_page->Title;
}
}
Three things spring to mind when I look at your code:
That "mypage" in config.yml should be the name of a public method on MyPage_Controller. As it is, SilverStripe cannot find a matching method called mypage and will default to calling index() instead.
Routes should really go in a separate routes.yml file so you can "namespace" it to be invoked before or after SilverStripe's own core routes. If you don't do this, then it may result in the weird behaviour you're experiencing.
Did you know that you can debug your routes using the ?debug_request=1 URL param? See: https://docs.silverstripe.org/en/3.3/developer_guides/debugging/url_variable_tools#general-testing

Unable to resolve the request in Yii using modules

This is my controller
class CarsController extends Controller {
public function actionIndex() {
echo 1; exit();
}
}
this is the module file:
<?php
class CarsModule extends CWebModule {
public $defaultController = "cars";
public function init() {
// this method is called when the module is being created
// you may place code here to customize the module or the application
// import the module-level models and components
$this->setImport(array(
'cars.models.*',
'cars.components.*',
));
}
public function beforeControllerAction($controller, $action) {
if (parent::beforeControllerAction($controller, $action)) {
// this method is called before any module controller action is performed
// you may place customized code here
return true;
}
else
return false;
}
}
my problem is if I access my project like: localhost/cars it works. If I access localhost/cars/index I am getting this message: Unable to resolve the request . If I create a new function and I access like this: localhost/cars/myfunction, still the same. I am working on Windows. Can someone help me with this ?
Typically the default url rule for modules is module/controller/actin, so for access actionIndex inside CarsController inside CarsModule, your url should be localhost/cars/cars/index, not localhost/cars/index. If you don't like the url be like localhost/cars/cars/index, you can write one url manager rule to map localhost/cars/cars/index into localhost/cars/index. Something like this:
'cars/index' => 'cars/cars/index'

Pass Database Values to Layout

In my Zend application there is a layout file used in multiple modules. Now i need to retrieve data from database (table gateway) and display on layout. Then it should appear across all the modules.
How do i achieve that ?
Ex -
<?php echo $user_name; ?>
Value for $user_name should be taken from database and pass to layout file.
you dont have to set it in every controller. You could just attach it to a layout variable in your module.php.
public function onBootstrap(MvcEvent $e)
{
$sm = $e->getApplication()->getServiceManager();
$tableWhatever = $sm->get('tableWhatever');
$viewModel = $e->getApplication()->getMvcEvent()->getViewModel();
$viewModel->userName = $tableWhatever->getUserName();
}
Depending on the zf2 version you may have to access the variable in your layout like so:
$this->layout()->userName;
You also have the possibility to extend the AbstractActionController and add the layout variables trough that. I usually just go with the quick onBootstrap method though.
I believe, in Zend, your controller(s) will want:
$this->view->assign('variableName', 'variableValue');
And in your view(s), you will want:
$this->variableName;
You could use Zend Plugin to achieve something like that, like:
class MyPlugin extends Zend_Controller_Plugin_Abstract {
public function preDispatch(Zend_Controller_Request_Abstract $request) {
// Get instance
$layout = Zend_Layout::getMvcInstance();
$view = $layout->getView();
$view->user_name = 'your_username';
}
}
and register your plugin in frontController:
Zend_Controller_Front::getInstance()->registerPlugin(new MyPlugin());
then in layout , you could do:
<?php echo $this->user_name; ?>

Zend Framework: How do I change the default layout script to something other than layout.phtml?

I'd like to name my default layout file something other than layout.phtml, since it doesn't really describe what type of layout it is. How can I do this? Thanks!
From your Bootstrap.php file, you could do something like this:
protected function _initLayoutName()
{
// use sitelayout.phtml as the main layout file
Zend_Layout::getMvcInstance()->setLayout('sitelayout');
}
If you want to use a different layout for a different module, you need to register a plugin in the Bootstrap and have the plugin contain the following code:
class Application_Plugin_LayoutSwitcher extends Zend_Controller_Plugin_Abstract
{
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
$module = $request->getModuleName(); // get the name of the current module
if ('admin' == $module) {
// set the layout to admin.phtml if we are in admin module
Zend_Layout::getMvcInstance()->setLayout('admin');
} else if ('somethingelse' == $module) {
Zend_Layout::getMvcInstance()->setLayout('somethingelse');
}
}
}
From within your application.ini, you can do this to set the layout script:
resources.layout.layout = "layoutname"
This will not work on a per layout basis, however. If you need to change the layout based on the module, you will have to use a plugin, but you can use the setting in application.ini to set the default layout name.
If you want to have a specific layout depending on based on your modules
you can create a plugin and register it in your boostrap :
<?php
class Plugin_LayoutModule extends Zend_Controller_Plugin_Abstract
{
/**
* preDispatch function.
*
* Define layout path based on what module is being used.
*/
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$module = strtolower($request->getModuleName());
$layout = Zend_Layout::getMvcInstance();
if ($layout->getMvcEnabled())
{
$layout->setLayoutPath(APPLICATION_PATH . '/modules/' . $module . '/layouts/');
$layout->setLayout($module);
}
}
}
//Register it in your bootstrap.php
<?php
defined('APPLICATION_PATH')
or define('APPLICATION_PATH', dirname(__FILE__));
...
Zend_Layout::startMvc();
$frontController->registerPlugin(new Plugin_LayoutModule());
?>
EDIT :
to set your layout to another file using .ini file :
create layout.ini file and put in it :
[layout]
layout = "foo"
layoutPath = "/path/to/layouts"
contentKey = "CONTENT"
in your bootstrap file :
$config = new Zend_Config_Ini('/path/to/layout.ini', 'layout');
$layout = Zend_Layout::startMvc($config);

Rendering a different Kohana template at the action level

I have an account controller with a template called 'account'. I'm just trying to figure out how to specify a different template for my login / forgot password actions.
I'm assuming your controller is extended Controller_Template? In the controllers before method, you could check the name of the action and change the template based on that:
<?php
class Controller_Account extends Controller_Template {
// This is the default template used for all actions
public $template = 'account';
public function before()
{
// You can add actions to this array that will then use a different template
if (in_array($this->request->action(), array('login', 'forgot_password')))
{
$this->template = 'diff_template';
}
parent::before();
}

Categories