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

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

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

現場からは以上です。

WAFを使って国内アクセスのみに絞る

はじめに

こんにちは。

今回は AWS WAF を使用してアクセスを国内アクセスのみに絞る対応をしましたのでログを起こしておきます。

参考サイト

dev.classmethod.jp

cloud-aws-gcp.hateblo.jp

本題

国内アクセス制限

大体は参考サイトに乗っている部分で設定できます。

参考サイトに乗っている AWSコンソールのUIは古いので、ちょっと悩みましたが、親切だったので簡単でした。

f:id:kojirooooocks:20201119031123p:plainf:id:kojirooooocks:20201119031137p:plain

事前に 使用している alb に設定する必要があります。

こちらも簡単に設定できます。

f:id:kojirooooocks:20201119031905p:plainf:id:kojirooooocks:20201119031915p:plain

これで、国内アクセスのみに絞ることが出来ます。

Botアクセス開放

また、 googlebotや pagespeedなどの各種 Bot系のアクセスのみ通すなどの対応も、参考サイトを見ながら簡単に設定できました。

f:id:kojirooooocks:20201119032131p:plainf:id:kojirooooocks:20201119032134p:plain

User-Agentから対象の文字列にマッチするかどうかを判定して通すようにしています。

終わりに

こんな感じで簡単にできました。

もうちょっと aws力がほしい今日このごろ。 使ってないけど実はすごく使える機能とかあるかもしれないし、もうちょい調べてみます。

現場からは以上です。

MysqlのJSON型へのINSERTやUPDATEやDELETE

はじめに

こんばんは。

やっとリリースが出来て、落ち着いてきました。

今回も簡単ですが備忘録を書き書き。

MySQLJSON型とかを時々使ってるんですが、JSONに向けて UPDATE や INSERT DELETE を実行したので、ログを残しておきます。

本題

こんなテーブルを作りました。

mysql> desc example_table;
+---------+---------------------+------+-----+---------+----------------+
| Field   | Type                | Null | Key | Default | Extra          |
+---------+---------------------+------+-----+---------+----------------+
| id      | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| options | json                | NO   |     | NULL    |                |
+---------+---------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)


mysql > INSERT INTO example_table VALUES
(1, JSON_OBJECT('aaa', 100, 'bbb', 200, 'ccc', 300)),
(2, JSON_OBJECT('eee', 1000, 'fff', 2000, 'ggg', 3000)),
(3, JSON_OBJECT('xxx', 10000, 'yyy', 20000, 'zzz', 30000));


mysql> SELECT * FROM example_table;
+----+--------------------------------------------+
| id | options                                    |
+----+--------------------------------------------+
|  1 | {"aaa": 100, "bbb": 200, "ccc": 300}       |
|  2 | {"eee": 1000, "fff": 2000, "ggg": 3000}    |
|  3 | {"xxx": 10000, "yyy": 20000, "zzz": 30000} |
+----+--------------------------------------------+
3 rows in set (0.00 sec)

UPDATE

mysql> UPDATE example_table SET options = JSON_SET(options, "$.fff", 2222) WHERE id = 2;


mysql> SELECT * FROM example_table;
+----+--------------------------------------------+
| id | options                                    |
+----+--------------------------------------------+
|  1 | {"aaa": 100, "bbb": 200, "ccc": 300}       |
|  2 | {"eee": 1000, "fff": 2222, "ggg": 3000}    |
|  3 | {"xxx": 10000, "yyy": 20000, "zzz": 30000} |
+----+--------------------------------------------+
3 rows in set (0.00 sec)

対象のレコードの対象のjson keyがupdateされてます。

INSERT

mysql> UPDATE example_table SET options=JSON_MERGE(options, JSON_OBJECT('hhh', 4000)) WHERE id = 2;


mysql> SELECT * FROM example_table;
+----+------------------------------------------------------+
| id | options                                              |
+----+------------------------------------------------------+
|  1 | {"aaa": 100, "bbb": 200, "ccc": 300}                 |
|  2 | {"eee": 1000, "fff": 2222, "ggg": 3000, "hhh": 4000} |
|  3 | {"xxx": 10000, "yyy": 20000, "zzz": 30000}           |
+----+------------------------------------------------------+
3 rows in set (0.00 sec)

対象のレコードの対象のjson dataに 指定したkeyが指定したvalueで追加されています!

DELETE

mysql> UPDATE example_table SET options = JSON_REMOVE(options, '$.fff') WHERE id = 2;


mysql> SELECT * FROM example_table;
+----+--------------------------------------------+
| id | options                                    |
+----+--------------------------------------------+
|  1 | {"aaa": 100, "bbb": 200, "ccc": 300}       |
|  2 | {"eee": 1000, "ggg": 3000, "hhh": 4000}    |
|  3 | {"xxx": 10000, "yyy": 20000, "zzz": 30000} |
+----+--------------------------------------------+
3 rows in set (0.01 sec)

対象のレコードの対象のjson dataに 指定したkeyが削除されています。

こんな感じで簡単にいきました!

ちなみに JSON型ではなく String型でJSONの形で保存されているデータでも問題なく動きます。

終わりに

アドベントカレンダーの季節になったので、僕も何個かチャレンジしてみたいなと思ってます!

では現場からは以上です。

deployerで範囲指定でhostを選択

はじめに

こんばんは。

最近リリースが迫っていて、余裕がありません。。。

とりあえず今回も備忘録です。

本題

現在開発中のサイトは、deployerを使ってデプロイを実現しています。

