もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

CakePHP4を試す

はじめに

こんばんは。

こちらの記事はユアマイスターアドベントカレンダー2020の3日目の記事です。

弊社ではバックエンドに PHPを採用しており、フレームワークに CakePHP3を採用しています。

CakePHPの現在の最新バージョンは 4 なので、弊社でもいつかはアップデートという茨の道を進む事になると思います。

そのために、今回はCakePHP4の素振りをしておこうと思います。

参考サイトは基本的に 公式の ドキュメントサイト です。

本題

1. インストール

$ composer create-project --prefer-dist cakephp/app:~4.0 example_4
$ cd example_4
$ ./bin/cake version
4.1.6

現状では 4.1.6 がインストールされます

2. .env作成 & 設定

$ cp config/.env.example config/.env
$ vi config/.env ← よしなに書き換え

$ cat config/.env
export APP_NAME="Example4"
export DEBUG="true"
export APP_ENCODING="UTF-8"
export APP_DEFAULT_LOCALE="ja_JP"
export APP_DEFAULT_TIMEZONE="Asia/Tokyo"
export SECURITY_SALT="__SALT__"
export DATABASE_URL="mysql://kojirock:1qazxcvb@localhost/example_db"

3. bootstrap.php修正

作成した .env を読み込みます。 以下のコードがコメントアウトされていますので、それを解除します。

 if (!env('APP_NAME') && file_exists(CONFIG . '.env')) {
     $dotenv = new \josegonzalez\Dotenv\Loader([CONFIG . '.env']);
     $dotenv->parse()
         ->putenv()
         ->toEnv()
         ->toServer();
 }

4. 確認

$ ./bin/cake server

