2015-08-24 30 views
11

W naszej aplikacji CakePHP 3 znaleźliśmy inne zachowanie. Jesteśmy pewni, że działa to dobrze w CakePHP 2, więc przypuszczam, że coś zmieniło się w nowej wersji.Przekierowanie Cakephp 3 przedFiltrem klasy nadrzędnej

Gdy użytkownik odwiedza ten URL: /b2controller/myMethod te metody run:

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

następnie użytkownik jest przekierowywany do tego adresu URL /ccontroller/myMethod10/

Ale musimy to:

Gdy użytkownik odwiedza /b2controller/myMethod i $isOk stan to true, a następnie przekieruj użytkownika do /ccontroller/myMethod10/, bez uruchamiania BController::beforeFilter(), B2Controller::beforeFilter(), B2Controller::myMethod() i BController::MyMethod2().

Nasz minimalny kod jest tak:

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

Jak mogę zrobić użytkownik, aby przekierować do innego działania kontrolera, z beforeFilter głównej klasie? Zwróć uwagę, że występuje przekierowanie. Ale użytkownik jest przekierowywany po wywołaniu myMethod() i myMethod2().

Należy również zauważyć, że istnieją inne kontrolery, takie jak CController, które używają funkcji przekierowania przed filtrem.

+0

Spróbuj zwrócić 'parent :: beforeFilter ($ event)' w 'BController'. 'Controller :: redirect' zwraca obiekt' Response', jeśli nie zwróci go w wywołaniu 'beforeFilter', Cake [nie będzie w stanie wykryć] (http://api.cakephp.org/3.0/ source-class-Cake.Controller.Controller.html # _startupProcess), które chcesz wykonać przekierowanie. – Holt

+0

Masz na myśli? 'class BController rozszerza funkcję AppController { beforeFilter (Event $ event) { return parent :: beforeFilter ($ event); } } ' – trante

+0

Tak. Nie jestem pewien, ale patrząc na źródło 'startupProcess', wygląda na to, że musisz coś zwrócić, aby zatrzymać proces żądania. – Holt

Odpowiedz

5

Oto 3 sposoby, które działa:

Metoda 1 - Przestawianie startupProcess w kontrolerze (ów)

zastąpić metodę startupProcess z AppController:

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

Jest to krótki i dość metoda czysta, więc wybrałbym tę, jeśli to możliwe. Jeśli to nie odpowiada Twoim potrzebom, zobacz dwie metody poniżej.

Uwaga: W przypadku zastosowania tej metody, składniki mogą nie zostać zainicjowane po obliczeniu $isOk, ponieważ inicjalizacją zajmuje się parent::startupProcess.

Metoda 2 - umożliwia wysłanie odpowiedzi z AppController:

Jedna łatwa, ale nie bardzo czysty sposób mogą zostać wysłać odpowiedź w AppController:

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

Metoda 3 - Wykorzystanie Dispatcher Filters

Bardziej "czystym" sposobem byłoby użycie Dispatcher Filters:

W src/Routing/Filtr/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 ; 
     } 
    } 
} 

W config/bootstrap.php:

DispatcherFactory::add('Redirect'); 

I można usunąć przekierowanie w AppController. To może być najczystszy sposób, jeśli jesteś w stanie obliczyć $isOk z Dispatcher Filter.

Pamiętaj, że jeśli masz zdarzenie beforeRedirect, nie będą one wywoływane tą metodą.


Edit: To była moja poprzednia odpowiedź, która nie działa bardzo dobrze, jeśli masz wiele B -jak kontrolerów.

Jak już mówiłem w komentarzach, należy zwrócić obiekt Response zwrócony przez . Jednym ze sposobów osiągnięcia tego celu jest w następujący sposób (nie wiem, czy jest lepiej/bardziej przejrzysty sposób to zrobić):

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 
    } 

} 

To działa na mnie, kod poniżej z if jest wykonywana tylko wtedy, gdy nie było przekierowania (parent::beforeFilter ($event) nie zwrócił obiektu Response).

Uwaga: nie wiem jak ustawić isOk, ale należy zachować ostrożność z nieskończoną pętlę przekierowania jeśli zadzwonisz $this->redirect() Dzwoniąc /ccontroller/mymethod10.

+0

To jest metoda 2, czy 'die()' jest dobre czy może '$ this-> response-> stop()' być użyte dla tego samego? – trante

+0

@trante W rzeczywistości '$ this-> response-> stop ($ status)' jest ściśle równoważne 'exit ($ status)' (patrz source), a 'exit' jest równoważne' die', więc kod będzie równoważny , Nie jestem pewien, czy jest to bardzo czysta metoda robienia tego, co chcesz. – Holt

+0

metoda 2 działała dobrze dla mnie, wielkie dzięki, sprawiła, że ​​mój dzień – dav

-2

Jeśli dowolne rozwiązanie nie działa, wykonaj poniższy kod.

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