CakePHP App with Auth + ACL and Plugin with Auth but no ACL - cakephp

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
}
}

Related

How to change only frontend language in Cakephp 3

I have created multilingual website in English and Danish language using I18N and .po file. But if I change the language using I18n::locale() it changes the language of admin panel too. I want to change the language of frontend only. Please suggest.
Thanks in advance.
Changing the locale the way you're doing it is correct:
I18n::locale('da_DK');
But if it's changing it in your admin panel too, then the question is purely about how your application is structured and where you are changing the locale.
If you set the locale in AppController for example, then it's going to change for all controllers. There are many ways you could do it. You could create an AdminController which handles an /admin prefix, and changes the locale just for that prefix.
namespace App\Controller\Admin;
use App\Controller\AppController;
use Cake\Event\Event;
use Cake\I18n\I18n;
/**
* Application Controller for `admin` prefixed controllers.
*
* All controllers within the `app/Controller/Admin` directory should extend this
* controller rather than the normal `AppController`.
*/
class AdminController extends AppController
{
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
I18n::locale('en_GB');
}
}
Then ensure you have correctly set up a prefix route for /admin so that you can put all your admin controllers in app/Controller/Admin, and all those controllers should extend AdminController instead of AppController.
https://book.cakephp.org/3.0/en/development/routing.html#prefix-routing
I didn't want to change the flow of my website. So I used 18n::locale('en_GB') in my all front-end controllers. That resolved my problem.

Creating static home page for CakePHP3

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 {}
}

Allowing the user to change config settings in CakePHP

Using CakePHP 2.6.7
I have created a plugin and there are 2 variables which for the most part are effectively constants - but the user should be able to change their values (they are paths to header and footer images).
I had been trying to use Configure::read() and Configure::write() but now realise that isn't what Configure is intended for and doesn't actually work in that manner at all.
How should these two variables be stored so that the values can be changed by a user and these changes would be permanent (until they make another change)?
Initial Solution
I've now solved the problem by serializing the data in an array to a text file. It would be great if someone had a more elegant solution though.
Simplest solution would be to store these values in the database as settings and then load them in.
We often do this using a Setting model to store the name-value pairs then attach a component (often to AppController) that loads in the data. For example, create a component like this:-
App::uses('Component', 'Controller');
class SettingsComponent extends Component {
public function initialize(Controller $Controller) {
$Controller->loadModel('Setting');
$settings = $Controller->Setting->find('all');
foreach($settings as $setting) {
Configure::write('Setting.' . $setting['Setting']['name'], $setting['Setting']['value']);
}
return;
}
}
Then load this for any controller that needs these settings:-
public $components = array('Settings');
You can then access the values in your code like:-
Configure::read('Setting.app_name', 'My Cake App');
You can easily extend the functionality of the component and what is stored in the settings table to make this approach as flexible as you need.

Load something on every CakePHP page

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.

Cakephp: Routing and default views

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.

Resources