表題の通り。これ結構ハマったので、技術メモとして残しておきます。
【前提】子クラスのController内でbeforeFilter()を定義し、parent::beforeFilter()を呼び出してredirect()をさせる処理がある
AppControllerを継承するUsersControllerがあったとします。中身はこんな感じ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php namespace App\Controller; use App\Controller\AppController; use Cake\ORM\TableRegistry; use Cake\Event\Event; class UsersController extends AppController { public function beforeFilter(Event $event) { parent::beforeFilter($event); } public function index() { $users = $this->Users->find() ->where(['deleted' => 0]) ->all(); $this->set(compact('users')); } } |
AppControllerの中身はこんな感じ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php namespace App\Controller; use Cake\Controller\Controller; use Cake\Event\Event; use Cake\Core\Configure; class AppController extends Controller { public function beforeFilter(Event $event) { if ($this->name == 'Users' && $this->request->action == 'index') { $this->Flash->error(__('アクセス権限がありません。')); return $this->redirect('/login'); } } } |
これでUsersControllerのindex()にアクセスしようとすると、index()の処理を通過せずに/loginにリダイレクトされることが期待できそうです。
【問題】リダイレクトはされたが、なぜかUsersControllerのindex()内を通過してからリダイレクトされてしまう
実際リダイレクトされるにはされたのですが、どういうわけかUsersControllerのindex()の処理を通過してからリダイレクトされてしまうという現象が起こりました。なぜか?
【解決方法】子クラスからparent::beforeFilter()を呼び出しその中のredirect()を即実行したければ、子クラス内でparent::beforeFilter()からreturnされるResponseオブジェクトを受け取りさらにreturnせよ
つまり、下記のように書き換えるのが正解らしいです:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?php namespace App\Controller; use App\Controller\AppController; use Cake\ORM\TableRegistry; use Cake\Event\Event; class UsersController extends AppController { public function beforeFilter(Event $event) { $result = parent::beforeFilter($event); if ($result) { return $result; } } public function index() { $users = $this->Users->find() ->where(['deleted' => 0]) ->all(); $this->set(compact('users')); } } |
解決の際に参考にした記事はこちら:https://github.com/cakephp/cakephp/issues/6705