20200218のlaravelに関する記事は11件です。

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をご紹介します。

Dockerfile
FROM 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-devlibfreetyep6-devlibjpeg62-turbo-devlibpng-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も未熟なので、誤りがありましたらご指摘いただけると幸いです。

参考

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

MacからWindowsにlaravel開発環境を移してみた!(サーバー起動まで)

用意したもの

virtual box
vagrant
cyberdock
tera term

vagrant 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 500

Laravel5.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

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

LaravelのModelに補完が効かなくて辛い人たちに贈る「Laravel IDE Helper Generator」の紹介

Eloquent Model でプロパティや scope を扱うときに補完が効いて欲しい。しかし、例えば下記のようにコードを書いても補完が効かなくて辛いですよね。

SampleRepository.php
    $sample = new Sample();
    dd($sample->id); // ここでidに補完が効いて欲しい!できればタイプヒンティングもしてほしい!

このように Model からカラム名にアクセスした際に補完が効かないのに加え、クエリをカプセル化してくれる scope を利用したときも補完は効きません。

App\Models\Sample.php
    public 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 すると型定義が出ますし、補完も効きます。

スクリーンショット 2020-02-18 13.21.29.png

また、カラム名へのアクセスに対しては型補完が効いています(業務ソースなので隠しまくりなのですがご容赦ください)。

スクリーンショット 2020-02-18 17.21.49.png

この例ですと、とあるテーブルの transferred_at カラムへ日付を保存しているわけですが、日付保存可能かつ、振り込みされていない場合は null が格納されている、といったことがある程度型情報から読み取ることができます(null が良いのかはさておき)。

セットアップ

https://github.com/barryvdh/laravel-ide-helper

に概ね書いてあるとおりです。

まずは composer でインストールします。

composer require --dev barryvdh/laravel-ide-helper

Laravel5.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 扱いにして、各自で生成しましょうという運用にしたほうが望ましいと思います。

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

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.html

Cognitoには以下の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.html

IDプール

Amazon Cognito ID プール (フェデレーテッドアイデンティティ) では、ユーザーの一意の ID を作成し、ID プロバイダーで連携させることができます。ID プールを使用すると、権限が制限された一時的な AWS 認証情報を取得して、他の AWS サービスにアクセスできます。
https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/cognito-identity.html

今回はWebアプリへのログインに使用したいので、 ユーザープール を使用します。

手順

LaravelアプリにCognitoを使用したログイン機能を実装するために、以下の流れで作業していきます。

  1. Cognitoユーザープールを作成
  2. AWS SDK for PHPをインストール
  3. 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との連携を実装

ここからが本題です?‍?
今回は以下のようにして認証機能を実装しました。

  1. Cognitoへ認証情報(ID/password)をリクエスト
  2. 認証に成功したら、払い出されたIDトークンとリフレッシュトークンをCookieに保存
  3. middlewareでIDトークンを検証
  4. IDトークンが正しいと検証できればログインが必要なページを表示、または処理を実行する

実装

CognitoユーザープールAPI には接頭辞 "Admin" がついたものがいくつか用意されています。
これらは管理者として操作できるもので、インスタンス化する際にcredentials(IAMユーザー情報)が必要です。

1. Cognitoへ認証情報(ID/password)をリクエスト

こちらの記事 を参考にさせていただきました?‍♀️

まずはじめに、 adminInitiateAuth で認証情報をCognitoへリクエストします。
今回アカウントはユーザーがサインアップするのではなく、管理者が発行する仕様なのでいきなりここからです。
"AuthFlow" には ADMIN_NO_SRP_AUTH を指定します。(最新では ADMIN_USER_PASSWORD_AUTH に置き換わったようです)

CognitoService.php
namespace 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)をデコードして検証するのに以下のライブラリを使用しました。

この検証処理を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で認証の情報管理、および処理を賄うことができたのは、実装面でも運用面でもメリットが多かったと感じています。
メールアドレス登録時に検証コードを送信してくれるのはありがたいですし、管理画面上でユーザーの検索、無効化なども簡単にできます。
一度仕組みを理解さえしてしまえば、だいぶ簡単にログイン機能を導入できるなという感じです。

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

laravelでのメール通知実装(SendGridAPI)

laravelでお問い合わせフォームを作成し、入力された内容をメールに通知する必要があったので、そこで学習したことを残しておきます。(WebAPI経由)

