How to use $this->autoRender = false in cakephp 3.6.10? - cakephp

I am trying to display the test data on the screen by running function test() in the pagesController. Used $this->autoRender = false for it, but it is still giving me error:
Please help me out. I think some version problem is there, but I can't figure it out. Thankyou.

Cakephp by default takes Pages controller's display actions as a home page. display function manages pages and subpages itself that is why you are getting error. Either you can change your default home page in your /config/routes.php
$routes->connect('/', ['controller' => 'Pages', 'action' => 'index']);
OR
define your test action in some other controller.
OR
Remove code from display action
class PagesController {
function display()
{
// default controller code here
// your custom code here
}
}
Hope this will work.

Related

CakePHP 3.5 redirect missing controller exception

I am struggeling with the missing controller exception thrown by CakePHP.
Once an unknown controller is called, it should redirect on my login page.
First I tried to route to my standart login page once there is an controller/action unknown.
//default routing
$routes->connect('/:controller', ['action' => 'index'], ['routeClass' => 'InflectedRoute']);
$routes->connect('/:controller/:action/*', [], ['routeClass' => 'InflectedRoute']);
$routes->connect('/', ['controller' => 'Users', 'action' => 'login']);
//redirect if controller is not known
$routes->connect('/*', ['controller' => 'Users', 'action' => 'login']);
However, this did not work at all, so I googled alot and it turned out that you should catch an the missing controller excpetion instead of rerouting. I can't find out where the error can be caught and it's very little written about it.
Did anyone already have something to do with it?
Short answer
As far as I know catching the MissinControllerException can only be done by customizing the Error Handling flow in Cakephp
Longer answer
To achieve the result you want to need to do the following.
If you are using Middleware in your Application class you need to disable the Error Handling middleware by commenting out this line:
->add(ErrorHandlerMiddleware::class)
Next you need to overwrite the default CakePHP Error handler with a custom one. So in src\Error create the file AppError.php with contents similar to this:
class AppError extends ErrorHandler
{
public function _displayException($exception)
{
if($exception instanceof MissingControllerException){
$response = new Response();
$response = $response->withLocation(Router::url(
['controller'=>'Users', 'action'=>'login'])
);
$emitter = new ResponseEmitter();
$emitter->emit($response);
}else{
parent::_displayException($exception);
}
}
}
Finally, in your bootstrap.php file you need to register your new Error handler. As per docs something like this needs to be added:
$errorHandler = new \App\Error\AppError();
$errorHandler->register();
Potential problems
Doing this redirect will hide away all of your missing controller exceptions. This may cause you trouble in case of typo's in the URL, since you will no longer get a clear error, but instead be redirected to the login page. The error.log file should still show you the original exception.
Good luck!
Potential Problems 2 - CakePHP >= 3.6.x
As pointed out by ndm in the comments disabling the Error Handling Middleware is not always a good idea, especially for CakePHP 3.6. In this case a better solution is to extend the ErrorHandling Middleware and register that.
You could try to handle this exception using custom Exception Renderer:
In src/Error create a new file, named eg MyExceptionRenderer.php, and handle missing controller exception there:
namespace App\Error;
use Cake\Error\ExceptionRenderer;
class MyExceptionRenderer extends ExceptionRenderer
{
public function missingController($error)
{
return $this->controller->redirect("/");
}
}
You will need also to enable this custom renderer in config/app.php:
'Error' => [
'errorLevel' => E_ALL,
'exceptionRenderer' => 'App\Error\MyExceptionRenderer',
'skipLog' => [],
'log' => true,
'trace' => true,
],
With this, when MissingControllerException will be raised, user will be redirected, in this case to main page.
More info can be found here:Error Handling

Cakephp Auth Component - Home page redirect loop

