父类的beforeFilter中的Cakephp 3重定向

父类的beforeFilter中的Cakephp 3重定向,php,cakephp,redirect,url-redirection,cakephp-3.0,Php,Cakephp,Redirect,Url Redirection,Cakephp 3.0,在我们的CakePHP 3应用程序中,我们发现了一种不同的行为。我们确信它在CakePHP2中工作得很好,所以我想在新版本中有些变化 当用户访问此url时:/b2controller/myMethod,这些方法将运行: AppController::beforeFilter() BController::beforeFilter() B2Controller::beforeFilter() B2Controller::myMethod() B2Controller::myMeth

在我们的CakePHP 3应用程序中,我们发现了一种不同的行为。我们确信它在CakePHP2中工作得很好,所以我想在新版本中有些变化

当用户访问此url时:
/b2controller/myMethod
,这些方法将运行:

AppController::beforeFilter()  
BController::beforeFilter()  
B2Controller::beforeFilter()  
B2Controller::myMethod()  
B2Controller::myMethod2()    
然后用户被重定向到此url
/ccontroller/myMethod10/

但我们需要:

当用户访问
/b2controller/myMethod
$isOk
条件为
true
,然后将用户重定向到
/ccontroller/myMethod10/
,而不运行
BController::beforeFilter()
b2controller::beforeFilter()
b2controller::myMethod()
BController::MyMethod2()

我们的最小代码如下所示:

class AppController {
  function beforeFilter(Event $event) {
        // set $isOk variable
        if ($isOk == TRUE) {
           return $this->redirect('/ccontroller/myMethod10/');
        }
        $aa=1;
        $ab=2;
  }
}

class BController extends AppController {
  function beforeFilter(Event $event) {
    parent::beforeFilter($event);

    $a=1;
    $b=2;
  }

  function myOtherMethod() {
      myOtherMethod2();
  }

  function myOtherMethod2() {
      ...
      ...
  }
}

class B2Controller extends BController {
  function beforeFilter(Event $event) {
    parent::beforeFilter($event);

    $m1=1;
    $m2=2;
  }

  function myMethod() {
      myMethod2();
  }

  function myMethod2() {
      ...
      ...
  }
}

class CController extends AppController {
  function beforeFilter(Event $event) {
    parent::beforeFilter($event);
  }

  function myMethod10() {
      ...
      ...
      ...
  }
}
如何让用户从主类的beforeFilter重定向到另一个控制器操作?请注意,会发生重定向。但用户在调用
myMethod()
myMethod2()
后会被重定向


还请注意,还有其他控制器,如
CController
,使用beforeFilter重定向行为。

以下是3种有效的方法:

方法1-在控制器中覆盖
startupProcess
覆盖
AppController
startupProcess
方法:

// In your AppController
public function startupProcess() {
    // Compute $isOk
    if ($isOk) {
        return $this->redirect('/c/myMethod10');
    }
    return parent::startupProcess();
}
public function beforeFilter(\Cake\Event\Event $event) {
    // Compute $isOk
    if ($isOk) {
        $this->response = $this->redirect('/c/myMethod10');
        $this->response->send();
        die();
    }
}
这是一个简短而干净的方法,所以如果可以的话,我会选择这个方法。如果这不符合您的需要,请参见下文

注意:如果使用此方法,在计算
$isOk
时可能不会初始化组件,因为初始化是由
parent::startupProcess
完成的

方法2-从
AppController
发送响应: 一种简单但并非真正干净的方法可能是从
AppController::beforeFilter
发送响应:

// In your AppController
public function startupProcess() {
    // Compute $isOk
    if ($isOk) {
        return $this->redirect('/c/myMethod10');
    }
    return parent::startupProcess();
}
public function beforeFilter(\Cake\Event\Event $event) {
    // Compute $isOk
    if ($isOk) {
        $this->response = $this->redirect('/c/myMethod10');
        $this->response->send();
        die();
    }
}
方法3-使用 更“干净”的方法是使用:

在src/Routing/Filter/RedirectFilter.php中

<?php

namespace App\Routing\Filter;

use Cake\Event\Event;
use Cake\Routing\DispatcherFilter;

class RedirectFilter extends DispatcherFilter {

    public function beforeDispatch(Event $event) {
        // Compute $isOk
        if ($isOk) {
            $response = $event->data['response'];
            // The code bellow mainly comes from the source of Controller.php
            $response->statusCode(302);
            $response->location(\Cake\Routing\Router::url('/c/myMethod10', true));
            return $response;
        }
    }
}
DispatcherFactory::add('Redirect');
您可以在
AppController
中删除重定向。如果您能够从
DispatcherFilter
计算
$isOk
,这可能是最干净的方法

请注意,如果您有beforeRedirect事件,则此方法不会触发这些事件


编辑:这是我以前的答案,如果您有多个类似
B
的控制器,则该答案不太适用

您需要返回由
$this->redirect()
返回的
响应
对象。实现这一目标的一种方法是执行以下操作:

class BController extends AppController {

    public function beforeFilter(\Cake\Event\Event $event) {
        $result = parent::beforeFilter($event);
        if ($result instanceof \Cake\Network\Response) {
            return $result;
        } 
        // Your stuff
    }

}
只有在没有重定向(
parent::beforeFilter($event)
未返回
响应
对象)时,才会执行
if
下面的代码


注意:我不知道如何计算
isOk
,但如果调用
$this->redirect()
时调用
/ccontroller/mymethod10

请在
BController
中尝试返回
父对象::预过滤($event)
Controller::redirect
返回一个
响应
对象,如果在
beforeFilter
调用中未返回该对象,则表明要执行重定向。您的意思是这样的<代码>类BController扩展AppController{函数beforeFilter(Event$Event){返回父级::beforeFilter($Event);}}Yes。我一点也不确定,但看看
startupProcess
的源代码,似乎您需要返回一些东西才能停止请求过程。我更新了代码。假设我更改了
BController::beforeFilter()
,并在该函数中添加了return。在这种情况下,如果
$isOk
为false,则
BController::beforeFilter()
中的剩余代码将无法工作。我终于能够在一个工作的CakePHP安装上测试您的代码,请参阅我的答案。方法2是
die()
很好,或者可以
$this->response->stop()
用于相同的事情吗?@trante实际上
$this->response->stop($status)
严格等同于
退出($status)
(参见源代码),而
退出
相当于
死亡
,所以代码是等效的,我不确定这是一个非常干净的方法来做你想做的事情,非常感谢,让我开心