Cakephp 3 перенаправляет в beforeFilter родительского класса

В нашем приложении CakePHP 3 мы обнаружили другое поведение. Мы уверены, что он хорошо работает в CakePHP 2, поэтому я предполагаю, что что-то изменилось в новой версии.

Когда пользователь посещает этот 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 в контроллере ( startupProcess )

Переопределить метод startupProcess для AppController :

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

Это короткий и довольно чистый метод, поэтому я мог бы пойти на этот, если возможно. Если это не соответствует вашим потребностям, см. Два метода ниже.

Примечание. Если вы используете этот метод, ваши компоненты могут не инициализироваться при вычислении $isOk поскольку инициализация выполняется с помощью parent::startupProcess .

Способ 2 – Отправка ответа от AppController :

Одним простым, но не совсем чистым способом может быть отправка ответа в вашем AppController :

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

Способ 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 ; } } } 

В config / bootstrap.php :

 DispatcherFactory::add('Redirect'); 

И вы можете удалить перенаправление в своем AppController . Это может быть самым чистым способом, если вы можете вычислить $isOk из Dispatcher Filter .

Обратите внимание, что если у вас есть событие beforeRedirect , они не будут запускаться с помощью этого метода.


Edit: Это был мой предыдущий ответ, который не очень хорошо работает, если у вас несколько 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 } } 

Это работает для меня, код ниже if выполняется только в том случае, если не было перенаправления ( parent::beforeFilter ($event) не возвращал объект Response ).

Примечание. Я не знаю, как вы устанавливаете isOk , но будьте осторожны с бесконечным циклом перенаправления, если вы вызываете $this->redirect () при вызове /ccontroller/mymethod10 .

Если какое-либо решение не работает, выполните следующий код.

 public function beforeFilter(Event $event) { // set $isOk variable if ($isOk == TRUE) { $url = '/'; //set url here echo '<script type="text/javascript">'; echo 'window.location="'.$url.'"'; echo '</script>'; exit; } $aa=1; $ab=2; }