20200908のlaravelに関する記事は7件です。

【Laravel】ラズパイのDBと連携させる

ラズパイ側の操作とLravel側の操作に分けて解説していく。

DBでのユーザの作成と権限付与は別々でやる

ラズパイ側の操作

DB操作用ユーザ作成

 CREATE USER 'user'@'%' IDENTIFIED BY 'pass';

%を使用することでどんなホストでも接続ができる

権限確認

登録されているユーザ名を確認

select user,host from mysql.user;

特定ユーザの権限確認

show grants for 'ユーザ名'@'ホスト名';

ユーザ名とホスト名は'"で囲むこと

権限付与

形式
GRANT [権限] ON [レベル] TO [ユーザ] IDENTIFIED BY PASSWORD '[パスワード]'
権限は
  • select
  • update
  • insert
  • delete
  • all
レベル 説明
GRANT [権限] ON *.* TO [ユーザ] グローバルレベル
GRANT [権限] ON [DB名].* TO [ユーザ] データベースレベル
GRANT [権限] ON [DB名].[テーブル名] TO [ユーザ] テーブルレベル
GRANT [権限](カラム1,カラム2,...) ON [DB名].[テーブル名] TO [ユーザ] カラムレベル

ポートの確認

show variables like 'port';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| port          | 3306  |
+---------------+-------+

Laravel側の操作

後は今まで得た情報を.envdatabase.phpに反映するだけ
ここでは.envだけ書いておく

.env
DB_CONNECTION=mysql
DB_HOST=IPアドレス
DB_PORT=3306
DB_DATABASE=DB名
DB_USERNAME=作成したユーザ名
DB_PASSWORD=パスワード

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

メモ書き : Laravel8 Release & Upgrade

2020/09/08 リリース。バグフィックス期間は 2021/03/08 セキュリティフィックスは2021/09/08 までという予定。

そして、新機能が多いため Upgrade の量は少ないですが、factory をゴリゴリ使っているとちょっと注意です。( migration の schema:dump やった後の migrate したときの挙動が怖そうなので、そこらへんは自己責任でしてください)

アップグレードに対する更新をソースコード単位で見たい場合は Github comparision tool を見ると良いですよ。

個人的なメモ: upgrade の時は phpstan で静的解析を通すのが良いですよーよー。

[新機能] Laravel Jetstream

see : https://github.com/laravel/jetstream

新しいパッケージだそうです。

Scaffolding の livewireInertiaを使って、ええ感じに Vue や Tailwind CSS っぽく使って…?

なんやこれ全くわからん。bladeを抜かした管理画面を自動で作るよってことかしら。

[新機能] Model Directory

Eloquent Model の初期位置が app/Models の中になりました。

[新機能] Model Factory Classes

factory がクラスになりました。例えば User factory が旧だとベタなPHPスクリプトだったのが、クラスで指定するようになります。

旧 Factory を使う場合は laravel/legacy-factories を使うことになります。極力書き換えるのをおすすめします。

<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */

use Faker\Generator as Faker;

$factory->define( \App\Eloquent\User::class, function (Faker $faker){
    return [
            'name' => $this->faker->name,
            'email' => $this->faker->unique()->safeEmail,
            'email_verified_at' => now(),
            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
            'remember_token' => Str::random(10),
    ];
} );

新::

<?php

namespace Database\Factories;

use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class UserFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = User::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'name' => $this->faker->name,
            'email' => $this->faker->unique()->safeEmail,
            'email_verified_at' => now(),
            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
            'remember_token' => Str::random(10),
        ];
    }
}

これに伴い、Eloquent 側からfactory を作ることになるそうです。

<?php

use App\Model\User;

User::factory()->count(50)->create();

[新機能] Migration Squash

SQL で書かれたスキーマの出力ができるようになります。出力されたスキーマは database/schema に保存されます。

migration にも関わってくる。(後で)

php artisan schema:dump

[新機能] Job Batching

Bus でバッチ処理が追加されて、axios みたいな書き方で使えるっぽいです。

<?php
use App\Jobs\ProcessPodcast;
use App\Podcast;
use Illuminate\Bus\Batch;
use Illuminate\Support\Facades\Batch;
use Throwable;

$batch = Bus::batch([
    new ProcessPodcast(Podcast::find(1)),
    new ProcessPodcast(Podcast::find(2)),
    new ProcessPodcast(Podcast::find(3)),
    new ProcessPodcast(Podcast::find(4)),
    new ProcessPodcast(Podcast::find(5)),
])->then(function (Batch $batch) {
    // All jobs completed successfully...
})->catch(function (Batch $batch, Throwable $e) {
    // First batch job failure detected...
})->finally(function (Batch $batch) {
    // The batch has finished executing...
})->dispatch();

return $batch->id;

[新機能] Improved Rate Limit

Requtest Rate Limit を throttle ミドルウェアで制御してるが、もうちょっとフレキシブルにレートリミットを変えられるようになるっぽいです。

例えば、会員ユーザのレートリミットは無し、それ以外はレートリミットは100回/分にする、とする場合は下記のように変更できるみたいです。

<?php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;


// おそらく AppServiceProvider の中で設定
RateLimiter::for('uploads', function (Request $request) {
    return $request->user()->vipCustomer()
                ? Limit::none()
                : Limit::perMinute(100);
});

ミドルウェアの throttole で指定することで使える様になるみたいです。

Route::middleware(['throttle:uploads'])->group(function(){
  Route::post('/audio', function(){ });

  Route::post('/video', function(){ });
});

[新機能] Improved Maintenance Mode

php artisan down でメンテナンスモードにした時の挙動を云々。

  1. --secret='1630542a-246b-4b66-afa1-dd72a4c43515'

