Zend Framework

::assertRedirectTo does not work as expected

Details

  • Type: Bug Bug
  • Status: Resolved Resolved
  • Priority: Major Major
  • Resolution: Not an Issue
  • Affects Version/s: 1.7.3
  • Fix Version/s: None
  • Component/s: Zend_Amf
  • Labels:
    None

Description

The assertRedirectTo does not work as expected.

Cases:

1. Empty action with redirector, works fine
public function indexAction(){
     $this->_helper->redirector('login');
}
2. Action with other code and view renderer, works fine
public function indexAction(){
     if( !$this->_request->isPost() ){
          $this->_helper->redirector('login');
     }
     
     // Do other stuff
}
3. Action with other multiple redirects aren't broken, unexpected behavior
public function indexAction(){
     if( !$this->_request->isPost() ){
          $this->_helper->redirector('identify');
     }
     
     // Do other stuff

     if( $this->_request->getPost('user_id') ){
           $this->_helper->redirector('login');
     } else{
            $this->_helper->redirector('logout');
     }

}

In the last case the redirection in the browser goes well, but in the unittest it validates with the last redirection.
When return null; is put below the redirector, the problem is resolved, but it doesn't look like a good solution.

Also the redirectAndExit function causes the unittest to crash.

EDIT

Why can't I find a @# reply button!!

@below: That does resolve the issue. But it's weird that the first redirect does work as expected and with testing it doesn't. I think this should be more clear in the documentation. I can imagine that more people will have problems with this. It's stated in the docs, but not explicitly. (Some examples uses the return).

Issue Links

Activity

Hide
Matthew Weier O'Phinney added a comment -

The primary issue I'm seeing right now is actually in your code. When you call _forward() or one of the _redirect() or redirector methods, you should always return immediately; if you do not do so, the action continues to execute, which can lead to the problems you're describing.

Can you do the following: in each place above where you call $this->_helper->redirector(), change the call to:

return $this->_helper->redirector(...);

and let me know if that corrects the issue.

Show
Matthew Weier O'Phinney added a comment - The primary issue I'm seeing right now is actually in your code. When you call _forward() or one of the _redirect() or redirector methods, you should always return immediately; if you do not do so, the action continues to execute, which can lead to the problems you're describing. Can you do the following: in each place above where you call $this->_helper->redirector(), change the call to:
return $this->_helper->redirector(...);
and let me know if that corrects the issue.
Hide
Rafal Radulski added a comment -

I can confirm this bug. You can reproduce it by calling Zend_Controller_Action_Helper_Redirector::setUseAbsoluteUri(true). Then perform redirect and check for the redirect.

By the way, HTTP standard requires use of absolute URL for redirect (in location header).

Show
Rafal Radulski added a comment - I can confirm this bug. You can reproduce it by calling Zend_Controller_Action_Helper_Redirector::setUseAbsoluteUri(true). Then perform redirect and check for the redirect. By the way, HTTP standard requires use of absolute URL for redirect (in location header).
Hide
Kim Blomqvist added a comment - - edited

I can also confirm this unexpected behaviour in my unit tests. Consider the following controller and test ...

class AccountController extends Zend_Controller_Action
{
    /** @var Application_Model_Account */
    protected $_account;

    public function init()
    {
        // may redirect, thus placed at the beginning ...
        $id = $this->_getId();

        $account = new Application_Model_Account();
        $this->_getAccountMapper()->find($id, $account);

        ...

        $this->_account = $account;
    }

    protected function _getId()
    {
        $request = $this->getRequest();
        if (($id = $request->getParam('id', null)) === null) {
            $this->_helper->redirector('index', 'index');
        }
        return (int) $id;
    }
}


class AccountControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
    ...

    public function testIndexActionShouldRedirectIfAccountIdNotGiven()
    {
        $this->dispatch('/account');
        $this->assertRedirectTo('/'); // FAILS
    }
}
Show
Kim Blomqvist added a comment - - edited I can also confirm this unexpected behaviour in my unit tests. Consider the following controller and test ...
class AccountController extends Zend_Controller_Action
{
    /** @var Application_Model_Account */
    protected $_account;

    public function init()
    {
        // may redirect, thus placed at the beginning ...
        $id = $this->_getId();

        $account = new Application_Model_Account();
        $this->_getAccountMapper()->find($id, $account);

        ...

        $this->_account = $account;
    }

    protected function _getId()
    {
        $request = $this->getRequest();
        if (($id = $request->getParam('id', null)) === null) {
            $this->_helper->redirector('index', 'index');
        }
        return (int) $id;
    }
}


class AccountControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
    ...

    public function testIndexActionShouldRedirectIfAccountIdNotGiven()
    {
        $this->dispatch('/account');
        $this->assertRedirectTo('/'); // FAILS
    }
}
Hide
Kim Blomqvist added a comment - - edited

I overlooked Metthew's comment ...

Can you do the following: in each place above where you call $this->_helper->redirector(), change the call to:

return $this->_helper->redirector(...);
and let me know if that corrects the issue.

This fix the problem. The new AccountController looks like this ...

public function init()
{
    $id = $this->_request->getParam('id', null);

    $mapper = Application_Model_Mapper::factory('Account');
    $this->_account = $mapper->find($id);
}

public function indexAction()
{
    if (!$this->_account instanceof Application_Model_Account || $this->_account->id === null) {
        $this->_helper->flashMessenger(
            new Application_Model_FlashError('Account does not exist'));
        return $this->_helper->redirector('index', 'index');
    }

    // ...
}
Show
Kim Blomqvist added a comment - - edited I overlooked Metthew's comment ...
Can you do the following: in each place above where you call $this->_helper->redirector(), change the call to:
return $this->_helper->redirector(...);
and let me know if that corrects the issue.
This fix the problem. The new AccountController looks like this ...
public function init()
{
    $id = $this->_request->getParam('id', null);

    $mapper = Application_Model_Mapper::factory('Account');
    $this->_account = $mapper->find($id);
}

public function indexAction()
{
    if (!$this->_account instanceof Application_Model_Account || $this->_account->id === null) {
        $this->_helper->flashMessenger(
            new Application_Model_FlashError('Account does not exist'));
        return $this->_helper->redirector('index', 'index');
    }

    // ...
}
Hide
Kim Blomqvist added a comment -

I think this issue can be resolved as not an issue. The documentation has been updated in ZF-7455.

Show
Kim Blomqvist added a comment - I think this issue can be resolved as not an issue. The documentation has been updated in ZF-7455.

People

Vote (1)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: