Cakephp 3 redirect controller - cakephp

In my CakePHP 3 application, after a controller redirect I get this error:
Error: [LogicException] Controller action can only return an instance of Response
Request URL: /mycontroller/
Stack Trace:
#0 /var/www/vhosts/example.com/httpdocs/vendor/cakephp/cakephp/src/Routing/Dispatcher.php(87): Cake\Routing\Dispatcher->_invoke(Object(App\Controller\SigninsController))
#1 /var/www/vhosts/example.com/httpdocs/webroot/index.php(37): Cake\Routing\Dispatcher->dispatch(Object(Cake\Network\Request), Object(Cake\Network\Response))
#2 {main}
Regarding to CakePHP 2 controller documentation redirect was like this:
$this->redirect('/orders/thanks');
$this->redirect('http://www.example.com');
return $this->redirect(
array('controller' => 'orders', 'action' => 'confirm')
);
But in CakePHP 3 documentation it seems like this:
return $this->redirect('/orders/thanks');
return $this->redirect('http://www.example.com');
return $this->redirect(
['controller' => 'Orders', 'action' => 'thanks']
);
When I add return word before $this->redirect, error is solved. So does this makes problem ? Because I couldn't see a return redirect part in cakephp 3 migration guide. Migration guide only mentions that third parameter is dropped.

Return in CakePHP 3 application is used when you want to redirect to other pages or we can say actions/methods of other controllers or even if you want to redirect to 3rd Party Links like you have specified :-
return $this->redirect('/orders/thanks');
return $this->redirect('http://www.example.com');
return $this->redirect(['controller' => 'Orders', 'action' => 'thanks']);
And if you want to redirect to other method in the same controller then you can leave the return and use setAction as below but here URL will remain the same.
$this->setAction('thanks');
Return is better approach and URL will redirect if you use below code.
return $this->redirect(['action' => 'thanks']);

Take a look at this
Response provides an interface to wrap the common response-related tasks such as:
Sending headers for redirects.
and this
You should return the response instance from your action to prevent view rendering and let the dispatcher handle actual redirection.

if you are using route name then use this-
$this->redirect(['_name' => 'view-details']);
you are using route then use this-
$this->redirect('/page/view-details');
and last option is this
$this->redirect(['controller' => 'Pages', 'action' => 'view']);
----------------------------------------------------------------------
if you are use route name in view file then this use-
use Cake\Routing\Router;
echo Router::url(['_name' => 'view-details']);
echo Router::url(['controller' => 'Articles', 'action' => 'view', 'id' => 15]);

In cakephp, 3.6 to go to specific view/page Use $this->render('filename');
like below
public function search()
{
$this->render();
$this->render('profile');
}

You need to turn off Autorendering
since cakephp methods by default want to end with a redirect to a CTP file
use $this->autoRender = false
inside you function

Related

Cakephp redirect in isAuthorized method not working