I want to have a login form in my home page, the registered users should be redirected to users/index
with the below code, my home page is going to redirect loop
can anyone tell me where is the issue ??
Note:- infact it is perfectly working if i change the line to
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
App Controller
public function beforeFilter(){
$this->Auth->autoRedirect = false;
$this->Auth->loginAction = array('controller' => './', 'action' => 'index');
$this->Auth->loginRedirect = array('controller' => 'users', 'action' => 'index');
$this->Auth->logoutRedirect = array('controller' => './', 'action' => './');
$this->Auth->authorize = 'controller';
$this->Auth->authError= 'You need permissions to access this page';
$this->Auth->allow('index');
$this->set('Auth',$this->Auth);
}
UsersController
public function login(){
$id = $this->Auth->user('id');
if(empty($id)){
if($this->request->is('post')){
if($this->Auth->login()){
$this->redirect($this->Auth->redirect());
}else{
$this->Session->setFlash('Invalid Username or password');
}
}
}else{
$this->redirect(array('action'=>'index'));
}
}
Thanks for the help...
You pretty much answered your own question here:
Note:- infact it is perfectly working if i change the line to
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
Indeed that would work and that is what it should look like. Right now, you're telling the auth component your loginAction (the action which holds your login logic) is the index action of the ./ controller (which doesn't even exist). I'm assuming you're confusing it with the loginRedirect variable, which is for setting the page to go to after successful authentication.
If you only want Registered Users to Access Your Site you could have something like this... at least, this is how I implement something similar in my site...
In your app_controller file add the following to the beginning of your beforeFilter() function
function beforeFilter(){
//Check if user was able to log in thru Auth using your form in the homepage
if($this->isLoggedIn() == TRUE){
$this->layout = 'default'
}else{
// You can created this layout with a login form and
// whatever else you need except <?php echo $content_for_layout; ?>
// Any registered user will be allowed to login using the form
// and continue on to your site using the default layout
// But it guarantees no one else can see your default site
$this->layout = "unregistered_user"
}
}
On your App_controller.php you can create this function
function isLoggedIn(){
// You can also use $this->Auth->user directly in your App's beforeFilter()
// But I just like to have functions so I can reuse
if($this->Auth->user()){
$loggedin= TRUE;
}else{
$loggedin= FALSE;
}
return $loggedin;
}
I have something similar of my site but is only used when in maintenance mode. I am still developing my site. The only problem I've seen with this way, which I have not yet have time/need to look at, is that my errors are not sent to the layout I want. Supposed a user types in http://www.mydomain.com/inexistentpage then cake transfers them to my default layout. It might be easy to fix, but I havent got time to do that yet.
NOTE: I quickly did this off the top of my head and because of it, this code is untested. However, if you have any issues please let me know and I will test it and post back.
using $this->requestAction(anotherController/action); in the view might call to another controller->action. you must ensure that the another controller->action has the right permissions. or you'll get redirect loop.
solve it by adding $this->auth->allow('action name'); to the another controller page in the beforeFilter() callback.

How to tell cakephp to go to someurl.com/action/var1/var2

Please bear with me as I am a cakephp noob. I have this app that should go to www.name.com/complexes/somecomplex/unitnumber. I can correctly get it to advance to www.name.com/complexes/somecomplex, but I don't know how to get the full path to my unit number.
Here is my controller:
class ComplexesController extends AppController {
public $name='Complexes';
public $uses=array('User', 'Complex', 'Unit');
public $layout='pagelayout';
public function view() {
$this->set('complex', strtoupper($this->params['id']));
$c=$this->Complex->find('first', array('conditions'=>array('complex_name'=>$this->params['id'])));
$this->set('complex_data', $c);
}
}
and here is my route
Router::connect('/complexes/:id', array('controller' => 'complexes', 'action' => 'view'));
Where do I write the action for calling up a specific unit? Inside my 'view' action or another action called 'unit'? And how do i tell cake to route to that?
I figured it out! I had to pass an argument, called $unit in my view() function, where I set the conditions to look for the unitnumber that I had entered in the url ($unit). so, my code ended up looking like this:
public function view($unit=null) {
$this->set('complex', strtoupper($this->params['id']));
$c=$this->Complex->find('first', array('conditions'=>array('complex_name'=>$this->params['id'])));
$this->set('complex_data', $c);
$u=$this->Unit->find('first', array('conditions'=>array('unitnum'=>$unit)));
$this->set('unit', $u);
}
and in my routes file I added this line:
Router::connect('/complexes/:id/*', array('controller' => 'complexes', 'action' => 'view'));
And it worked!

