2015-08-24 8 views
11

Nella nostra applicazione CakePHP 3 abbiamo riscontrato un comportamento diverso. Siamo sicuri che ha funzionato bene in CakePHP 2, quindi suppongo che qualcosa sia cambiato nella nuova versione.Cakephp 3 reindirizza in beforeFiltro della classe madre

Quando l'utente visita questo URL: /b2controller/myMethod, questi metodi funzionano:

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

allora l'utente viene reindirizzato a questo URL /ccontroller/myMethod10/

Ma abbiamo bisogno di questo:

Quando le visite degli utenti /b2controller/myMethod e $isOk condizione è true, quindi reindirizzare l'utente a /ccontroller/myMethod10/, senza eseguire BController::beforeFilter(), B2Controller::beforeFilter(), B2Controller::myMethod() e BController::MyMethod2().

Il nostro codice minimo è come questo:

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

Come posso fare all'utente di reindirizzare ad un altro azione di controllo, dal beforeFilter di classe principale? Si noti che si verifica il reindirizzamento. Ma l'utente viene reindirizzato dopo aver chiamato myMethod() e myMethod2().

Si noti inoltre che esistono altri controller come CController che utilizzano il comportamento di reindirizzamento beforeFilter.

+0

Provare a restituire 'parent :: beforeFilter ($ event)' in 'BController'. 'Controller :: redirect' restituisce un oggetto' Response', se non lo si restituisce nella chiamata 'beforeFilter', Cake [non sarà in grado di rilevare] (http://api.cakephp.org/3.0/ source-class-Cake.Controller.Controller.html # _startupProcess) che si desidera eseguire un reindirizzamento. – Holt

+0

Intendi questo? 'classe BController estende la funzione AppController { beforeFilter (Event $ event) { return parent :: beforeFilter ($ event); } } – trante

+0

Sì. Non ne sono affatto sicuro, ma guardando l'origine di 'startupProcess', sembra che tu debba restituire qualcosa per fermare il processo di richiesta. – Holt

risposta

5

Qui ci sono 3 metodi che funziona:

Metodo 1 - override startupProcess nel controller (s)

l'override del metodo di AppControllerstartupProcess:

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

Questa è una breve e bella metodo pulito, quindi vorrei andare per questo, se possibile. Se questo non corrisponde alle tue necessità, vedi i due metodi seguenti.

Nota: se si utilizza questo metodo, i componenti potrebbero non essere inizializzati quando si calcola $isOk poiché l'inizializzazione viene eseguita da parent::startupProcess.

Metodo 2 - Inviare la risposta da AppController:

modo

Una facile, ma in realtà non pulito può essere quello di inviare la risposta nella vostra AppController:

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

Metodo 3 - Utilizzare Dispatcher Filters

Un modo più "pulito" sarebbe utilizzare Dispatcher Filters:

In src/Routing/filtro/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 ; 
     } 
    } 
} 

In config/bootstrap.php:

DispatcherFactory::add('Redirect'); 

E si può rimuovere il reindirizzamento nel vostro AppController. Questo può essere il modo più pulito se sei in grado di calcolare $isOk dal Dispatcher Filter.

Si noti che se si dispone di evento beforeRedirect, questi non verranno attivati ​​con questo metodo.


Edit: Questa era la mia risposta precedente, che non funziona molto bene se si dispone di più B -come controller.

Come dicevo nei commenti, è necessario restituire l'oggetto Response restituito da $this->redirect(). Un modo per raggiungere questo è facendo la seguente (non so se c'è un/modo più pulito migliore per farlo):

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 
    } 

} 

Questo funziona per me, il codice soffietto il if viene eseguito solo se non ci sono stati reindirizzamenti (parent::beforeFilter ($event) non ha restituito un oggetto Response).

Nota: Io non so come si imposta isOk, ma attenzione del ciclo reindirizzamento infinito se si chiama $this->redirect() quando si chiama /ccontroller/mymethod10.

+0

Il metodo 2, è 'die()' è buono o può '$ this-> response-> stop()' essere usato per la stessa cosa? – trante

+0

@trante In realtà '$ this-> response-> stop ($ status)' è strettamente equivalente a 'exit ($ status)' (vedi sorgente), e 'exit' è equivalente a 'die' quindi il codice sarebbe equivalente , Non sono sicuro che questo sia un metodo molto pulito per fare ciò che vuoi. – Holt

+0

metodo 2 ha funzionato bene per me, grazie mille, ha reso la mia giornata – dav

-2

Se la soluzione non funziona, seguire il codice seguente.

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