SendGrid APIKeyの取得

まずはSendGridのアカウントを作成する。
APIキーを発行する。発行ページがなかなかわかりづらいが、マイページの左側のメニューバーのSettings内にある。

スクリーンショット 2020-01-21 18.51.42.png

「CreateAPIKey」をクリックし、下記の画面に移ったら、APIキーに名前をつける。ここでは"laravel"。メールを送るだけなので、API Key Permissionsは Restrictedにしておく。
スクリーンショット 2020-01-21 18.54.40.png

ここもメールを送るだけならMail Sendのみで良い。Create&Viewへ。

スクリーンショット 2020-01-21 18.55.11.png

APIKeyが表示されるはず。クリックするだけでコピー可能。一度しか表示されないのでコピーを忘れずに。

スクリーンショット 2020-01-21 18.55.22.png

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));

    }

これでお問い合わせ完了メールを送ることができる。

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

複数の DB コネクションを使ってる場合に RefreshDatabase が失敗する

MySQL と PostgreSQL など、Laravel で複数のコネクションを使ってるときに RefreshDatabase を使ったテストを書くと、二度目以降の実行でエラーになります。

調べてみると、その原因は RefreshDatabase で使われている migrate:fresh にあることが分かりました。1
migrate:fresh では db:wipemigrate の 2 つのコマンドが呼ばれているのですが、db:wipe がデフォルトのコネクションに対してしか実行されないのです。2

RefreshDatabase のコードを見てみると、以下のような使用するコネクションを指定するための仕組みが用意されており、これを使えばうまくいくような気がしたんですけど、ここで指定したコネクションは、トランザクションでのみ使われるようでした。3
DatabaseTransactions にもこれと同じコードがあるので、そちらから派生させたときの名残なんでしょうね。4

src/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:wipemigrate がセットになってしまっているため、db:wipe を 2 回実行するようにすると、migrate まで 2 回実行されてしまいます。おのれ密結合。

しかも、migarate--database オプションは migrations テーブルを作るデータベースを指定するためのものなので、たとえ複数のコネクションを使っていたとしても、その中からひとつだけ指定すればよいものです。
一方で、db:wipe--database オプションはテーブルを削除するデータベースを指定するためのものなので、複数コネクションを使っている場合は、その全てを指定する必要があります。
というように、それぞれ意味が違うのですが、migrate:fresh では --database オプションで受け取った値を、その両方に渡してしまっています。2

そのため対策としては、migrate:fresh を使うのをやめて、代わりに migrate:refresh を使うようにするか、db:wipemigrate を自分で呼ぶようにするしかなさそうです。
以下に実装例を挙げておきます。

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();
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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はマークダウンを編集しながらプレビューも見られるので便利です。

スクリーンショット 2020-02-18 13.00.03.png

ただし、ブラウザで見る際はHTMLに変換したほうがわかりやすい。
そこでVSCodeの拡張機能「Markdown All in One」が役に立ちます。

スクリーンショット 2020-02-18 12.52.17.png

この拡張機能をインストールしてHTML出力のコマンドを実行すると、同じディレクトリresources/apiにHTMLファイルが出力されます。

スクリーンショット 2020-02-18 12.55.34.png

その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の仕様を表示できます。

スクリーンショット 2020-02-18 13.04.27.png

これによって、ひとつのLaravelリポジトリでAPIの実装と仕様管理の両方ができるのは便利ではないかと思っています:beer:

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

【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 で、コンソールに入れる。

スクリーンショット 2020-02-18 10.47.19.png

こんな感じでデバッグできる!!

rails cと同じことがしたければphp artisan tinkerでいける。

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

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 migrate
Lighthouse PHPをインストールする

Install lighthouse-php

lighthouse-phpをインストールする

docker run --rm -v $(pwd):/app composer require nuwave/lighthouse

graphqlのデフォルトスキーマを公開する

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 file

Graphql 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.phpinside the app\graphql\mutations folder

Lets 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 file

type 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
    }
  }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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 migrate
Lighthouse PHPをインストールする

Install lighthouse-php

lighthouse-phpをインストールする

docker run --rm -v $(pwd):/app composer require nuwave/lighthouse

graphqlのデフォルトスキーマを公開する

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 file

Graphql 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.phpinside the app\graphql\mutations folder

Lets 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 file

type 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
    }
  }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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文を書かなくてもできると思うのですが・・・

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