20190415のlaravelに関する記事は8件です。

laradockでLaravelの環境構築をしてみる(Mac)

ローカル環境はLaradockを利用して開発します。
最終的には以下のような構成になります。

/(任意の名前)
|-- laradock
|-- laravel

1.Dockerをインストールする

Dockerのインストール

2.Laradockの入手

$ mkdir 任意のディレクトリ
$ cd 任意のディレクトリ
$ git clone https://github.com/LaraDock/laradock.git
$ cd laradock

3.laradockの設定ファイルの編集

最初にenv.exampleファイルをコピーして.envファイルを作成します。この.envファイルに環境構築時の設定情報を書き込んでいく。

$ cp env-example .env

DATAの保存する場所を変更する。標準の設定だとルートディレクトリの配下にファイルが永続化されている。
任意のディレクトリ配下のlaradockディレクトリにファイルを保存するように変更します。

# .env
# Choose storage path on your machine. For all storage systems 

- DATA_PATH_HOST=~/.laradock/data
+ DATA_PATH_HOST=.laradock/data

続いて、MYSQLの設定をしていく。

# .env
### MYSQL #################################################
MYSQL_VERSION=5.7 # versionを固定
MYSQL_DATABASE=homestead1 #データベース名を変更
MYSQL_USER=homestead1 #ユーザー名を変更
MYSQL_PASSWORD=hogehoge #パスワードを変更
MYSQL_PORT=3306
MYSQL_ROOT_PASSWORD=root
MYSQL_ENTRYPOINT_INITDB=./mysql/docker-entrypoint-initdb.d

4.Dockerコンテナを起動する。

$ docker-compose up -d nginx mysql phpmyadmin

5.composerをインストールする

laradockのディレクトリ内に移動して、workspaceのbashにログインする

$ docker-compose exec --user=laradock workspace bash
$ cd training-laravel
$ composer install

6 laravelの.envの編集

laravelの.envに以下を貼り付ける

APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=homestead1
DB_USERNAME=homestead1
DB_PASSWORD=hogehoge

BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

7.APP_KEYの生成と初回のマイグレーションを実行

$ docker-compose exec workspace php artisan migrate
$ docker-compose exec workspace php artisan key:generate
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelでバリデーションにモックを仕掛ける

バリデーションにモックを仕掛ける

ファサードには下記のようにshouldReceiveメソッドが実装されていて楽にモックを仕掛けることができます。
私のケースではexistsでテーブルに値があるか確認していて、apiのテスト時にDBアクセスを避けたかったので利用しました。

shouldReceiveメソッドを使用し、Cacheファサードへの呼び出しをモックできます。これはMockeryインスタンスを返します。ファサードはLaravelのサービスコンテナにより管理され、依存解決されていますので、典型的な静的クラスよりもかなり高いテスタビリティーを持っています。

makeメソッドだけではなく正常系チェック用のpassesメソッドも範囲にして、返り値を設定することです。
existsを使って無い時でも別途バリデーションのテストをしている等であれば使ってもよさそう。

ExampleTest.php
        Validator::shouldReceive('make->passes')
            ->once()
            ->andReturn(true);

        $response = $this->json('GET', /example, $param);

(参考)

https://readouble.com/laravel/5.5/ja/mocking.html

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

Laravel/Lumenでバリデーションにモックを仕掛ける

バリデーションにモックを仕掛ける

ファサードには下記のようにshouldReceiveメソッドが実装されていて楽にモックを仕掛けることができます。
今回、existsルールを使ってテーブルに値があるか確認していて、apiのテスト時にDBアクセスを避けたかったので利用しました。

shouldReceiveメソッドを使用し、Cacheファサードへの呼び出しをモックできます。これはMockeryインスタンスを返します。ファサードはLaravelのサービスコンテナにより管理され、依存解決されていますので、典型的な静的クラスよりもかなり高いテスタビリティーを持っています。

https://readouble.com/laravel/5.5/ja/mocking.html

makeメソッドだけではなく正常系チェック用のpassesメソッドも対象にして、返り値を設定することが重要です。
今回みたいなexistsルールを使って無い時に別途バリデーションのテストをしている等であれば、使うこともありそうですね。

ExampleTest.php
        Validator::shouldReceive('make->passes')
            ->once()
            ->andReturn(true);

        $response = $this->json('GET', /example, $param);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel/LumenでValidatorにモックを仕掛ける

バリデーションにモックを仕掛ける

Laravel/LumenのValidatorクラスにはファサードが用意されています。ファサードには下記の説明にあるように最初からモックできるヘルパがあり、楽にモック化することができます。しかしValidatorに仕掛けるケースの記事がなかったので備忘録として。

Laravelにはイベント、ジョブ、ファサードを最初からモックできるヘルパが準備されています。これらのヘルパは主にMockery上で動作する便利なレイヤーを提供しているので、複雑なMockeryのメソッドコールを自分で作成する必要はありません。

https://readouble.com/laravel/5.5/ja/mocking.html

実装

重要なのはバリデーションのmakeメソッドだけではなく、正常系確認用にあるpassesメソッドもつないで、返り値を設定することでバリデーションが実行される心配がなくなります。