So after login in isAuthorized method I'm trying to redirect user based on a condition. But problem is it's not redirecting. Below the code that I have tried.
protected function isAuthorized($LoginUser)
{
if ($this->getTable('Users')->hasCompany($LoginUser) == false){
$this->redirect(['controller'=>'Companies','action'=>'edit']);
dd("hello");
}
}
It's not redirecting and getting hello message. How can I redirect after login user to another page based on condition ?
As mentioned in the comments, the auth component's authorization objects are supposed to return a boolean, and depending on that, let the component do the unauthorized handling-
What you could do, is for example dynamically set the component's unauthorizedRedirect option (and probably also authError) from the controller's authorization handler for that specific case (I guess you'd also have to exclude the respective company controller's action from that check, as otherwise you'll end up in an infinite redirect loop):
if (!$this->getTable('Users')->hasCompany($LoginUser)) {
$message = __('You must provide company information in order to proceed.');
$url = \Cake\Routing\Router::url([
'controller' => 'Companies',
'action' => 'add'
]);
$this->Auth->setConfig([
'authError' => $message,
'unauthorizedRedirect' => $url,
]);
return false;
}
// ...
return true;
If you find yourself in a situation where there's no such possibility, brute forcing a redirect by throwing a \Cake\Http\Exception\RedirectException could be a solution too, even though it's ideally avoided, it's better than dying, as it will at least emit a clean redirect response:
$url = \Cake\Routing\Router::url([
'controller' => 'Companies',
'action' => 'add'
]);
throw new \Cake\Http\Exception\RedirectException($url);
See also
Cookbook > Controllers > Components > AuthComponent > Configuration options

CakePHP 3 - Rename controller in routes.php

What would be the correct way to reroute all actions from fakeController to controller1 using Cake's routing engine?
I'd like to reroute actions index and any other actions and also parameters.
app/fake/ => app/controller1/
app/fake/action1 => app/controller1/action1
app/fake/action2/any/params => app/controller1/action2/any/params
Is it possible with just one line of code?
Why I am doing this? - because in CakePHP 3 the routes are case-sensitive. I'd like to keep my controllers names UpperCase, but it results in paths like app/Users/login, if I write users it says usersController not found. If there is a way around this, I wouldn't need all this rerouting.
The default route is case-sensitive, yes, however by default there should be fallbacks defined using the InflectedRoute class, which behave as known from 2.x, ie it will inflect users to Users (as of 3.1.0 the default is DashedRoute, which inflects too).
https://github.com/cakephp/app/blob/3.0.4/config/routes.php#L73
If you want this to be the default behavior (note that this is relatively slow) for all routes, then simply set this to be the default via Router::defaultRouteClass()
Router::defaultRouteClass('InflectedRoute');
https://github.com/cakephp/app/blob/3.0.4/config/routes.php#L42
or in order to restrict it to a specific scope, use the fallbacks() method.
$routes->fallbacks('InflectedRoute');
https://github.com/cakephp/app/blob/3.0.4/config/routes.php#L73
Alternatively you could create appropriate routes for all your controllers, similar to as shown in your apps routes.php file:
Router::scope('/', function (\Cake\Routing\RouteBuilder $routes) {
// ...
$routes->connect('/users', ['controller' => 'Users', 'action' => 'index']);
$routes->connect('/users/:action/*', ['controller' => 'Users']);
$routes->connect('/foos', ['controller' => 'Foos', 'action' => 'index']);
$routes->connect('/foos/:action/*', ['controller' => 'Users']);
// and so on...
});
https://github.com/cakephp/app/blob/3.0.4/config/routes.php#L60-L62
See Cookbook > Routing for more information about routing.

Cakephp Routing to generate URL parameter

Simple question for Cakephp 2.0.
I want to set a routing rule such that:
www.abc.com/z/abc123
will resolve to the full URL of (including the URL parameter)
www.abc.com/bookings/bookingref/?ref=abc123
Where bookings is the Controller, and bookingref is the action.
Can someone teach me what I need to write in the routes.php?
Kevin
In routes.php:
Router::connect('/bookingref/', array('controller' => 'bookings', 'action' => 'bookingref'));
In controller:
public function bookingref(){
}
So you should have a view name after your function. i.e. bookingref.ctp
This is how I would implement your solution:
In Config/routes.php add:
Router::connect('/z/:reference',
['controller' => 'bookings', 'action' => 'bookingref'],
[
'pass' => ['reference'],// Passed to corresponding function argument (order matters if 2 or more)
'reference' => '[a-z0-9]+'// RegExp validation if you need it
]
);
In your BookingsController use:
public function bookingref($reference = null)
{
...
}
Unfortunately, Router::redirect() cannot redirect to string based URLs that include variables. The controller based approach Progredi mentioned is your best bet.

Cakephp route and prefix

I have a problem with Routes in CakePHP. Let me explain.
I'm using authentication through the Auth component. I have a routing prefix called account.
When I want to edit a user, I'm calling the users controller which gives me a URL like:
/account/users/edit/5
What I want is to have a URL like:
/account/edit/5
So I changed my router like this:
Router::connect('/:prefix/edit/:id',
array('controller' => 'users', 'action' => 'edit'),
array('pass' => array('id'), 'id' => '[0-9]+')
);
which worked when I try to access /account/edit/5
My problem is located in my view. How can I access this route using the Html->link helper?
So far, I'm just doing it like this:
'/'.$this->Session->read('Auth.User.role').'/edit/'.$this->Session->read('Auth.User.id')
But it's not really clean in my opinion. I want to use the helper.
Thanks a lot for your help
Using a prefix "account" would mean needing an action like "account_edit" in your controller. That's probably not what you want. Also why put the "id" in url when it's already there in the session? Why not just use url "/account" for all users and get the id (and role if required) from session in the action?
Router::connect('/account',
array('controller' => 'users', 'action' => 'edit')
);
This would be the clean way to generate required url:
$this->Html->link('Account', array(
'controller' => 'users',
'action' => 'edit'
));
// Will return url "/account"
In general always use array form to specify url to benefit from reverse routing.
everything is just fine except router. it should be
Router::connect('/account/*',
array('controller' => 'users', 'action' => 'edit')
);
and creating anchor link in various way using Helper you can CHECK HERE

Adding a controller function for the "home" view in CakePHP

When visiting a default CakePHP site, it takes you to "home.ctp" page.
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
I want to add a few elements there (like blog posts), so I thought I could just add this to the PagesController() class:
public function home() {
$this->set('blogposts', $this->Blogpost->find('all'));
}
But that does not work.
So: what is the correct way to add something like this on the home page (or any other page for that matter)
The preferred option is to create a custom route for the home page but you can also override the PagesController's display function
Option 1: (Preferred Method)
Router::connect('/', array('controller' => 'mycontroller', 'action' => 'myaction'));
Option 2
Router::connect('/', array('controller' => 'pages', 'action' => 'home'));
Option 3:
class PagesController {
function display()
{
// default controller code here
// your custom code here
}
}
The final option is using requestAction in your view, but it isn't recommended as it has a huge performance drawback
Option 4: (Not recommended)
$newsitems = $this->requestAction(array('controller' => 'newsitems', 'action' => 'getlatestnews', 'limit' => 10));
In fact, the action is display, home is a parameter. So your main method in the Controller Pages must call display, not home. After that, create display.ctp view.
Reference:
Routing
To actually answer the original question:
$this->loadModel('Blogpost');
Ideally the model should be called
$this->loadModel('BlogPost');

Resources