Cakephp 3在父类的beforeFilter中重定向

tra*_*nte 12 php redirect cakephp url-redirection cakephp-3.0

在我们的CakePHP 3应用程序中,我们发现了不同的行为.我们确信它在CakePHP 2中运行良好,所以我想在新版本中有些变化.

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

AppController::beforeFilter()  
BController::beforeFilter()  
B2Controller::beforeFilter()  
B2Controller::myMethod()  
B2Controller::myMethod2()    
Run Code Online (Sandbox Code Playgroud)

然后用户被重定向到此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() {
      ...
      ...
      ...
  }
}
Run Code Online (Sandbox Code Playgroud)

如何让用户从主类的beforeFilter重定向到另一个控制器操作?请注意,重定向发生.但是,用户呼叫后重定向myMethod()myMethod2().

另请注意,还有其他类似的控制器CController使用beforeFilter重定向行为.

Hol*_*olt 6

以下是3种有效的方法:

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

覆盖以下startupProcess方法AppController:

// In your AppController
public function startupProcess() {
    // Compute $isOk
    if ($isOk) {
        return $this->redirect('/c/myMethod10');
    }
    return parent::startupProcess();
}
Run Code Online (Sandbox Code Playgroud)

这是一个简短而且非常干净的方法,所以如果可以,我会选择这个.如果这不符合您的需求,请参阅下文.

注意:如果使用此方法,则在计算时可能无法初始化组件,$isOk因为初始化完成后parent::startupProcess.

方法2 - 发送响应AppController:

一种简单但不太干净的方式可能是从AppController::beforeFilter以下方式发送响应 :

public function beforeFilter(\Cake\Event\Event $event) {
    // Compute $isOk
    if ($isOk) {
        $this->response = $this->redirect('/c/myMethod10');
        $this->response->send();
        die();
    }
}
Run Code Online (Sandbox Code Playgroud)

方法3 - 使用 Dispatcher Filters

使用更"干净"的方式Dispatcher Filters:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

config/bootstrap.php:

DispatcherFactory::add('Redirect');
Run Code Online (Sandbox Code Playgroud)

你可以删除你的重定向AppController.如果你能够从中计算$isOk,这可能是最干净的方法DispatcherFilter.

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


编辑:这是我以前的答案,如果您有多个B类似的控制器,它将无法正常工作.

您需要返回返回的Response对象$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
    }

}
Run Code Online (Sandbox Code Playgroud)

if只有在没有重定向(parent::beforeFilter($event)没有返回Response对象)的情况下才执行代码.

注意:我不知道你如何计算isOk,但如果你在调用$this->redirect()时调用,请注意无限重定向循环/ccontroller/mymethod10.