ブログ
これまでに経験してきたプロジェクトで気になる技術の情報を紹介していきます。
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 # yum -y install docker-ce # 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
■2020.04.04追記
Dockerfileの「FROM php:7.3-fpm」を「FROM php:7.4-fpm」に変更した場合は、docker-compose upの時に次のようなエラーメッセージ(鬼車がない)が表示されます。
・・・ checking for oniguruma... no configure: error: Package requirements (oniguruma) were not met: No package 'oniguruma' found ・・・
その場合はDockerfileを次のように修正して下さい。
■修正前 apt-get -y install libxml2-dev libcurl4-openssl-dev zip unzip git && \ ■修正後 apt-get -y install libxml2-dev libcurl4-openssl-dev libonig-dev zip unzip git && \
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をソースで確認すると
というコードになっており、このsrc属性に$baseURLの値が使用されています。
以上の設定を行ってhttp://192.168.56.101/ にアクセスすると、画面右下に炎上?のアイコンが表示されており、これをクリックすると次のようなパネルが表示されます。
リードスルー
次は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として扱われます。
[ 'id' => 'integer', 'user_id' => 'integer', 'age' => '?integer', ], 'dates' => [], ]; }
app/Models/UserModel.php
usersテーブルを操作するためのモデルを作成します。
モデルはCodeIgniter\Modelクラスを継承する必要があります。
Modelには多くのプロパティがありますが、ここではモデルが扱うテーブルの名前と、結果データの型の2つのみを定義しています。
app/Controllers/User.php
最後にコントローラを作成します。
コントローラはApp\Controllers\BaseControllerクラスを継承する必要があります。
モデルは$this->load->model
ではなく、普通のクラスのようにnewでインスタンスを生成して使用します。
モデルメソッドの使い方はCodeigniter3とほぼ同じですが、firstメソッドの戻り値は、UserModelモデルで定義したとおりUserエンティティになっています。キャッシュの読み込みは
cache(キー名)
、キャッシュの書き込みはcache()->save(キー名, 値, 生存期間(秒))
で行います。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/ にアクセスすると、次のような画面が表示されます。
なお、http://192.168.56.101/user/index/104/ のようにusersテーブルに存在しないuser_idを指定するとスタックトレースが表示されます。
これはfirstメソッドの戻り値がnullであるにも関わず、プロパティを参照しようとしているためです。
コメントはありません。