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

Laravel6系で始めるか、Laravel5系を使うべきか迷う人へ

最近、新しくLaravel 6がリリースされました。

これまで『5.1』『5.2』等で刻んでいた中、『6.0』が出たのは大きな変更に思えます。

Laravel 6.0がリリースされたばかりで記事や書籍などが出揃っていないため、Laravel 6.0を採用するのは時期尚早なのでしょうか。

結論から言うと、Laravel 6.0はLaravel 5.8と大きな違いはありません。これまでのバージョンアップと同程度の差なので、Laravel5系の書籍や記事の情報はそのまま使うことができます。

注意

この記事はLaravel 6.0がリリースされた2019年9月時点での事情を説明しています。

■結論

  1. Laravelのバージョンは6.0以降セマンティックバージョニングが採用された
  2. Laravel 6.0は実質5.9なので、変更の差は今までのバージョンアップと一緒(今回言いたいこと)
  3. Laravel 6.0を使うといいよ(LTS等、理由の詳細略)

なぜ迷うのか

たぶん、この記事を見た人は、きっと不安に思っていると思います。

『Laravel 6系の記事まだ少ない』

『出版されてる本、Laravel 6系対応のはまだない』

『Laravel 5系ならいろいろ本あるし安心』

この『Laravel 5系』という言葉に、誤解があり、それを解くのが今回の記事の目的です。

6.0は実質5.9

今回のバージョンアップ、『一番上の数値が増えたから、きっといっぱい変わったんだろう』。

いいえ、違います。そんなに大きな違いはありません。

以下は詳細に読む必要はありませんが、ちらっとリリースノートを見てください。

項目少なくないですか?

■リリースノート
https://readouble.com/laravel/6.0/ja/releases.html

■アップグレードガイド
https://readouble.com/laravel/6.0/ja/upgrade.html

ここで重要なのが、『セマンティックバージョニングに変わった』という点です。

Laravel 6.0から、番号の付け方変わった

簡単にいうと、

Laravel 5.1->5.2->5.3

Laravel 6->7->8

ってバージョンアップに変わります。

つまり。

Laravel 6.0は実質Laravel 5.9だよ!

Laravel 6系の本がない・・・って思っても、Laravel 5.7とか5.8使ってた知識で、だいたい使えるよ!

どうでもいい話。

https://github.com/laravel/laravel/blob/5.8/composer.json#L13

https://github.com/laravel/laravel/blob/master/composer.json#L13

セマンティックバージョニングになったから、composer.jsonも『^』の書き方になりましたね!

これはテンション上がりますよね(*‘ω‘ *)

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

【Laravel】LengthAwarePaginatorで1つのページに複数ページネーションを実装 -Laravel

LengthAwarePaginatorを使って1つのページに複数ページネーションを実装。

参考
Laravel5で1ページに複数のPaginationを実装する
https://qiita.com/sano1202/items/371a59ea46cb66993b8b

こちらを参考にさせていただきました!

が、LengthAwarePaginatorを使用して複数ページネーションを実装しようとした際に詰まったので備忘録。

Paginationのパラメータ名を変更する

パラメータ名が変更できずに随分困りましたが第5引数に

['pageName' => 'hogehoge']

を入れるだけでした。。

$players = new LengthAwarePaginator($list , $all_num, $disp_limit, $page, ['pageName' => 'hogehoge']);

これで、user/index?hogehoge=2
のようになります。

初心者なので、、こんなのもわからないの?!と言わずお手柔らかにmm
備忘です。

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

【Laravel】LengthAwarePaginatorで1つのページに複数ページネーションを実装 -Laravel5

LengthAwarePaginatorを使って1つのページに複数ページネーションを実装。

参考
Laravel5で1ページに複数のPaginationを実装する
https://qiita.com/sano1202/items/371a59ea46cb66993b8b

基本的にはこちらを参考にさせていただきました!

が、LengthAwarePaginatorを使用して複数ページネーションを実装しようとした際に詰まったので備忘録。

Paginationのパラメータ名を変更する

パラメータ名が変更できずに随分困りましたが第5引数に

