I am new to cakephp 3 and I don't know how to add our application layout to specific plugin controller.
My folder structure like below:
<pre>
projectName(folder)
->Plugins(folder)
->PluginsName
->src
->controller
->UsersController
->src(folder)
->Template(folder)
->Layout(folder)
->login.ctp
</pre>
How can I use this login.ctp layout in my plugins controller (UsersController)?
You can add layout in specific function by following way.
// Set the layout.
$this->viewBuilder()->setLayout('login');
// Before 3.4
$this->viewBuilder()->layout('login');
// Before 3.1
$this->layout = 'login';
if you need add it in full controller then you can add it in beforeRender
public function beforeRender(Event $event)
{
parent::beforeRender($event);
$this->viewBuilder()->setLayout('Admintheme');
}
Ref: beforeRender and Layout
Related
Is it possible to add a js file to view from a controller beforeRender()? Is it advisable? If not, and if I cannot use a View, should I just use the Event System?
Basically the idea is to have a plugin that I created inject a JS file into 'script' block of the Theme plugin (Separate plugin)
After some more attempts I decided to go thru and use the Event System. I accomplished it this way:
<?php
namespace App\Event;
use Cake\Event\EventListenerInterface;
class ApplicationListener implements EventListenerInterface {
public function implementedEvents() {
return [
'View.beforeLayout' => 'injectJsFile'
];
}
public function injectJsFile(Event $event, $layoutFile){
$event->getSubject()->Html->script('myscript', ['block' => 'script']);
}
}
This does the job for me, but if there is a controller way or a better Event System way, I would love to hear it.
I have written a CakePHP plugin https://github.com/anuj9196/CakePHP-App-Installer
The plugin is using default.ctp layout from plugin_path/src/template/layout/default.ctp
When there is some other theme used in the host application. Like in my case I have setup one in AppController's beforeRender()
$this->viewBuilder()->setTheme('DashboardTemplate');
DashboardTemplate is in application's /plugin/ directory.
Now, when I access my plugin's URL using example.com/installer/install
The template loads on top of DashboardTemplate theme.
How can I disable them in plugin's AppController?
The AppController inside plugin directory contains
<?php
namespace Installer\Controller;
use App\Controller\AppController as BaseController;
class AppController extends BaseController
{
// nothing here
}
Remove the theme by using beforeRender() in your plugin's AppController.
<?php
namespace Installer\Controller;
use App\Controller\AppController as BaseController;
class AppController extends BaseController
{
/**
* #param \Cake\Event\Event $event The beforeRender event.
* #return \Cake\Http\Response|null|void
*/
public function beforeRender(Event $event)
{
try {
return parent::beforeRender($event);
} finally {
$this->viewBuilder()->setTheme(null);
}
}
}
You can switch between layouts in your view and controllers fairly easily.. using plugin syntax
// inside controller
$this ->layout = 'Plugin.layout';
//inside view template
$this ->layout = 'Plugin.layout';
If you just want to disable the theme, use Mathew's method above. But be careful that will disable the theme for the whole application not just this plugin in case some of your app code is ran after your plugin
For example, from within a Controller (this doesn't work):
$this->Components->load('api/UserComponent');
... calling a component from folder structure like so:
app/Controller/Component/api/UserComponent.php
try adding this into your bootstrap: it will tell cake to consider also your subdirectory when loading components from your controller
App::build(array(
'Controller/Component' => array(
APP.'Controller/Component/api/'
)
));
after that you should be able to include and use component as if it would be in Component directory
Solutions is two in CakePHP 2.x
Add now Path by App::build()
// Append Path in bootstrap.php
App::build(array(
'Controller/Component' => array(
APP . 'Controller'.DS.'Component'.DS.'Reports' . DS,
)
), App::APPEND);
// Load in controller MyController ....
public $components = array('Paginator', 'Session', 'ReportUsers');
// In controller
$this->ReportUsers->Demo('bla..bla..');
// OR load in fly in action form controller.
$this->ReportUsers = $this->Components->load('ReportUsers');
$this->ReportUsers->Demo('bla..bla..');
Or by CakePlugin, Create one Plugin Reports for example:
// Add Plugin in file bootstrap.php
CakePlugin::load('Reports');
// MyController use Example
// Load in controller MyController ....
public $components = array('Paginator', 'Session', 'Reports.ReportUsers');
// In controller
$this->ReportUsers->Demo('bla..bla..');
// OR load in fly in action form controller.
$this->ReportUsers = $this->Components->load('Reports.ReportUsers');
$this->ReportUsers->Demo('bla..bla..');
You can't have your components in a sub folder under Component folder. If you want to better organize your classes use plugins.
I'm working on a CakePHP 1.2 app where I don't have control over the /app directory and have relocated my views folder to, say /path/to/mycomponent/views and can render my views by setting my controller's default view path
var $viewPath = "mycomponent/views";
I have some layouts (including basic.ctp) under /path/to/mycomponent/views/layouts
Is there a way to render my views inside a specific layout?
Calling this from my controller gives me a page not found error:
function index()
{
$this->autoLayout = true;
$this->pageTitle = 'Browse items';
$this->render("browse", "basic");
// also tried: $this->render("browse", "/path/to/mycomponent/views/layouts/basic.ctp");
}
Finally got it to work by adding a path to the viewPaths array of the app configuration. This code goes in you controller constructor or in the override beforeFilter metod:
$config = Configure::getInstance();
$config->viewPaths[] = " /path/to/mycomponent/views/";
Now I can just specify the following:
$this->layout = 'basic';
And my controller's views render in the basic.ctp layout.
Just for any further reference.
I believe in cakePhp 2.x it's to be done this way.
public function beforeRender() {
parent::beforeRender();
$this->layout = 'mylayout';
}
which would go to the path: /app/View/Layouts/mylayout.ctp
Note:
If you want to modify the view paths for some controller, add before the controller class declaration:
App::build(array('View' => '/Folder/'));
class ExampleController extends AppController{...}
which will set the path for all rendered view for Example controller to /app/Views/Folder/
so the full example would be:
App::build(array('View' => '/Folder/'));
class ExampleController extends AppController{
public function beforeRender() {
parent::beforeRender();
$this->layout = 'mylayout';
}
public function index() {
$this->render('Home');
//This will load view: "/app/Views/Folder/Home.ctp"
//From layout: "/app/Views/Layouts/mylayout.ctp"
}
}
I cannot set title_for_layout in the PagesController that comes by default with CakePHP 1.3.
I am using the following code in the display function:
$this->set('title_for_layout','some title');
What am I doing wrong?
In your controller, the corresponding value is $this->pageTitle.
UPDATE
Oops, as noted in the comments, this is the 1.2 solution. 1.3 possibilities (after doing some research) include:
Ensuring that $title_for_layout is being echoed in the layout
Placing the $this->set() code in the view rather than in the controller
If you'd like to mimic the behavior of cake 1.2, you can do the following:
In your app_controller, create the following method:
in app/app_controller.php (you may need to create this file if you haven't already)
public $pageTitle;
public function beforeRender() {
$this->set('title_for_layout', $this->pageTitle);
}
Then in any of your action methods, you may then use the pageTitle as you would in 1.2.
public function index() {
$this->pageTitle = 'Some Title';
}
The beforeRender() method will be called after your controllers have finished processing, but prior to the layout being rendered, thus allowing you to set variables for the layout.
In the action method, try this:
function index()
{
$this->pageTitle= 'Your Title';
}
Just thought I'd add to any new people finding this solution, you can do $this->set('title', $title); in CakePHP 1.3 inside the controller and the title will be rendered automatically.
You can use :
$this->assign('title', 'Some title');
and in ctp :
<title><?= $this->fetch('title'); ?></title>
It work in CakePHP 3.0
For CakePHP 3.x,
you can follow the advice here
Essentially,
Inside UsersController.php:
$this->set('title', 'Login');
Inside src/Template/Layouts/default.ctp
above the $this->fetch('title');
write:
if (isset($title)) {
$this->assign('title', $title);
}
Use beforeRender() instead. Put the following in AppController:
class AppController extends Controller {
var $content;
function beforeRender() {
$this->set('content',$this->content);
}
}
And in the controller, you can just do:
function index() {
$this->content['title'] = '123'; }
That'll do the trick.