このオプションを使うことで / に来たユーザは /1630542a-246b-4b66-afa1-dd72a4c43515 にリダイレクトされます。

  1. --render='errors::503'

このオプションを使うことで、表示するテンプレを指定することができる。

[新機能] Closure Dispatch/Chain

dispatch helper に ->catch(function(){}) ができるようになりました。おそらく、上記の Bus と同じ理屈。

<?php

use Throwable;

dispatch(function () use ($podcast) {
    $podcast->publish();
})->catch(function (Throwable $e) {
    // This job has failed...
});

[新機能] Dynamic Blade Components

Blade::component('package-alert', AlertComponent::class); で登録したコンポーネントを <x-package-alert/> とテンプレート側に書くことで使えるようになります。

クラス名は camelCase で書き、コンポーネント名は kebab-case で書くみたい。

Component Methods

コンポーネントテンプレート内でメソッドを動かすことができる。

/**
 * Determine if the given option is the current selected option.
 *
 * @param  string  $option
 * @return bool
 */
public function isSelected($option)
{
    return $option === $this->selected;
}
<option {{ $isSelected($value) ? 'selected="selected"' : '' }} value="{{ $value }}">
    {{ $label }}
</option

(何か vue みたいだなとぼんやり)

[新機能] Event Listener Improvements

Facade で \Event::listen をする時に、Queueを使うようにデコレートする事ができます。

use App\Events\PodcastProcessed;
use function Illuminate\Events\queueable;
use Illuminate\Support\Facades\Event;

Event::listen(queueable(function (PodcastProcessed $event) {
    //
}));

そして queue job のように細かくしてする事ができて ->catch チェインができます。

Event::listen(queueable(function (PodcastProcessed $event) {
    //
})->catch(function (PodcastProcessed $event, Throwable $e) {
    // The queued listener failed...
})->onConnection('redis')
  ->onQueue('podcasts')
  ->delay(now()->addSeconds(10))
);

[新機能] Time Testing Helpers

Carbon::now() で返す時間を指定することができます。

[新機能] Artisan serve Improvements

.env ファイルを更新したばあいに、artisan serve は自動に設定を読み直します。

[新機能] Tailwind Pagination Views

Pagination のテンプレートに今までの Bootstrap3, Bootstrap4 の他に Tailwind が使えます。

[Upgrade] パッケージ依存

  • "laravel/framework": "^8.0"
  • "nunomaduro/collision": "^5.0"
  • "guzzlehttp/guzzle": "^7.0.1"
  • "facade/ignition": "^2.3.6"

他のパッケージを使っているばあいは、それらもアップデートしてください

[Upgrade][Medium] Use PHP >=7.3.0

事情により PHP は 7.3.0 以上を指定してください。

[Upgrade][Low] isset method

Illuminate\Support\CollectionoffsetExists の挙動がかわりました。ので isset で確認した時の挙動が変わります。

<?php

$collection = collect([null]);

// Laravel 7.x - true
isset($collection[0]);

// Laravel 8.x - false
isset($collection[0]);

[Upgrade][High] Model Factories

model factories がクラス化されました。7.x までの factory を書き換えをせずに使い続ける場合は laravel/legacy-factory を使う必要があります。

[Upgrade][Low] The Castable Interface

CastablecastUsing の引数 $arguments に、arrayのタイプ指定が加わりましたので、追加をしてください。

[Upgrade][Low] Increment / Decrement Events

model の update および save が動いた時に increment,decrement インスタンスメソッドが動きます。

[Upgrade][Low] The Dispatcher Contract

Illuminate\Contracts\Events\Dispatcherlisten メソッドの第二引数 $listener の標準値に null を付けられました。

public function listen($events, $listener = null);

[Upgrade][Optional] Mentenance Mode Updates

新しく入った機能 --render 等を使う場合は public/index.php を更新してください。この条件分岐の行は LARAVEL_START の直下に書く必要があります。

<?php
define('LARAVEL_START', microtime(true));

if (file_exists(__DIR__.'/../storage/framework/maintenance.php')) {
    require __DIR__.'/../storage/framework/maintenance.php';
}

[Upgrade][Low] Manager $app Property

Illuminate\Support\Manager クラスの $app プロパティが消えました。もしそのプロパティを使用している場合は $container プロパティを使用してください。

[Upgrade][Low] The elixir Helper

elixir ヘルパーは削除されました。Laravel Mix に移行してください。

[Upgrade][Low] Mail::sendNow Method

Mail facade にあった sendNow メソッドは削除されました。 send メソッドを使ってください。

[Upgrade][High] Pagination Defaults

Paginate の標準テンプレートが Tailwind CSS になりました。いままでの BootStrap を使い続ける場合は AppServiceProviderboot メソッドに \Illuminate\Pagination\Paginator::useBootstrap(); を記入してください。

[Upgrade][High] Queue::retryAfter method / property

QueuedJob, Mailer, Notification, Listener にある retryAfter メソッドと retryAfter プロパティの名前が backoff に変更されました。

[Upgrade][High] Queue::timeoutAt property

QueueJob、Notification, Listener の timeoutAt プロパティが retryUntil になりました。

[Upgrade][Optional] Failed Jobs Table Batch Support

queue_driver がdatabasefailed_jobs を使用している時に、uuid フィールドが必要になります。

<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::table('failed_jobs', function (Blueprint $table) {
    $table->string('uuid')->after('id')->unique();
});

次に queue.phpfailed.driverdatabase-uuids を設置します。

[Upgrade][Low] The cron-expression Library