['pageName' => 'hogehoge']

を入れるだけでした。。

$users = new LengthAwarePaginator($users , $count, $per_page, $page, ['pageName' => 'hogehoge']);

$users->setPath(url('/users'));

これで、/users?hogehoge=2
のようになります。

初心者なので、、こんなのもわからないの?!と言わずお手柔らかにmm
備忘です。

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

Laravelでフォーム保存後のフィードバックにSessionのフラッシュデータを使うのと、そのテスト方法

Webページでは何らかのフォームで保存ボタンを押した後に次のページにリダイレクトすることがあり、
リダイレクトされた次のページでフィードバックしたいということがよくあります。

image.png
※画像はイメージです

Laravelにおいてこのフィードバックを出す方法と、そのテスト方法について説明します。

バックエンドでセッションのフラッシュデータに値を入れる

Controller で以下のようにwithでフラッシュデータに値を入れておきます。

 public function add() {
   // 保存とか色々する
   // 最後に次のページへリダイレクトさせる
   return redirect()->route('/')->with('success', '保存が成功しました');
 } 

公式ドキュメントでいうと https://readouble.com/laravel/5.8/ja/responses.html

フラッシュデータを保存するリダイレクト

あたりの章です。

フィードバックの HTML と SCSS

Laravelのヘルパ関数でsession()というのがあるので、それで値をとります。

LaravelのBladeファイルで書くとHTMLは以下のようになります。

@if(session('success'))
    <div class="feedback-wrapper">
        <div class="feedback success">
            {{ session('success') }}
        </div>
    </div>
@endif

対応するSCSS

.feedback-wrapper {
  .feedback {
    margin: auto;
    padding: 12px;
    border-radius: 4px;
    text-align: center;

    &.success {
      border: 1px solid green;
      color: green;
      font-weight: bold
    }
  }
}

テスト方法

Featureテストを書く時に、フラッシュデータが何が入っているかというのをテストに書きます。

    public function testAdd()
    {
        $this->post('/test/add', [
            'text' => '入力したテキストです',
        ])->assertRedirect('/text')->assertSessionHas('success');
    }

assertSessionHas() を使えば、仮にリダイレクト先が同じでも、入っているフラッシュデータが違う 'success' と 'warning' であっても区別することができます。

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

Laravelのl5-swaggerで、OpenAPI記法でmultipart/form-dataを表示する

はじめに

Laravelのl5-swaggerでAPIドキュメント兼API動作確認を行う際に、multipart/form-data形式でのswaggerを作成する方法。

TL; DR;

RequestBodyMediaTypemediaType="multipart/form-data"を指定する。
SchemaProperty で項目を列挙する

記載方法

/**
 *
 * @OA\Post(
 *      path="/sample",
 *      operationId="multipart sample",
 *      @OA\RequestBody(
 *          @OA\MediaType(
 *              mediaType="multipart/form-data",// <-ここでマルチパートを指定する
 *              @OA\Schema(
 *                  type="object",// <-object形式にして複数の値を送信
 *                  @OA\Property(// <-送信項目の単位
 *                      property="item_1",// <-送信のキー名(formのname)
 *                      type="integer",
 *                      format="int32",
 *                      description="multipartの数値データとして送信する",//<-説明をつけられる
 *                  ),
 *                  @OA\Property(
 *                      property="image_file",
 *                      type="string",
 *                      format="binary",//<-バイナリデータも送信できる
 *                      description="画像などのバイナリも送信可能",
 *                  ),
 *              ),
 *          )
 *      ),
 *  )
 */

作成例

/**
 * APIコントローラの説明
 *
 * Class SampleController
 * @package App\Http\Controllers
 */
class SampleApiController extends Controller
{


