Is it possible to load something on every CakePHP page without having to add a request in every actions in every model? Just add it somewhere and it's done for all the pages?
First off, Models do not have actions. Controllers have actions.
You can load data in all controllers by using AppController::beforeFilter()
class AppController extends Controller {
public function beforeFilter() {
$this->set('something', $foobar);
}
}
You can also load view stuff on all pages in the layout file.
Related
I am working on a CakePHP3 project. I want a static homepage that will be loaded on www.mysite.com.
For this I have created a PagesController which will handle all the static pages in the website like about,contact,etc.
I am having display.ctp view in Template/Pages/display.ctp to load on www.mysite.com.
But, for testing (routes are not configured yet), I'm using www.mysite.com/pages and www.mysite.com/pages/display to show the view but it gives error as
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'mysite.pages' doesn't exist
Do I need to create Table for this ?
It is much, much easier than that
For this I have created a PagesController
There is already a pages controller for serving static content, and a
static template for the home page, there is no need to create/overwrite the default pages controller, to replace it with the same (or less) functionality. This is also mentioned in the documentation
The steps to modify static pages (with default routes) are:
edit src/Template/Pages/home.ctp - look at the url /
create/edit src/Template/Pages/something.ctp - look at the url /pages/something
The error means that the application is looking for a model named Page. To tell the application that your controller does not refer to any model you have to use something like bellow. Also add the proper action. www.mysite.com/pages/display means in controller "pages" call action "display".
class MyController extends AppController {
var $uses = false;
public function display {}
}
I am working with cakephp , i need some clarification regarding initiating.
which file will be loaded first in cakephp whether index.php or bootstrap file
The answer of Ganesh is not really correct. It does not redirect and it does not load AppController as third file, nor does it load it ever directly.
First you should always configure your site to be accessed from the app/webroot folder NOT the index.php in the level above, because if you do that you expose the whole app structure to the public web as well.
When app/webroot/index.php is accessed CakePHP sets a bunch of constants like the CAKE_CORE_INCLUDE_PATH, WWW_ROOT and a few others, the best is to have a look at this file.
Then it will include the bootstrap.php file.
At the end of this file you'll see that not AppController but the Dispatcher is called first and the Request/Response classes are passed to it.
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch(
new CakeRequest(),
new CakeResponse()
);
See Dispatcher::dispatch().
Then, still no controller is loaded. It first fires events and by this dispatcher filters which can interrupt the request and already send data back to the client. That's how the AssetDispatcher works for example. Again, still no controller here.
If the filters passed then the dispatcher will call the controller that matches the requested url, not AppController, if you called /users/index it will instantiate the UsersController and call its index() method. See Dispatcher::_loadController().
All your Controllers should extend AppController but AppController actually never gets called directly.
When a cakephp application is accessed first it will load the index.php from there it redirects to bootstrap.php and then AppController.php.
I have a CakePHP app setup with Auth and ACL.
I have also made a Plugin within this app that includes a separate login to another part of the site away from the App. This uses Auth to login on a different table, and doesn't require ACL as users will be able to access all areas of this small section of the site.
I have managed to separate the two Auths using:
AuthComponent::$sessionKey= 'Auth.Recipient';
in the Plugin's AppController and
AuthComponent::$sessionKey= 'Auth.User';
in the App's AppController
This seems to work well and lets me login to both areas of the site separately.
Next when I tried to add more methods inside my Plugin I received the error:
AclNode::node() - Couldn't find Aro node identified by "Array ( [Aro0.model] => Group [Aro0.foreign_key] => ) "
I tried running AclExtras.AclExtras aco_sync out of desperation but that, not surprisingly didn't work.
I attempted to work around this, by adding another group (I am using Group ACL) called "Customer" and then assigning all users created in my Plugin table the Customer group id.
This stopped the error, I next tried to add a new row for my users/initdb method for these users so that they could only access the customers controller. However, if they attempt to access this they are kicked out to the login page as if they do not have access to this controller.
Adding the method names to:
$this->Auth->allow('');
works but obviously isn't a solution, although is pointing me in the direction of this being permission related.
The ideal solution for me, would be one where I could simply stop the plugin having any inheritance of ACL from the App.
I have 2 possible suggestions for breaking the inheritence structure of CakePHP to prevent the plugin from loading the components
Pseudo App Controller
Create a new controller class for example MyAppController which extends the core AppController which can then be used as a parent for main app's controllers, while the core AppController which remains empty is used for the plugins. The plugins then do not inherit anything
Your structure should be something like
A normal AppController class
// app/Controller/AppController.php
class AppController extends Controller
{
// left empty intentionally
}
A pseudo-AppController for your plugin
class MyAppController extends Controller
{
// all code for the main app
// used for all your normal app controllers
public $components = array('Acl', 'Auth');
// -- snip -- //
}
An example controller from the main app
App::uses('Controller', 'MyAppController');
class PostsController extends MyAppController
{
}
And the plugin app controller
class PluginAppController extends AppController
{
}
This will prevent any methods or instance variables being inherited by the plugin, but obviously is not great design as you will loose any methods you wish to share between the App and its plugins. Unless you extract them into components and add them to the AppController
Override the plugin controller __construct
Take advantage of OOP and override the __construct method in the plugins PluginAppController to prevent the ACL component from being loaded at all
class PluginAppController extends AppController
{
public __constrcut($request = null, $response = null)
{
// modify this to prevent components you don't want
}
}
I've run into a problem in my CakePHP app as a result of adding some ajax actions.
My table is called orders so obviously my controller is called OrdersController and the model is called Order
It is my understanding of CakePHP's best practices that if I am going to run any logic on the Order model, that it should be done in the OrdersController. This is fine for the basic CRUD stuff but now that some of my views need to send ajax requests to manipulate Order data I have a problem.
The problem is that for ajax to work properly, I have to put this at the beginning of the OrdersController
var $layout = 'ajax'; // uses an empty layout
var $autoRender=false; // renders nothing by default
Then, to stop the security component interfering with my Ajax form submissions, I also need this:
public function beforeFilter() {
parent::beforeFilter();
$this->Security->csrfUseOnce = false;
$this->Security->csrfExpires = '+1 hour';
}
None of this would be a problem if the controller was only being used for Ajax requests, but the problem is that it's being used for regular Cake actions too.
Is the answer that I should have two controllers? One for regular actions and one for ajax actions? This doesn't seem to be mentioned in the Cake docs and it doesn't seem like a very efficient way of doing things.
I know I can change the layout and possibly the auto-render setting on a per-action basis, but I don't see how it's possible to do this with the csrf settings, which need to be in the beforeFilter.
No need for a separate controller. Use cakes request handler. In your controller method, you can test if it's an Ajax request.
if ($this->request->is('ajax')) {
//set to Ajax layout and security settings, etc
You'll need to include the request handler component at the top of your controller:
public $components = array('RequestHandler');
See this page in the cook book For more info: http://book.cakephp.org/2.0/en/core-libraries/components/request-handling.html
I'm currently trying to add an admin mode to my cakephp site.
I followed a tutorial on the web and added a routing prefix:
Configure::write('Routing.prefixes', array('admin'));
Then I implemented login and logout functionality.
I added a admin_view.ctp and admin_index.ctp to a model where I want to restrict access. Therefore I deleted view.ctp and index.ctp and expected that only admins could view the model by using:
http://xxxx/model/admin/index
But when I entered
http://xxxx/model/index
a default view appeared that I could not disable (it allows model manipulation). Is there a standard way to disable all these default views or do I have to create a index.ctp and view.ctp that simply show error messages?
If you want to disallow certain action, you need to setup ACL, which is described here. And for authentication, in your controller you need something like this:
class SomethingsController extends AppController
{
var $components = array('Auth');
//this will allow all users access to the index
//and view methods ( but not any other)
function beforeFilter() {
$this->Auth->allow('index','view');
}
// other actions
}
Hope this helps.
Delete default controller methods: function index(), view(), add(), edit() and delete(). Removing *.ctp templates is not enough.