CakePHP: Prevent Auth component's "authError" message on homepage

I have a CakePHP project where I modified "app/config/routes.php" so that the root points to the "Users" controller's "dashboard" action. In other words, these two URLs go to the same place:
http://example.com/
http://example.com/users/dashboard
I have the "Auth" component set up in my "App" controller like so:
class AppController extends Controller {
var $components = array('Auth', 'Session');
function beforeFilter() {
$this->Auth->authorize = 'controller';
$this->Auth->loginRedirect = array('controller' => 'users', 'action' => 'dashboard');
if ($this->Auth->user()) {
$this->set('logged_in', true);
}
else {
$this->set('logged_in', false);
}
}
}
I want it so that if a non-authenticated user goes straight to http://example.com/users/dashboard , they are taken to the login page with the "Auth" component's "authError" message showing, but if they go to http://example.com/ , they are taken to the login page without the "Auth" component's "authError" message showing. Is this possible?
I resolved this by putting the following code in my "Users" controller's "login" action:
if ($this->Session->read('Auth.redirect') == $this->webroot && $this->Session->read('Message.auth.message') == $this->Auth->authError) {
$this->Session->delete('Message.auth');
}
been looking for somthing like that for a long time! Thank you.
I had to make a little change then $this->webroot is not "/":
if (str_replace("//","/",$this->webroot.$this->Session->read('Auth.redirect')) == $this->webroot && $this->Session->read('Message.auth.message') == $this->Auth->authError) {
$this->Session->delete('Message.auth');
}
Well, I don't understand why sometimes you show the error and why sometimes not.. but you can afford this creating an isAuthorized method and modifying all the logic of the default AuthComponent behavior.
Open your Auth component and check for method "startup()". There, at it's last line, you will se this:
$this->Session->setFlash($this->authError, $this->flashElement, array(), 'auth');
$controller->redirect($controller->referer(), null, true);
This is the part responsible for displaying the error.
Before it, you will se...
if ($this->isAuthorized($type)) {
return true;
}
So you can change your isAuthorized method to change this message when you want.
Is a lot of work for (I think..) nothing.
PS. There may be a simpler way to be ignoring me
If you really wants to prevent authError message on homepage and simple redirect to login page then you have to put false as parameter of authError
class AppController extends Controller {
public function initialize() {
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authError' => false
]);
}
}

CakePHP Logout issues

I know this must be something really stupid, but I am having issues with logging out. I can still see the full user Auth variable after calling Auth->logout(). In my users controller I have the standard:
function login()
{
}
function logout()
{
$this->redirect($this->Auth->logout());
}
But when I call logout, in my view I can still print the User by doing this:
$auth = $this->Session->read('Auth.User');
print "<pre>";
print_r($auth);
print "</pre>";
Am I missing something basic here? Thanks!
mine:
function logout() {
$this->Session->destroy();
$this->redirect($this->Auth->logout());
}
you have not allowed the use of the logout function, and the user is redirected instead of logged out.
in your controller containing logout the function, add this in your before filter:
$this->Auth->allow('logout');
In your app controller you must define a loginAction, in case of a not authorized entry, the view is redirected to that URL
'Auth' => array(
'loginRedirect' => array('controller' => 'products', 'action' => 'all'),
'logoutRedirect' => array('controller' => 'products', 'action' => 'index'),
'loginAction' => array('controller'=>'admins', 'action'=>'login'),
)
You'll find that if you just create a beforeFilter() function in UserController with that one line, you'll break the authorization on the Users model. That is, any user will be able to do users/add, users/edit, etc. To fix this, make sure you call AppController's beforeFilter. The complete beforeFilter() function looks like this:
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('logout');
}
If CakePHP is using PHP sessions and not rolling their own, you could just clear out the session on logout via session_destroy();. Sorry I have no CakePHP experience, so I'm just going off of an assumption.
what cake version do you have? I think you have to manually clear session in Cake 1.2. In newer Cake, if the logout function is called, it would clear out Auth.User; I'm sure on that.
I can't see a reason why this shoudn't work as I use exactly the same code...
did you confirm that the method is actually called? a simple "die('xyz')" etc before the Auth logout part can confirm that your action code is triggered.

Resources