    /**
     *
     * @OA\Post(
     *      path="/sample",
     *      operationId="Sample API",
     *      tags={"User"},
     *      summary="multipart/form-dataのサンプル",
     *      description="l5-swaggerで、OpenAPI記法でmultipart/form-dataを表示する",
     *      @OA\RequestBody(
     *          @OA\MediaType(
     *              mediaType="multipart/form-data",
     *              @OA\Schema(
     *                  type="object",
     *                  @OA\Property(
     *                      property="item_1",
     *                      type="integer",
     *                      format="int32",
     *                      description="multipartで数値データを送信",
     *                  ),
     *                  @OA\Property(
     *                      property="image_file",
     *                      type="string",
     *                      format="binary",
     *                      description="画像などのバイナリも送信可能",
     *                  ),
     *              ),
     *          )
     *      ),
     *      @OA\Response(
     *          response=200,
     *          description="正常な処理",
     *          @OA\JsonContent(
     *              type="object",
     *              @OA\Property(
     *                  property="property_1",
     *                  type="string",
     *                  description="返り値1(テキスト)",
     *              ),
     *              @OA\Property(
     *                  property="property_2",
     *                  type="integer",
     *                  description="返り値2(数値)",
     *              ),
     *          )
     *      ),
     *      @OA\Response(
     *          response=400,
     *          description="requsetデータに問題がある",
     *          @OA\JsonContent(
     *              type="object",
     *              @OA\Property(
     *                  property="error message",
     *                  type="object",
     *              ),
     *          )
     *      ),
     *      @OA\Response(response=500, description="Internal Server Error"),
     *      @OA\Response(response=404, description="Resource Not Found"),
     *  )
     *
     *
     * functionのコメント上に記載すると "swagger"の表示がバグるので、この位置に記載する
     * 
     * @param Request $request 入力データの説明
     * @return array|StreamInterface|JsonResponse 正常な返り値 or エラー結果
     */
    public function hogeFunction(Request $request)
    {
        // 処理
    }

}

以上です。

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

LaravelのwhereHasメソッドが重いのでその代替案

みなさんこんにちは tyamahoriです。
仕事でちょっとしたシステムをLaravelで作成する機会がありました。その中で注意しなければいけない点があったのでここに書き残したいともいます。

whereHasメソッドは重くて辛いょ。。

やっまりwhereHasメソッドを使うと重くて辛いんですよ。。ネットでググるとこんな感じで記事が出てきます

代替案ありました!

GitHubのissueを読み込んでみるとなんと解決策があるではないですか!!!
WhereHas query is too slow のコメント

Laravel is creating a temporary column on literally every row in the database, in which it fills with true or false. If any indexes can be used, they are probably used after this. Any query that uses whereHas is probably going to be a full table scan.

Here is a similar query, except it does not induce full table scans.

Profile::whereIn('profiles.id', function($query) use ($mac_address) {
    $query->from('devices')
        ->select('devices.profile_id')
        ->where('devices.mac_address', $mac_address);
})

なんとwhereInを使えばいいんですね。勉強になりました。issueに乗っているコードを必要に応じて読み替える必要はあります。実際、案件にてwhereHasとwhereInを比較してみたら、驚くくらいに挙動が軽くなりました!。whereHasを使っている方はぜひともwhereInを使ってみてくださいね!!

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

Laravelのアクセサの注意点について

みなさんこんにちは tyamahoriです。
仕事でちょっとしたシステムをLaravelで作成する機会がありました。その中で注意しなければいけない点があったのでここに書き残したいともいます。

アクセサを使う際のメソッド名の命名には注意

getHogeHogeAttribute をモデル内に記載しているかと思います

具体例はこちらです。
まずはカラム名そのままになんのひねりもなくアクセサを使ってみます。

SampleEloquent.php
class SampleEloquent extends Model
{
    protected $table = 'sample_tables';

    /**
     * nameを取得するアクセサ
     *
     * @return string
     */
    public function getNameAttribute(): string
    {
        return $this->attributes['name'];
    }
}

次の例では注意が必要です

SampleEloquent.php
class SampleEloquent extends Model
{
    protected $table = 'sample_tables';

    /**
     * idカラムをhex形式で取得するアクセサ
     *
     * @return string
     */
    public function getIdAttribute(): string
    {
        return bin2hex($this->attributes['id']);
    }
}