Cron 書式の解析に使用している dragonmantank/cron-expression のバージョンが 3.x に更新されました。
下手に込み入った書き方をしている場合だと意図しない時間に動きますので、変更履歴を見て確認をする必要があります。

[Upgrade][Low] The Session Contract

\Session::pull() メソッドが追加されました。

/**
  * Get the value of a given key and then forget it.
  *
  * @param  string  $key
  * @param  mixed  $default
  * @return mixed
  */
 public function pull($key, $default = null);

[Upgrade][Medium] Testing, The assertExactJson Method

assertExactJson メソッドは数値キーの順番が同じである事をチェックするようになりました。順番が違っても良い場合は assertSimilarJson を使うようにしてください。

ぼんやり:: こういう事?

$asset = [ 0 =>1,  1 =>1,  2 =>1];
$data  = ['1'=>1, '0'=>1, '2'=>1];
$this->assertExactJson(json_encode($asset), json_encode($data)) // => false
$this->assertSimilarJson(json_encode($asset), json_encode($data)) // => true

[Upgrade][Low] Database Rule Connections

unique,exists ルールに getConnectionName メソッドが追加されました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel 】localhost/プロジェクト名/public ←publicをなくす方法

調べたところ方法はいくつかあるが一番スマートな方法かなと思ったのでメモとして残します。

.htaccessを作成する

.htaccessとは隠しファイルの1つでリダイレクトなどの設定を記述するファイルのことです。

そこに以下記述をコピペします。

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    RewriteCond %{REQUEST_FILENAME} -d [OR]
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteRule ^ ^$1 [N]

    RewriteCond %{REQUEST_URI} (\.\w+$) [NC]
    RewriteRule ^(.*)$ public/$1 

    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ server.php

</IfModule>

参照:https://gist.github.com/liaotzukai/8e61a3f6dd82c267e05270b505eb6d5a

vscodeなどでコードを貼り付けてLaravelのルートディレクトリに保存します。

保存しても隠しファイルなのでフォルダには表示されていません。
隠しファイルを表示させたい時はそのフォルダで
(macの場合)

command + shift + .(ドット)

を入力すると表示させることができます。

以上で完了です!
localhost/プロジェクト名 でルートディレクトリへ遷移できます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

kintoneクローン? OSSWebDBのExmentをLightsail+Dockerで立ち上げたら結構ハマったのでメモしておく

Exment is 何?

2020-09-08_11h46_18.png
Exmentは、Laravel製(ということは、LAMPですね。ということは、レンタルサーバーでも動きますね。)のWeb DBシステムです。リレーショナルなデータベースをGUI管理画面から操作できます。

ExmentはOSSで、GPLライセンスです。開発は株式会社カジトリ​が中心となって行っています。詳細は開発者の方の記事をご覧ください

GUIのWeb DBというと、なんとなくサイボウズ社のkintoneを連想する方もいるのではないでしょうか。

開発元からはキントーンのキの字も聞こえてきませんが、筆者はひそかにkintoneクローンだと思っていて、かなり可能性を秘めているOSSプロダクトだと考えています。

正直、かなりほれ込んでいるのですが、この記事ではお気に入りポイントは解説しません。また別の機会に。

クラウドでなるべくお安くExmentを運用したい!

ローカルでは、Dockerを使ってExmentを試すことができます。作ってくれた人ありがとう!

ローカルで実際やってみたところ(macOS Mojave、Windows 10 Home WSL2で確認)、あっさり出来ました。すごいですね。

そうしたら、クラウドでホスティングして、外出先などからもアクセスしたくなるというのが人情ですよね。

ホスティング先をいろいろ考えてみました。フロントエンドだけなら、NetlifyやVercelといった無料のサービスもあるのですが、残念ながらこれはバックエンドのシステムです…

先述していますが、Exmentはレンタルサーバーでも運用できます。

Exment公式サイトには、さくらやエックスサーバーといったレンサバでのインストール手順が公開されていますが、残念ながら、さくらやエックスサーバーのアカウントを私は持ち合わせておりません。つまり、筆者はレンサバの契約をしていないのですね。(フロント寄りの作りかけ個人プロダクトがNetlifyやVercelにはわんさかあるんですけど)

Exmentのためだけにレンサバ借りるのもなんだかなあ、だったらVPSのほうが良くない? と色々調べた結果、AmazonのLightsailが私の用途にぴったりだと気付きました。

(なお、筆者はこの時点でVPS、AWS童貞です)

ではさっそくLightsailのアカウントを取得して、始めるぞ!

Lightsailにログインしてからインスタンスの作成あたりまでは、下記記事が詳しいです。

今回は、一番安い$3.5/月の512MBRAMのインスタンスにしました。なるべくお安く、というテーマなので。どうしてもスペック足りなかったら、その時にスケールアップなりなんなり対応を考えようというスタンスです。

Lightsailには、WordPressなどのWebアプリケーションがセットになったインスタンスひな形があるのですが、当然知名度まだまだのExmentひな形というのはありません。

そこで、OSのみのインスタンスを選択します。今回は、CentoOS7を選択しました。

CentOSにフツーにインストールする? それとも…?

Exment公式には、CentOS7にインストールする手順も公開されており、またそれを補強する記事もあります。(下記参照)

が、公式を見ていただければわかる通り、結構な手順があります。で、実際1度やりました。何度か環境を捨てたりやり直したりする過程で「この手順毎回やってられんわ!」となり、他の方法を考えることに至ります。

せや、Dockerそのまま載せたったらええやん?

Lightsail+DockerでExmentを動かす(httpsもあるよ!)

ここからは、ハマりポイントを踏まえた回避策も含めて手順を記します。ここを守れば、最短でExment on Lightsail+Dockerが実現できます。

