DockerでCodeigniter4 betaを動かす

  • Kitaru Kitaru
  • 3 months ago
DockerでCodeigniter4 betaを動かす

CodeIgniter3はシンプルな作りでカスタマイズしやすく、しかもとても速く動作します。
そういう理由から、ソーシャルゲームの案件でも使用しているのですが、 後発のLaravelやCakephp3と比べるとどうしても古臭いと感じてしまう時があります。

そこでCodeIgniter3の代わりになるような軽量なPHPフレームワークがないか調べてみたら、 2019年3月にCodeIgniter4のベータ版がリリースされており、 ドキュメントも整備されているようなので、少し触ってみることにしました。

Dockerのインストール

CentOS 7.6にDockerをインストールしてCodeIgniter4が動く環境を構築します。

    # cat /etc/redhat-release 
    CentOS Linux release 7.6.1810 (Core) 

    # yum install -y yum-utils device-mapper-persistent-data lvm2
    # yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    # systemctl start docker
    # docker --version
    Docker version 18.09.6, build 481bc77156
    # systemctl enable docker
一般ユーザがsudoなしでdockerコマンドを実行できるようにdockerグループに所属させます。 なお、もし一般ユーザがログインしている場合は、一度ログアウトしてログインし直す必要があります。
    # gpasswd -a (一般ユーザ) docker

Docker Composeのインストール

復数のコンテナをまとめて管理するために、Docker Composeもインストールします。

    # curl -L https://github.com/docker/compose/releases/download/1.24.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
    # chmod +x /usr/local/bin/docker-compose
    # docker-compose --version
    docker-compose version 1.24.0, build 0aa59064

Dockerの構成

    ~/ci4_project
     ├── docker-compose.yml
     ├── mysql
     │       └── my.cnf
     ├── nginx
     │       └── default.conf
     ├── php-fpm
     │       ├── Dockerfile
     │       └── php.ini
     └── src   <- この下にCodeigniter4のソースを設置します。

docker-compose.yml

    version: '3'
    services:
      nginx:
        image: nginx
        restart: always
        ports:
          - 80:80
        volumes:
          - ./src:/var/www/html
          - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
        depends_on:
          - php-fpm
      php-fpm:
        build: ./php-fpm
        restart: always
        volumes:
          - ./src:/var/www/html
          - ./php-fpm/php.ini:/usr/local/etc/php/php.ini
        depends_on:
          - mysql
          - redis
      mysql:
        image: mysql:5.7
        restart: always
        ports:
          - 3306:3306
        environment:
          MYSQL_ROOT_PASSWORD: root001
          TZ: "Asia/Tokyo"
        volumes:
          - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
          - mysql-storage:/var/lib/mysql
      redis:
        image: redis:4
        restart: always
        ports:
          - 6379:6379
        volumes:
          - redis-storage:/data
    volumes:
      mysql-storage:
      redis-storage:

mysql/my.cnf

    [mysqld]
    character-set-server=utf8

    [client]
    default-character-set=utf8

nginx/default.conf

    server {
        listen       80;
        server_name  localhost;
        root         /var/www/html;
        index        index.php;

        access_log /var/log/nginx/access.log;
        error_log  /var/log/nginx/error.log;

        location / {
            try_files $uri $uri/ /index.php$is_args$args;
        }

        location ~ \.php$ {
            fastcgi_pass php-fpm:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        }
    }

