- 投稿日:2020-02-18T22:46:05+09:00
Docker上でPHP拡張モジュール『GD』を有効化する
この記事ではDocker上でPHP拡張モジュール『GD』を有効化する方法をお伝えします。
どうしてGDの有効化が必要になったか
LaravelとVueを用いたSPAを勉強したく、『Vue + Vue Router + Vuex + Laravelで写真共有アプリを作ろう』に取り組んでいました。
(9)写真投稿APIでテストを実行した際に
Error: Call to undefined function Illuminate\Http\Testing\imagecreatetruecolor().
というエラーで行き詰まり、原因を調査したところPHP拡張モジュール『GD』の有効化が必要との情報にたどり着きました。環境
version PHP 7.4.1 Laravel 6.15.0 Docker for Mac 19.03.5 GD有効化の方法
DockerファイルにGDの有効化、必要なライブラリのインストールの部分を記載することでGDを有効化できます。
有効化した後、再ビルドすることで正しく動作するようになります。まずはGDが使えない状態のDockerfileをご紹介します。
DockerfileFROM php:7.4.1-fpm COPY install-composer.sh / RUN apt-get update \ && apt-get install -y wget git unzip libpq-dev \ && : 'Install Node.js' \ && curl -sL https://deb.nodesource.com/setup_12.x | bash - \ && apt-get install -y nodejs \ && : 'Install PHP Extensions' \ && docker-php-ext-install -j$(nproc) pdo_pgsql \ && : 'Install Composer' \ && chmod 755 /install-composer.sh \ && /install-composer.sh \ && mv composer.phar /usr/local/bin/composer WORKDIR /var/www/html/vuesplash【参考】
Vue + Vue Router + Vuex + Laravelで写真共有アプリを作ろう (3) SPA開発環境とVue Routerこれを下記のように変更します。
:Dockerfile FROM php:7.4.1-fpm COPY install-composer.sh / RUN apt-get update \ && apt-get install -y wget git unzip libpq-dev libfreetype6-dev libjpeg62-turbo-dev libpng-dev \ && : 'Install Node.js' \ && curl -sL https://deb.nodesource.com/setup_12.x | bash - \ && apt-get install -y nodejs \ && : 'Install PHP Extensions' \ && docker-php-ext-install -j$(nproc) pdo_pgsql \ && docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) gd \ && : 'Install Composer' \ && chmod 755 /install-composer.sh \ && /install-composer.sh \ && mv composer.phar /usr/local/bin/composer WORKDIR /var/www/html/vuesplash変更点は3行です。
まずは5行目。
- && apt-get install -y wget git unzip libpq-dev \ + && apt-get install -y wget git unzip libpq-dev libfreetype6-dev libjpeg62-turbo-dev libpng-dev \
libfreetype6-dev
、libfreetyep6-dev
、libjpeg62-turbo-dev
、libpng-dev
の4つのライブラリを追加しています。【参考】
docs/php at master · docker-library/docs
2点目の変更点は、変更後のファイル11行目に新たに一行挿入しています。
+ && docker-php-ext-configure gd --with-freetype --with-jpeg \PHP7.4系では
docker-php-ext-configure
の引数が変更されているので注意が必要です。【参考】
【PHP】Docker PHP7.4系でgdをインストールしてimagecreatefromjpegを使う
docs/php at master · docker-library/docs
最後に変更後のファイルの12行目のように、GDのインストールコマンドを追加して変更完了です。
+ && docker-php-ext-install -j$(nproc) gd \【参考】
docs/php at master · docker-library/docsまとめ
Laravelを勉強しているものの、基本的な言語仕様は同じだろうと高をくくっており、PHP自体の構成や拡張モジュールについては全く勉強しておらず、長時間ハマり続けてしまいました…
これを機に基本的な言語仕様や拡張モジュールについても勉強していければと思います。
また、長時間ハマり続けた別の理由として、古い情報がうまくいかない場合が多かったこともあるので、今回の記事のように苦労して解決したことは積極的に記事にしていきたいです。
まだまだPHPもLaravelもDockerも未熟なので、誤りがありましたらご指摘いただけると幸いです。
参考
- 投稿日:2020-02-18T18:57:54+09:00
MacからWindowsにlaravel開発環境を移してみた!(サーバー起動まで)
用意したもの
virtual box
vagrant
cyberdock
tera termvagrant upしてvirtual boxを起動します。
virtual boxにログインするためtera termを使いsshでログイン
その後、virtual boxにファイルをアップロードするためcyeberdockを使いアップします。
php artisan serveを起動するとこんなエラーが・・・・
PHP Parse error: syntax error, unexpected '?' in /home/vagrant/laravel_lessons_copy/myblog/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php on line 500Laravel5.5はPHPのバージョンが7.0.0以上を必要としています。PHPのバージョンが7未満だと上記エラーになる場合があります。特にCentOSをはじめとするサーバOSはデフォルトでPHP7以上になっているものが少ないため、注意が必要です。
Laravel初期設定でやりがちなミス:引用元URL(https://www.inet-solutions.jp/technology/laravel-setting/)ということなのでバージョンアップ
sudo yum install --enablerepo=remi,remi-php71 php php-devel php-mbstring php-pdo php-gd php-mcrypt
これでphp artisan serveが実行できるはずです。
ちなみにここでも繋がらなかったので下記で起動を行いました。
$ php artisan serve --host 192.168.33.10 --port 8000
- 投稿日:2020-02-18T17:40:16+09:00
LaravelのModelに補完が効かなくて辛い人たちに贈る「Laravel IDE Helper Generator」の紹介
Eloquent Model でプロパティや scope を扱うときに補完が効いて欲しい。しかし、例えば下記のようにコードを書いても補完が効かなくて辛いですよね。
SampleRepository.php$sample = new Sample(); dd($sample->id); // ここでidに補完が効いて欲しい!できればタイプヒンティングもしてほしい!このように Model からカラム名にアクセスした際に補完が効かないのに加え、クエリをカプセル化してくれる scope を利用したときも補完は効きません。
App\Models\Sample.phppublic function scopeIsPublic($query) { return $query->where('is_public', true); }SampleRepository.php$sample = new Sample(); dd($sample->isPublic()->get()); // ここでisPublic()に補完が効いて欲しい!補完が効かないから、カラム名は typo や型を間違えて代入してしまうリスクもあるし、scope も大文字や小文字を間違えてしまうこともあるでしょう。
本記事では Laravel の Model に補完・型情報を付与してくれるライブラリ【Laravel IDE Helper Generator】について解説します。
本記事でできるようになること
このように scope を hover すると型定義が出ますし、補完も効きます。
また、カラム名へのアクセスに対しては型補完が効いています(業務ソースなので隠しまくりなのですがご容赦ください)。
この例ですと、とあるテーブルの transferred_at カラムへ日付を保存しているわけですが、日付保存可能かつ、振り込みされていない場合は null が格納されている、といったことがある程度型情報から読み取ることができます(null が良いのかはさておき)。
セットアップ
https://github.com/barryvdh/laravel-ide-helper
に概ね書いてあるとおりです。
まずは composer でインストールします。
composer require --dev barryvdh/laravel-ide-helperLaravel5.5 以上を利用している方はこれでセットアップはもう終わりです。
Model の phpDocs を自動生成
続いて Model の scope やカラム名に対応した phpDocs を自動生成します。
下記コマンドを実行します。
php artisan ide-helper:model --nowrite
ide-helper:model
コマンドで実行できるわけですが、型定義ファイルをつくるオプションと、各 Model に直接上書きするオプションがあります。個人的には、自動生成されたコメントがプロダクトコードに入り込むのは、運用ルールが増えてしまってあまり好きではないので
--nowrite
オプションをつけて実行するのがおすすめです。さて、コマンド実行後に、root ディレクトリに
_ide_helper_models.php
が生成されています。一部抜粋するとこのような内容です。
_ide_helper_models.php/** * App\Models\User * * @property int $id * @property string|null $email * ...以上でやることはもう終わりました。さっそく自身の Repository や Model ファイルを開き、hover してみましょう。
補足
運用面では
_ide_helper_models.php
を git 管理してしまうと、複数メンバー間で Conflict が多発すると思うので、gitignore 扱いにして、各自で生成しましょうという運用にしたほうが望ましいと思います。
- 投稿日:2020-02-18T17:39:01+09:00
AWS Cognitoを利用してLaravelアプリに認証機能を実装する
artisan
コマンドで簡単に認証機能を実装できるLaravelですが、認証情報の管理は自DBで行うことになります。
今回はよりセキュリティを高めるために、AWS Cognitoに認証情報と機能を切り出した構成で実装してみることにします。ですが 公式ドキュメント では主に、iOS/Androidアプリやjavascriptアプリへ組み込む例が紹介されています。
AWS SDK for PHP も用意されてはいるのですが、有用な日本語情報がかなり少なかったので概要を紹介したいと思います。AWS Cognito とは
AWSが提供するアクセスコントロールサービスです。
IDプロバイダとして認証情報を保管し、トークンを払い出してくれるものです。Amazon Cognito は、ウェブアプリケーションやモバイルアプリケーションの認証、許可、ユーザー管理をサポートしています。ユーザーは、ユーザー名とパスワードを使用して直接サインインするか、Facebook、Amazon、Google などのサードパーティーを通じてサインインできます。
https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/what-is-amazon-cognito.htmlCognitoには以下の2種類の管理プールがあります。
ユーザープール
ユーザプールは Amazon Cognito のユーザディレクトリです。ユーザープールを使用すると、ユーザーは Amazon Cognito を通じてウェブまたはモバイルアプリにログインできます。また、ユーザーは Google、Facebook、Amazon などのソーシャル ID プロバイダー、および SAML ベースの ID プロバイダー経由でユーザープールにサインインすることもできます。
https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/cognito-user-identity-pools.htmlIDプール
Amazon Cognito ID プール (フェデレーテッドアイデンティティ) では、ユーザーの一意の ID を作成し、ID プロバイダーで連携させることができます。ID プールを使用すると、権限が制限された一時的な AWS 認証情報を取得して、他の AWS サービスにアクセスできます。
https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/cognito-identity.html今回はWebアプリへのログインに使用したいので、 ユーザープール を使用します。
手順
LaravelアプリにCognitoを使用したログイン機能を実装するために、以下の流れで作業していきます。
- Cognitoユーザープールを作成
- AWS SDK for PHPをインストール
- Laravelアプリ内にCognitoとの連携を実装
1. Cognitoユーザープールを作成
まずは認証情報を管理する場所を作ります。
こちら を参考にしてください。外部のアプリケーションからCognitoへリクエストするためにトークン(アプリクライアントID/シークレット)を払い出す必要があります。
「アプリクライアント」を作成し、以下のように設定します。
- 作成時に "クライアントシークレットを生成" に✅を入れて、アプリクライアントのシークレットも生成します
- 今回はバックエンドアプリからのリクエストなので "認証用の管理 API のユーザー名パスワード認証を有効にする (ALLOW_ADMIN_USER_PASSWORD_AUTH)" に✅を入れて
ADMIN_USER_PASSWORD_AUTH
の認証フローを使用できるようにしておきます。参考:
? ユーザープールのアプリクライアントの設定
? ユーザープール認証フロー - サーバー側の認証フロー2. AWS SDK for PHPをインストール
PHPで実装するためにSDKをインストールします。
こちら を参考にしてください。3. Laravelアプリ内にCognitoとの連携を実装
ここからが本題です??
今回は以下のようにして認証機能を実装しました。
- Cognitoへ認証情報(ID/password)をリクエスト
- 認証に成功したら、払い出されたIDトークンとリフレッシュトークンをCookieに保存
- middlewareでIDトークンを検証
- IDトークンが正しいと検証できればログインが必要なページを表示、または処理を実行する
実装
CognitoユーザープールAPI には接頭辞 "Admin" がついたものがいくつか用意されています。
これらは管理者として操作できるもので、インスタンス化する際にcredentials(IAMユーザー情報)が必要です。1. Cognitoへ認証情報(ID/password)をリクエスト
こちらの記事 を参考にさせていただきました?♀️
まずはじめに、 adminInitiateAuth で認証情報をCognitoへリクエストします。
今回アカウントはユーザーがサインアップするのではなく、管理者が発行する仕様なのでいきなりここからです。
"AuthFlow" にはADMIN_NO_SRP_AUTH
を指定します。(最新ではADMIN_USER_PASSWORD_AUTH
に置き換わったようです)CognitoService.phpnamespace App\Services; use Aws\CognitoIdentityProvider\CognitoIdentityProviderClient; use Aws\CognitoIdentityProvider\Exception\CognitoIdentityProviderException; class CognitoService { private $library_version; private $region; private $access_key; private $secret_key; private $user_pool_id; private $client_id; private $client_secret; private $COGNITO_CLIENT; public function __construct() { $this->library_version = config('auth.aws.library_version'); $this->region = config('auth.aws.default_region'); $this->access_key = config('auth.aws.access_key'); $this->secret_key = config('auth.aws.secret_key'); $this->user_pool_id = config('auth.cognito.user_pool_id'); $this->client_id = config('auth.cognito.client_id'); $this->client_secret = config('auth.cognito.client_secret'); } private function adminInstantiation(): void { $this->COGNITO_CLIENT = new CognitoIdentityProviderClient( [ 'version' => $this->library_version, 'region' => $this->region, 'credentials' => [ 'key' => $this->access_key, 'secret' => $this->secret_key, ], ] ); } /** * ユーザー認証 * * @param string $username * @param string $password * * @return array */ public function authenticate(string $username, string $password): array { try { $this->adminInstantiation(); $response = $this->COGNITO_CLIENT->adminInitiateAuth( [ 'AuthFlow' => 'ADMIN_NO_SRP_AUTH', 'AuthParameters' => [ 'USERNAME' => $username, 'PASSWORD' => $password, 'SECRET_HASH' => self::cognitoSecretHash($username), ], 'ClientId' => $this->client_id, 'UserPoolId' => $this->user_pool_id, ] ); } catch (InvalidArgumentException $e) { return [ 'result' => false, 'message' => __('validation.custom.auth_id.form'), ]; } catch (CognitoIdentityProviderException $exception) { $errorCode = $exception->getAwsErrorCode(); // エラーメッセージ $errorMessage = __('auth.other'); if ($errorCode === self::NOT_AUTHORIZED) { if (strpos($exception->getAwsErrorMessage(), 'exceeded') == false) { $errorMessage = __('auth.incorrect'); } else { // 試行回数超過 $errorMessage = __('auth.exceeded'); } } elseif ($errorCode === self::TOO_MANY_REQUESTS) { $errorMessage = __('auth.too_many'); } else { // 上記以外のエラーコードの場合 } return [ 'result' => false, 'message' => $errorMessage, ]; } return [ 'result' => true, 'data' => $response->toArray(), ]; } protected function cognitoSecretHash($username) { return $this->hash($username.$this->client_id); } protected function hash($message) { $hash = hash_hmac( 'sha256', $message, $this->client_secret, true ); return base64_encode($hash); } }adminInitiateAuth のリクエスト項目にある
SECRET_HASH
の詳細については以下を参照してください。参考:
ユーザーアカウントのサインアップと確認 - SecretHash 値の計算2. 認証に成功したら、払い出されたIDトークンとリフレッシュトークンをCookieに保存
adminInitiateAuth で無事認証されると、Cognitoから3種類のトークンが返されます。
Amazon Cognito ユーザープールには、OpenID Connect (OIDC) オープン標準で定義されている ID トークン、アクセストークン、および更新トークンが実装されています。
・ID トークンには、name、email、phone_number といった、認証されたユーザーの ID に関するクレームが含まれます。
・アクセストークンは、スコープとグループを含み、承認されたリソースへのアクセスを許可するために使用されます。
・更新トークンには、新しい ID またはアクセストークンの取得に必要な情報が含まれます。
https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.htmlこのうち IDトークン と リフレッシュトークン をCookieに保存します。
3. middlewareでIDトークンを検証
ユーザーが先ほどのIDトークンを伴ってリクエストしてきたときに、それが正しいか検証することでログイン状態であると判断します。
モバイルアプリ向けのSDKなどではこのへんをいい感じに使いやすくしてくれているようですが、for PHPではそうでなかったので理解するのに苦労しました。ドキュメント を参考に、IDトークン(JWT)をデコードして検証するのに以下のライブラリを使用しました。
- firebase/php-jwt :JWTの検証
- acodercat/php-jwk-to-pem :JWKの変換
この検証処理をmiddlewareから呼び出すようにします。
4. IDトークンが正しいと検証できればログインが必要なページを表示、または処理を実行する
middlewareで先ほどのIDトークン検証処理を実行し、検証に成功した場合は
return $next($request);
、失敗した場合はログイン画面にリダイレクトさせます。まとめ
そもそもCognitoってなんか便利そう!使えそう!ぐらいのテンションで採用しましたが、ふたを開けてみるとOpenID Connectの仕組みをちゃんと理解できていなくて、まずそこから始まりました?
OpenID Connectについてはこちらを参考にさせていただきました?♀️
一番分かりやすい OpenID Connect の説明また、Laravel + Cognitoで実装しようとした当時(2019年5月ごろ)は "cognito laravel" なんかでぐぐっても情報がほとんどありませんでした。
あったとしてもサインアップまでのものが多く、そのあとアプリケーション側でどう認証するの?というところで悩みました。いま検索してみると、とても素敵な記事を見つけることができましたのでリンクさせていただきます。
こちらではちゃんとLaravelのGuardを利用するかたちで実装されています。
わたしはLaravelへの造詣もそこまで深くなかったので、この方法には至れませんでした。。Laravel + AWS Cognito での認証機能の実装【ユーザー新規登録編】
Laravelのユーザ認証をAmazon Cognitoで行う方法結果的にCognitoで認証の情報管理、および処理を賄うことができたのは、実装面でも運用面でもメリットが多かったと感じています。
メールアドレス登録時に検証コードを送信してくれるのはありがたいですし、管理画面上でユーザーの検索、無効化なども簡単にできます。
一度仕組みを理解さえしてしまえば、だいぶ簡単にログイン機能を導入できるなという感じです。
- 投稿日:2020-02-18T16:33:45+09:00
laravelでのメール通知実装(SendGridAPI)
laravelでお問い合わせフォームを作成し、入力された内容をメールに通知する必要があったので、そこで学習したことを残しておきます。(WebAPI経由)
SendGrid APIKeyの取得
まずはSendGridのアカウントを作成する。
APIキーを発行する。発行ページがなかなかわかりづらいが、マイページの左側のメニューバーのSettings内にある。「CreateAPIKey」をクリックし、下記の画面に移ったら、APIキーに名前をつける。ここでは"laravel"。メールを送るだけなので、API Key Permissionsは Restrictedにしておく。
ここもメールを送るだけならMail Sendのみで良い。Create&Viewへ。
APIKeyが表示されるはず。クリックするだけでコピー可能。一度しか表示されないのでコピーを忘れずに。
envファイルにAPIキー、メールドライバ(ここではSendGrid)、Fromアドレス、From名を記述する。
デフォルトではSendGridをドライバーに指定できないが、パッケージを作ってくださった方がいるので、composerを使ってインストール。
ありがたいドライバー様(問題あれば消します。)MAIL_DRIVER=sendgrid SENDGRID_API_KEY='コピーしたAPIKey' MAIL_FROM_ADDRESS=送信元メールアドレス MAIL_FROM_NAME="送信元の名前"mailable作成
いよいよ実装部分。Mailableクラスを作成する。
php artisan make:mail SendGridSample
App/Mail/SendGridSampleというファイルができる。これを編集する
(忘れずに先ほどのありがたいドライバー様のuseも記述しておく。)
buildメソッドを作り、その中に処理を書いていく。fromはenvファイルに書いているのでここに書かなくても良い。
SendGridSample.php<?php namespace App\Mail; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Mail\Mailable; use Illuminate\Queue\SerializesModels; use Sichikawa\LaravelSendgridDriver\SendGrid; class SendGridSample extends Mailable { use SendGrid; /** * Create a new message instance. * * @return void */ // 引数で受け取ったデータ用の変数 protected $contact; public function __construct($contact) { // 引数で受け取ったデータを変数にセット $this -> contact = $contact; } /** * Build the message. * * @return $this */ public function build() { return $this ->view('emails.email') //呼び出すテンプレートを指定 ->subject('お問い合わせ内容確認') //件名 ->with(['contact' => $this -> contact]) //withオプションでセットしたデータをテンプレートに渡す ]); } }service.phpファイルに、envのSENDGRID_API_KEYの使用を記述する。
service.php[ 'sendgrid' => [ 'api_key' => env('SENDGRID_API_KEY') ] ];メールテンプレート作成
お名前、メールアドレス、受信したお問い合わせ内容を返す簡単なもの。
<div class="row"> <h1>お問い合わせ内容を受け付けました。</h1> </div> <br> ・お名前<br> {{ $contact['name'] }}様<br> <br> ・メールアドレス<br> {{ $contact['email'] }}<br> <br> ・お問い合わせ内容<br> {!! nl2br(e($contact['post'])) !!}<br> <div class="row"> <p>お問い合わせありがとうございました。</p> </div>ContactControllerを編集
ContactController.php<?php // 作成したメールクラスをuseする use Illuminate\Support\Facades\Mail; use Sichikawa\LaravelSendgridDriver\SendGrid; public function send(Request $request) { \Mail::to($request -> email) ->send(new SendGridSample($request)); }これでお問い合わせ完了メールを送ることができる。
- 投稿日:2020-02-18T14:10:36+09:00
複数の DB コネクションを使ってる場合に RefreshDatabase が失敗する
MySQL と PostgreSQL など、Laravel で複数のコネクションを使ってるときに
RefreshDatabase
を使ったテストを書くと、二度目以降の実行でエラーになります。調べてみると、その原因は
RefreshDatabase
で使われているmigrate:fresh
にあることが分かりました。1
migrate:fresh
ではdb:wipe
とmigrate
の 2 つのコマンドが呼ばれているのですが、db:wipe
がデフォルトのコネクションに対してしか実行されないのです。2
RefreshDatabase
のコードを見てみると、以下のような使用するコネクションを指定するための仕組みが用意されており、これを使えばうまくいくような気がしたんですけど、ここで指定したコネクションは、トランザクションでのみ使われるようでした。3
DatabaseTransactions
にもこれと同じコードがあるので、そちらから派生させたときの名残なんでしょうね。4src/Illuminate/Foundation/Testing/RefreshDatabase.php/** * The database connections that should have transactions. * * @return array */ protected function connectionsToTransact() { return property_exists($this, 'connectionsToTransact') ? $this->connectionsToTransact : [null]; }じゃあ
migrate:fresh
の方でもこの値を使うようにしたいと思ったのですが、migrate:fresh
ではdb:wipe
とmigrate
がセットになってしまっているため、db:wipe
を 2 回実行するようにすると、migrate
まで 2 回実行されてしまいます。おのれ密結合。しかも、
migarate
の--database
オプションはmigrations
テーブルを作るデータベースを指定するためのものなので、たとえ複数のコネクションを使っていたとしても、その中からひとつだけ指定すればよいものです。
一方で、db:wipe
の--database
オプションはテーブルを削除するデータベースを指定するためのものなので、複数コネクションを使っている場合は、その全てを指定する必要があります。
というように、それぞれ意味が違うのですが、migrate:fresh
では--database
オプションで受け取った値を、その両方に渡してしまっています。2そのため対策としては、
migrate:fresh
を使うのをやめて、代わりにmigrate:refresh
を使うようにするか、db:wipe
とmigrate
を自分で呼ぶようにするしかなさそうです。
以下に実装例を挙げておきます。tests/RefreshDatabase.php(refreshを使うパターン)<?php namespace Tests; use Illuminate\Contracts\Console\Kernel; use Illuminate\Foundation\Testing\RefreshDatabase as BaseTrait; use Illuminate\Foundation\Testing\RefreshDatabaseState; trait RefreshDatabase { use BaseTrait; /** * Refresh a conventional test database. * * @return void */ protected function refreshTestDatabase() { if (! RefreshDatabaseState::$migrated) { $this->artisan('migrate:refresh'); $this->app[Kernel::class]->setArtisan(null); RefreshDatabaseState::$migrated = true; } $this->beginDatabaseTransaction(); } }tests/RefreshDatabase.php(wipeとmigrateを自分で呼ぶパターン)<?php namespace Tests; use Illuminate\Contracts\Console\Kernel; use Illuminate\Foundation\Testing\RefreshDatabase as BaseTrait; use Illuminate\Foundation\Testing\RefreshDatabaseState; trait RefreshDatabase { use BaseTrait; /** * Refresh a conventional test database. * * @return void */ protected function refreshTestDatabase() { if (! RefreshDatabaseState::$migrated) { foreach ($this->connectionsToTransact() as $database) { $this->artisan('db:wipe', array_filter([ '--database' => $database, '--drop-views' => $this->shouldDropViews(), '--drop-types' => $this->shouldDropTypes(), '--force' => true, ])); } $this->artisan('migrate', [ '--force' => true, ]); $this->app[Kernel::class]->setArtisan(null); RefreshDatabaseState::$migrated = true; } $this->beginDatabaseTransaction(); } }
https://github.com/laravel/framework/blob/6.x/src/Illuminate/Foundation/Testing/RefreshDatabase.php#L45-L64 ↩
https://github.com/laravel/framework/blob/6.x/src/Illuminate/Database/Console/Migrations/FreshCommand.php#L40-L53 ↩
https://github.com/laravel/framework/blob/6.x/src/Illuminate/Foundation/Testing/RefreshDatabase.php#L75-L94 ↩
https://github.com/laravel/framework/blob/6.x/src/Illuminate/Foundation/Testing/DatabaseTransactions.php#L30-L39 ↩
- 投稿日:2020-02-18T13:21:40+09:00
Laravel & VSCodeによるAPI仕様書管理の一案
今回の記事は、LaravelでAPI開発をすると同時に、
VSCodeの拡張機能を用いてAPI仕様書の管理もしてしまおうという狭い話です。まずLaravel。
ひとまず最新の6を使うこととします。
今回の主題はAPI実装よりもAPIの仕様管理ということで、
マークダウンでAPIの仕様を記述します。
場所はresources/api
を作るなどして保存しましょう。api_template.md# API API説明 # エンドポイント ## パス ### /api/hoges/{id} ## HTTPメソッド ### GET # リクエスト | パラメータ名 | データ型 | 必須 | 制約 | 説明 | | ------------ | -------- | :---: | ---- | ---- | | id | integer | ⭕️ | | ID | # レスポンス ## 200 取得成功 ``json { "id": 1, "name": "Hoge", "foos": [ { "id": 1, "hoge_id": 1, }, { "id": 2, "hoge_id": 1, } ] } `` ## 500 エラー --- [戻る](/api_docs)APIを使う際に必要な情報を記述します。
ちなみにVSCodeはマークダウンを編集しながらプレビューも見られるので便利です。ただし、ブラウザで見る際はHTMLに変換したほうがわかりやすい。
そこでVSCodeの拡張機能「Markdown All in One」が役に立ちます。この拡張機能をインストールしてHTML出力のコマンドを実行すると、同じディレクトリ
resources/api
にHTMLファイルが出力されます。そのHTMLファイルをLaravelのルーティングで読み込んで表示しようというのが、本記事の肝です。
routes/web.php<?php Route::get('api_docs/{name?}', function ($name = 'index') { if (config('app.env') === 'production') { return abort(404); } $path = resource_path() . '/api/' . $name . '.html'; if (file_exists($path)) { return file_get_contents($path); } else { return abort(404); } });一応本番環境では表示しないようにしています。
このルーティングで、例えば/api_docs/api_template
とアクセスすることでAPIの仕様を表示できます。これによって、ひとつのLaravelリポジトリでAPIの実装と仕様管理の両方ができるのは便利ではないかと思っています
- 投稿日:2020-02-18T10:49:23+09:00
【Laravel】railsのbinding.pryみたいにデバッグする
【laravel5】 tinkerを利用してpryのように楽にデバッグする!
この記事を参考にしました。ポイント1 デバッグしたいところに
eval(\Psy\sh());
を置く。public function update(ArticleRequest $request, $id) { $article = Article::findOrFail($id); $article->update($request->validated()); eval(\Psy\sh()); return redirect()->route('articles.show',$article->id)->with('message', '記事を更新しました。'); }ポイント2
php -S localhost:8000 -t public server.php
でサーバーを立てる。(今の場合)更新ボタンを押す=>
: q
で、コンソールに入れる。こんな感じでデバッグできる!!
rails c
と同じことがしたければphp artisan tinker
でいける。
- 投稿日:2020-02-18T09:01:48+09:00
Laravel Graphql Server using Lighthouse-PHP
みなさんこんにちは、最近行方不明になって申し訳ありませんが、仕事で忙しくて、ブログを更新する時間を見つけることができませんでした
Hello everybody, sorry I´ve been missing lately, but I´ve been busy with work, and couldn´t find the time to update the blog
始めましょう
Dockerコンテナを使用してlaravelをインストールする
Install laravel using docker container
Create Laravel Project using Docker
初期移行を実行する
Run Initial Migrations
sudo docker-compose exec app-server php artisan migrateLighthouse PHPをインストールする
Install
lighthouse-php
lighthouse-php
をインストールするdocker run --rm -v $(pwd):/app composer require nuwave/lighthousegraphqlのデフォルトスキーマを公開する
Publish default schema for graphql
sudo docker-compose exec app-server php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=schema
app-server
で、docker-composeファイルで使用する名前を忘れずに変更してくださいin
app-server
, remember to change for the name you use on your docker-compose fileGraphql Playgroundをインストールする
次の手順はオプションですが、推奨されますが、graphql-playgroundをインストールします
Next step is optional, but recommended, install the graphql-playground
docker run --rm -v $(pwd):/app composer require mll-lab/laravel-graphql-playground遊び場のURLは
http://localhost/graphql-playground
url for the playground is
http://localhost/graphql-playground
構成
コンテナをもう一度実行し、
docker-compose up --build
graphqlのデフォルト設定をエクスポートします
run the containers once more,
docker-compose up --build
export the graphql default config
docker-compose exec app-server php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=config突然変異とクエリ
クエリを実行する前に、データを挿入する必要があります。最初に突然変異を作成します
Before doing a query, we need to insert data, lets first create a mutation
sudo docker-compose exec app-server php artisan lighthouse:mutation createUserこれにより、
app \ graphql \ mutations
フォルダー内にCreateUser.php
が作成されます。簡単なリゾルバを追加しましょう
This will create a
CreateUser.php
inside theapp\graphql\mutations
folderLets add a simple resolver
public function __invoke($rootValue, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) { $args["password"] = Hash::make($args["password"]); return User::create($args); }
schema.graphql
ファイル内にルート変更を追加しますAdd the route mutation inside the
schema.graphql
filetype Mutation { createUser(name: String!, email: String!, password: String!): User }これで、不眠症を使用しているので、簡単な突然変異を作成できます。これが私の突然変異の作成方法です
または、
http:// localhost / graphql-playground
のプレイグラウンドを使用できますWith this, you can create a simple mutation, since I´m using insomnia, this is how I create my mutation
or you can use the playground at
http://localhost/graphql-playground
Insomnia POST : http://localhost/graphql Playground : http://localhost/graphql-playground mutation{ createUser(name:"My Name",email:"my@email.com",password:"mypassword"){ id, name, } }200を取得すると、応答がすでにjsonであることがわかります。クエリリクエストを作成してユーザーを確認できます。
Once you get the 200, you can see the response is already a json, we can check the users by going making a query request
POST: http://localhost/graphql Playground : http://localhost/graphql-playground query{ users{ data{ id, name, email } } }
- 投稿日:2020-02-18T09:01:48+09:00
Lighthouse-PHPを使用したLaravel Graphqlサーバー
みなさんこんにちは、最近行方不明になって申し訳ありませんが、仕事で忙しくて、ブログを更新する時間を見つけることができませんでした
Hello everybody, sorry I´ve been missing lately, but I´ve been busy with work, and couldn´t find the time to update the blog
始めましょう
Dockerコンテナを使用してlaravelをインストールする
Install laravel using docker container
Create Laravel Project using Docker
初期移行を実行する
Run Initial Migrations
sudo docker-compose exec app-server php artisan migrateLighthouse PHPをインストールする
Install
lighthouse-php
lighthouse-php
をインストールするdocker run --rm -v $(pwd):/app composer require nuwave/lighthousegraphqlのデフォルトスキーマを公開する
Publish default schema for graphql
sudo docker-compose exec app-server php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=schema
app-server
で、docker-composeファイルで使用する名前を忘れずに変更してくださいin
app-server
, remember to change for the name you use on your docker-compose fileGraphql Playgroundをインストールする
次の手順はオプションですが、推奨されますが、graphql-playgroundをインストールします
Next step is optional, but recommended, install the graphql-playground
docker run --rm -v $(pwd):/app composer require mll-lab/laravel-graphql-playground遊び場のURLは
http://localhost/graphql-playground
url for the playground is
http://localhost/graphql-playground
構成
コンテナをもう一度実行し、
docker-compose up --build
graphqlのデフォルト設定をエクスポートします
run the containers once more,
docker-compose up --build
export the graphql default config
docker-compose exec app-server php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=config突然変異とクエリ
クエリを実行する前に、データを挿入する必要があります。最初に突然変異を作成します
Before doing a query, we need to insert data, lets first create a mutation
sudo docker-compose exec app-server php artisan lighthouse:mutation createUserこれにより、
app \ graphql \ mutations
フォルダー内にCreateUser.php
が作成されます。簡単なリゾルバを追加しましょう
This will create a
CreateUser.php
inside theapp\graphql\mutations
folderLets add a simple resolver
public function __invoke($rootValue, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) { $args["password"] = Hash::make($args["password"]); return User::create($args); }
schema.graphql
ファイル内にルート変更を追加しますAdd the route mutation inside the
schema.graphql
filetype Mutation { createUser(name: String!, email: String!, password: String!): User }これで、不眠症を使用しているので、簡単な突然変異を作成できます。これが私の突然変異の作成方法です
または、
http:// localhost / graphql-playground
のプレイグラウンドを使用できますWith this, you can create a simple mutation, since I´m using insomnia, this is how I create my mutation
or you can use the playground at
http://localhost/graphql-playground
Insomnia POST : http://localhost/graphql Playground : http://localhost/graphql-playground mutation{ createUser(name:"My Name",email:"my@email.com",password:"mypassword"){ id, name, } }200を取得すると、応答がすでにjsonであることがわかります。クエリリクエストを作成してユーザーを確認できます。
Once you get the 200, you can see the response is already a json, we can check the users by going making a query request
POST: http://localhost/graphql Playground : http://localhost/graphql-playground query{ users{ data{ id, name, email } } }
- 投稿日:2020-02-18T00:58:35+09:00
laravel クエリビルダ プレーンなselect文でカラム同士の足し算
こんにちは!
lravelでカラム同士の足し算がしたくていろいろやったけどうまくいかず、リファレンスを読んだところ便利なクエリビルダの方法があったので紹介します!
laravel6.x系です
紹介するコードを参考にするのであれば、データベースに対応するモデルが作成済みであることを前提とします!〇〇Repository.php<?php namespace App\Repositories\Cost; use App\Models\Cost; use Illuminate\Support\Facades\DB; class CostRepository implements CostRepositoryInterface { protected $cost; public function __construct(Cost $cost) { $this->cost = $cost; } /** * ユーザーの全ての情報+spendingの合計をゲット */ public function getAllRecordByUser($user_id) { return $this->cost->select(DB::raw(' *, morning_spending + daytime_spending + night_spending AS spending_all'))->where('user_id', '=', $user_id)->get(); } }ファイルはRepositoryですが、基本ファサードのDBをuseすればコントローラとかでも使えるはず
select(DB::raw('この中に記述したいselect文を記載'))こうするとプレーンなsqlのselect文を記載することができます!
このクエリビルダで得られるsql文は
"select *, morning_spending + daytime_spending + night_spending AS spending_all from `costs` where `user_id` = ?"こんな感じになります
上のコードで得られるテーブル構造はuser_idカラムが引数で渡したuser_idの
colmun1 colmun2 mroning_spending daytime_spending night_spending spending_all *** *** 100 200 300 600 のようなテーブル構造を得られます!
laravel使い始めてまだまもないですが、sqlベースで手っ取り早く値を取得したいときはプレーンなsql文を書いた方が楽ですね!
まぁ、クエリビルダをもっと勉強すれば、多分プレーンなsql文を書かなくてもできると思うのですが・・・