CentOS7でインスタンス作成後、Docker、Docker-composeとgitをインストールする

では、もろもろインストールしていきます。

毎回、sudo つけるの大変なので、rootになります。

Lightsailでrootになるには、こちらの記事を参考にしました。

$ sudo su -

Dockerをインストールします。こちらの記事が詳しいです。

[root@ip-172-xx-xx-x ~]# yum install -y docker          # dockerのインストール
[root@ip-172-xx-xx-x ~]# service docker start           # dockerの起動
[root@ip-172-xx-xx-x ~]# groupadd docker                # ユーザー権限で実行できるようにしておく
[root@ip-172-xx-xx-x ~]# usermod -g docker centos       # 作成したグループにcentosユーザを追加
[root@ip-172-xx-xx-x ~]# sudo /bin/systemctl restart docker.service
[root@ip-172-xx-xx-x ~]# docker info        

これでDockerはインストールできました。
続いて、Docker-composeです。

[root@ip-172-xx-xx-x ~]# curl -L https://github.com/docker/compose/releases/download/1.21.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
[root@ip-172-xx-xx-x ~]# chmod +x /usr/local/bin/docker-compose
[root@ip-172-xx-xx-x ~]# docker-compose --version

最後に、Gitをインストールします。CentOS7のyumで入るGitは、1.8.2と古いバージョンのものです。気になる人は、下記記事を参考に新しいのを入れてみてください。今回は、git cloneしたいだけなので、そのままyumでインストールします。

[root@ip-172-xx-xx-x ~]# yum install -y git

これで、Gitもインストールできました。

スワップ領域を作る

RAM512MBのインスタンスなので、DockerでMySQLまで動かすとメモリ不足になりました。(ハマりポイント1)なので、先んじてスワップ領域を作っておきましょう。

スワップの作り方は下記記事を参考にしました。

[root@ip-172-xx-xx-x ~]# dd if=/dev/zero of=/swapfile bs=1M count=4096 status=progress

コマンドの書き方をミスってたため、結構ハマりました(ハマりポイント2)

あれこれ試行錯誤した過程で、/dev/zeroが何のファイルかわかっておらず、rm -rfしちゃったのはいい思い出です。

/dev/zeroを復活させるのは、こちらの記事を参考にしました。

[root@ip-172-xx-xx-x ~]# mknod -m 666 /dev/zero c 1 5
[root@ip-172-xx-xx-x ~]# chown root:mem /dev/zero

status=progressオプションですが、今回はスワップ領域が4Gと大きめなので、しばらくターミナルが沈黙しちゃうと心配です。なので、ddコマンドの進捗をお知らせしてくれるオプションをつけました。下記記事を参考にしています。

ddでスワップ領域が作成されたら、粛々と残りの作業を進めます。

[root@ip-172-xx-xx-x ~]# chmod 600 /swapfile #パーミッションの変更
[root@ip-172-xx-xx-x ~]# mkswap /swapfile #スワップの作成
Setting up swapspace version 1, size = 1048572 KiB
no label, UUID=d0519bf6-8abf-4c0d-9375-8068c9e5e9a1
[root@ip-172-xx-xx-x ~]# swapon /swapfile #スワップの有効化
[root@ip-172-xx-xx-x ~]# free -m #スワップの確認

最後に、スワップの永続化をします。
viで/etc/fstabを開き、

/swapfile                                 swap                    swap    defaults        0 0

でおしまいです。

git cloneで、docker-compose.ymlとDockerfileを拾ってくる。

先述ご紹介した、ExmentのDockerを作ってくれた方のGithubから拾います

[root@ip-172-xx-xx-x /home/centos/]# git clone https://github.com/yamada28go/docker-exment.git

場所はどこでもいいと思うんですけど、デフォルトユーザーディレクトリ直下にしました。

httpsは?

Dockerでhttpsというと、https-portalが有名なようです。

結論から先にいうと、https-portalを先に設定した状態でExmentをインストールしたら、上手くいきませんでした!!!(ハマりポイント3)

なので、SSLを設定する前に非SSLの状態でExmentのインストールを進めます。

一応、docker-compose.ymlに目を通しておきますか。

docker-compose.yml
version: '3'
services:
  nginx:
    image: nginx:latest
    ports:
      - 8080:80
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
      - www-data:/var/www
    depends_on:
      - php

  php:
    build: ./php
    volumes:
      - www-data:/var/www
    depends_on:
      - db

  db:
    image: mysql:5.7
    ports:
      - 13306:3306
    volumes:
      - mysql-data:/var/lib/mysql
    environment:
      MYSQL_DATABASE: exment_database
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_USER: exment_user
      MYSQL_PASSWORD: secret

  phpmyadmin:
    image: phpmyadmin/phpmyadmin:latest
    ports:
      - 8888:80
    depends_on:
      - db

# volumes を定義する
volumes:
  # volume の名前を指定
  # Exmentのインストールパス
  www-data:
    # Compose の外ですでに作成済みの volume を指定する場合は ture を設定する。
    # そうすると、 docker-compose up 時に Compose は volume を作成しようとしません。
    # かつ、指定した volume が存在しないとエラーを raise します。
    #external: true
  # mysql dbのインストールパス
  mysql-data:

あとでhttps-portalが80番ポートを使うので、nginxが8080になっているのは逆に都合がいいです。特にこのまま何も編集しません。

docker-compose.ymlとDockerfileは何もさわりませんが、php.iniだけは1行だけ追記します。

最後の行に

memory_limit=-1

を追記しておきます(ハマりポイント4、詳細は後述)

ではいよいよ…

[root@ip-172-xx-xx-x /home/centos/]# docker-compose up -d

