I want to override "redirect" to insert a language prefix. For that I've added thist to AppController.php
public function redirect( $url, $status = NULL, $exit = true ) {
die(debug('$url'));
if (!isset($url['language']) && $this->Session->check('Config.language')) {
$url['language'] = $this->Session->read('Config.language');
}
parent::redirect($url,$status,$exit);
}
Obviously the die(..) is just for testing if this function is called.
My controller code:
public function add() {
if ($this->request->is('post')) {
$this->request->data['Party']['language_id'] = $this->Session->read('Config.LanguageId');
$this->Party->create();
if ($this->Party->save($this->request->data)) {
$this->Session->write('partyId', $this->Party->id);
return $this->redirect(array(
'controller' => 'parties',
'action' => 'editGuestlist',
));
} else {
$this->Session->setFlash(__('The party could not be saved. Please, try again.'));
}
}
}
I expected that "$this->redirect" in XyzController will call my public function "redirect" in AppController.
If I'm adding a party I'm getting redirected to /parties/editGuestlist no prefix is added and the code doesn't stop. So it is prety obvious that my overriding is not working. As I'm new to cakephp I'm hoping that somebody can explain this behavior to me.
UPDATE
I've found an error in /config/routes.php that fixed the behavior but I still have no clue why my overriding function isn't called at all.
I've added array('language' => '[a-z]{3}') to
Router::connect('/:language/:controller/:action/*',
array(),
array('language' => '[a-z]{3}')
);
Related
Hey Guys I have the following Scenario and I can't think of a better way. Maybe you guys can provide a more DRY method
So update method BaseController from Laravel Voyager
public function update(Request $request, $id)
{
// Update Logic Here
// Redirect Logic
if (auth()->user()->can('browse', app($dataType->model_name))) {
$redirect = redirect()->route("voyager.{$dataType->slug}.index");
} else {
$redirect = redirect()->back();
}
}
return $redirect->with([
'message' => __('voyager::generic.successfully_updated')." {$dataType->getTranslatedAttribute('display_name_singular')}",
'alert-type' => 'success',
]);
Custom Controller that extends the above Base Controller
public function update(Request $request, $id)
{
// Update Logic Copied and Pasted from Base ( Yuck :( )
// Small Change to the Redirect Logic
if (auth()->user()->can('browse', app($dataType->model_name))) {
$redirect = redirect()->route("voyager.{$dataType->slug}.index");
} else {
$redirect = redirect()->route("voyager.{$dataType->slug}.show",$id);
}
}
return $redirect->with([
'message' => __('voyager::generic.successfully_updated')." {$dataType->getTranslatedAttribute('display_name_singular')}",
'alert-type' => 'success',
]);
So my question is with the current structure of the Base Controller Is there any other way to override the redirect logic without literally copying and pasting the whole lot of code
I do not want to edit the BaseController as it will stop me from updating the package
Any thoughts would be great
Cheer
Simply use smaller functions to extract that logic and override it, similar approaches with overriding function through inheritance for changing logic, is used by Laravel on Models see getRouteKey() for example.
In your BaseController.php, i would split it up like so.
{
if (auth()->user()->can('browse', app($dataType->model_name))) {
$redirect = redirect()->route("voyager.{$dataType->slug}.index");
} else {
$redirect = $this->browseRedirectLocation();
}
}
return $redirect->with([
'message' => __('voyager::generic.successfully_updated')." {$dataType->getTranslatedAttribute('display_name_singular')}",
'alert-type' => 'success',
]);
}
protected function browseRedirectLocation() {
{
return $redirect = redirect()->back();
}
Now you should be able to override redirect location in your CustomController.php, instead of the whole function in your implementation class. As i could see it was only the redirect that was changed.
protected function browseRedirectLocation() {
{
return redirect()->route("voyager.{$dataType->slug}.show",$id);
}
In Controller
public function add(){
$this->loadModel('User'); //load model
if($this->request->is('post')){
$filename=$this->User->checkFileUpload($this->request->data);
$this->User->set($this->request->data); //set data to model
if ($this->User->validates()){
$datas = array(
'User' => array(
'name' => $this->request->data['User']['name'],
'email'=>$this->request->data['User']['email'],
'password'=>$this->request->data['User']['password'],
'image'=>$filename
)
);
$pathToUpload= WWW_ROOT . 'upload/';
move_uploaded_file($this->request->data['User']['image']['tmp_name'],$pathToUpload.$filename);
// prepare the model for adding a new entry
$this->User->create();
// save the data
if($this->User->save($datas)){
//$this->Session->setFlash('User Information has been saved!');
return $this->Flash('User Information has been saved!',array('action' => 'index'));
//return $this->redirect(array('action' => 'index'));
}
} else {
$errors = $this->User->validationErrors; //handle errors
}
}
//$this->layout = NULL;
$this->viewpPath='Users';
$this->render('add');
}
In above code, i used flash() method to direct a user to a new page after an operation. This method showing the message but not redirecting in given url.
Please help me. What am i doing wrong here for redirecting with help of flash() method?
flash() does not redirect, it renders. It is very similar to the render() function, it will continue the execution of the script, unlike the redirect() function.
but if you still want to use this
you should use following in config file.
Configure::write('debug', 0);
Update
after add this into main.php use like
$this->flash(__("Some message for the user here..."), array("action" => "index"));
it'll work perfactly . Follow this forrefrence
Render != Redirect
If you need to redirect to the referer page you can use:
$this->redirect($this->referer());
if you want redirect to different controller:
$this->redirect(('controller' => 'YOURCONTROLLER', 'action' => 'YOURACTION'));
or if you want redirect to different action in same controller:
$this->redirect(('action' => 'YOURACTION'));
I'm using isAuthorized to deny access to methods if the record id doesn't belong to the user. Profiles can have many documents and documents belong to one profile:
Controller/DocumentsController.php
public function add($id = null) {
if ($this->request->is('post')) {
$this->request->data['Document']['profile_id'] = $id;
$this->request->data['Document']['user_id'] = $this->Auth->user('id');
$this->Document->create();
if ($this->Document->save($this->request->data)) {
$this->Session->setFlash(__('The document has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The document could not be saved. Please, try again.'));
}
}
}
public function isAuthorized($user) {
if ($this->action === 'index') {
return true;
}
if (in_array($this->action, array('view', 'add', 'edit', 'delete'))) {
$document_id = $this->request->params['pass'][0];
if ($this->Document->isOwnedBy($document_id, $user['id'])) {
return true;
}
}
return parent::isAuthorized($this->Auth->user());
}
Model/Document.php
public function isOwnedBy($document, $user) {
return $this->field('id', array('id' => $document, 'user_id' => $user)) === $document;
}
I'm passing the profile id as $id to docments/add from one of my profile views via Cake link helper:
View/Profiles/view.ctp
echo $this->Html->link('New Document',
array('controller' => 'documents', 'action' => 'add',$profile['Profile']['id'])
);
What happens when I click on New Document from profiles/view is that it sends the request but doesn't redirect, just refreshes the page, or it redirects back to profiles/view, not sure which. My first guess is since I'm not defining the profile id in the isAuthorized callback within DocumentsController, isOwnedBy is returning false. Any suggestions on how to get the profile id in isAuthorized within DocumentsController?
Thanks in advance!
The solution to this is relativley easy. When using isAuthorized with parameters from another controller, be sure to reference the right model.
if ($this->Document->Profile->isOwnedBy($document_id, $user['id'])) {
return true;
}
In my CakePHP application, I have setup the PersistantValidation plugin to validate my forms on the model level thanks to a kind previous suggestion. The plugin essentially makes it so that you can use model validation on a partial without having it redirect to the underlying page (ie. the register.ctp view or the login.ctp view, for example).
The validation works great for the login form, but it's not working properly on the user registration form for some reason.
The controller looks like this:
function register() {
if(!empty($this->data)) {
$name = $this->data['User']['name'];
$email = $this->data['User']['email'];
$password = $this->Password->generatePassword();
$this->data['User']['password'] = $this->Auth->password($password);
$this->User->create();
if($this->User->save($this->data)) {
$this->Session->setFlash(__('Your account has been created!', true));
$this->redirect(array('controller' => 'users', 'action' => 'offers'));
} else {
$this->redirect($this->referer());
}
}
}
The PresistentValidation component is also properly setup and included, since it works just fine in the login() function in the same controller. When I run this code, nothing happens. There is no redirect away from the partial, which is good, but the errors don't show up. Also, the errors do show up going to the register.ctp view, which means it isn't a problem with the validations themselves.
Does anyone have any ideas?
function register() {
if(!empty($this->data)) {
$this->data['User']['password'] = $this->Auth->password($password);
if($this->User->save($this->data)) {
$this->Session->setFlash(__('Your account has been created!', true));
$this->redirect(array('controller' => 'users', 'action' => 'offers'));
} else {
$this->redirect($this->referer());
}
}
}
I am trying to use the isAuthorized() method to do a check for an admin flag, but the function never seems to be called. Even when I set the function to always return false, it allows any user. It just seems like it isn't being called.
Do I need to do something more than setting $this->Auth->authorize = 'controller' ?
from /app/app_controller.php
class AppController extends Controller
{
var $components = array('Auth');
function beforeFilter()
{
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Auth->loginRedirect = array('controller' => 'pages', 'display' => 'home');
$this->Auth->logoutRedirect = '/';
$this->Auth->authorize = 'controller';
$this->Auth->userScope = array('User.active' => 1);
}
function isAuthorized()
{
if (strpos($this->action, "admin_") != false)
{
if ($this->Auth->user('isAdmin') == '0')
{
return false;
}
}
return true;
}
}
You should check if you're overriding your Auth settings in your other controller.
First, to verify that isAuthorized() is being called, try putting a simple debug($this); die; in it.
If it is not dying, you're probably overriding it in some other controller (you're missing the parent::isAuthorized() call).
If it's not that, then you're probably doing that same thing with beforeFilter().
Additional to the Answer of dr Hannibal Lecter, there is another possible reason if you experience this problem (as i did ...):
If your controller is named tests_controller, the startUp method of the Auth-Component aborts without starting the authentication (at least in cakePHP 1.3.10 - haven't checked 2.x). So be sure that you never name a Controller tests_controller...
Excerpt from cake\libs\controller\components\auth.php
function startup(&$controller) {
$isErrorOrTests = (
strtolower($controller->name) == 'cakeerror' ||
(strtolower($controller->name) == 'tests' && Configure::read() > 0)
);
if ($isErrorOrTests) {
return true;
}
...
you need to make sure that 'Auth' is in the components array for that controller:
$this->components[] = 'Auth';
drop that in the constructor and it should work (unless, of course, it doesn't). Good luck!