#爆速・軽量フレームワーク codeigniter PHP 開発

仕事の関係で laravel も使ったことありますが、最初はあれこれ設定に悩まれましたが、1 年くらい使ったら laravel の便利さ強さがわかりました。
codeigniter になれたせいかわからないけど、やっぱり codeigniter のクエリビルダーの使いやすさはわすれられなくて、twig テンプレエンジンと組み合わせると最強最高のコーディング体験になります。久々 codeigniter やってなかったこともあり、メモもいままでなかったので、自由研究しながら、1 年ぶりに codeigniter でプロジェクト立ち上げです。
laravel との比べはしないけど、主に codeigniter の便利機能と忘れがちのところメモります。

#htaccess 設定して url にある index.php 削除

.htaccess ファイル

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]

#モデル query builder

laravel のクエリビルダーも使ったことありますが、やはり codeigniter のほうが抜群に使いやすい

codeigniter 3.2 公式 query builder 編(opens new window)

#insert した行の id を返却 insert_id

insert_id は laravel の insertGetId() のように codeigniter model に insert した行の id 取得可能

User_model.php




 


    public function insertRow($data)
    {
        $this->db->table($this->table)->insert($data);
        return $this->db->insert_id();
    }

#コンパイル sql 文出力 get_compiled_select

get_compiled_select は laravel の toSql()のように codeigniter model にコンパイルしたクエリ sql 文を返却

echo $this->db->select('title, content, date')->get_compiled_select();
// 出力: SELECT title, content, date FROM mytable

#where の4つの使い方

  • key,value 個別指定
$this->db->where('column_key', $value);
  • イコールじゃないパターン
$this->db->where('column_key !=', $value);
$this->db->where('id <', $id);
  • 連想配列指定
$this->db->where(['id' => $id]);
  • string 生の文字列渡す

ちょっと違和感感じるけど、文字列も配列もそのままwhereに掘り込んだら動いてくれる、PHP らしいプログラム!

$where = "name='Joe' AND status='boss' OR status='active'";
$this->db->where($where);

// $this->db->where() にはオプションで第3の引数を渡すこともできます。
// FALSE を渡した場合、CodeIgniter はフィールド名やテーブル名を守りません。
$this->db->where('MATCH (field) AGAINST ("value")', NULL, FALSE);

#get_where

get_where(テーブル名,where 配列,limit,offset)

// get_where(テーブル名,where 配列,limit,offset)
$this->db->get_where('table_name', ['id' => $id], $limit, $offset);