Welcome to CakePHP v4.1.6 Console
-------------------------------------------------------------------------------
App : src
Path: /path/to/example_4/src/
DocumentRoot: /path/to/example_4/webroot
Ini Path: 
-------------------------------------------------------------------------------
built-in server is running in http://localhost:8765/
You can exit with `CTRL-C`
[Thu Dec  3 03:11:35 2020] PHP 7.4.5 Development Server (http://localhost:8765) started

f:id:kojirooooocks:20201203044809p:plain

Security.salt を変更しろって Notice が出てますが、一旦無視します。

5. 簡単なCRUD作成

マイグレーションファイル作成

$ ./bin/cake bake migration CreateUsers 

Creating file /path/to/config/Migrations/20201202182340_CreateUsers.php
Wrote `/path/to/config/Migrations/20201202182340_CreateUsers.php`

$ vi config/Migrations/20201202182340_CreateUsers.php  ← よしなに作成
config/Migrations/20201202182340_CreateUsers.php
<?php
declare(strict_types=1);

use Migrations\AbstractMigration;

class CreateUsers extends AbstractMigration
{
    /**
     * Change Method.
     *
     * More information on this method is available here:
     * https://book.cakephp.org/phinx/0/en/migrations.html#the-change-method
     * @return void
     */
    public function change()
    {
        $table = $this->table('users');
        $table->addColumn('name', 'string', [
            'limit'   => 255,
            'null'    => false,
            'comment' => 'ユーザー名'
        ]);
        $table->addColumn('password', 'string', [
            'limit'   => 255,
            'null'    => false,
            'comment' => 'パスワード'
        ]);
        $table->addColumn('created', 'datetime', [
            'null'    => false,
            'comment' => '登録日'
        ]);
        $table->addColumn('modified', 'datetime', [
            'null'    => false,
            'comment' => '更新日'
        ]);
        $table->create();
    }
}

マイグレーション実行

$ ./bin/cake migrations migrate                       
using migration paths 
 - /path/to/config/Migrations
using seed paths 
 - /path/to/config/Seeds
using environment default
using adapter mysql
using database example_db
ordering by creation time

 == 20201202182340 CreateUsers: migrating
 == 20201202182340 CreateUsers: migrated 0.0193s

All Done. Took 0.0249s

Dumps the current schema of the database to be used while baking a diff

using migration paths 
 - /path/to/config/Migrations
using seed paths 
 - /path/to/config/Seeds
Writing dump file `/path/to/config/Migrations/schema-dump-default.lock`...
Dump file `/path/to/config/Migrations/schema-dump-default.lock` was successfully written

bakeコマンドで諸々作成

model
$ ./bin/cake bake model users
One moment while associations are detected.

Baking table class for Users...

Creating file /path/to/src/Model/Table/UsersTable.php
Wrote `/path/to/src/Model/Table/UsersTable.php`
Deleted `/path/to/src/Model/Table/.gitkeep`

Baking entity class for User...

Creating file /path/to/src/Model/Entity/User.php
Wrote `/path/to/src/Model/Entity/User.php`
Deleted `/path/to/src/Model/Entity/.gitkeep`

Baking test fixture for Users...

Creating file /path/to/tests/Fixture/UsersFixture.php
Wrote `/path/to/tests/Fixture/UsersFixture.php`
Deleted `/path/to/tests/Fixture/.gitkeep`
Bake is detecting possible fixtures...

Baking test case for App\Model\Table\UsersTable ...

Creating file /path/to/tests/TestCase/Model/Table/UsersTableTest.php
Wrote `/path/to/tests/TestCase/Model/Table/UsersTableTest.php`
Done
controller
$ ./bin/cake bake controller users                  
Baking controller class for Users...

Creating file /path/to/src/Controller/UsersController.php
Wrote `/path/to/src/Controller/UsersController.php`
Bake is detecting possible fixtures...

Baking test case for App\Controller\UsersController ...

Creating file /path/to/tests/TestCase/Controller/UsersControllerTest.php
Wrote `/path/to/tests/TestCase/Controller/UsersControllerTest.php`
Done
template
$ ./bin/cake bake template users   

Baking `index` view template file...

Creating file /path/to/templates/Users/index.php
Wrote `/path/to/templates/Users/index.php`

Baking `view` view template file...

Creating file /path/to/templates/Users/view.php
Wrote `/path/to/templates/Users/view.php`

Baking `add` view template file...

Creating file /path/to/templates/Users/add.php
Wrote `/path/to/templates/Users/add.php`

Baking `edit` view template file...

Creating file /path/to/templates/Users/edit.php
Wrote `/path/to/templates/Users/edit.php`

確認してみる

f:id:kojirooooocks:20201203044837p:plain f:id:kojirooooocks:20201203044851p:plain f:id:kojirooooocks:20201203044908p:plain f:id:kojirooooocks:20201203044923p:plain

デフォルトのスタイルもいい感じです。(bakeコマンドでコントローラとかひさびさ作った)

6. コマンド作成

今度は簡単なコマンド(Shell)を作ってみます。

作るのは、 laravelでいう key:generate コマンドみたいなものです。

Security.salt の警告が出てるのがちょっと嫌だったので、それを消す用のコマンドです。中身はほぼほぼlaravelのものです。

Shellはかなり限定的な動きとしてかなりざっくり作りました。

bakeで作成

$ ./bin/cake bake shell KeyGenerate

Creating file /path/to/src/Shell/KeyGenerateShell.php
Wrote `/path/to/src/Shell/KeyGenerateShell.php`

Baking test case for App\Shell\KeyGenerateShell ...

Creating file /path/to/tests/TestCase/Shell/KeyGenerateShellTest.php

src/Shell/KeyGenerateShell.php

<?php
declare(strict_types=1);

namespace App\Shell;

use Cake\Console\Shell;

class SecuritySaltGenerateShell extends Shell
{
    public function main()
    {
        $key = $this->generateRandomKey();

        if (!$this->setKeyInEnvironmentFile($key)) {
            return;
        }

        $this->out('SecuritySalt set successfully.');
    }

    private function generateRandomKey(): string
    {
        // AES-256-CBC決め打ち
        return 'base64:' . base64_encode(random_bytes(32));
    }

    private function setKeyInEnvironmentFile(string $key): bool
    {
        $this->writeNewEnvironmentFileWith($key);

        return true;
    }

    private function writeNewEnvironmentFileWith(string $key): void
    {
        $filePath = CONFIG . '.env';

        file_put_contents($filePath, preg_replace(
            $this->keyReplacementPattern(),
            'export SECURITY_SALT="'.$key.'"',
            file_get_contents($filePath)
        ));
    }

    private function keyReplacementPattern(): string
    {
        $escaped = preg_quote('="__SALT__"', '/');
        return "/^export SECURITY_SALT{$escaped}/m";
    }
}

実行して確認

$ ./bin/cake security_salt_generate
SecuritySalt set successfully.

$ cat config/.env
export APP_NAME="Example4"
export DEBUG="true"
export APP_ENCODING="UTF-8"
export APP_DEFAULT_LOCALE="ja_JP"
export APP_DEFAULT_TIMEZONE="Asia/Tokyo"
export SECURITY_SALT="base64:KtTpixi+dX4CEVmoMP6850uHlLJyR2484laQLAtC7zQ="  ← 更新されてる
export DATABASE_URL="mysql://kojirock: 1qazxcvb@localhost/example_db"

f:id:kojirooooocks:20201203045021p:plain

警告が消えました。

終わりに

簡単な確認で終わりましたが、CakePHP3 やってたら ほぼ迷うことはないかなと思いました。

また、今回 待望のDIが4.1からはいるという噂を聞いてたので試したのですが、残念ながら4.2へ持ち越しになったということを コネヒトさんのブログで 紹介されていました。残念。

CakePHP3が出たての頃は、pimple入れて頑張ってた時があったので、本当にDI待ち遠しいです。

また、ユアマイスターではエンジニアを積極採用中です。

ご興味がある方はご連絡ください。

corp.yourmystar.jp

現場からは以上です。