Cakephp 3 redirige en beforeFilter de la clase padre

En nuestra aplicación CakePHP 3 encontramos un comportamiento diferente. Estamos seguros de que funcionó bien en CakePHP 2, así que supongo que algo cambió en la nueva versión.

Cuando el usuario visita esta url: /b2controller/myMethod , se /b2controller/myMethod estos métodos:

 AppController::beforeFilter() BController::beforeFilter() B2Controller::beforeFilter() B2Controller::myMethod() B2Controller::myMethod2() 

a continuación, el usuario se redirige a este url /ccontroller/myMethod10/

Pero necesitamos esto:

Cuando el usuario visita /b2controller/myMethod y $isOk condición es true , entonces redirige al usuario a /ccontroller/myMethod10/ , sin ejecutar BController::beforeFilter() , B2Controller::beforeFilter() , B2Controller::myMethod() y BController::MyMethod2() .

Nuestro código mínimo es así:

 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() { ... ... ... } } 

¿Cómo puedo hacer que el usuario redirija a otra acción del controlador desde el filtro anterior de la clase principal? Tenga en cuenta que ocurre la redirección. Pero el usuario se redirige después de llamar a myMethod() y myMethod2() .

También tenga en cuenta que hay otros controladores como CController que utilizan el comportamiento de redireccionamiento de beforeFilter.

Aquí hay 3 métodos que funcionan:

Método 1 – Anular startupProcess en su (s) controlador (es)

Reemplazar el método AppController de AppController :

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

Este es un método breve y bastante limpio, así que iría por este si es posible. Si esto no coincide con su necesidad, consulte los dos métodos a continuación.

Nota: Si usa este método, es posible que sus componentes no se inicialicen cuando calcule $isOk dado que parent::startupProcess realiza la inicialización.

Método 2: envíe la respuesta desde AppController :

Una manera fácil pero no muy limpia puede ser enviar la respuesta en su AppController :

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

Método 3 – Usar Dispatcher Filters

Una forma más “limpia” sería usar Dispatcher Filters :

En src / Routing / Filter / RedirectFilter.php :

 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 ; } } } 

En config / bootstrap.php :

 DispatcherFactory::add('Redirect'); 

Y puede eliminar la redirección en su AppController . Esta puede ser la forma más limpia si puede calcular $isOk desde el Dispatcher Filter .

Tenga en cuenta que si tiene evento beforeRedirect , estos no se activarán con este método.


Editar: Esta fue mi respuesta anterior, que no funciona muy bien si tienes múltiples controladores tipo B

Como decía en los comentarios, debe devolver el objeto Response devuelto por $this->redirect () . Una forma de lograr esto es haciendo lo siguiente (no sé si hay una forma mejor / más limpia de hacerlo):

 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 } } 

Esto funciona para mí, el código debajo de if se ejecuta solo si no hubo redirección ( parent::beforeFilter ($event) no devolvió un objeto Response ).

Nota: no sé cómo establecer isOk , pero tenga cuidado con el bucle de redirección infinito si llama $this->redirect () al llamar a /ccontroller/mymethod10 .

Si alguna solución no funciona, haga el siguiente código.

 public function beforeFilter(Event $event) { // set $isOk variable if ($isOk == TRUE) { $url = '/'; //set url here echo ''; exit; } $aa=1; $ab=2; }