上記の場合ですと、場合によっては挙動がおかしくなります。自分が経験したポイントを以下にまとめます。

ポイント

  • 何かしらの処理をアクセサに噛ませる場合は、getColumnNameAttribute() ではなく、getSomeActionColumnNameAttribute() にしておく
  • 特に、デーブルのリレーションで使われるカラムに何かしらの処理を絡ませるアクセサをつける場合は気をつける。getColumnNameAttribute()にするとバグる
  • traitでModel間の共通処理を作って、アクセサを使う場合もgetColumnNameAttribute()は避ける。getSomeNameColumnNameAttribute()みたいな命名にする。

まとめ

アクセサのメソッド名の命名には気を使いましょう。思わぬところで変なバグを生みます。それでは良きLaravelライフを~

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

Laravelでレコード生成、更新時に自動更新されるタイムスタンプをミリ秒にする

概要

Laravelでレコード生成、更新時に自動更新されるタイムスタンプをミリ秒にする。

実装

モデルクラス
class モデル名 extends Model
{
    // このメソッドをオーバーライドする
    public function getDateFormat()
    {
        return 'Y-m-d H:i:s.u';
    }
}
マイグレートクラス
class マイグレート名 extends Migration
{
    public function up()
    {
        Schema::create('table_name', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->dateTime('created_at', 6); // 精度を6にする。
            $table->dateTime('updated_at', 6); // 精度を6にする。
        });
    }
}

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

サーバアプリケーションのログを取る方針、脳死でも出来る事

ログを取る時に考える事

PHP, Laravel を今扱ってるからとりあえず前提は PHP, Laravel で。
他の環境の時も別にやる事は変わらないと思う。

サーバ業務をやってると幸運な事に色々な設計を任せて貰えるんだけど、自分が直接担当しない時にログどうしましょうかと相談されたので、そういう時に伝える基本方針を書いておく。

というか、何も知らない人は頼むからこれだけは最低限やっておいてくれって感じの内容 (そこも人によって違うからあれだけど参考にして損はないはず)。

ログとは