初回なので、イメージの取得とビルド、ボリュームの作成をやってくれます。

起動が完了したら、docker-comopse psで、全コンテナがUpしていることを確認します。(スワップを作っていなかった時は、ここでMySQLがExitしてました)

無事起動したら、IPアドレスでアクセスしてみよう

Lightsail側で以下の手順を済ませておきます。

  • 静的IPのアタッチ
  • ポート8080番の開放

xx.xx.xx.xx:8080にブラウザでアクセスしてみて、Laravelの初期画面が表示されていれば成功です。

xx.xx.xx.xx:8080/adminにアクセスすると、Exmentの初期設定画面になります。

画面は3部構成になっていて、

  1. 言語とタイムゾーンの指定
  2. DB設定
  3. DB設定開始ボタン

の3画面です。何か入力するのは2画面目のDB設定です。

Dockerを使っていますので「ExmentのDocker環境を作ってみた」の記事を参考に、設定を埋めます。

  • ホスト名 → db
  • データベース名 → exment_database
  • ユーザー名 → exment_user
  • パスワード → secret

この後、無事インストールが完了すれば、Exmentの初期画面となります。

添付ファイルとかはS3に保存したいじゃんね!

今回のLightsailインスタンスは、保存領域が20GBと、まあ何か動かすのはいいけど、バイナリデータ突っ込んでいったらすぐパンパンになるよね、って容量です。

Exmentには、外部のストレージサービスに各種ファイルを保存するオプションがあります。

せっかくですので、AWSでそろえて、S3に保存させるようにしてみましょう。

S3も童貞でしたので、下記記事を参考にバケットを作成してみました。

Exment側でも設定が必要です。既にdocker-compose exec php bashで立ち上がっているコンテナの中に入ります。

[root@ip-172-xx-xx-x /home/centos/]# docker-compose exec php bash

これで、Exmentが動いているphpコンテナの中に入れます。プロンプトの表示がこんな感じに変われば成功です。

root@f54bef27801a:/var/www#

つまり、クラウド上にあるLightsailの中にあるDockerコンテナphpの中にいるという二重構造なわけですね。

引き続き、「(上級者向け)ファイルの保存先変更」を読み解きながら、Exment(Laravel)のファイルを修正していきます。

Exmentルートフォルダにある、.envファイルをvimで修正/追記します。

EXMENT_DRIVER_EXMENT=s3
EXMENT_DRIVER_BACKUP=s3
EXMENT_DRIVER_TEMPLATE=s3
EXMENT_DRIVER_PLUGIN=s3

AWS_ACCESS_KEY_ID=(AWS S3のアクセスキー)
AWS_SECRET_ACCESS_KEY=(AWS S3のシークレットアクセスキー)
AWS_DEFAULT_REGION=(AWS S3のリージョン)

AWS_BUCKET_EXMENT=(添付ファイルで使用するAWS S3のバケット)
AWS_BUCKET_BACKUP=(バックアップで使用するAWS S3のバケット)
AWS_BUCKET_TEMPLATE=(テンプレートで使用するAWS S3のバケット)
AWS_BUCKET_PLUGIN=(プラグインで使用するAWS S3のバケット)

なお、EXMENT_DRIVER_xxxはすべて設定する必要はなく、必要があるものだけ設定します。それに紐づくAWS_BUCKET_xxxも必要なものだけでOKです。

私は添付ファイルとバックアップデータはS3に保存したかったので、

  • EXMENT_DRIVER_EXMENT
  • EXMENT_DRIVER_BACKUP
  • AWS_BUCKET_EXMENT
  • AWS_BUCKET_BACKUP

の4つのみ設定しました。

最後に、composerでライブラリをインストールします。

先ほど、docker-compose up -dの前にphp.iniを編集しましたが、Composerはメモリ食いで、すぐPHPのメモリ利用可能上限に達してしまうので、この上限を解除する設定をしたのでした。

Composerはインストールに時間がかかるので、時間かかった結果失敗した、って辛いですよね…(筆者はとても悲しかったです。)なので、この設定はcomposer requireをする前にもう一度確認しておきましょう。

root@f54bef27801a:/var/www# php -i | grep memory_limit
memory_limit => -1 => -1

-1になっていればOKです。(メモリ上限なし、の意味)

では、いよいよライブラリのインストールです

root@f54bef27801a:/var/www# composer require league/flysystem-aws-s3-v3 ~1.0 -vvv

-vvvオプションは、もっとも粒度細かくログを出す、という意味の指示です。composerはインストールにとても時間がかかるので、長い時間ターミナルが沈黙していると心配になります。

なので、逐次ログを出してくれるようにします。このオプションをして長いこと沈黙があれば、それは本当に何かしらの理由で止まっているか、めちゃくちゃ重い処理をしている、ということになります…

S3に添付ファイルをアップするオプションの設定は以上です。適当な画像でもアップして、バケットの中にファイルがあることを確認しましょう。

最後に呪いのhttpsです…

いや、httpsに何の悪いところもないのですが、かなりハマって悩まされたので…

色々やり方が悪かったのかと思い、Docker環境全捨てからの再インストールを何度も行ったので、かなり時間を食ってしまいました。

さっきも言いましたが、docker-composeにhttps-portalも混ぜて書いてしまうと、初回インストールに失敗します。結局はよくわからんエラーに遭遇して詰みました。

インストールは3画面あるといいましたが、最後の3画面目のインストールボタンを押したら、あのLaravelのグレーみの強いエラー画面で

Use of undefined constant STDIN - assumed 'STDIN' (this will throw an Error in a future version of PHP)

って出てきて、DBにデータが差し込めないことに。PHPやLaravelに明るくない筆者であるため、ここで断念しました。