php-fpm/Dockerfile

    FROM php:7.3-fpm

    ENV COMPOSER_ALLOW_SUPERUSER 1

    # apcuとopcacheはインストールしなくても問題ありません。
    RUN apt-get update && \
        apt-get -y install libxml2-dev libcurl4-openssl-dev zip unzip git && \
        apt-get clean && \
        rm -rf /var/lib/apt/lists/* && \
        docker-php-ext-configure mysqli --with-mysqli=mysqlnd && \
        docker-php-ext-install intl json mbstring mysqli xml curl opcache && \
        pecl install redis apcu && \
        docker-php-ext-enable redis apcu && \
        curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

php-fpm/php.ini

    [Date]
    date.timezone = "Asia/Tokyo"

    [mbstring]
    mbstring.internal_encoding = UTF-8
    mbstring.language = Japanese

Dockerコンテナの起動

    $ cd ~/ci4_project
    $ docker-compose up -d
    ・・・
    $ docker-compose ps
            Name                       Command               State                 Ports              
    --------------------------------------------------------------------------------------------------
    ci4_project_mysql_1     docker-entrypoint.sh mysqld      Up      0.0.0.0:3306->3306/tcp, 33060/tcp
    ci4_project_nginx_1     nginx -g daemon off;             Up      0.0.0.0:80->80/tcp               
    ci4_project_php-fpm_1   docker-php-entrypoint php-fpm    Up      9000/tcp                         
    ci4_project_redis_1     docker-entrypoint.sh redis ...   Up      0.0.0.0:6379->6379/tcp
4つのコンテナのStateが全てUpになっていたらOKです。

CodeIgniter4のインストール

php-fpmコンテナの中に入って、Composerを使用してCodeigniter4をインストールします。
    $ docker-compose exec php-fpm /bin/bash
    # composer create-project codeigniter4/framework:v4.0.0-beta.3 ci4
    ・・・
    # exit
作成したCodeigniter4のプロジェクトの所有者はrootになっており、そのままだと扱いにくいので一般ユーザに変更します。
    $ su -
    # cd ~(一般ユーザ)/ci4_project/src
    # chown -R (一般ユーザ):(一般ユーザ) ci4
    # exit
Webサーバがwritableディレクトリの中にキャッシュやログなどのファイルを作成するため、パーミッションを変更します。
    $ cd ~/ci4_project/src
    $ chmod -R 777 ci4/writable
srcディレクトリの直下にpublic/index.phpのシンボリックリンクを作成します。
こうすることによってhttp://192.168.56.101/ci4/public/ではなく、http://192.168.56.101/でもアクセスできるようになります。
※ 以降、IPの部分は自分の環境にあわせて適宜置き換えてください。
    $ ln -s ci4/public/index.php index.php

CodeIgniter4のサンプル

Debug Toolbar

CodeIgniter3では開発中にプロファイラ機能を使用してクエリの内容や実行時間を見ていましたが、 CodeIgniter4ではDebug Toolbarというものを利用するようです。まずはこれを使ってみたいと思います。

.envファイル
Codeigniter4のプロジェクトの直下にenvファイルがあり、これをコピーしてenvファイルと同階層に.envファイルを作成します。
そして.envの17行目を次のように修正します。
    # CI_ENVIRONMENT = production
    ↓
    CI_ENVIRONMENT = development
CI_ENVIRONMENTにはproduction、development、testingが定義できますが、 Debug Toolbarはdevelopmentではないと表示されません。

app/Config/App.php
App.phpの24行目を次のように修正します。
    public $baseURL = 'http://localhost:8080';
    ↓
    public $baseURL = 'http://192.168.56.101';
画面に表示されるDebug Toolbarをソースで確認すると
    <script type="text/javascript"  id="debugbar_loader" data-time="1558795940" src="http://192.168.56.101/index.php?debugbar"><script type="text/javascript"  id="debugbar_dynamic_script">
というコードになっており、このsrc属性に$baseURLの値が使用されています。

以上の設定を行ってhttp://192.168.56.101/にアクセスすると、画面右下に炎上?のアイコンが表示されており、これをクリックすると次のようなパネルが表示されます。 Debug Toolbar

リードスルー

次はRedisを参照してデータが存在しない場合はMySQLからデータを読み込むサンプルを作ります。

MySQL
まず準備としてMySQLにデータベースとテーブル、初期データを作成します。
    $ docker-compose exec mysql /bin/bash
    # mysql -u root -p
    Enter password: ← root001を入力します。
    ・・・
    mysql> CREATE DATABASE ci4_db;
    mysql> use ci4_db;
    mysql> CREATE TABLE `users` (
        -> `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
        -> `user_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
        -> `name` VARCHAR(32) NULL DEFAULT NULL,
        -> `age` INT(10) UNSIGNED NULL DEFAULT NULL,
        -> PRIMARY KEY (`id`),
        -> UNIQUE INDEX `user_id` (`user_id`)
        -> )
        -> COLLATE='utf8_general_ci'
        -> ENGINE=INNODB
        -> ;
    mysql> INSERT INTO `ci4_db`.`users` (`user_id`, `name`, `age`) VALUES (100, '屋代駿介', 35),(101, '須加友枝', 29),(102, '永来一八', 15),(103, '荷宮知愛', NULL);
    mysql> SELECT * FROM users;
    +----+---------+--------------+------+
    | id | user_id | name         | age  |
    +----+---------+--------------+------+
    |  1 |     100 | 屋代駿介     |   35 |
    |  2 |     101 | 須加友枝     |   29 |
    |  3 |     102 | 永来一八     |   15 |
    |  4 |     103 | 荷宮知愛     | NULL |
    +----+---------+--------------+------+
    4 rows in set (0.00 sec)
    mysql> exit;
    # exit
app\Config\Database.php
MySQLの接続先をmysqlコンテナに変更します。
    public $default = [
        'DSN'      => '',
        'hostname' => 'mysql',     // 修正する
        'username' => 'root',      // 修正する
        'password' => 'root001',   // 修正する
        'database' => 'ci4_db',    // 修正する
        'DBDriver' => 'MySQLi',
        'DBPrefix' => '',
        'pConnect' => false,
        'DBDebug'  => (ENVIRONMENT !== 'production'),
        'cacheOn'  => false,
        'cacheDir' => '',
        'charset'  => 'utf8',
        'DBCollat' => 'utf8_general_ci',
        'swapPre'  => '',
        'encrypt'  => false,
        'compress' => false,
        'strictOn' => false,
        'failover' => [],
        'port'     => 3306,
    ];
app\Config\Cache.php
キャッシュのデフォルトの書き込み先がファイルになっているのでRedisにして、 Redisの接続先をredisコンテナに変更します。
    public $handler = 'file';
    ↓
    public $handler = 'redis';
    public $redis = [
        'host'     => 'redis',    // 修正する
        'password' => null,
        'port'     => 6379,
        'timeout'  => 0,
        'database' => 0,
    ];
app/Entities/User.php
usersテーブルのレコードを保存するエンティティを作成します。 また、Entitiesディレクトリも存在しないため一緒に作成する必要があります。

エンティティはCodeIgniter\Entityクラスを継承する必要があります。
エンティティにはテーブルのカラムと対応したプロパティを定義します。
テーブルから取得した値は文字列としてプロパティに設定されるため、整数として扱いたい場合は$_optionsの中でキャストの設定を行う必要があります。
もしカラムがNullableの場合は?integerのようにキャストの型の前に?をつける必要があります。?がないとnullは参照時に0として扱われます。
     <?php namespace App\Entities;

     use CodeIgniter\Entity;

     class User extends Entity
     {
         protected $id;
         protected $user_id;
         protected $name;
         protected $age;

         protected $_options = [
             'casts'   => [
                 'id'           => 'integer',
                 'user_id'      => 'integer',
                 'age'          => '?integer',
             ],
             'dates'   => [],
         ];
     }
app/Models/UserModel.php
usersテーブルを操作するためのモデルを作成します。

モデルはCodeIgniter\Modelクラスを継承する必要があります。
Modelには多くのプロパティがありますが、ここではモデルが扱うテーブルの名前と、結果データの型の2つのみを定義しています。
    <?php namespace App\Models;

    use CodeIgniter\Model;

    class UserModel extends Model
    {
        protected $table         = 'users';
        protected $returnType    = 'App\Entities\User';
    }
app/Controllers/User.php
最後にコントローラを作成します。

コントローラはApp\Controllers\BaseControllerクラスを継承する必要があります。
モデルは$this->load->modelではなく、普通のクラスのようにnewでインスタンスを生成して使用します。
モデルメソッドの使い方はCodeigniter3とほぼ同じですが、firstメソッドの戻り値は、UserModelモデルで定義したとおりUserエンティティになっています。

キャッシュの読み込みはcache(キー名)、キャッシュの書き込みはcache()->save(キー名, 値, 生存期間(秒))で行います。
  <php namespace App\Controllers;

    use App\Models\UserModel;

    class User extends BaseController
    {
        public function index($userId)
        {
            $user = cache($userId);

            if ($user === null)
            {
                $userModel = new UserModel();

                $user =  $userModel->where('user_id', (int) $userId)->first();    // 指定されたuser_idのレコードが存在しない場合はnullが返る

                cache()->save($userId, $user, 600);
            }

            d($user);
            d($user->id);
            d($user->user_id);
            d($user->name);
            d($user->age);
        }
    }
以上の修正を行ってからhttp://192.168.56.101/user/index/103/にアクセスすると、次のような画面が表示されます。

Debug Toolbar2

なお、http://192.168.56.101/user/index/104/のようにusersテーブルに存在しないuser_idを指定するとスタックトレースが表示されます。
これはfirstメソッドの戻り値がnullであるにも関わず、プロパティを参照しようとしているためです。

Debug Toolbar3

Kitaru

Kitaru

Programmer

DockerでCodeigniter4 betaを動かす

お気軽に
お問い合わせください。

営業担当がご要望を詳しくヒアリングさせていただきます。

お問い合わせ