В нашем приложении 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 метода, которые работают:
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
.
AppController
: Одним простым, но не совсем чистым способом может быть отправка ответа в вашем AppController
:
public function beforeFilter (\Cake\Event\Event $event) { // Compute $isOk if ($isOk) { $this->response = $this->redirect('/c/myMethod10') ; $this->response->send () ; die () ; } }
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; }