httpならちゃんとうまくいったので、結局このエラーをつぶすことはあきらめ、httpでインストール完了させ、その後httpsにするという作戦に切り替えた次第です。

https-portalをdocker-compose.ymlに追記する

https-portalの部分だけ書き出します。

docker-compose.yml
https-portal:
  image: steveltn/https-portal:1
  ports:
    - '80:80'
    - '443:443'
  links:
    - nginx
  restart: always
  volumes:
    - ./certs:/var/lib/https-portal
  environment:
    STAGE: 'production'
    DOMAINS: >-
      example.com -> http://nginx:8080
  depends_on:
    - php

特に難しいことはありません。公式のサンプルとそんなに変わりませんし。ポイントとしては、enviroment:STAGE:が、'production''staging'でないと、Let's Encryptの本チャンの証明書はもらえないということです。ここがlocalとか指定なしだと、ローカル開発ってことで、なんちゃって証明書が発行されます。ここも地味にハマりポイントでした(ハマりポイント5)

さて、最後に https://example.com/ にアクセスして、Laravelの初期画面が表示されれば晴れて成功です…

と言いたいのですが、まだあります。

https://example.com/admin にアクセスすると、盛大に画面崩れを起こしているじゃないですか!

ブラウザコンソールを見ると、mixed contentでhttpがソースのCSS/JS類が全部ブロッキングされています。

これの対処が最初全然わからなかったのですが、試行錯誤の結果、LaravelおよびLaravel-adminが犯人と断定されました! asset('/css/hoge.css')みたいな記述のところで、http付のパスを出力しちゃってるようです…

以下、この件についての対策です。またdocker-compose exec php bashして中に入ってください。

/var/www/exment/.env
APP_ENV=production
/var/www/exment/app/Providers/AppProvider.php
class AppServiceProvider extends ServiceProvider
    public function boot()
    {
    if (config('app.env') === 'production') {
       \URL::forceScheme('https'); //Schemaじゃなくて、Scheme!!!(ハマりポイント6)
    }
    }
/var/www/exment/config/admin.php
    /*
    |--------------------------------------------------------------------------
    | Access via `https`
    |--------------------------------------------------------------------------
    |
    | If your page is going to be accessed via https, set it to `true`.
    |
    */
    'https' => env('ADMIN_HTTPS', true), // ←デフォはfalseなので、trueに!

これで、すべてのアセットがhttpsから配信され画面崩れなく表示されるようになりました。

正直、これが本当の意味で正解かどうかわかりません。もしかしたら、AppProvider.phpは不要かもしれません… Laravelのバージョンによってコードの書き方が微妙に違うようでした。これは、本当にたくさんの参考ソースを読みまくって、なんとか動くコードに落ち着いたというのが実情です。

もし、もっと良い方法があるよ、という方はぜひコメント欄で教えてください。

以上、無事動くようになりました!

今のところ、機嫌よく動いてくれています。

セキュリティ等

本記事は検証目的の環境づくりのため、セキュリティ等については触れておりません。詳しい方は補足いただけると助かります。

今後

Exmentの素敵なところをほめまくる記事とか書きたいですね!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelでFirebase Admin SDK for PHPを利用する(トークン再取得編)

Firebase Admin SDK for PHPでは、自動でトークン取得はできないっぽい

例えば、Javascriptなら以下のようにcurrentUser.getIdToken()で取得できる。
期限切れ前に自動で更新してくれるので便利。

firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
  // Send token to your backend via HTTPS
  // ...
}).catch(function(error) {
  // Handle error
});

Firebase Admin SDK for PHPには似たような機能はなかった。
トークンが切れるたびにいちいちログインし直すのもなんだか嫌。

解決方法

    // ログインしていない場合
    if(!Session::get('token')){
      $signInResult = $this->auth->signInAnonymously();
      Session::put('token', $signInResult->idToken());
      Session::put('refresh_token', $signInResult->refreshToken());
    }

    // トークン認証
    try {
      $auth->verifyIdToken(Session::get('token'));
    } catch (\Exception $e) { // ここはExpiredTokenとかに絞った方が良い
      // 期限切れなら更新トークンを使って再取得
      $refresh_token = Session::get('refresh_token');
      $signInResult = $auth->signInWithRefreshToken($refresh_token);
      Session::put('token', $signInResult->idToken());
    }

流れは以下のような感じ。
1)ログイン時の結果にrefresh_tokenがあるので、セッションか何かに取っておく。
2)トークンが期限切れになったらverifyIdToken()で例外が発生するので、signInWithRefreshToken()で再取得

リフレッシュトークンが変更されるタイミングはそんなにないので、とりあえず使いたい場合は上記で間に合うと思う。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel オリジナルの設定ファイルを作成してコントローラで呼び出す

目的

  • Laravelの設定ファイルへの追記方法と設定ファイルの読み込み方法をまとめる
  • ※本説明でいう設定ファイルとは.envファイルではなく、アプリ名ディレクトリ/config直下にあるファイルを指す

実施環境

  • ハードウェア環境
項目 情報
OS macOS Catalina(10.15.5)
ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)
プロセッサ 2GHzクアッドコアIntel Core i5
メモリ 32 GB 3733 MHz LPDDR4
グラフィックス Intel Iris Plus Graphics 1536 MB
  • ソフトウェア環境
項目 情報 備考
PHPバージョン 7.4.3 Homwbrewを用いて導入
Laravelバージョン 7.0.8 commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う
MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする

前提条件

  • 実施環境に記載した環境、またはそれに準ずる環境が用意されておりLaravelアプリが作成されていること。

前提情報

