0

I am facing an issue with Auth.redirect functionality in Cakephp 2.5.3. Following is the Scenario:

Scenario

There is an action (controller=>TalkComments, action=>add) which is login protected. The data is submitted to this action using POST HTML Method. Now, if the user is not logged in, it takes the user to login view. Once the user logs in, it successfully redirects the user to the required controller and action. The problem is, it does not send the POST data as well, because of which the add() function is not executed.

How can I make the Auth.redirect to also store my post data and send it once the redirectUrl is called.

Following is my code:

UsersController.php

class UsersController extends AppController {

//put your code here

public function beforeFilter() {
    parent::beforeFilter();
    $this->Auth->allow('add', 'login');
}

public function login() {
    if ($this->request->is('post')) {
        if ($this->Auth->login()) {
            return $this->redirect($this->Auth->redirectUrl());
        }
        $this->Session->setFlash(__('Invalid username or password, try again'));
    }
}

public function logout() {
    return $this->redirect($this->Auth->logout());
}
public function isAuthorized() {
    return true;
}
}

TalkCommentsController.php

class TalkCommentsController extends AppController {

//put your code here
public function add() {
    if ($this->request->is('post')) {
        $this->TalkComment->create();
        if ($this->TalkComment->save($this->request->data)) {
            $this->Session->setFlash(__('Comment Saved'));
            return $this->redirect($this->referer());
        }
        $this->Session->setFlash(__('Could not post comment'));
    }
}

public function isAuthorized() {
    return true;
}
}

Please do let me know if anything else is also required from my end.

Thanks in advance :)

addicted20015
  • 644
  • 7
  • 16
  • You could save yourself a lot of time by making the add action require to login first, before even the user can enter data to be saved... just a suggestion... – savedario Oct 13 '14 at 17:19

1 Answers1

1

The only way to make this work fine is to use Session Component !

AuthComponent won't let you access to the add action before you get Authenticated. So we'll use beForeFilter function in our AppController, like that's documented right here, as this:

  public function beforeFilter() {
    //i used strtolower function the test is a case sensitive & i do not know the output of $this->params['controller'] and $this->params['action'] in your application but in this case it will work fine !
    if((strtolower($this->params['controller']) == 'talkcomments') && (strltolower($this->params['action']) == 'add') && ($this->is('post')){
       //do not forget to use Session Component in AppController before to use!
       $this->Session->write('data',$this->data);   
    }
  }

Now the time to use our Session stored data to make add automatically a record !

  public function login() {

    if ($this->request->is('post')) {
      if ($this->Auth->login()) {
        $comment = $this->Session->read('data');
        if(isset($comment) && !empty($comment)){
          $this->loadModel('TalkComment');
          $this->TalkComment->set($comment);
          if($this->TalkComment->validate()){
            if($this->TalkComment->save($comment))
              $this->Session->setFlash(__('Comment Saved'));
            else
              $this->Session->setFlash(__('Could not post comment'));
          }
          else
            $this->Session->setFlash(__('Could not post comment'));
        }
        return $this->redirect($this->Auth->redirectUrl());
      }
      $this->Session->setFlash(__('Invalid username or password, try again'));
    }
  }

this should work for you as a charm.


If you have more than just one Add you need to make a DynamicAdd action like this:

private function DYnamicAdd($model, $data, $success_message, $error_message){
  $record = $data;
    if(isset($record) && !empty($record)){
      App::uses($model,'model');
      $this->$model->set($record);
      if($this->$model->validate()){
        if($this->$model->save($data))
          $this->Session->setFlash($success_message);
        else
          $this->Session->setFlash($error_message);
      }
      else
        $this->Session->setFlash($error_message);
}

Let's make an example:

we suppose that we have two controllers that have adds method, TestOnesController, TestTwosController ! Then the login method will be like this

public function login(){
  if ($this->request->is('post')) {
    if ($this->Auth->login()) {

      //in the case of TestOnesController
      $this->DynamicAdds('TestOne', $this->Session->read('TestOne'), 'Testone Saved', 'Could not post Testone');

      //in the case of TestTwosController
      $this->DynamicAdds('TestTwo', $this->Session->read('TestTwo'), 'Testtwo Saved', 'Could not post Testtwo');

      return $this->redirect($this->Auth->redirectUrl());
    }
    $this->Session->setFlash(__('Invalid username or password, try again'));
  }
}

In beforeFilter action at AppController !

Also a dynamic writing in the Session with:

public function beforeFilter(){
  //C1 C2 C3 C4 are the controllers you may have a Add method in
  if(in_array(strtolower($this->params['controller']), array('C1','C2','C3','C4')) && (strltolower($this->params['action']) == 'add') && ($this->is('post')){
   //ucfirst and singularize to extract the name of the model from controller name !
   $this->Session->write(ucfirst(Inflector::singularize($this->params['controller'])),$this->data);   
}
}
  • This is a solution. But I have many more such add() methods which take POST data. So by this, I will have to accommodate all of them here only, in the login() method. Also, I am writing the same functionality at two different places. Could there be any better way to do it? – addicted20015 Oct 13 '14 at 12:58
  • @addicted20015 check the answer's update i hope this will solve your problem you. – Abdelilah Lbardi Oct 13 '14 at 16:27