12
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Codeigniter3で使っていたアレをCodeigniter4で使う

Last updated at Posted at 2020-04-29

Codeigniter4が3と違いすぎて辛い

ついにCodeigniter4が正式リリースされたが、

などを読んで「・・・」となった方も多いのではなだろうか。
正直、Codeigniter3のプログラムの移行はほぼ諦めモード。

ただ、今後の新たに制作すものについては触らないわけにもいかないので、マニュアルに記載がなく(分かりづらく)、かつ、私がよく使っているやり方をCodeigniter4で再現するための方法を記載しておく。

コントローラ、メソッド名の取得

routerから取得できるコントローラの値が名前空間に変わってしまっている。
あまりスマートじゃないが、やや強引に解決。

Codeigniter 3

$controller = $this->router->fetch_class();
$method = $this->router->fetch_method();

Codeigniter 4

$router = \Config\Services::router();

$controller = $router->controllerName();
// App\Controllers\Indexといったnamespaceが取得されるので「\」で分割して最後を取得し、小文字にしている
$controller = explode('\\', $controller);
$controller = strtolower(end($controller)); // ex) index

// methodはこれだけ
$method  = $router->methodName(); 

コントローラで変数を設定してビューで使っていたものを利用できるようにする

コントローラ(神クラス)内で $this->hoge = 'fuga' として利用して、グローバルにビューで使えるようにいた場合。
自分は上記のコントローラ名とメソッド名をここに入れていた。
(WordPressのようにbodyに入れてCSSでページごとの出し分けをしていた)
神はもういない。

Codeigniter 3

  • Controller(拡張コントローラにて設定の例)
application/core/My_Controller.php
class MY_Controller extends CI_Controller {
    public $hoge = '';
    public function __construct() {
        parent::__construct();
        $this->hoge = 'fuga';
    }
}

  • View
<?= $this->hoge; ?>

Codeigniter 4

  • ConfigのAppに変数を宣言
app/Config/App.php
// 追記
public static $hoge  = '';
  • 親コントローラに設定の例
app/Controllers/BaseController.php
namespace App\Controllers;
use CodeIgniter\Controller;
// use Config\App // App::$hoge でアクセスできるようにするなら追記 

class BaseController extends Controller
{
	protected $helpers = [];
	public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
	{
		// Do Not Edit This Line
		parent::initController($request, $response, $logger);
		
		// 追記
		Config\App::$hoge = 'fuga';
	}
}
  • Controller
echo \Config\App::$hoge
  • View
<?= Config\App::$hoge;?>

なお、これらは app/Config/View.php に記述し、 \Config\View::$hoge とすることもできる。
表示に関わる値を設定する場合はこちらに書くのも良いと思われる。

事前リダイレクト

URLヘルパにあった redirect('hoge') が使えなくなっており、コントローラの return(Response) として呼び出さなければならず、かなり戸惑う。
例えば、会員制サイトでログイン状況を見てログインしていなければログインページにリダイレクト、を例に取ると。

Codeigniter 3

  • Controller(拡張コントローラにて設定の例)
application/core/My_Controller.php
class MY_Controller extends CI_Controller {
    public function __construct() {
        parent::__construct();
        // セッションにログイン情報がなければリダイレクト
        if(!$this->session->userdata('isLogin')) {
            redirect('login');
        }
    }
}

Codeigniter 4

Codeigniter3で言うところのフックを作成する。
コントローラの読み込み前に実行されるため、上記のBaseControllerなどで処理した値は利用できない。

app/Config/Filters.php
    // 該当箇所に追記する

	public $aliases = [
		'login' => \App\Filters\LoginFilter::class,  // エイリアス追加
	];

	public $globals = [
		'before' => [
			// すべてのページで利用する場合
			'login', 
			// 除外ページ(URIパターン)を指定する場合
			'login' => ['except' => ['index/*', 'login/*']],
		],
	];
app/Filters/LoginFilter.php
<?php

namespace App\Filters;

use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;

class LoginFilter implements FilterInterface {

	public function before(RequestInterface $request) {
		$session = session();
		if (!$session->get('isLogin')) {
			// 除外ページを指定していない場合は除外ページ対象がどうかを判定してからリダイレクト
			return redirect()->to('/login');
		}
	}
}
  • その2、BaseControllerのコンストラクタ(initController)で設定

リダイレクト前にあれこれしたいならこちら。
私はフィルタだと逆に面倒になる処理を作っているのでこちらを利用している。

app/Controllers/BaseController.php

class BaseController extends Controller {
	protected $helpers = [];

	public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger) {
		// Do Not Edit This Line
		parent::initController($request, $response, $logger);

		$router = \Config\Services::router();
		Config\App::$M = $router->methodName();
		$_controller = explode('\\', $router->controllerName());
		Config\App::$C = strtolower(end($_controller));

		// ここから追記
		$session = session();
		if (!$session->get('isLogin') && App::$C !== 'login') {
			$response = redirect()->to('/login');
			$response->send();
			exit();
		}
	}
}