ExampleTest.php
        Validator::shouldReceive('make->passes')
            ->once()
            ->andReturn(true);

        $response = $this->json('GET', /example, $param);

まとめ

今回はバリデーションでexistsルールを使ってテーブルに値があるか確認していて、APIのテスト時にはDBアクセスを避けたかったのでモックを利用してますが、他にも複雑なカスタムバリデーションなどを組んでいる時などにも良いと考えてます。(もちろん別途テストは必要)

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

51歳からのプログラム 備忘録 laravel 連続した整数

factoryで連続する整数を作る

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

【PHP】CarbonのaddMonth()を使ってハマった話(CarbonとDateTimeクラスの仕様を今一度確認してみる)

TL;DR

特に理由がなければCarbonを用いて月の計算をする場合はaddMonthsNoOverflow()メソッドを使うようにしたほうがいい

DateTimeクラスの仕様に度々ひっかかる

Carbonを用いて月の計算を行っていると、どうやら28~31日のデータを扱うときに挙動がおかしいことに気が付きました
前もこんなのあったなーと思いつつ再現させる
(前:【PHP】ある月の初日と末日を取得する方法(DateTimeクラス & Carbon編)#要注意引数は年月日を渡しましょう - Qiita

検証

例:契約日が15日未満の場合は翌月の27日、15日以降なら翌々月の27日が請求月になる
みたいな場合の処理
(ここでは契約日が2018-01-31で考えます)
環境としてはLaravelのv5.5系に入っているCarbon(1.36)を使用して以下の例の処理を動かします

use Carbon\Carbon;

$array = [];
$contractDate = new Carbon('2018-01-31');

// 5回払い
for ($i = 0; $i < 5; $i++) {
    // 契約日が15日以降か
    if ((int)$contractDate->format('d') < 15) {
        $array['date'] = (new Carbon($contractDate))->addMonth($i + 1)->format("Y-m-27");
    } else {
        $array['date'] = (new Carbon($contractDate))->addMonth($i + 2)->format("Y-m-27");
    }

    $array['target_month'] = (new Carbon($array['date']))->format('Y-m');

    var_dump($i);
    var_dump($array);
}

↓以下、tinker(laravel用REPL)で実行した結果

int(0)
array(2) {
  ["date"]=>
  string(10) "2018-03-27"
  ["target_month"]=>
  string(7) "2018-03"
}
int(1)
array(2) {
  ["date"]=>
  string(10) "2018-05-27"
  ["target_month"]=>
  string(7) "2018-05"
}
int(2)
array(2) {
  ["date"]=>
  string(10) "2018-05-27"
  ["target_month"]=>
  string(7) "2018-05"
}
int(3)
array(2) {
  ["date"]=>
  string(10) "2018-07-27"
  ["target_month"]=>
  string(7) "2018-07"
}
int(4)
array(2) {
  ["date"]=>
  string(10) "2018-07-27"
  ["target_month"]=>
  string(7) "2018-07"
}
>>>

なんだこれは・・・

CarbonのaddMonth()について調べてみる

CarbonDateTimeクラスのラッパーなので、基本的にDateTimeクラスの仕様に依存してるみたいです。
んでaddMonth()の処理がどうなっているかCarbonのソースコード(Carbon/Carbon.php at version-1.36)を見てみると

Carbon/Carbon.php
    /**
     * Add a month to the instance
     *
     * @param int $value
     *
     * @return static
     */
    public function addMonth($value = 1)
    {
        return $this->addMonths($value);
    }

addMonths()メソッドを呼び、

Carbon/Carbon.php
    /**
     * Add months to the instance. Positive $value travels forward while
     * negative $value travels into the past.
     *
     * @param int $value
     *
     * @return static
     */
    public function addMonths($value)
    {
        if (static::shouldOverflowMonths()) {
            return $this->addMonthsWithOverflow($value);
        }
        return $this->addMonthsNoOverflow($value);
    }

static::shouldOverflowMonths()で呼ばれているmonthsOverflowプロパティはデフォルトでtrueになっているので、
オーバーフローで月を計算するメソッドaddMonthsWithOverflow()を呼びます。

Carbon/Carbon.php
    /**
     * Add months to the instance. Positive $value travels forward while
     * negative $value travels into the past.
     *
     * @param int $value
     *
     * @return static
     */
    public function addMonthsWithOverflow($value)
    {
        return $this->modify((int) $value.' month');
    }

でその中身はDateTimeクラスのmodify()メソッドでした。
ドキュメント(PHP: DateTime::modify - Manual)にも書いてある通り、月の加減算には注意ということで以下の処理例が載ってます。

例2 月の加減算には注意

<?php
$date = new DateTime('2000-12-31');

$date->modify('+1 month');
echo $date->format('Y-m-d') . "\n";

$date->modify('+1 month');
echo $date->format('Y-m-d') . "\n";
?>

上の例の出力は以下となります。
2001-01-31
2001-03-03

要は月の計算(加算)時に存在しない日(2月が28日までで、31日がない)になった場合、あふれた日数(3日)次の月(3月)+して計算する(=3月3日)という仕様になってるんですね

確認するためにmodify()メソッドを使用して処理を書いてみました

date_default_timezone_set('Asia/Tokyo');

for ($i = 0; $i < 10; $i++) {
    $date = new DateTime('2018-01-31');
    $date->modify((int) ($i + 2).' month');
    var_dump($date->format('Y-m-d H:i') ." → " . $date->format('Y-m-27'));
    echo PHP_EOL;
}

以下実行結果

string(35) "2018-03-31 00:00 → 2018-03-27"
string(35) "2018-05-01 00:00 → 2018-05-27"
string(35) "2018-05-31 00:00 → 2018-05-27"
string(35) "2018-07-01 00:00 → 2018-07-27"
string(35) "2018-07-31 00:00 → 2018-07-27"
string(35) "2018-08-31 00:00 → 2018-08-27"
string(35) "2018-10-01 00:00 → 2018-10-27"
string(35) "2018-10-31 00:00 → 2018-10-27"
string(35) "2018-12-01 00:00 → 2018-12-27"
string(35) "2018-12-31 00:00 → 2018-12-27"

https://3v4l.org/WfDnT

案の定、最初に書いた処理と同じような結果になりました。
(※4月や6月は30日までしかないので、1日分、次の月に+されてしまってます)

オーバーフローしないメソッドaddMonthsNoOverflow()

ならオーバーフローしない計算メソッドを使えばいいんではないか、ということで
CarbonのaddMonthsNoOverflow()メソッドの処理を見てみます。

Carbon/Carbon.php
    /**
     * Add months without overflowing to the instance. Positive $value
     * travels forward while negative $value travels into the past.
     *
     * @param int $value
     *
     * @return static
     */
    public function addMonthsNoOverflow($value)
    {
        $day = $this->day;
        $this->modify((int) $value.' month');
        if ($day !== $this->day) {
            $this->modify('last day of previous month');
        }
        return $this;
    }

結局はmodify()メソッドを使用してるみたいですが、'last day of previous month'(前の月の最後の日)と書かれてるので、オーバーフローした際は前月の最終日を返すようになっているようです。

参考:PHP: 相対的な書式 - Manual

正しい処理になるように修正

ということで、CarbonのaddMonthsNoOverflow()メソッドを用いて計算するように先ほどの処理を修正してみます。

use Carbon\Carbon;

$array = [];
$contractDate = new Carbon('2018-01-31');

// 5回払い
for ($i = 0; $i < 5; $i++) {

    if ((int)$contractDate->format('d') < 15) {
        // $array['date'] = (new Carbon($contractDate))->addMonth($i + 1)->format("Y-m-27");
        $array['date'] = (new Carbon($contractDate))->addMonthsNoOverflow($i + 1)->format("Y-m-27");
    } else {
        // $array['date'] = (new Carbon($contractDate))->addMonth($i + 2)->format("Y-m-27");
        $array['date'] = (new Carbon($contractDate))->addMonthsNoOverflow($i + 2)->format("Y-m-27");
    }

    $array['target_month'] = (new Carbon($array['date']))->format('Y-m');

    var_dump($i);
    var_dump($array);
}

以下、tinker(laravel用REPL)で実行した結果

int(0)
array(2) {
  ["date"]=>
  string(10) "2018-03-27"
  ["target_month"]=>
  string(7) "2018-03"
}
int(1)
array(2) {
  ["date"]=>
  string(10) "2018-04-27"
  ["target_month"]=>
  string(7) "2018-04"
}
int(2)
array(2) {
  ["date"]=>
  string(10) "2018-05-27"
  ["target_month"]=>
  string(7) "2018-05"
}
int(3)
array(2) {
  ["date"]=>
  string(10) "2018-06-27"
  ["target_month"]=>
  string(7) "2018-06"
}
int(4)
array(2) {
  ["date"]=>
  string(10) "2018-07-27"
  ["target_month"]=>
  string(7) "2018-07"
}
>>>

期待通りの処理になりました。

ということで特に理由がなければCarbonを用いて月の計算をする場合はaddMonthsNoOverflow()メソッドを使うようにしたほうがいいかなというお話でした。

おわり

  • DateTimeクラスの仕様には度々振り回されます・・・
  • というかドキュメントちゃんと読みましょう>自分

参考URL

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

Laravelのクエリビルダーの戻り値を勘違いしていた件について

Laravelのクエリビルダーの戻り値

insert

新規登録が完了したかの正否を論理値で返却する。
つまり、true/falsebooleanで返してくれる。

update

影響を受けたレコード件数を返す。
つまり、1や10などのintegerで返してくれる。

delete

影響を受けたレコード件数を返す。
つまり、1や10などのintegerで返してくれる。

失敗談

updateやdeleteもbooleanで返却してくれると思って下記のようなコードを書いてデバックしてました。。。

確かに0が来ていれば更新はしていないんですが…

$res = DB::table('hoge')
    ->where('id', $id)
    ->update([
        'name' => $name
    ]);

// 別クラスで
if (!$res) '更新に失敗';
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelリンク集

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