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.
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'm trying to re-use a plugin's controller method for adding a user (the plugin is usermgmt, a purchased plugin). The plugin's method does everything I need, however it finishes by doing a redirect to another page.
I don't want to modify the plugin code, and I am wondering if it is possible to temporarily disable the Controller:redirect method
class MyController extends AppController{
function signUpUser(){
//populate $this->request->data to be what plugin controller method is looking for
//temporarily disable Controller::redirect
//make call to plugin's controller method
$usersController = new UsersController();
$usersController->constructClasses();
$usersController->addUser();
//re-enable Controller::redirect
//Do my own redirect
$this->redirect('/welcome');
}
}
You are not supposed to use controllers that way, there's probably a model or component which you could use instead. Extending the users controller may also be an option. Anyways, since you said you've bought it, why don't you contact the support, they should know best how their stuff works?
That being said, let me answer the actual question. In order to be able to disable redirection via your controller, you would have to override the Controller::redirect() method and implement some logic that allows you to disable the functionality.
Here's an untested example, it uses a property which defines whether redirects are enabled:
public $redirectEnabled = true;
public function redirect($url, $status = null, $exit = true) {
if($this->redirectEnabled) {
parent::redirect($url, $status, $exit);
}
}
This should be pretty much self-explantory.
In your controller you could set $this->redirectEnabled to true/false to enable/disable the redirect functionality.
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 am using auth component and it works ok.
But in my default layout before the content I have some menu which is different if user is logged in. So I want to determine if user is logged in or not - normally I use $this->Auth->user('id') but $this->Auth doesnt work in layout (it only works in view which controller is using Auth component).
How to do it?
In beforeRender() just call
$this->set('userData', $this->Auth->user());
and set the data to the view and do your checks in the view.
In order to get data in layout, you should call beforeRender() method in AppController.
Passing it through session is not a good idea IMHO. It might be not the usual case but at least I prefer to do things solid: If you're using the session for that your code will fail in a system that is not using a session (stateless auth). Overall I'm not a big fan of accessing the session in a view at all. Session is for me more like a datasource.
You can read Auth data from session. Something like:
$user = $session->read('Auth');
Don`t forget to add Session helper in your AppController.
var $helpers = array('Session');
I am using CakePHP 2.0's integrated Auth component.
I have the following tables :
Users
Groups
Profiles
My model relations are as follows:
User belongsTo Group
User hasMany Profiles
While logged in to the site, I noticed the Auth session contains only User table information, but I need the information of Groups and Profiles tables too for the logged in user.
Is there any way to do that with the Auth component?
There is no way to do this with the AuthComponent because of the way it handles the session keys. You can, however, just save it to the session yourself.
The only way to do this is to add to the session when the user logs in:
function login() {
if ($this->Auth->login($this->data)) {
$this->User->id = $this->Auth->user('id');
$this->User->contain(array('Profile', 'Group'));
$this->Session->write('User', $this->User->read());
}
}
Then in your beforeFilter() in your AppController, save a var for the controllers to get to:
function beforeFilter() {
$this->activeUser = $this->Session->read('User');
}
// and allow the views to have access to user data
function beforeRender() {
$this->set('activeUser', $this->activeUser);
}
Update: As of CakePHP 2.2 (announced here), the AuthComponent now accepts the 'contain' key for storing extra information in the session.
As far as I'm aware the Auth component only caches the data from your Users model. You can use that information to retrieve the desired data from the other models, by for example using this in your controller:
$group_data = $this->Group->findById($this->Auth->user('group_id'));
Or
$profile_data = $this->Profile->findByUserId($this->Auth->user('id'));
But I don't think you can get it from the Auth component directly, as it doesn't cache the related model data out of the box.
Two ways:
1) Extend the FormAuthenticate class (see /Controller/Component/Auth) or whatever you use to login and override the _findUser() method and tell the Auth component to use this authorize class. See this page how to do all of that http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html
2) Simply implement a method in the model that will fetch all data you want and call it in the login method of your controller and write the data into the session. IMO it is handy to have such a method because sometimes you need to refresh the session data anyways.
Because of your comment on the other answer:
You will have to write a method and some code in a model that will return you the data. CakePHP can't read your mind and a database without code. No matter which of both suggested ways you're going to use, you'll have to write code.