ログと一括りにすると色々あるだろと突っ込みを貰う事になるので、ここではアプリケーション保守を念頭に置いたログの事を指す。
それも (ry みたいな話はあれど、OS に踏み込んだりはせず、サーバサイドアプリケーションエンジニア (長い...) が気にするポイントを書きだしておけば迷いは消える筈。

アクセスログを取る

別に PHP に限らない話になってきそうな気がすでにしてるけど、一旦無視して、前提として HTTPD (Apache や Nginx など) のアクセスログは取る。

アプリケーションログを取る

API のリクエスト時に送信されてくる POST 等のデータ変更系のメソッドは、リクエストデータ加工前にログを吐いておく。
また、レスポンスは有無を言わさず全て取る。

GET, POST, PUT, DELETE はそれぞれ取るようにしておく (POST で投げて _method: 'delete' を DELETE として扱うようなフレームワークの場合、そこの考慮も忘れずやる)。
パラメータは全て保存と言いたい所だけど、クレジットカードなどの平文保存がまずいものに関しては任意のフィールドをマスク (番号を xxxxx... と他の文字列で置き換えて戻せなくする) する事ができる仕組みを入れておく。

いつ誰がサーバに訪問したか、どういうリクエストを投げたのかという情報はサービス全ての起点になるため、これを取らなかったりすると調査が不可能になったりする。

ログレベルは INFO で脳死 (プロジェクト的に理由があって変える場合は違うログレベルで吐く)。

DB 接続とかその多詳細なプログラムレベルのログについて

DB 接続エラーとか、個々の要件毎のエラーケースみたいなものはサービスレベルでどういうログが欲しいとかがあるし、この変は脳死では対応できないので、深刻度に合わせて話して決めておく。

この辺りは INFO というよりはもっと上の深刻度の高いログの為、適切な対応が必要 (本当に脳死は良くない)。
ただ、そういう書き方をすると何も設定しない人がでてきたりするので、\Exception で catch して error 詳細と使ったパラメータを吐くくらいは入れとくと良い (そのままエラーを握り潰さないようにとりあえず同じ例外を再度 throw しておく)。

DEBUG を上手く使う

少し余談。

開発していると皆 dd 挟んだりブレークポイント入れたり工夫してデバッグするけど、止めて眺める系は作業効率は良くなかったりするし、一連のデータを俯瞰して見る事に適さないので、log で吐く事を覚えると幸せになれる。

不要なコードやログを入れたくないという意見がたまにあるけど、そもそもそれは DEBUG が担う部分なので、気兼ねなく Log::DEBUG を仕込むといい。
特に共通化しているような処理 (Model レベルでのデータ整形や Service 層、Job とか視認しづらい部分は特に) に前提にしているデータと加工後のデータや返却したデータなどを吐いておくとどこでおかしくなってるかが分かるようになるのでバンバン差し込んでおくこと。

ログローテーションは必ず動作確認する

未設定の場合は必ず設定する事。
吐く場所がどこかによって変わるけど、ボリュームの空きを使いきったら (usage 100% とか) サーバが動かなくなったり心あたりの無い挙動をする事になるので。
多分監視とか入れるだろうから基本的には大丈夫だと思うけど、たまにログで使いきって死ぬサーバがいる (そもそも log のボリューム分けてないのかという話はあるが、あくまでもリスクコントロールの話)。

またローテーション設計はログの回収、バックアップ頻度、ボリュームサイズなどインフラ依存のため、担当と相談して決める。

この辺りは使ってるフレームワークでローテーションが動いてる事を確認するのと、設定、変更方法を確認しておく (後から変更が難しい場合や、変更箇所が多い場合は先に決めてしまう)。

最後に

書いてると全部脳死って訳にはいかないなーという感想になったけど、とりあえず細かい所は置いておいて、最低ないとやばいのは書けたと思う。

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

laravel ログファイルエラーになる

laravelのログファイルを見るphpを組んでいるんだが、
毎回削除するようにするとふとした瞬間に権限エラーになる。

ということで、

・logファイルの権限を変更
・ログを表示したらファイルを空にする。

ということをやってみよう。

エラー内容

UnexpectedValueException
The stream or file "/path/to/storage/logs/laravel.log" could not be opened: 
failed to open stream: Permission denied


権限を置き換え

sudo chown -R nginx:nginx storage
sudo chmod -R 775 storage


これで動くようになる。

ログファイル表示して削除はこれで。

//    ログ・ファイル取得し表示
    public function log()
    {
        $log = storage_path()."/logs/laravel.log";

        if(is_file($log)){
            $res = file_get_contents($log);

            $fp = fopen($log, 'r+');
            flock($fp, LOCK_EX);
            ftruncate($fp,0);
            flock($fp, LOCK_UN);
            fclose($fp);

        } else {
            $res = 'ログはありません';
        }


        $res = str_replace(",",",<br>",$res);



        print_r($res);


        die;
    }


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

【Laravel】publicディレクトリの中にサブディレクトリを作成したら「Access forbidden」が出た

publicディレクトリの中にサブディレクトリを作成したらAccess forbidden(403エラー)が出た。
気づかずにしばらくハマったのでメモ。

ディレクトリ構成

/
  resources/
    public/
       foo/
         css/
    views/
       foo/
         index.blade.php
routes/web.php
Route::get('/foo', 'FooController@index');

publicディレクトリの.htaccessを確認したら下記の記述があった。

public/.htaccess
    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]

LaravelはURLにアクセスした場合フロントコントローラーで処理されているが、
RewriteCond %{REQUEST_FILENAME} !-dの記述によって既存のディレクトリは除外されているよう。

publicディレクトリの既存のディレクトリに直接アクセスしていたため Access fobidden がでていたと思われる。

解決策

1.RewriteCond %{REQUEST_FILENAME} !-dをコメントアウトする

public/.htaccess
    # Handle Front Controller...
    # RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]

でもLaravelの他の機能に影響が出そうでちょっと怖い。

2.Routeのurlを変更する

routes/web.php
Route::get('/foo/index', 'FooController@index');

無難な気がする。

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