読後感

  • アプリ名ディレクトリ/config直下の設定ファイルに独自の設定を追記することができる。
  • アプリ名ディレクトリ/config直下の設定ファイルに記載されている値を読み込み表示することができる。

概要

  1. 設定ファイルの作成と記載
  2. ルーティング情報の追記
  3. コントローラファイルの作成と記載
  4. ビューファイルの作成と記載
  5. 確認

詳細

  1. 設定ファイルの作成と記載

    1. アプリ名ディレクトリで下記コマンドを実行して設定ファイルを作成する。

      $ vi config_test.php
      
    2. 開いたファイルに下記の内容を追記し保存して閉じる。

      アプリ名ディレクトリ/config/config_test.php
      <?php
      
      return [
          # 文字列の設定
          'config_str' => 'これは設定ファイルで設定された文字列です。',
      ]
      
      ?>
      
  2. ルーティング情報の追記

    1. アプリ名ディレクトリで下記コマンドを実行してルーティングファイルを開く。

      $ vi routes/web.php
      
    2. 下記の内容を追記する。

      アプリ名ディレクトリ/routes/web.php
      Route::get('/config_check', 'ConfigCheckController@config_check')->name('config_check');
      
  3. コントローラファイルの作成と記載

    1. アプリ名ディレクトリで下記コマンドを実行してコントローラファイルを作成する。

      $ php artisan make:controller ConfigCheckController
      
    2. アプリ名ディレクトリで下記コマンドを実行してただいま作成したコントローラファイルを開く。

      $ vi app/Http/Controllers/ConfigCheckController.php 
      

      下記の様に記載を行う。

      アプリ名ディレクトリ/app/Http/Controllers/ConfigCheckController.php
      <?php
      
      namespace App\Http\Controllers;
      
      use Illuminate\Http\Request;
      // 下記を追記する
      use Illuminate\Support\Facades\Config;
      
      class ConfigCheckController extends Controller
      {
          // 下記を追記する
          public function config_check()
          {
              // アプリ名ディレクトリ/config直下に存在するconfig_test.phpファイルで定義されているconfig_strの文字列を$strに格納する処理
              $str = Config::get('config_test.config_str');
              return view('checks.config_check', [
                  'str' => $str,
              ]);
          }
          // 上記までを追記する
      }
      
  4. ビューファイルの作成と記載

    1. アプリ名ディレクトリで下記コマンドを実行してビューファイルを格納するディレクトリを作成する。

      $ mkdir resources/views/checks
      
    2. アプリ名ディレクトリで下記コマンドを実行してビューファイルを作成する。

      $ vi resources/views/checks/config_check.blade.php
      
    3. 開いたビューファイルに下記の内容を記載する。

      アプリ名ディレクトリ/resources/views/checks/config_check.blade.php
      {{ $str }}
      
  5. 確認

    1. アプリ名ディレクトリで下記コマンドを実行してローカルサーバを起動する。

      $ php artisan serve
      
    2. ブラウザで下記にアクセスする。(Authの認証機能が付与されているLaravelアプリで下記にアクセスする場合、ログインが必要になる場合がある。)

    3. 下記の様に、設定ファイルに記載した内容がブラウザ上で表示されていれば作業完了である。

      *画像

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ドメイン駆動設計における5層アーキテクチャの全体図とソースの実装例

今回の記事では、過去に記述した以下のバックエンドに関する記事を一つに統合した内容となっている。
従来のドメイン駆動設計4層アーキテクチャにDCIアーキテクチャを組み込んでいく過程で、様々なパラダイムが発生し、
最終的に4層アーキテクチャミッション層を追加した5層アーキテクチャという形に落ち着いた。
今回の記事では、投稿した過去の記事の内容を5層アーキテクチャによって概念を整理し、整合性を担保している。

投稿した過去の記事一覧

・ドメイン駆動設計のユースケース層(アプリケーション層)を軍事思想(作戦術)でドーピング
https://qiita.com/aLtrh3IpQEnXKN7/items/853ecb3cd109dd016476

・OOUI(オブジェクト指向設計)によるバックエンド設計のパラダイムシフト
https://qiita.com/aLtrh3IpQEnXKN7/items/3aa05f9628544c43f279

・DCIアーキテクチャの活用方法を紹介
https://qiita.com/aLtrh3IpQEnXKN7/items/355ad12f82ac424abea3

・エリック・エヴァンスが提唱したアーキテクチャの4層モデルを拡張する
https://qiita.com/aLtrh3IpQEnXKN7/items/b7fe2014ccefcbb9e458

・ドメイン駆動設計のミッション層を設計する手法を紹介
https://qiita.com/aLtrh3IpQEnXKN7/items/98e0c2d2ee0776e0e039

・5層アーキテクチャモデルにおけるドメイン分析
https://qiita.com/aLtrh3IpQEnXKN7/items/e5d1a276c07f1fe140be

各レイヤーの説明

レイヤーの全体図

image.png

1.コントロール層

アプリ外からアクセスの入り口となるインターフェースを主にRestApiで提供する。アプリ外からのアクセスがWeb、iOS、Androidと増加するたびにインターフェースを追加する必要がある。
インターフェース以外の機能として、コントロール層からユースケース層へデータを受け渡す際のデータ変換、コントロール層からアクセス元へのデータ変換(JSON化)を行う。データの受け渡し、データ変換機能をメインに担当する。

2.ユースケース層

ビジネスロジックで実現したい目的を記載するための層。ミッション層のメソッドの呼び出しのみを行う。
ユースケース層では、フロントエンドから取得したデータを格納するためのBeanクラスを必ず用意する。
Beanクラスミッション層へ引数として渡し、ミッション層内で具体的なロジック内容を実装する。