toBtoC、社内画面という感じで、複数台のサーバーに対してデプロイを実行する形ですが、以下みたいな形でhostsを最初は指定してました

<?php

host('front-1', 'front-2', 'front-3', 'partner-1', 'admin')
    ->stage('production')
    ->set('rsync_src', '/var/www/project')
    ->set('deploy_path', '/var/www/project');

host() は可変長引数リストを使ってるので、このような感じで指定するみたいです。

配列指定はその先の Rangeクラスでエラーが出てしまいます。

$ PHP Warning:  preg_match() expects parameter 2 to be string, array given in /path/to/vendor/deployer/deployer/src/Host/Range.php on line 18

サーバーが増えるたびに ここに追加するのは流石にだるいので、なんか無いかな?と思ったらありました。

deployer.org

数値だけならば 範囲指定が出来るみたいです。

<?php

host('front-[1:3]', 'partner-1', 'admin')
    ->stage('production')
    ->set('rsync_src', '/var/www/project')
    ->set('deploy_path', '/var/www/project');

これで front-1 〜 front-3が対象になります。

終わりに

awsの設定系話も溜まってるのですが、リリース作業が忙しくて、書く時間もありません。。。

来週になれば落ち着くので、がんばります !

Github-Actionsで非推奨となっていたものを対応した

はじめに

こんばんは。

現在あるプロジェクトで github actionを使って サーバへのデプロイなどを行っています。

そこで起きた簡単なエラー対応の備忘録です。

参考サイト

github.blog

本題

いつものように github-actionのログを見ていると以下みたいなエラーが出ていました。

f:id:kojirooooocks:20201108232323p:plain

調べてみると非推奨になるものを使っていたらしく、かつ、自分が使っていた action-aws-cliアーカイブされているようなので、この際別のものに乗り換えてみようと思い対応しました。

乗り換えたのはこちらになります。

github.com

作業は簡単で workflowに書かれていたコードを以下のように修正しました。

before

      - uses: chrislennon/action-aws-cli@v1.1
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}

after

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_DEFAULT_REGION }}

このように変更したことで、非推奨となっている設定を使うことなく errorがなくなりました。

終わりに

リリース前でごたついて大変なので、今回はこんな簡単なものですいません。

albのホストベースルーティングを試した

はじめに

こんばんは。

タイトルの通り、ホストベースルーティングを試しました。

経緯としては、 EC2にawsの証明書を直接設定できないという事が発覚して、となると、サーバごとにalbを用意するのか...?

と思い、うーん。うーん。と調べてたところ、ホストベースルーティングたるものがあったので、早速試してみました。

本題

まずalbを作成します。

f:id:kojirooooocks:20201025224100p:plain

次に、リスナーで、ルールの編集をします。

f:id:kojirooooocks:20201025224410p:plain

例えば、すでに設定済みのルールの前に、もう一つルールを追加してみます。

f:id:kojirooooocks:20201025225435p:plain f:id:kojirooooocks:20201025225442p:plain f:id:kojirooooocks:20201025225446p:plain f:id:kojirooooocks:20201025225450p:plain f:id:kojirooooocks:20201025225453p:plain f:id:kojirooooocks:20201025225456p:plain f:id:kojirooooocks:20201025225501p:plain f:id:kojirooooocks:20201025225504p:plain

こんな感じで、設定します。

そして、設定したターゲットグループに、別々のサーバを設定しておきます。

f:id:kojirooooocks:20201025230252p:plain f:id:kojirooooocks:20201025230300p:plain

これで、設定したホストでアクセスが来ると、それぞれのターゲットグループにアクセスが振り分けられます。

出来てよかった〜!!!

終わりに

awsただただ難しい。

現在一番悩んでるのは、 cloudfrontです。。。

誰か教えて。

現場からは以上です。

Laravelのエラーページのディレクトリをデフォルトの場所から変えたい

はじめに

こんばんは。

Laravelで404とか500とかのエラーページを修正したいとかってあると思います。

今回はそれで、デフォルトのディレクトリ以外の場所の指定をしたい場合の備忘録です。

本題

だいたい、こちらカスタムHTTPエラーページ とかを参照して、エラーページをカスタマイズしていくと思います。

ただ、レポジトリが一緒でadmin用、front用みたいに2サイト分の情報が入っているプロジェクトの場合、テンプレートも分けないといけません。

だいたい resources/views のしたに admin customer みたいな感じでさらにディレクトリを掘ると思います。

しかしこれだと エラーページをカスタマイズしたいとなった場合、そのままでどちらも同じものを使うことになります。

それは、 エラーページが resources/views/errors/ を参照するようになっているからです。

これを回避する方法は、 app/Exceptions/Handler.php をカスタムする必要があります。

といっても 継承しているクラスから、 registerErrorViewPaths() メソッドをオーバライドするだけです。

僕の場合は以下のような感じで対応してます。

<?php
    /**
     * Register the error template hint paths.
     *
     * @return void
     */
    protected function registerErrorViewPaths()
    {
        $paths = collect(config('view.paths'));

        View::replaceNamespace('errors', $paths->map(function ($path) {
            if (config('app.project') === 'admin') {
              $path .= '/admin';
            } elseif (config('app.project') === 'customer') {
              $path .= '/customer';
            }

            return "{$path}/errors";
        })->push(__DIR__ . '/views')->all());
    }

終わりに

そういえば仕事がもしかしたら途切れるかもしれません。

お仕事ください。

現場からは以上です。