// 以下のものと同じ
$this->db->where(['id' => $id])
         ->limit($limit)
         ->offset($offset)
         ->get('table_name);

#dotenv 使う

laravel 使い慣れてたら、.envは便利でいいですね。codeigniter もデフォルトで入れるべきだと思うくらい。
調べてたら composer に dotenv があったので、codeigniter に dotenv 入れてみる

#方法 1 vlucas/phpdotenv

  • 環境:CodeIgniter3
  • ライブラリ: vlucas/phpdotenv
  • php: ^5.5.9 || ^7.0

codeigniter の hook 機能使って、pre_systemシステム読み込む前に env の読み込んで初期設定することで、グローバルに env 内容展開。

#vlucas/phpdotenv インストール

composer require vlucas/phpdotenv

#config ファイル設定

config/config.phphook 有効化

// composer autoload有効化
$config['composer_autoload'] = TRUE;

// hooks有効化
$config['enable_hooks'] = TRUE;

#hooks ファイル編集

codeigniter/config/hooks.php






 












<?php
defined('BASEPATH') or exit('No direct script access allowed');

$hook['pre_system'] = function () {
    try {
        $dotenv = Dotenv\Dotenv::createImmutable(APPPATH . '../');  // 自分の環境に合わせてenvファイルのパス設定
        $dotenv->load();
    } catch (Exception $e) {
        //
    }

    function env(string $key, $default = null)
    {
        $value = $_ENV[$key];
        return ($value) ? $value : $default;
    }
};

ポイント:パス設定

createImmutable で.env ディレクトリまで指定

.env

DB_HOST=localhost
DB_USER=root
DB_PASS=
DB_NAME=test2

config/database.php

$db['default'] = array(
    'dsn' => '',
    'hostname' => env('DB_HOST'),
    'username' => env('DB_USER'),
    'password' => env('DB_PASS'),
    'database' => env('DB_NAME'),

完了!任意の場所からenv()使えます。

config/config.php の中で使えない

どこでも env 可能だと思って config/config.php の中は設定したらエラーになった

config.php の中で base_url 設定も env から呼び込めばいいなあと思って設定して見ました

$config['base_url'] = 'http://' . env('BASE_URL');

#Call to undefined function env()エラー

Fatal error: Uncaught Error: Call to undefined function env() in C:\xampp\htdocs\hclo\application\config\config.php:26 Stack trace: #0 C:\xampp\htdocs\hclo\system\core\Common.php(249): require() #1 C:\xampp\htdocs\hclo\system\core\Common.php(300): get_config() #2 C:\xampp\htdocs\hclo\system\core\Common.php(171): config_item('subclass_prefix') #3 C:\xampp\htdocs\hclo\system\core\Common.php(652): load_class('Exceptions', 'core') #4 [internal function]: _exception_handler(Object(Error)) #5 {main} thrown in C:\xampp\htdocs\hclo\application\config\config.php on line 26

Fatal error: Uncaught Error: Call to undefined function env() in C:\xampp\htdocs\hclo\application\config\config.php:26 Stack trace: #0 C:\xampp\htdocs\hclo\system\core\Common.php(249): require() #1 C:\xampp\htdocs\hclo\system\core\Common.php(300): get_config() #2 C:\xampp\htdocs\hclo\system\core\Common.php(171): config_item('subclass_prefix') #3 C:\xampp\htdocs\hclo\system\core\Common.php(617): load_class('Exceptions', 'core') #4 C:\xampp\htdocs\hclo\system\core\Common.php(689): _error_handler(1, 'Uncaught Error:...', 'C:\\xampp\\htdocs...', 26) #5 [internal function]: _shutdown_handler() #6 {main} thrown in C:\xampp\htdocs\hclo\application\config\config.php on line 26

結論: config 内に env 使うことができない

SERVER の HTTP_HOST 指定しました。

$config['base_url'] = $_SERVER['HTTP_HOST'];

#方法 2 symfony/dotenv

  • 環境:CodeIgniter3
  • ライブラリ: symfony/dotenv
  • php: ^7.2.5

symfony dotenv は、シンフォニーチームが開発した php システムが利用できる.env ファイル読み込むためのコンポーネントです。
MY_Controller で実装すると、controller 読み込んでからでないと env 設定使えないので、hook の pre_system 使うべき
vlucas/phpdotenv もいけるけど、個人的に symfony が好きなシンフォニー派なので、symfony/dotenv 使います。愛用 twig もシンフォニー製
ただ、php 7.2 からはちょっとバージョン高くない?

env function作成しておくと便利に使える

#symfony/dotenv インストールと初期設定

上記の vlucas/phpdotenv と一緒で割愛

#hooks 設定

codeigniter/config/hooks.php








 











<?php
defined('BASEPATH') or exit('No direct script access allowed');
use Symfony\Component\Dotenv\Dotenv;

$hook['pre_system'] = function () {
    try {
        $dotenv = new Dotenv();
        $dotenv->load(APPPATH . '../.env'); // 自分の環境に合わせてenvファイルのパス設定
    } catch (Exception $e) {
        //
    }

    function env(string $key, $default = null)
    {
        $value = $_ENV[$key];
        return $value ?? $default;
    }
};

ポイント

.env ファイルまでパス設定する必要がある

.env

DB_HOST=localhost
DB_USER=root
DB_PASS=
DB_NAME=test2

config/database.php

$db['default'] = array(
    'dsn' => '',
    'hostname' => env('DB_HOST'),
    'username' => env('DB_USER'),
    'password' => env('DB_PASS'),
    'database' => env('DB_NAME'),

完了!任意の場所からenv()使えます。

#Message: Class 'Symfony\Component\Dotenv\Dotenv' not found エラー発生




 



An uncaught Exception was encountered
Type: Error

Message: Class 'Symfony\Component\Dotenv\Dotenv' not found

Filename: /Users/t/Documents/www.com/application/config/hooks.php

windows では動いてくれてたけど、mac では動かない!あるあるパターンですけど、dotenv not found って composer install 忘れたかなあと思ったりしますが、install コマンド走らせても特に解消しない
composer update かけてみたら原因がわかりました。

 












$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - symfony/dotenv v5.0.4 requires php ^7.2.5 -> your PHP version (7.1.23) does not satisfy that requirement.
    - symfony/dotenv v5.0.3 requires php ^7.2.5 -> your PHP version (7.1.23) does not satisfy that requirement.
    - symfony/dotenv v5.0.2 requires php ^7.2.5 -> your PHP version (7.1.23) does not satisfy that requirement.
    - symfony/dotenv v5.0.1 requires php ^7.2.5 -> your PHP version (7.1.23) does not satisfy that requirement.
    - symfony/dotenv v5.0.0 requires php ^7.2.5 -> your PHP version (7.1.23) does not satisfy that requirement.
    - Installation request for symfony/dotenv ^5.0 -> satisfiable by symfony/dotenv[v5.0.0, v5.0.1, v5.0.2, v5.0.3, v5.0.4].

原因はドキュメントに書いてあります。requires php: ^7.2.5

うん、ドキュメントはちゃんと読むべき!

比べてどうするちなみに、vlucas/phpdotenv の php 環境要件はずっと低いけど、php: ^5.5.9 || ^7.0で動きます。
vlucas/phpdotenv のほうが人気の理由がこれにあるかもしれません。

#ライフサイクル

codeigniter のライフサイクル知りたかったけど、調べても見つからなくて、そういえば laravel はどうかなあと laravel のライフサイクルを調べました。

laravel ライフサイクル

  1. public/index.php
  2. Http/Console カーネル($bootstrappersmiddleware)
    リクエスト実行前$bootstrappers 配列に定義しているサービスプロバイダ,env,config,Facadeとかがここでこ見込まれる。
  3. Router
  4. Controller
  5. View

laravel$bootstrappers

vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php

protected $bootstrappers = [
    \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
    \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
    \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
    \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
    \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
    \Illuminate\Foundation\Bootstrap\BootProviders::class,
];

laravel config 読み込み LoadConfiguration

vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/LoadConfiguration.php

public function bootstrap(Application $app)
{
     $items = [];

     if (file_exists($cached = $app->getCachedConfigPath())) {
         $items = require $cached;

         $loadedFromCache = true;
     }

     $app->instance('config', $config = new Repository($items));

     if (! isset($loadedFromCache)) {
         $this->loadConfigurationFiles($app, $config);
     }

     $app->detectEnvironment(function () use ($config) {
         return $config->get('app.env', 'production');
     });

     date_default_timezone_set($config->get('app.timezone', 'UTC'));

     mb_internal_encoding('UTF-8');
}

#codeigniter のフック

フレームワークコアの拡張として紹介されていますが、非常にわかりやすくて使いやすい!これですぐに middleware やアクセス トラッキング、IP 制限など作れてしまう!

#フック有効化

application/config/config.phpファイル編集でフックの有効化$config['enable_hooks'] = TRUE;

#フック定義

application/config/hooks.php

<?php
defined('BASEPATH') or exit('No direct script access allowed');
use Symfony\Component\Dotenv\Dotenv;

$hook['pre_controller'] = array(
        'class'    => 'MyClass',
        'function' => 'Myfunction',
        'filename' => 'Myclass.php',
        'filepath' => 'hooks',
        'params'   => array('beer', 'wine', 'snacks')
);

$hook['pre_system'] = function () {
    try {
        $dotenv = new Dotenv();
        $dotenv->load(APPPATH . '../.env');
    } catch (Exception $e) {
        //
    }

    function env(string $key, $default = null)
    {
        $value = $_ENV[$key];
        return $value ?? $default;
    }
};

#フックポイント

  • pre_system

    システム実行中の非常に早い段階で呼び出されます。ベンチマーククラスと フッククラスだけがこの時点でロードされています。ルーティングや 他のプロセスは実行されていません。

  • pre_controller

    いずれかのコントローラが呼び出される直前に呼び出されます。 すべての基本クラス、ルーティング、およびセキュリティチェックは実行済みです。

  • post_controller_constructor

    コントローラがインスタンス化された直後に、 しかしメソッド呼び出しをする前に呼び出されます。

  • post_controller

    コントローラの実行が完全に終わった直後に呼び出されます。

  • display_override

    _display()メソッドをオーバーライドします。システム実行の最後で ウェブブラウザに確定ページを送信するために使用されるものです。これにより 独自の方法による表示が可能になります。 CI スーパーオブジェクトへの参照が $this->CI =& get_instance() により必要となること、 そして確定データは $this->CI->output->get_output() を呼び出すことによって利用できるようになることを覚えておいてください。

  • cache_override

    _display_cache()メソッドのかわりに独自のメソッドを呼び出すことができます。これにより、 独自のキャッシュ表示機構を使用できるようになります。

  • post_system

    最終的にレンダリングされるページがブラウザに送られた後、 つまりブラウザに確定データが送信されシステム実行が終了する時に 呼び出されます。

ここでみる codeigniter のライフサイクル

  1. ベンチマーククラス & フッククラス
  2. config 系設定ファイル
  3. controller & model
  4. view など display メソッド

参考:フック――フレームワークコアの拡張(opens new window)

#twig テンプレートエンジン実装

PHP テンプレートエンジン twig 3 インストール

  1. composer install してから MY_Controller の設定

  2. application/config/config.php ファイル composer autoload 設定
    $config['composer_autoload'] = true;composer_autoload をtrueに変更

  3. application/core/MY_Controller.php ファイル設定

#twig2 初期設定

<?php
class MY_Controller extends CI_Controller
{
    protected $twig;

    public function __construct()
    {
        parent::__construct();

        $loader = new Twig_Loader_Filesystem('./application/views');
        $this->twig = new Twig_Environment($loader);
        // option設定
        // $this->twig = new Twig_Environment($loader, array('cache' => APPPATH.'/cache/twig', 'debug' => true));

        // twig global 設定
        // if (!empty($this->session->is_login)) {
        //     $this->twig->addGlobal('is_login', $this->session->is_login);
        // }

        // debug
        // $this->output->enable_profiler('TRUE');
    }
}

#twig3 初期設定

<?php
class MY_Controller extends CI_Controller
{
    protected $twig;

    public function __construct()
    {
        parent::__construct();

        // Twig 初期化
        $loader = new \Twig\Loader\FilesystemLoader('../application/views');
        $this->twig = new \Twig\Environment($loader, [
            // 'cache' => '/path/to/compilation_cache',
        ]);
    }
}

#Class 'Twig_Loader_Filesystem' not found エラー対応

An uncaught Exception was encountered
Type: Error

Message: Class 'Twig_Loader_Filesystem' not found

twig loader 見つからないと言ってます。twig3 初期設定と従来 twig2 の初期設定と違うので twig2 から twig3 にアップしたらエラー出ます。

#The "./application/views" directory does not exist エラー対応

An uncaught Exception was encountered
Type: Twig\Error\LoaderError

Message: The "./application/views" directory does not exist ("\x\public_html./application/views").

public index.php 対してのパス設定ミスが原因

$loader = new \Twig\Loader\FilesystemLoader('../application/views');

環境によりますが、MY_Controller.php の\Twig\Loader\FilesystemLoader を../application/viewsに設定したり、./application/viewsに設定したりする必要があります。

#Call to a member function display() on null エラー対応

An uncaught Exception was encountered
Type: Error

Message: Call to a member function display() on null

display function が見つからないことが原因$this->twigにセットしてない可能性?

#Call to a member function insert() on null エラー対応

An uncaught Exception was encountered
Type: Error

Message: Call to a member function insert() on null

model insert 呼び込みできないエラー

  • $this->load->model('model_name')忘れているでは?

  • ライブラリ自動読み込みしてないでは?

config/autoload.php

$autoload['libraries'] = array('database');

#Invalid argument supplied for foreach() エラー対応

A PHP Error was encountered
Severity: Warning

Message: Invalid argument supplied for foreach()

foreach()で回す時に出てくるエラーで、foreach が使えるのは配列とオブジェクトだけって怒られています

回す前に(array)配列変換してあげることで問題解決

foreach((array) $items as $i){
    echo $i;
}
2020-01-30
  • php

関連記事

twig 3 人気 PHP テンプレートエンジンがバージョンアップ
php curl 使って クリックなしで POST 送信
allowurlinclude の設定で ftp_connect()エラー
Lumen と Laravel 違い比較
Laravel5.7 の MVC 使う時のメモ
php 開発におけるルール・規約
PHP 7.4 にアップグレードして使えなくなる機能
解決!phpMyAdmin テーブル構造の内容が表示されない問題
正規表現一覧 よく使う検索・置換のパターン
開発時によく使うゼロ埋めパディング作業まとめ
知ってるようで知らなかった composer のコマンドとオプションの世界
Laravel 5.1 から 8.1 にバージョンアップ
laravel vuejs 初期設定
HTML から PDF に変換 PHP ライブラリ mPDF の設定
nuxtjs と codeigniter で jwt システム構築
Laravel Error についてのメモ