コントローラのコンストラクタを拡張コントローラより後に利用する

上記で設定している拡張コントローラ(BaseController)をコントローラのコンストラクタの後に実行したい。

Codeigniter 3

拡張コントローラは標準ではMY_Controllerとなっているので、

application/core/MY_Controller.php
class MY_Controller extends CI_Controller {
	public function __construct() {
		parent::__construct();
		// 先に行われるコンストラクタ処理
	}
}
application/controller/Hoge.php
class Hoge extends MY_Controller {
	public function __construct() {
		parent::__construct();
		// 後に行われるコンストラクタ処理
	}
}

CodeIgniter 4

ここまで読んでいれば分かると思うが、BaseController.php の initController を継承する必要がある。
普通にコンストラクタを利用してもエラーとなる(BaseControllerやシステムコントローラにコンストラクタが存在しないため)し、
parent::__construct(); を削除すれば自分のコンストラクタとしては利用できる)

app/Controllers/BaseController.php
class BaseController extends Controller {
	public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger) {
		parent::initController($request, $response, $logger);
		// 先に行われるコンストラクタ処理
	}
}
app/Controllers/Hoge.php
class Hoge extends BaseController {
	public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger) {
		parent::initController($request, $response, $logger);
		// 後に行われるコンストラクタ処理
	}
}

フォームヘルパの初期値(value)にNULLを入れられなくなった

form_input('hoge', $this->input->get('fuga')) のように、初期値にNULLになり得る変数 を利用するケースがあるが、これはCodeIgniter4ではエラーとなる。
原因はvalue部にタイプヒンティングが追加されたため。

良し悪しは兎も角、これをそのまま使いたいなら、以下のようにタイプヒンティングを(デメリットを承知した上で)消してやれば良い。

CodeIgniter4

app/Helpers/form_helper.php
// system\Helpers\form_helper.php からコピーしてタイプヒンティングを消すだけ
function form_input($data = '', $value = '', $extra = '', string $type = 'text'): string {
	$defaults = [
		'type' => $type,
		'name' => is_array($data) ? '' : $data,
		'value' => $value,
	];
	return '<input ' . parse_form_attributes($data, $defaults) . stringify_attributes($extra) . " />\n";
}

form_textarea や form_password 等も同様に設定してやれば良い。

GET、POSTの値を上書きできない

CodeIgnoter3は都度 $_GET$_POSTへアクセスしているため、上書きすると結果も変わるが、CodeIgniter4は最初にキャッシュしてしまうため、上書きしても変わらなず、再度キャッシュし直す必要がある。

CodeIgnoter3

echo $this->input->get('hoge');  // hoge
$_GET['hoge'] = 'fuga';
echo $this->input->get('hoge');  // fuga

CodeIgniter4

// 詳しくは system\HTTP\Request.php を参照
echo $this->request->getGet('hoge'); // hoge
$_GET['hoge'] = 'fuga';
echo $this->input->get('hoge');  // hoge(変わらない)
$this->request->setGlobal('get', $_GET);  // GETを再設定
// $this->request->setGlobal('post', $_POST);  // POSTを再設定
echo $this->request->getGet('hoge'); // fuga(変わった!)

Viewの内容を変数で受け取る

CodeIgnoter3

$hoge = $this->load->view('fuga', $piyo, true);

CodeIgniter4

trueとか必要なくなった。
(逆に出力するときに echo しなければならない)

$hoge = view('fuga', $piyo);

ここまではマニュアルに書いてあるが、development環境ではデバッグコードがHTMLのコメントとして取得されてしまうので、Codeigniter 4 でビューを変数に代入するときにデバッグコードが出ないようにする 必要がある。

return を返せないときのリダイレクト

CodeIgnoter3

// どんなときでもこれで行ける
$this->load->helper('url');
redirect('path/to');

CodeIgniter4

単純に書き換えると以下のURLに従い
https://codeigniter4.github.io/userguide/general/common_functions.html?highlight=redirect#redirect

// コントローラー内ならこれだけ
return redirect()->to('/path/to');

とすればリダイレクトができるが、例えば共通メソッド(private function)だったりモデル内でリダイレクトしたいという需要もある。
つまり、単純にreturnができない(コントローラーを終了できない)場面。
実はこれはエラーハンドリング側にマニュアルがある。
https://codeigniter4.github.io/userguide/general/errors.html?highlight=redirectexception

// returnが返せないときのリダイレクト
throw new \CodeIgniter\Router\Exceptions\RedirectException('/path/to'); // 302
throw new \CodeIgniter\Router\Exceptions\RedirectException('/path/to', 301); // 301

面倒ならこちらだけ使えば統一できる(エラーハンドリングだらけになるのを気持ち的に許容できれば)

12
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?