ユースケース層のビジネスロジックは以下の種類で実装する。
偵察・・・画面に表示するデータを取得する
順次・・・ビジネスのワークフローを順番通りに進める
ゲリラ・・・不定期に行われるイベント処理を実施する
監視・・・DB内部の情報を監視し、アプリの規約に違反したユーザーの発見などを行う
エスカレーション・・・アプリのルールに違反しているユーザーへの通知、警告などを行う
エマージェンシ・・・緊急事態に対応する
相対・・・キャンセル処理などビジネスのワークフローから外れる例外処理

3.ミッション層

具体的なビジネスロジックを記述するための層。ビジネスロジックはDCIアーキテクチャによって実装が行われる。
この層では、ユースケース層で実現したい目的をドメイン層のメソッドを組み合わせて実現する。
以下の観点で、ドメイン層のメソッドを組み合わせロジックを作成する。

イベント・・・DBへデータを書き込む事象
リソース・・・企業が取り扱うサービス or 商品
ルール・・・イベントに紐づく運用ルール
テクノロジー・・外部ライブラリを使用して実装されるメールの転送やファイルアップロード
エージェント・・・ミッション層のロジックを統率する。イベント、リソース、テクノロジーのメソッドが全て集約する。

4.ドメイン層

ミッション層のロジックを構成する層。ミッション層内でメソッドの呼び出しが行われる。
ドメイン層では、アプリ全体で共通するデータ構造の取得、共通するデータ構造に依存した業務ルールの提供、データ集約に基づいたデータ登録 or 更新 or 削除処理を取り扱う。

5.インフラ層

外部ライブラリを使用したロジックを記述し、全レイヤーに外部ライブラリの機能を提供する。例としてメールの送信、ログの出力などが該当する。
ライブラリはバージョンアップや使用するライブラリ変更されるなど、頻繁に発生する箇所する。そのため、DIP(依存関係逆転の原則)に従って、
ドメイン層にインターフェースを配置し、実際のロジックはインフラ層に記述する。インターフェースをデータインジェクション(依存性注入)機能を利用してインタンス生成を行う。

実装するクラス一覧

各レイヤー層に記述するクラス一覧について記載

1.コントロール層

Controller・・・REST APIの提供、Convetクラスのメソッドの呼び出し、ユースケース層の画面レベルのメソッドの呼び出し、
Web用、Andoroid、iOSへ引数を返却する際の値変換(JSON化)など
Coverter・・・REST APIから取得した画面の入力値の値をユースケース層へ引き渡す際の値の変換

2.ユースケース層

Bean・・・コントロール層から取得した入力値を格納して、ユースケース層へ引き渡す際のクラス。getter setterでメソッドを構成。表示画面と1対1の関係にある。
SearchOperation・・・検索したデータを画面表示することを目的としたビジネスロジック
RegularOperation・・・ビジネスのワークフローを次状態に進めるデータ登録、更新処理を目的としたビジネスロジック
GuerrillaOperation・・・ゲリライベントで発生するデータ登録、更新、削除処理を目的としたビジネスロジック
MonitoringOperation・・・DBのデータを監視し、規約違反が発見した場合、規約違反のデータ登録、更新、削除処理を目的としたビジネスロジック
EscalationOperation・・・エスカレーションラダーを設定し、規約違反を起こしているユーザーに各エスカレーションに応じた通知処理を目的としたビジネスロジック
EmergencyOperation・・・緊急事態対応を目的としたビジネスロジック
IrregularOperation・・・従来のビジネスのワークフローから外れるデータ登録、更新、削除処理を目的としたビジネスロジック

3.ミッション層

Mission ・・・Beanクラスを引数として受け取り、Beanクラスに対応したActorクラスのインスタンス、Actorクラスの型となるRoleインターフェスの選択、Roleメソッドの実行を行う。
Actor・・・Roleインターフェースを実装するクラス。Mixinを使用して多重継承を実施。
Role・・・インターフェース。ミッション層のEvent、Resource、Rule、Technologyのメソッドを集約する。ミッション層のロジックを組み合わせ ユースケース層で実現したいロジックを実装する。
Event・・・DBの登録 or 更新 or 削除に関する事象を実装するクラス。ドメイン層の、Aggregates、Servicesの組み合わせで実装される。
Resource・・・企業が取り扱う商品 or サービスのデータをDBから取得するクラス。ドメイン層の、Value Objects、Factories、Entities、Repositoriesの組み合わせで実装される。
Rule・・・運用ルールを実現するクラス。ドメイン層の、Specification、Value Objects、Factories、Entities、Repositoriesなどのメソッドの組み合わせで運用ルールを実現する。
Technology・・・技術的なビジネスロジックを実装するクラス。インフラ層のメソッドとインフラ層のメソッドを組み合わせて実現する。

4.ドメイン層

Factorys・・・DTOクラスを引数とし、ValueObjectインスタンスを生成
ValueObject・・・共通構造クラス。DTOをフィールド変数として持ち、getterメソッドとisメソッドのみで構成されている。DTOのデータを加工して提供、DTOのデータに応じたif分の提供などを行う。
Specifications・・・ビジネスルール or 入力値チェックなどのビジネスロジックを提供する
Repositorys・・・DBからデータ検索処理を行うクラス。
Aggregates・・・特定のデータ範囲に応じて、データの登録、更新、削除を行うクラス。
Services・・・上記で上げたドメイン層のロジックに分類できない処理を取り扱うクラス。

5.ドメイン層

Mail・・・メール送信を行う。
SFTP・・・SFTPによるデータ送受信を行う。
FileUpload・・・ファイルアップロードを行う。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む