人気のPHP WEBアプリケーションフレームワークLaravelのTipsを記録していきます

Laravel で モデルを json にして渡すとき削除(unset)したいカラムを設定する。日本語をUnicode化せずそのままjson化する

● Laravel で モデルを json にして渡すとき削除(unset)したいカラムを設定する

JSON で API データを渡す時などにパスワードなどを含めたくないということが多々あります。
Laravelでは一撃で書くことができます。

$json = $model->toJson();

  ↓ makeHiddenメソッドを挟みます。

$json = $model->makeHidden(['password','remember_token'])->toJson();

引用 : http://bit.ly/2z5fqLk

● Laravel で モデルを json にして渡すとき日本語をUnicode化せずそのまま渡す

$json = $model->toJson();

  ↓ toJsonメソッドにオプションを渡します。

$json = $model->toJson(JSON_UNESCAPED_UNICODE);

簡単ですね!

No.1574
08/19 19:15

edit

Laravel で データベース更新時にフックをかけて自動的に処理を行う。

● Laravel で データベース更新時にフックをかけて自動的に処理を行う。

Laravelではフックというとても便利な機能があります。
これはデータベースのデータに更新や削除などデータ操作があった際に好きな 処理を挟み込むことができます。
またトレイトも使用できますのでコントローラーから分離することもできます。

● 公式マニュアル

https://laravel.com/docs/5.8/eloquent#events

● 日本語公式マニュアル

(イベント)の項目を参照
https://readouble.com/laravel/5.8/ja/eloquent.html

● Traitを使ったフックの使用

一番簡単な Trait を使ったフックを紹介します。

・1. まずトレイトを作成します

/app/WebApiTrait.php

<?php
namespace App;
trait WebApiTrait
{
    public static function bootWebApiTrait()
    {
       static::created(function ($model) {
            dd( 'created hook', $model );
        });

       static::updated(function ($model) {
            dd( 'updated hook', $model );
        });

       static::deleted(function ($model) {
            dd( 'deleted hook', $model );
        });
    }
}

・2. フックをかけたいモデルから呼び出します。

Userモデルに追加してみましょう

<?php
namespace App;
use App\Notifications\UserResetPassword;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
    // ===== Trait フック(この行を追加) =====
    use WebApiTrait;
    // ===== / Trait フック(この行を追加) =====

これだけです。
これだけでDBデータに「新規登録」「更新(実際にデータ更新があった時)」「削除」
の時に dd(); が動いて、ダンプして停止します。
実際のロジックはdd() を書き換えればいいでしょう。

No.1573
08/19 16:03

edit

Laravel Blade に ディスクの残り容量を表示させる

resources/views/admin/inc/disk_info.blade.php

@php
        // ディスク容量
        $d =  `df -hT`;
        $d_array = preg_split("/\n/",$d);
        $disk_info = $d_array[0]. "<br>" .$d_array[1];
@endphp
<div class="disk_free_space">
<b>ディスク情報</b><br>
<pre>
{!! $disk_info !!}
</pre>
</div>

他のBladeから呼び出します

@include('admin.inc.disk_info')
No.1568
08/07 10:00

edit

Laravel Collection で 重複するデータを削除する

● Laravel Collection で 重複するデータを削除する

同じ user_id を持つデータを1つ(後ろにある方を有効)にする

$reports_diet = $reports->keyBy('user_id');
No.1560
07/25 13:36

edit

Laravelで別のコントローラーのメソッドを実行する

● Laravelで別のコントローラーのメソッドを実行する

わざわざ別のクラスを作成したりトレイトに外出ししなくてもLaravel では簡単に別のコントローラーのパブリックメソッド実行することができます

App\Http\Controllers\User\MypageControllercreateParam メソッドを実行してみます
なお呼び出されるメソッドは public である必要があります

$mypage_controller = app()->make('App\Http\Controllers\User\MypageController');
$user_param = $mypage_controller->createParam( $hogehoge );
No.1559
07/25 09:50

edit

● LaravelのマイグレーションでDBにカラムを追加する

● LaravelのマイグレーションでDBにカラムを追加する

Laravelのマイグレーションでカラムのを追加するには、
今既にあるマイグレーションファイルは 変更せずに置いておいて、変更を記述したマイグレーションファイルを新規に作成します。

テーブル名 カラム名
catalogs start_date datetime

 ↓ (例)こちらの2カラムを追加するとします。

テーブル名 カラム名
catalogs start_date datetime
catalogs start_dat_2 datetime
catalogs start_dat_3 datetime

●1. 変更用マイグレーションファイルの新規作成

マイグレーションファイル名はなんでもいいですが、クラス名が被ってしまうとエラーになるので、注意して命名してください。

php artisan make:migration change_catalogs_table_add_2columns  --table=catalogs

成功すると 次のようなファイルが生成されます

2019_07_08_180737_change_catalogs_table_add_2columns

次のように記述します。
(複数カラムを追加する時は追加する順番に注意しましょう)
after('start_date') で start_date カラムの後ろに追加しています。
before() メソッドはうまく動作しないことがあるので、after を使いましょう。

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class ChangeCatalogsTableAdd2columns extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('catalogs', function (Blueprint $table) {
            $table->datetime('start_date_3')->nullable()->after('start_date')->comment('開始時間_3(開始日時_3)');
        });

        Schema::table('catalogs', function (Blueprint $table) {
            $table->datetime('start_date_2')->nullable()->after('start_date')->comment('開始時間_2(開始日時_2)');
        });

    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('catalogs', function (Blueprint $table) {
            $table->dropColumn('start_date_3');
        });
        Schema::table('catalogs', function (Blueprint $table) {
            $table->dropColumn('start_date_2');
        });
    }
}

・カラムの型

コマンド 説明
$table->bigIncrements('id'); 符号なしBIGINTを使用した自動増分ID(主キー)
$table->bigInteger('votes'); BIGINTカラム
$table->binary('data'); BLOBカラム
$table->boolean('confirmed'); BOOLEANカラム
$table->char('name', 100); オプションの文字長を指定するCHARカラム
$table->date('created_at'); DATEカラム
$table->dateTime('created_at'); DATETIMEカラム
$table->dateTimeTz('created_at'); タイムゾーン付きDATETIMEカラム
$table->decimal('amount', 8, 2); 有効(全体桁数)/小数点以下桁数指定のDECIMALカラム
$table->double('amount', 8, 2); 有効(全体桁数)/小数点以下桁数指定のDOUBLEカラム
$table->enum('level', ['easy', 'hard']); ENUMカラム
$table->float('amount', 8, 2); 有効(全体桁数)/小数点以下桁数指定のFLOATカラム
$table->geometry('positions'); GEOMETRYカラム
$table->geometryCollection('positions'); GEOMETRYCOLLECTIONカラム
$table->increments('id'); 符号なしINTを使用した自動増分ID(主キー)
$table->integer('votes'); INTEGERカラム
$table->ipAddress('visitor'); IPアドレスカラム
$table->json('options'); JSONフィールド
$table->jsonb('options'); JSONBフィールド
$table->lineString('positions'); LINESTRINGカラム
$table->longText('description'); LONGTEXTカラム
$table->macAddress('device'); MACアドレスカラム
$table->mediumIncrements('id'); 符号なしMEDIUMINTを使用した自動増分ID(主キー)
$table->mediumInteger('votes'); MEDIUMINTカラム
$table->mediumText('description'); MEDIUMTEXTカラム
$table->morphs('taggable'); 符号なしINTERGERのtaggable_idと文字列のtaggable_typeを追加
$table->multiLineString('positions'); MULTILINESTRINGカラム
$table->multiPoint('positions'); MULTIPOINTカラム
$table->multiPolygon('positions'); MULTIPOLYGONカラム
$table->nullableMorphs('taggable'); NULL値可能なmorphs()カラム
$table->nullableTimestamps(); timestamps()メソッドの別名
$table->point('position'); POINTカラム
$table->polygon('positions'); POLYGONカラム
$table->rememberToken(); VARCHAR(100)でNULL値可能なremember_tokenを追加
$table->smallIncrements('id'); 符号なしSMALLINTを使用した自動増分ID(主キー)
$table->smallInteger('votes'); SMALLINTカラム
$table->softDeletes(); ソフトデリートのためにNULL値可能なdeleted_at TIMESTAMPカラム追加
$table->softDeletesTz(); ソフトデリートのためにNULL値可能なdeleted_atタイムゾーン付きTIMESTAMPカラム追加
$table->string('name', 100); オプションの文字長を指定したVARCHARカラム
$table->text('description'); TEXTカラム
$table->time('sunrise'); TIMEカラム
$table->timeTz('sunrise'); タイムゾーン付きTIMEカラム
$table->timestamp('added_on'); TIMESTAMPカラム
$table->timestampTz('added_on'); タイムゾーン付きTIMESTAMPカラム
$table->timestamps(); NULL値可能なcreated_atupdated_atカラム追加
$table->timestampsTz(); タイムゾーン付きのNULL値可能なcreated_atupdated_atカラム追加
$table->tinyIncrements('id'); 符号なしTINYINTを使用した自動増分ID(主キー)
$table->tinyInteger('votes'); TINYINTカラム
$table->unsignedBigInteger('votes'); 符号なしBIGINTカラム
$table->unsignedDecimal('amount', 8, 2); 有効(全体桁数)/小数点以下桁数指定の符号なしDECIMALカラム
$table->unsignedInteger('votes'); 符号なしINTカラム
$table->unsignedMediumInteger('votes'); 符号なしMEDIUMINTカラム
$table->unsignedSmallInteger('votes'); 符号なしSMALLINTカラム
$table->unsignedTinyInteger('votes'); 符号なしTINYINTカラム
$table->uuid('id'); UUIDカラム
$table->year('birth_year'); YEARカラム

●3. 変更用マイグレーションファイルの実行

php artisan migrate

●4. 変更をやっぱり戻す(ロールバック)

php artisan migrate:rollback

● ロールバックする時にテーブルのカラムが存在するかどうかをチェックする

ロールバックする時にDBカラムが存在しないとエラーとなります。
そこで存在チェックを入れましょう

$table->dropColumn('text_name');

   ↓ ( newsテーブルに text_name カラムが存在するなら削除する)

if (Schema::hasColumn('news', 'text_name')){
    $table->dropColumn('text_name');
}
No.1552
08/20 14:53

edit

Laravel の Eloquent で 日付が今日に近い順

->orderBy(\DB::raw('abs(datediff(CURDATE(), start_date))'),"ASC")
No.1551
07/12 19:54

edit

Laravelのマイグレーションでカラムの名前と型を変更する

● Laravelのマイグレーションでカラムの名前と型を変更する

Laravelのマイグレーションでカラムの名前と型を変更するには、
今既にあるマイグレーションファイルは 変更せずに置いておいて、変更を記述したマイグレーションファイルを新規に作成します。

テーブル名 カラム名
artists year_birth_no smallint

 ↓ (例)こちらに変更するとします。

テーブル名 カラム名
artists year_birth_no_name string

●1. 変更用マイグレーションファイルの新規作成

マイグレーションファイル名はなんでもいいです。

php artisan make:migration change_artists_table_column_year_birth_no  --table=artists

成功すると 次のようなファイルが生成されます

2019_07_08_180737_change_artists_table_column_year_birth_no

●2. 変更用マイグレーションファイルの編集

以下のように変更用の命令と戻し用の命令を記述しておきます。

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class ChangeArtistsTableColumnYearBirthNo extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        // カラム名を変更
        Schema::table('artists', function (Blueprint $table) {
            $table->renameColumn('year_birth_no', 'year_birth_no_name');
        });

        // 型を変更
        Schema::table('artists', function (Blueprint $table) {
            $table->string('year_birth_no_name')->default(NULL)->change();
        });

    }


    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        // 型を戻す
        Schema::table('artists', function (Blueprint $table) {
            $table->smallInteger('year_birth_no_name')->change();
        });

        // カラム名を戻す
        Schema::table('artists', function (Blueprint $table) {
            $table->renameColumn('year_birth_no_name','year_birth_no');
        });
    }

}

●3. 変更用マイグレーションファイルの実行

php artisan migrate

●4. 変更をやっぱり戻す(ロールバック)

php artisan migrate:rollback
No.1545
07/13 09:45

edit

artisan

Laravel で CLI から起動したのかWEBから起動したのかを検知する

● Laravel で CLI から起動

if (strpos(php_sapi_name(), 'cli') !== false) {
    // Run from command
}

● Laravel で WEB から起動

if (strpos(php_sapi_name(), 'cli') === false) {
    // Run from web
}

引用 : http://bit.ly/2Ji9Efi

No.1544
07/06 23:27

edit

Laravel の laravel-responsecache で表示を10倍(?) 高速化する

● spatie/laravel-responsecache

laravel-responsecacheは ララベルのミドルウェアとして動作するキャッシュクラスです。 Laravelのルーティングを通る時に動作する( テンプレートファイルの更新すら確認しない)ので とても高速に動作します

1. インストール

composer require spatie/laravel-responsecache

2. 設定ファイルの生成

php artisan vendor:publish --provider="Spatie\ResponseCache\ResponseCacheServiceProvider"

↑ このコマンドを実行すると
/config/responsecache.php ファイルが生成されます。

3. ミドルウェアにセット

キャッシュをミドルウェア(アクセスのたびに自動的に呼び出されるクラス)にセットします。

既存の $routeMiddleware の一番最後に追加します。

app/Http/Kernel.php

protected $routeMiddleware = [
   ...
   'cacheResponse'      => \Spatie\ResponseCache\Middlewares\CacheResponse::class, // 追加
   'doNotCacheResponse' => \Spatie\ResponseCache\Middlewares\DoNotCacheResponse::class, // 追加
];

次に routes/web.php のキャッシュを適応したいルートをこちらのミドルウェアで囲みます。

	Route::group(['middleware' => 'cacheResponse'], function () {
		Route::get("/", function (Request $request) {
                   // 何かしらの処理
		});
	});

以上でキャッシュは実行されています。
確認してみましょう。

● spatie/laravel-responsecache の動作を確認する。

1. .env の APP_DEBUG=true を確認する

.env の以下の記述があるか確認しましょう

APP_DEBUG=true

2. Laravel の GETメソッドでアクセスできるページへ2回アクセスしてGoogle Chrome でヘッダを見る。

● 管理画面でデータが変更されたときに自動的にキャッシュをクリアする

app/ResponsecacheTrait.php を以下の内容で新規作成します

<?php
namespace App;
use Spatie\ResponseCache\Facades\ResponseCache;

trait ResponsecacheTrait
{
    public static function bootClearsResponseCache()
    {
        self::created(function () {
            ResponseCache::clear();
        });

        self::updated(function () {
            ResponseCache::clear();
        });

        self::deleted(function () {
            ResponseCache::clear();
        });
    }
}

Laravelアプリで使用する全てのモデルファイルに以下のトレイトを追加します

例 : app/news.php に追加します

class News extends Model
{
    // ===== Trait =====
    use \App\ResponsecacheTrait;  // ● 追加
    // ===== Trait =====

これで DBにデータを「新規登録」「変更」「削除」したときにキャッシュがクリアされます。

● spatie/laravel-responsecache の効果をベンチマーク

こちらのコマンドで実際にWEBアプリのベンチマークを3回ずつとってみたところ

ab -n 100 -c 100 https://TEST-SITE.TLD/
Requests per second:    9.19 [#/sec] (mean)
Requests per second:    7.54 [#/sec] (mean)
Requests per second:    6.50 [#/sec] (mean)

 ↓

Requests per second:    80.19 [#/sec] (mean)
Requests per second:    73.79 [#/sec] (mean)
Requests per second:    76.89 [#/sec] (mean)

約9.9倍 速くなりました !!

● 設定を .env にセットする

開発時にこのミドルウェアが入っていると 一時的にキャッシュをオンにしたりオフにしたり する必要が出てきますそこで設定を .env ファイルに設定しておき そこで簡単に切り替えられるようにします

.env

RESPONSE_CACHE_FLAG=true

routes/web.php

// キャッシュミドルウェア( .env の RESPONSE_CACHE_FLAG が true の場合 キャッシュ on)
$cache_middleware = [];
if ( env('RESPONSE_CACHE_FLAG',false) == true ){
	$cache_middleware = ['middleware' => 'cacheResponse'];
}

Route::group($cache_middleware, function () {
	Route::get("/", function (Request $request) {
        ........... 何かしらの処理
	});
});
添付ファイル1
No.1543
07/27 09:42

edit

添付ファイル

Laravel で オブジェクトの存在確認を省略するヘルパー optionalヘルパー

● Laravel optionalヘルパー

https://laravel.com/docs/5.8/helpers

if ( $user->touroku_date ){
    echo $user->touroku_date->format("Y年n月j日");
}

↓ このように記述できます。

echo $accountId = optional($user->touroku_date)->format("Y年n月j日");

オブジェクトが存在しない場合は null が返ります。
便利ですね

引用 : http://bit.ly/31QDPkW

No.1540
06/28 14:37

edit

Laravel で リレーション先のさらに先のリレーションの件数を取得する。検索条件にする。

● Laravel で リレーション先のさらに先のリレーションの件数を取得する

受診データ (hasOne) -> 患者 (hasMany)-> 担当医(複数)

こちらの例のように、リレーション先の患者にさらにリレーションで担当医が複数いる場合の担当医の数を取得します。

・普通に「受診データ」 + 「患者データリレーション」のみ取得する場合

$data_loop = $model->with('patient')->get();

 ↓ このように追加します

・普通に「受診データ」 +「患者データリレーション」+「担当医リレーション(データ)」を取得する場合

$data_loop = $model->with(['patient' => function($query){
    $query->with('doctors');
}])->get();

・普通に「受診データ」 +「患者データリレーション」+「担当医リレーション(の件数)」を取得する場合

$data_loop = $model->with(['patient' => function($query){
    $query->withCount('doctors');
}])->get();

● Laravel で リレーション先のさらに先のリレーションの件数を検索条件にする。

「doctors を2人以上持つ」「patient」のデータを取得する

$data_loop = $model->with(['patient' => function($query){
    $query->with('doctors');
}])->has('patient.doctors','>',1)get();
No.1539
06/27 23:24

edit

タスクランナー Laravel Envoy と git を使って本番環境へのデプロイを自動化する

● タスクランナー Laravel Envoy と git を使って本番環境へのデプロイを自動化する

本番環境にデプロイするときに複数のリポジトリからデータを取ってくる必要があったりだとか
何かシェルコマンドを実行する必要があったりだとか処理が多い場合はタスクランナーを是非使いましょう。
Envoyは シンプルでとても使いやすいタスクランナーです。
(Laravel がインストールされていなくても使用することができます)

● Laravel Envoy 公式ドキュメント

https://readouble.com/laravel/5.8/ja/envoy.html
https://laravel.com/docs/5.8/envoy

● Laravel Envoy のインストール

composer global require laravel/envoy

パスを通します。

cd
vi .bash_profile

次の内容を追加

# laravel / envoy
export PATH="~/.composer/vendor/bin:$PATH"

● コマンド実行の確認

envoy -v

次のようにバージョンが帰って来ればインストール成功です

Laravel Envoy 1.5.0

Usage:
  command [options] [arguments]

● Eovoy コマンドの作成

(ディレクトリはどこでもokです。自分で好きなディレクトリを作成し、そのディレクトリ内で Envoy コマンドを作成して実行できます。)

ディレクトリの作成

mkdir test
cd test

envoyコマンドファイルの作成 (ローカルで作業する場合)

envoy init 127.0.0.1

envoyコマンドファイルの作成 ( 他のサーバに対して作業する場合)

envoy init [user]@[host]

実行するとカレントディレクトリに Envoy.blade.php が生成されます。
少し編集して以下のようにします。

@servers(['web' => '127.0.0.1'])

@task('deploy')
    cd /path/to/site
    git pull origin master
@endtask


@task('hoge')
    ls -la
@endtask

上の例ではタスク deployhoge が登録されています。

● Envoy タスクの実行

envoy run hoge

実行結果

[127.0.0.1]: total 8
[127.0.0.1]: drwxr-xr-x   3 akimitsu  staff    96  6 26 22:44 .
[127.0.0.1]: drwxr-xr-x+ 45 akimitsu  staff  1440  6 26 22:43 ..
[127.0.0.1]: -rw-r--r--@  1 akimitsu  staff   144  6 26 22:44 Envoy.blade.php

このようにタスクを登録して使用します。

● 登録されている Envoyタスクを確認する

envoy tasks

● Envoy 複数タスク(ストーリー)の実行

複数のタスクをまとめてストーリーとして登録しておいてそのストーリーを 実行することができます。

ストーリーの登録 

Envoy.blade.php ファイル内に以下を記述

@story('story_deploy_all__dev')
    task_deploydev_cms
    task_deploydev_html
@endstory

ストーリーの実行 

envoy run story_deploy_all__dev
No.1537
06/28 18:35

edit

Laravel で 自動リダイレクトを使用せずに Validate(バリデーション)を行う

● Laravel で 自動リダイレクトを使用せずに Validate(バリデーション)を行う

        // validation(自動リダイレクト)
        $request->validate([
            $this->username() => 'required|string',
            'password'        => 'required|string',
        ]);

 ↓ このように書き換えます。

        // validation(チェックのみ)
        $validator = Validator::make($request->all(), [
            $this->username() => 'required|string',
            'password'        => 'required|string',
        ]);

        // validation エラーがある場合、エラーメッセージをダンプする
        if ($validator->fails()) {
            dd( $validator->messages()->toArray() );
        }

これで、とりあえず バリデーションエラーがあるときはエラーメッセージが表示されます。 好きな動作を ダンプメソッド dd( $validator->messages()->toArray() ); のところに書き込めば自由にカスタマイズできます。

No.1534
06/24 18:14

edit

Laravel の 複数形を事前に調べる

DBマイグレーションする前に複数形のチェックは行いましょう。

php artisan tinker

として tinker を立ち上げて次のコマンドで調べます。

echo str_plural('複数形を調べたい単語');

● 例: book → books

echo str_plural('book');

 → 結果 : books

● 例: blog → blogs

echo str_plural('blog');

 → 結果 : blogs

● 例: information → information

echo str_plural('information');

 → 結果 : information

● 例: news → news

echo str_plural('news');

 → 結果 : news

No.1533
06/19 18:50

edit

Laravel で 404 を返す

● Laravel で 404 を返す

return \App::abort(404);

● Laravel で 独自ページの404 を返す

$data['title'] = '404';
$data['name'] = 'Page not found';
return response()->view('errors.404',$data,404);
No.1531
06/17 18:00

edit

Laravel アプリ の 高速化

● Laravel アプリ の 高速化

● 1. composer の高速化

次のうちどちらかを行いコンポーザのオートローダーを高速化しておきましょう。

● composer を updateする時に パスを絶対パスに書き換えて高速化する

composer --optimize-autoloader update

● composer の autoloader の パスを絶対パスに書き換えて高速化する

composer dumpautoload -o

● 2. Laravel の クラスマップの最適化

次のコマンドを実行してLaravelのクラスマップを最適化し高速化しておきましょう

php artisan optimize

↑ 上記コマンドで php artisan config:cache , php artisan route:cache が実行されます。

No.1528
07/09 10:22

edit

Laravel の Blade で テンプレートファイルの代わりに文字列からレンダリングする

● Laravel の Blade で テンプレートファイルの代わりに文字列からレンダリングする

    private function renderString($string, $data)
    {
        $php = \Illuminate\Support\Facades\Blade::compileString($string);

        $obLevel = ob_get_level();
        ob_start();
        extract($data, EXTR_SKIP);

        try {
            eval('?' . '>' . $php);
        } catch (Exception $e) {
            while (ob_get_level() > $obLevel) ob_end_clean();
            throw $e;
        } catch (Throwable $e) {
            while (ob_get_level() > $obLevel) ob_end_clean();
            throw new FatalThrowableError($e);
        }

        return ob_get_clean();
    }

● 使い方

$user = \App\User::first();
$text = "こんにちは {{ $user->name }} さん";
$html = $this->renderString($text, compact('user'));
dump( $html );
No.1526
06/07 15:16

edit

Laravel で 動的に locale を変更し、フォームバリデーションを多言語対応する

● Laravel で 動的に locale を変更する

コントローラーのコンストラクタで変更しても、フォームのエラーメッセージには適用されないので、ミドルウェアで locale を設定します

・1. ミドルウェアを作成

php artisan make:middleware Language

app/Http/Middleware/Language.php が自動で 作成されるので以下のように書き換えます。

<?php
namespace App\Http\Middleware;
use Closure;
class Language
{
    public function handle($request, Closure $next)
    {
        $now_url = request()->fullUrl();

        $pattern_zh = '/' . preg_quote( env('BASE_URL_ZH') , '/') . '/';
        $pattern_ja = '/' . preg_quote( env('BASE_URL_JA') , '/') . '/';
        $pattern_en = '/' . preg_quote( env('BASE_URL_EN') , '/') . '/';

        if ( preg_match($pattern_zh, $now_url) ){
            \Illuminate\Support\Facades\App::setLocale( 'zh-TW' );
        }
        elseif ( preg_match($pattern_ja, $now_url) ){
            \Illuminate\Support\Facades\App::setLocale( 'ja' );
        }
        elseif ( preg_match($pattern_en, $now_url) ){
            \Illuminate\Support\Facades\App::setLocale( 'en' );
        }
        return $next($request);
    }
}

・2. ミドルウェアを app/Http/Kernel.php に登録

app/Http/Kernel.php

$middlewareGroups のリストに追加します。
これでWEBアクセスの時には必ず読み込まれます。

    protected $middlewareGroups = [
        'web' => [
            ......
            ......
            \App\Http\Middleware\Language::class,   // ● この行を追加
        ],

・3. 多言語を設定する方法を決める

いろいろやり方はあるかと思いますが今回は .env ファイルに 他言語のサイトのベース URL を設定して、 その「ベースURLにマッチする言語を現在の言語」と判別させてみます

.env

BASE_URL_JA=https://ja.YOUR-SITE.TLD
BASE_URL_ZH=https://zh.YOUR-SITE.TLD
BASE_URL_EN=https://en.YOUR-SITE.TLD

これでURLが「https://zh.YOUR-SITE.TLD」の場合は自動的にロケール「zh-TW」がセットされるようになりました。

・4. 多言語リソースを入手する

https://github.com/caouecs/Laravel-lang

ここから太陽市大言語のリソースファイルを入手して resources/lang に コピーすれば多言語対応は完了です。

引用 : http://bit.ly/2I0bWiA

No.1525
06/07 09:55

edit

Laravel で PHPの notice エラーを無視する

● Laravel で PHPの notice エラーを無視する

app/Providers/AppServiceProvider.php に以下を追加します

    public function boot()
    {
        // 767bytes問題の対応
        Schema::defaultStringLength(191);

        // notice を解除 ● ↓ これを追加 ●
        error_reporting(E_ALL ^ E_NOTICE);
    }
No.1523
06/04 11:23

edit

laravel のモデルの検索結果 collection をさらに検索する

● laravel のモデルの検索結果 collection をさらに検索する

https://readouble.com/laravel/5.8/ja/collections.html

laravel のモデルの検索結果 collection をさらに検索する時に便利なメソッドを紹介します。

・sortBy()

sortByメソッドは指定したキーでコレクションをソートします。
$sorted = $collection->sortBy('price');

・sortByDesc()

このメソッドの使い方はsortByと同じで、コレクションを逆順にソートします。

・first()

firstメソッドは指定された真偽テストをパスしたコレクションの最初の要素を返します。
No.1522
06/20 21:06

edit

PHP のCarbon2 で 多言語(日本語・英語・中国語)で日付を表示させる

● Carbonのバージョンが2以上かどうかチェック

composer show | grep carbon
nesbot/carbon                           2.17.1   A simple API extension for DateTime.

(バージョン2以上である事を確認します。)

● 多言語での日付表示

・1. 日本語での日付表示

\Carbon\Carbon::setLocale('ja_JP');
$dt = new \Carbon\Carbon();
return $dt->isoFormat('YYYY.M.D (dddd)');

結果例

2019.5.30 (木) 木曜日

・2. 英語での日付表示

\Carbon\Carbon::setLocale('en-US');
$dt = new \Carbon\Carbon();
return $dt->isoFormat('YYYY.M.D (dddd)');

結果例

2019.5.30 (Thursday)

・3. 中国語での日付表示

\Carbon\Carbon::setLocale('zh-TW');
$dt = new \Carbon\Carbon();
return $dt->isoFormat('YYYY.M.D (dddd)');

結果例

2019.5.30 (星期四)

● Carbon の isoFormat メソッドの書式

$dt->isoFormat("YYYY年MM月DD日 HH:mm:ss dddd");  // 2019年05月10日 12:34:56 水曜日

moment.js と互換があるそうなので、こちらを参考にするといいです。

http://momentjs.com/docs/#/parsing/string-format/

No.1520
06/07 16:46

edit

Laravel の データベースシーダー実行時に sql文 のダンプファイルを実行する

● Laravel の データベースシーダー実行時に sql文 のダンプファイルを実行する

Laravel シーダー実行時に、sql文(mysqlumpなどのダンプファイル)を実行したい。
という要件は結構あったりします。
Laravelならとても簡単にできます。

通常のデータベースシーダー ( database/seeds/MyTableSeeder.php )

<?php
use Illuminate\Database\Seeder;
class LangdicTableSeeder extends Seeder {
    public function run()
    {
        DB::table("mytable")->insert([
			'id'      => 1 ,
			'name'    => "ichitaro suzuki" ,
        ]);
    }
}

↓ このように書き換えます

SQL文を実行するデータベースシーダー ( database/seeds/MyTableSeeder.php )

<?php
use Illuminate\Database\Seeder;
class LangdicTableSeeder extends Seeder {
    public function run()
    {
        $path = 'database/sql/mytable_2019-05-20.sql';
        DB::unprepared(file_get_contents($path));
    }
}

sqlファイルをここにおきます。 database/sql/mytable_2019-05-20.sql'

シーダーを実行します

php artisan migrate:fresh --seed

以上です。簡単ですね。

No.1518
05/24 14:36

edit

Laravel で DBのER図を表示させる

● graphviz のインストール

yum install -y graphviz

● beyondcode/laravel-er-diagram-generator のインストール

composer require beyondcode/laravel-er-diagram-generator --dev

● ER図の生成

php artisan generate:erd

graph.png が生成されるので、これを見てみましょう。

No.1517
05/24 09:38

edit

php(Laravel)でzipファイルを解凍する

● chumper/zipper を使ってzipファイルを解凍する

・1. zipper のインストール

composer require chumper/zipper

・2. zipファイルの解凍

圧縮ファイル( myfile.zip )をフォルダ(myfile)を作成してその中に解凍する

$zipper = new \Chumper\Zipper\Zipper;
$zipper->make( "zip/myfile.zip" )->extractTo( "zip/myfile") );

● Mac OSX の余計なファイルをのぞいて解凍する

Macで圧縮したファイルに追加されるフォルダ __MACOSX を解凍しません

$zipper = new \Chumper\Zipper\Zipper;
$zipper->make( "zip/myfile.zip" )->extractMatchingRegex("zip/myfile", '/^(?!__MACOSX).+$/i');
No.1516
05/23 12:24

edit

laravel blade 独自ヘルパーを作成する

php artisan make:provider HelperServiceProvider

app/Providers/HelperServiceProvider.php が自動生成されます

    public function register()
    {
        // ここから追加
        foreach (glob(app_path().'/Helpers/*.php') as $filename){
            require_once($filename);
        }
        // ここまで追加
    }

● config.app の providers へ追加

'providers' => [
    ...
    ...
    // ここを追加
    App\Providers\HelperServiceProvider::class ,
],

● bootstrap/cache フォルダに書き込み権限を与える

(ディレクトリ権限エラーが出る場合は実行してください。)

chmod 0777 bootstrap/cache

● ヘルパーファイルを作成する

作成場所は app/Helpers/myhelper.php です。 myhelper は 好きな名前に変更してください。

if (!function_exists('myhelper')) {
    /**
     * 自作ヘルパー関数
     */
	function myhelper( $arg1=null, $arg2=null, $arg3=null, $arg4=null, $arg5=null )
	{
		return 'test';		
	}
 }

No.1514
06/26 18:15

edit

Laravel の パスワードリセット(再設定)時のユーザー検索カラムを増やす

● Laravel の パスワード再設定時のユーザー検索カラムを増やす

Laravelデフォルトでは、 パスワード再設定時にメールアドレスが同じユーザーの最初に検索されたユーザーに対して
パスワード変更が行われます。
これのユーザー検索するためのDB検索カラムを増やして見ましょう。

例として shop_id と email が同じユーザーで検索するように変更して見ましょう。 ( shop_id を追加します)

● shop_id を検索時に追加する

app/Http/Controllers/UserAuth/ResetPasswordController.php を変更します。
( Laravel デフォルトの authの場合は app/Http/Controllers/Auth/ )

    /**
     * オーバーライド用に  (vendor/laravel/framework/src/Illuminate/Foundation/Auth/ResetsPasswords.php) からコピー
     */
    protected function credentials(Request $request)
    {
        // ● shop_id をプラスする
        return $request->only(
            'shop_id', 'email', 'password', 'password_confirmation', 'token'
        );
    }
    /**
     * オーバーライド用に  (vendor/laravel/framework/src/Illuminate/Foundation/Auth/ResetsPasswords.php) からコピー
     * $shop_id は ルーターから受け取る
     */
    public function reset(Request $request, int $shop_id )
    {

        // ● request に shop_id をプラスする
        $request->request->add(['shop_id' => $shop_id]);

        $request->validate($this->rules(), $this->validationErrorMessages());

        $user = \App\User::where("shop_id","=",$shop_id)->where("email","=",$request->email)->first();

        // Here we will attempt to reset the user's password. If it is successful we
        // will update the password on an actual user model and persist it to the
        // database. Otherwise we will parse the error and return the response.
        $response = $this->broker()->reset(
            $this->credentials($request), function ($user, $password) {
                $this->resetPassword($user, $password);
            }
        );

        // If the password was successfully reset, we will redirect the user back to
        // the application's home authenticated view. If there is an error we can
        // redirect them back to where they came from with their error message.
        return $response == Password::PASSWORD_RESET
                    ? $this->sendResetResponse($request, $response)
                    : $this->sendResetFailedResponse($request, $response);
    }

以上です。
簡単ですね。

No.1512
06/19 15:35

edit

laravelのデータベースのidを文字列型(varchar)(Laravelで言う所の string )にする

● 1. マイグレーションファイル

	public function up()
	{
		Schema::create('dics', function(Blueprint $table) {
            $table->string('id')->primary(); //  ● id を string にする
            $table->text('name')->nullable()->comment('テキスト');
            $table->integer('sort_no')->unsigned()->comment('ソート順');
            $table->timestamps();

			$table->primary('id');            
        });
	}

● 2. モデルファイル

class dics extends Model
{
public $incrementing = false; 
}
No.1511
05/30 10:53

edit

Laravel で フォーム画面を開いたまま放置した時のCSRFトークンタイムアウトを防ぐ

● laravel-caffeine

フォームをかなりの時間スクリーン上に置いておいた後に送信するときに、フォームがタイムアウトしないようにします。 (Laravelのデフォルトは120分ですが、これは設定可能であり、サイトごとに異なる可能性があります。)

https://github.com/GeneaLabs/laravel-caffeine

No.1509
05/13 10:11

edit

Laravel で DBの数値型カラムが文字列型で返ってくる場合の対処法

● Laravel で DBの数値型カラムが文字列型で返ってくる場合の対処法

Laravelはもちろん(Laravel に限らず PHP で PDO を使っている場合)DBの数値型カラムが文字列型で返ってくる事があります。
なぜこのような自動型変換が起こるかというと、PHPのMySQL PDOドライバの仕様だそうです。

ただし、次の条件の時に

1. mysqlのドライバーが 「mysqlnd(MySQLNaitiveDriver)」である。
2. PDO::ATTR_EMULATE_PREPARES属性が false である。

自動型変換を回避することが可能です。

● 1. phpinfo() を使って mysqlnd ドライバーが使用されているかどうかチェックする

phpinfo() の出力から確認しましょう。

または次のコマンドで mysqlnd が表示されれば使用されています

php -m | grep mysqlnd

● 2. LaravelアプリのPHPのPDOオプションをチェックする

        $dbh = \DB::connection()->getPdo();

        $attributes = [
            "ATTR_CLIENT_VERSION",
            "ATTR_EMULATE_PREPARES",
            "ATTR_STRINGIFY_FETCHES",
            "ATTR_AUTOCOMMIT",
            "ATTR_ERRMODE",
            "ATTR_CASE",
            "ATTR_ORACLE_NULLS",
            "ATTR_PERSISTENT",
            "ATTR_PREFETCH",
            "ATTR_SERVER_INFO",
            "ATTR_SERVER_VERSION",
            "ATTR_TIMEOUT",
        ];

        foreach ($attributes as $val) {
            echo "PDO::{$val}: ";
            try {
                echo $dbh->getAttribute(constant("PDO::{$val}")) . "<br>\n";
            } catch (\Exception $e) {
                echo "error not supported !!! <br>\n";
            }
        }

結果例

PDO::ATTR_CLIENT_VERSION: mysqlnd 5.0.12-dev - 20150407 - $Id: 38fea24f2847fa7519001be390c98ae0acafe387 $
PDO::ATTR_EMULATE_PREPARES: 0

↑ この例の場合は(mysqlnd有り)(PDO::ATTR_EMULATE_PREPARES: 0)なので、数値型カラムの値は数値型で返ってきます。

レンタルサーバで(おそらく昔の)XSERVERとかは mysqlnd が入ってないので、自動型変換は必ず起きると思われます。

● mysqlnd が入っていないサーバーで MySQLの自動型変換をさせないようにする

Laravel の モデルには $casts プロパティがあり、これに型をセットすると、Eloquentが結果セットを返すときに、明示的にその方にキャストしてくれます。

    /**
     * 明示的なdb型変換
     *
     */
    protected $casts = [
        'id'                => 'int' ,
        'shop_id'           => 'int' ,
        'is_active'         => 'int' ,
        'price_no'          => 'int' ,
    ];

● いちいちデータベースの定義を見て、キャストを作成するのがめんどくさい

次のコードを実行してください。自動で生成します。( int のみ。) コントローラーから次のようなメソッドを実行します

    /**
     * Laravelのモデルの Casts を生成する
     *
     * [int, integer, real, float, double, string, bool, boolean, object, array, json, collection, date, datetime]
     *
     *
     */
    public function getModelCasts(string $table_name = '')
    {
        print "<hr>\n";
        echo "<strong>{$table_name}</strong>";
        print "<hr>\n";
        echo "<pre style='margin: 20px; border: solid #eee 1px;'>";

print <<< 'DOC_END'
/**
 * カラムの明示的なdb型変換
 *
 */
protected $casts = [

DOC_END;

        $query = "SHOW COLUMNS FROM {$table_name}";
        foreach (\DB::select($query) as $column) {
            if     (preg_match("{^int}", $column->Type)) {echo "'{$column->Field}' => 'int' ,\n";} 
            elseif (preg_match("{^tinyint}", $column->Type)) {echo "'{$column->Field}' => 'int' ,\n";} 
            elseif (preg_match("{^smallint}", $column->Type)) {echo "'{$column->Field}' => 'int' ,\n";} 
            elseif (preg_match("{^mediumint}", $column->Type)) {echo "'{$column->Field}' => 'int' ,\n";} 
            elseif (preg_match("{^bigint}", $column->Type)) {echo "'{$column->Field}' => 'int' ,\n";} 
            elseif (preg_match("{^(text|char|varchar)}", $column->Type)) {} 
            elseif (preg_match("{^}", $column->Type)) {} 
            else {
                dump($column);
            }
        }

print <<< 'DOC_END'
];
DOC_END;

        echo "</pre>";
        print "<hr>\n";
    }
No.1508
05/10 10:33

edit

Laravel で Gmail アカウント(Gmailのsmtpサーバ)を使ってメールを送信する

.env

(YOUR-NAME)(YOUR-PASSWORD)を適宜書き換えてください。

MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=YOUR-NAME@gmail.com
MAIL_PASSWORD=【gmail2段階認証のアプリパスワード】
MAIL_ENCRYPTION=tls

MAIL_FROM_ADDRESS=YOUR-NAME@gmail.com
MAIL_FROM_NAME=デフォルトサイト名

gmail2段階認証のアプリパスワード は通常のログインパスワードとは別に作成する必要があります。
https://myaccount.google.com/security

コントローラー

// テキストメール送信
$mail_subject = "メールのタイトルテスト";
$mail_content = "メールの本文です\nテスト";
$to_email = "customer@user.com";

\Mail::send([], [], function($message) use ($from_email, $from_name, $mail_subject, $mail_content, $to_email ) {
    $message->to( $to_email );
    $message->subject( $mail_subject );
    $message->setBody($mail_content);
});
No.1507
05/16 15:36

edit

Laravel で IDの auto_increment の値をセットする

● Laravel で IDの auto_increment の値をセットする

users テーブルのIDを5000番から始める場合は次のように記述します。

            // SET auto-increment start value
            DB::statement("ALTER TABLE users AUTO_INCREMENT = 5000;");
No.1506
05/08 15:27

edit

phpの便利な日付、時刻オブジェクト Carbon を使用する。平成、令和などの和暦を表示させる

● 文字列から Carbon オブジェクトを作成する

次のどちらもokです。

$carbon_obj = new Carbon('2019-03-11');
$carbon_obj = new Carbon('2019/03/11');

● UNIX Timestamp から Carbon オブジェクトを作成する

$carbon_obj = \Carbon\Carbon::createFromTimestamp( $v->getMTime() );

● UNIXタイムスタンプを出力する

dd(Carbon::now()->timestamp);

● 年月日などを出力する

echo $dt->year;
echo $dt->month;
echo $dt->day;
echo $dt->hour;
echo $dt->minute;
echo $dt->second;
2019
5
1
10
42
28

● LaravelのBlade内で直接 Carbon を呼び出して日付を表示させる

bladeテンプレートで Carbon を呼び出すには次のように記述します。

{{ \Carbon\Carbon::now() }}
{{ \Carbon\Carbon::now()->format("Y年m月d日") }}    // 2019年03月05日
{{ \Carbon\Carbon::now()->format("Y年n月j日") }}    // 2019年3月5日
{{ \Carbon\Carbon::now()->format("Y年m月d日 H:i:s") }} // 2019年03月05日 12:30:59
{{ \Carbon\Carbon::now()->format("Y年n月j日 H:i") }} // 2019年3月5日 12:30

format メソッドの引数は PHP の date と同じです。
http://php.net/manual/ja/function.date.php

● Carbonのリファレンス

https://carbon.nesbot.com/docs/

● Carbon で時刻 00:00:00 を指定する

$dt = new \Carbon\Carbon();
$dt->setTime(0, 0, 0)
dd($dt);

● 日付の指定

$dt->setDate($dt->year, $dt->month, 15);

● 日付の指定や加算で注意すること

$dt = new \Carbon\Carbon('2019-05-31');
dump( $dt->copy()->addMonth(1) );
dump( $dt->copy()->addMonthNoOverflow(1) );

 ↓ 結果

date: 2019-07-01 00:00:00.0 Asia/Tokyo (+09:00)
date: 2019-06-30 00:00:00.0 Asia/Tokyo (+09:00)

となります。addMonth() メソッドでは 6月31日がないので、7月1日になるのです。
安全のため addMonth () を 使うのを今すぐやめて addMonthNoOverflow() を使用しましょう
同じく
安全のため addYear () を 使うのを今すぐやめて addYearNoOverflow() を使用しましょう

● addMonthsNoOverflow() と addMonthNoOverflow() ( s ありと s なし)

addMonthNoOverflow は addMonthsNoOverflow を呼び出しているので、ほぼラッパーみたいな感じですが、デフォルトで引数1がセットされるので、1ヶ月だけ追加する場合はaddMonthNoOverflow() だけでもokです。

    public function addMonthsNoOverflow($value)
    public function addMonthNoOverflow($value = 1)

● 日付の加算、減算、指定

// 日付の加算(addition)
$dt->addDay();
$dt->addWeek();
$dt->addMonthNoOverflow();
$dt->addYearNoOverflow();
$dt->addHour();
$dt->addMinute();
$dt->addSecond();

// 日付の減算(subtraction)
$dt->subDay();
$dt->subWeek();
$dt->subMonthNoOverflow();
$dt->subYearNoOverflow();
$dt->subHour();
$dt->subMinute();
$dt->subSecond();

// 昨日
$dt->yesterday();

// 月初
$dt->startOfMonth();
// 月末
$dt->endOfMonth();

// その日の 00:00:00
$dt->startOfDay();

// その日の 23:59:59.999999
$dt->endOfDay();

// parseによる指定(来月末)
$dt->parse('last day of next month');

● Carbonで和暦(昭和、平成、令和)を表示させる

こちら https://qiita.com/chiyoyo/items/da32649b0e04957856c1
の DatetimeUtility.php を使わせてもらいましょう

date_default_timezone_set('Asia/Tokyo');

require_once('DatetimeUtility.php');
$dt = Carbon::parse('2019-05-01');

echo DatetimeUtility::date('JK年n月j日 H:i:s', $dt->timestamp)."\n";
echo DatetimeUtility::date('Jk年n月j日 H:i:s', $dt->timestamp)."\n";

$dt->subSecond(1);
echo DatetimeUtility::date('JK年n月j日 H:i:s', $dt->timestamp)."\n";
echo DatetimeUtility::date('Jk年n月j日 H:i:s', $dt->timestamp)."\n";
令和元年5月1日 00:00:00
令和1年5月1日 00:00:00
平成31年4月30日 23:59:59
平成31年4月30日 23:59:59
No.1429
06/06 09:36

edit

Laravel で DBに INSERT した時に ID(last inserted id )を取得する

● Laravel で insert() した時に id を取得する

$inserted_flag = $model->insert($insert_data);

  ↓  メソッド insertGetId() を使用します

$inserted_id = $model->insertGetId($insert_data);
insertGetId()
テーブルが自動増分IDを持っている場合、insertGetIdメソッドを使うとレコードを挿入し、そのレコードのIDを返してくれます。

その他 : INSERT時に使用するメソッド一覧 http://bit.ly/2PGUl1h

No.1502
05/01 10:19

edit

Laravel で「テキストメール」「htmlメール」を送信する

● Laravel で 「テキストメール」をシンプルに送信する

// テキストメール送信
$from_email = "shop@test.server.com";
$from_name = "ショップ名";
$mail_subject = "ホームページからお問い合わせがありました。";
$mail_content = "メールの本文です\nテスト";
$to_email = "customer@user.com";
\Mail::send([], [], function($message) use ($from_email, $from_name, $mail_subject, $mail_content, $to_email ) {
    $message->from( $from_email, $from_name );
    $message->to( $to_email );
    $message->subject( $mail_subject );
    $message->setBody($mail_content);
});

● Laravel で 「htmlメール」をシンプルに送信する

// htmlメール送信
$from_email = "shop@test.server.com";
$from_name = "ショップ名";
$mail_subject = "ホームページからお問い合わせがありました。";
$mail_content = "<h1>メールの本文です</h1>";
$to_email = "customer@user.com";
\Mail::send([], [], function($message) use ($from_email, $from_name, $mail_subject, $mail_content, $to_email ) {
    $message->from( $from_email, $from_name );
    $message->to( $to_email );
    $message->subject( $mail_subject );
    $message->setBody($mail_content, 'text/html');
});

メール送信方式は .env の値を参照しに行きます sendmail を使って送信する場合の設定

MAIL_FROM_ADDRESS=test@user.com
MAIL_FROM_NAME=サイト名
MAIL_DRIVER=sendmail
MAIL_HOST=localhost

● Laravel で メールの設定を動的に変更する

.env の メール設定を取得するには config() を使用します

$mailconfig = config('mail');
dump( $mailconfig );

メール設定を動的に変更する

$mailconfig = [];
$mailconfig['driver']     = 1;
$mailconfig['host']       = 2;
$mailconfig['port']       = 3;
$mailconfig['username']   = 4;
$mailconfig['password']   = 5;
$mailconfig['encryption'] = null;

// メール設定の変更
$mailconfig = config(['mail' => $mailconfig ]);
No.1496
05/16 15:36

edit

Laravelで一時的にメンテナンスモードに入る

● Laravelで一時的にメンテナンスモードに入る

127.0.0.1
123.123.123.0/24

からのアクセスのみ許す場合

php artisan down --allow=127.0.0.1 --allow=123.123.123.0/24  --message="現在メンテナンス中です"

● Laravelのメンテナンスモードから戻る

php artisan up
No.1494
06/04 08:10

edit

Laravel で バリデーションを使用する

● Laravel で バリデーションを使用する

一番シンプルなやり方はコントローラーに次のように記述します

● 方法1. Laravel で シンプルなバリデーションをコントローラーに使用する

public function confirm( Request $request )
{
        $validation_rule = [
            "name_sei"           => 'required' ,
        ];
        // バリデーション(エラーがある場合は前の画面に戻ります)
        $this->validate( $request, $validation_rule );
}

● Laravel のバリデーションの記述方法には2種類あります

1. パイプでつなぐ記法

'item_id' => 'required|integer',

2. 配列記法 (正規表現で | を使用したい時はこちら。)

'item_id' => ['required', 'integer'] ,
'name'    => ['required','regex:{^[^/]+$}'] ,

● よく使う Laravel のバリデーション記述

'hogehoge_date'   => 'nullable|date',            		 // 日付( null を許す )
'hogehoge_id'     => 'nullable|integer',          		 // 数字( null を許す )
'hogehoge_tax_no' => 'required_if:withtax_flg,0', 		 // 条件( withtax_flg が 0 の時は hogehoge_tax_no 必須 )
'price_initial_no' => 'required_unless:mt_payment_id,21', // 条件( mt_payment_id が 21以外 の時は price_initial_no 必須 )
'email' => 'required|email|confirmed',        // 必須 , メールアドレス , 「email_confirmation」にも同じ値が入っているかチェック
'password' => 'nullable|confirmed',         // nullを許す, 「password_confirmation」にも同じ値が入っているかチェック
'name'    => ['required','regex:{^[^/]+$}'] , // 入力文字列にスラッシュを含めない

● すでにDBに登録ずみのメールアドレスを除外(ユニーク)

・1-1. ユニーク

テーブル users の中に同じ email で登録がある場合はバリデーションエラーとしたい、場合は次のように記述します

'email' => 'unique:users'

・1-2. ユニーク( update時)

↑ 上の記述は不完全で、データ更新(update)の時に自分自身のメールアドレスもエラーとしてしまいます。
そこで、自分自身は除外するように次のように記述します。

		// update時の validation
		$this->validation_column['email'] = [ 'required',
       	            \Illuminate\Validation\Rule::unique('admins')->ignore($id),
		];

・2. 条件付きユニーク( 同じ shop_id と email を持つものをバリデーションエラーとしたい )

// 同じ shop_id の中で email はユニーク
$this->validation_column['email'] = [ 'required', \Illuminate\Validation\Rule::unique('users')->where(function ($query) use ($q) {
										return $query->where('shop_id', $q['shop_id']);
								    }) ];
// validation
$this->validate($request, $this->validation_column);

● 方法2. Laravel で FormRequest を使用してバリデーションルールを記述する

独自のバリデーションルールを適用したい時バリデーションルールを動的に変更したいときなどは FormRequest を使用すると、バリデーション部分が外に出るのでコントローラーがすっきりします。

UsersRequest という フォームリクエストを作成します

php artisan make:request UsersRequest

app/Http/Requests/UsersRequest.php が自動作成されます。

例として shop_id と email をチェックしてユニークかどうかを判定するバリデーションを記述してみます

app/Http/Requests/UsersRequest.php

<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UsersRequest extends FormRequest
{
    /**
     * 認証のロジックを記述する場合はここに記述する。
     * それ以外は常に true を返すように記述しておかないとバリデーションが動作しないので return true; とする。
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * バリデーションルールを記述
     *
     * @return array
     */
    public function rules()
    {
        return [
            "shop_id" => 'required' ,
            "email" => [ 'required', 'email', 'confirmed',
                        \Illuminate\Validation\Rule::unique('users')->ignore($this->input('id'))->where(function($query) {
                            // 入力されたshop_idの値と同じ値を持つレコードでのみ検証する
                            $query->where('shop_id', $this->input('shop_id'));
                        }),
            ] ,
        ];

    }
}

・コントローラーを次のように変更する

public function confirm( Request $request )
{
        $validation_rule = [
            "name_sei"           => 'required' ,
        ];
            // バリデーション(エラーがある場合は前の画面に戻ります)
            $this->validate( $request, $validation_rule );
}

  ↓

    /**
     * ユーザー登録確認
     *
     * \App\Http\Requests\UsersRequest による自動バリデーションが行われる(エラーの場合は前の画面に戻される)
     *
     */
    public function confirm( \App\Http\Requests\UsersRequest $request )
    {

これでOKです。コントローラーにバリデーションの記述が一切なくなりました。 コメントはどこかに記述しておくとよいでしょう。

● Blade内でバリデーションエラーを確認する

1. Bladeテンプレート内で確認する

@php
    dump( $errors );
@endphp

● Blade内でバリデーションエラーを表示する

emailパラメーターのエラーを表示させるには

@include('partial.error_message', ['param_name' => 'email'])

partial/error_message.blade.php

@if($errors->has($param_name))
    <div class="text-danger small" style="flex-wrap: wrap;">{{ $errors->first($param_name) }}</div>
@endif

● Bladeでバリデーションエラーで戻ってきた時に、入力済みの値をフォームに入れて表示する

old を使用します。

<input type="text" placeholder="" name="email" required value="{{ old('email') }}">
No.1485
08/21 12:23

edit

Laravel の 1対多 リレーション

● Laravel全リレーション

1対1
1対多
多対多
Has Many Through
1対1(ポリモーフィック)
1対多(ポリモーフィック)
多対多(ポリモーフィック)

これらのうち 1対多 リレーションを操作してみます。

● Laravel の 1対多リレーション(hasMany)

    /**
     * ● 1対多リレーション : ->items でショップ内の商品を取得します
     *
     * ソート順 : sort_no , ASC
     *
     */
    public function items()
    {
        return $this->hasMany('App\Item','shop_id')->orderBy('sort_no','ASC');
    }

● 使用方法

->items で取得できます

dump( $user->items );

● Laravel の 1対多リレーション(hasMany)に検索条件をつける

後ろの where() メソッドを追加することで条件をつけることができます。

    /**
     * ● 1対多リレーション : ->items_active でショップ内のアクティブな商品を取得します
     *
     * ソート順 : sort_no , DESC
     *
     */
    public function items_active()
    {
        return $this->hasMany('App\Item','shop_id')->where('is_active','=',1)->orderBy('sort_no','ASC');
    }
No.1484
06/21 13:07

edit

LaravelのBladeで パス, URL を表示する

● LaravelのBladeで public のパス , publicのURL を表示する

明示的に public ディレクトリを指定するときには asset('/') をおすすめします。

asset('/') はスラッシュ終わりの場合に最後にスラッシュがつきます。
url('/') はスラッシュ終わりの場合に最後にスラッシュがつきません。

{{ asset('/') }}
{{ url('/') }}

 ↓

https://YOUR-SERVER.TLD/
https://YOUR-SERVER.TLD

また YOUR-SERVER.TLD のところは、実際に駆動させているサーバ名 が入ります。( .env の APP_URL ではありません )

ファイル名まで指定する場合はどちらも同じです。

{{ asset('/assets/js/jquery-1.7.2.min.js') }}
{{ url('/assets/js/jquery-1.7.2.min.js') }}

 ↓

https://YOUR-SERVER.TLD/assets/js/jquery-1.7.2.min.js
https://YOUR-SERVER.TLD/assets/js/jquery-1.7.2.min.js

● その他のパス表示

{!! app_path() !!}
{!! base_path() !!}
{!! config_path() !!}
{!! database_path() !!}
{!! public_path() !!}
{!! resource_path() !!}
{!! storage_path() !!}
/PATH/TO/LARAVEL_APP/app
/PATH/TO/LARAVEL_APP
/PATH/TO/LARAVEL_APP/config
/PATH/TO/LARAVEL_APP/database
/PATH/TO/LARAVEL_APP/public
/PATH/TO/LARAVEL_APP/resources
/PATH/TO/LARAVEL_APP/storage
No.1347
06/12 10:10

edit

Laravel の Auth で ログイン後(ログイン済)の遷移先を変更する

● Laravel の Auth で ログイン後の遷移先を変更する

LoginController.php

    public $redirectTo = '/myhome/';    // ここを変更する

● Laravel の Auth で ログインしようとした時すでにログイン済みだった時の遷移先を変更する

app/Http/Middleware/RedirectIfAuthenticated.php

    public function handle($request, Closure $next, $guard = null)
    {
        if (Auth::guard($guard)->check()) {
            return redirect('/myhome');  // ここを変更する
        }
No.1483
04/12 14:41

edit

Laravelコントローラでバリデーションエラーがあるかどうか判別する

● Laravelコントローラでバリデーションエラーがあるかどうか判別する

        // バリデーションエラーがない場合の処理
        if ( \Session::get('errors') == null ){
                // ...
                // ...
                // ...
        }
No.1482
04/12 09:30

edit

Stripeでプランを作成する

https://stackoverflow.com/questions/30817249/create-plan-on-stripe-through-laravel

https://stripe.com/docs/api/plans/create

use \Stripe\Plan;

Plan::create(array(
  "amount" => 2000,
  "interval" => "month",
  "name" => "Amazing Gold Plan",
  "currency" => "usd",
  "id" => "gold")
);
No.1481
04/11 22:22

edit

Laravel の ルーティングで GET,POST を受け付けるルートを作成する

● Laravel の ルーティングで GET,POST を受け付けるルートを作成する

POSTメソッドのみのルーティング

Route::post("order/input", "OrderController@input")->name('order.input');

 ↓

GET , POSTメソッドを受け付けるルーティング

Route::match(['get', 'post'],"order/input", "OrderController@input")->name('order.input');

● コントローラーでメソッドを判別する $request->isMethod()

例)POSTメソッドの時だけバリデーションするようにします

if ( $request->isMethod('post') ){
    // バリデーション
    $this->validate( $request, $this->customer_info );
}
No.1479
04/11 11:54

edit

Laravel Bladeテンプレート で nl2br する

● Laravel Bladeテンプレート で nl2br する

htmlタグをエスケープする場合
(通常こちらを使用します)

{!! nl2br(e($shop->my_text)) !!}

エスケープしない場合

{!! nl2br($shop->my_text) !!}
No.1478
05/04 18:49

edit

Laravel の mysql の sql_mode を 調査し変更する

● Laravel の mysql の sql_mode を 調査する

Laravelアプリケーションではmysql の sql_mode はどうなっているのでしょうか?

$sql_mode = DB::select( 'SHOW VARIABLES LIKE "%sql_mode%"' );
dump($sql_mode);

戻り値()

ONLY_FULL_GROUP_BY,
STRICT_TRANS_TABLES,
NO_ZERO_IN_DATE,
NO_ZERO_DATE,
ERROR_FOR_DIVISION_BY_ZERO,
NO_AUTO_CREATE_USER,
NO_ENGINE_SUBSTITUTION

● Laravel の mysql の デフォルトの sql_mode を変更する

app/config/database.php

        'mysql' => [
            'driver' => 'mysql',
            .........
            // これをコメントアウトOFF  'strict' => true,
        ],

この状態で sql_mode を調べると

$sql_mode = DB::select( 'SHOW VARIABLES LIKE "%sql_mode%"' );
dump($sql_mode);

戻り値()

NO_AUTO_CREATE_USER,
NO_ENGINE_SUBSTITUTION

となります。
sql_mode を追加するには modes に記述してあげます。

● Laravel で groupBy() を使用した時のエラー「Syntax error or access violation: 1055」に対応する

app/config/database.php を以下のように変更します

            // 'strict' => true,    // OFF
            'modes' => [
                //'ONLY_FULL_GROUP_BY', // OFF
                'STRICT_TRANS_TABLES',
                'NO_ZERO_IN_DATE',
                'NO_ZERO_DATE',
                'ERROR_FOR_DIVISION_BY_ZERO',
                'NO_AUTO_CREATE_USER',
                'NO_ENGINE_SUBSTITUTION'
            ],
No.1477
04/08 09:18

edit

Laravel の Auth で ログイン認証に使用するカラムを追加(変更)する

app/Http/Controllers/Auth/LoginController.php に以下のメソッドを追加します

    /**
     * ログイン認証カラムを増やす
     *
     */
    protected function credentials(Request $request)
    {
        // ログインに必要なすべてのパラメーターが渡っているかチェックする
        if (! $request->has(['email', 'shop_id', 'password']) ) {
            throw new \Exception("ログインに必要なパラメーターが渡されていません");
        }
        return $request->only('email', 'shop_id', 'password');
    }

ログインに必要なすべてのパラメーターが渡っているかチェックしないと非常に危険です。
必ずチェックしてください。

No.1476
04/17 15:04

edit

Laravel で 長い文字列を切り詰める(mb_truncate)

● Laravel で 長い文字列を切り詰める

Smartyで言う所のmb_truncateは

echo str_limit($report->report_honnin_name, $limit = 80, $end = '...');

という風に記述します。

● Laravel の helper

https://laravel.com/docs/5.8/helpers

No.1475
04/04 17:43

edit

Laravel で Session(セッション)を使用する

● Laravelでセッションへ値を保存する

$request を使う場合

$request->session()->put('contact', $request->contact);

Session を使う場合

\Session::put('contact', 'hogehoge');

ヘルパーを使う場合

session(['contact' => 'hogehoge' ]);

● Laravelでセッションから指定の変数を読み込む

$request を使う場合

$request->session()->get('contact');

Session を使う場合

\Session::get('contact', 'xxx'); // 取得できない場合 xxx を返す

ヘルパーを使う場合

session('contact');

 

● Laravelでセッション値の存在確認をする has()

// $request を使う場合
if ( ! $request->session()->has('_old_input') ){ ..... }

// \Session を使う場合
if ( ! \Session::has('_old_input') ){ ..... }

// session() を使う場合
if ( ! session()->has('_old_input'); ){ ..... }

● Laravelでセッションから指定の変数を削除

$request->session()->forget('contact');

● Laravelでセッションから全データを削除

$request->session()->flush();
\Session::flush();

● Laravelで全てのセッションを読み込む

$session__all = \Session::all();
No.1474
07/04 19:51

edit

Laravel で最初にやっておいた方が良い初期設定

・varcharのデフォルト文字数を191文字にする

変更ファイル : app\Providers\AppServiceProvider.php

public function boot()
{
    // ↓ この行を追加
    \Illuminate\Support\Facades\Schema::defaultStringLength(191);
}

・ロケールの設定を変更する

変更ファイル : config/app.php

'locale' => 'en',

  ↓

'locale' => 'ja',

・timezoneの設定を変更する

変更ファイル : config/app.php

'timezone' => 'UTC',

 ↓

'timezone' => 'Asia/Tokyo',

・ディスク設定にパーミッションを追加する

変更ファイル : config/filesystems.php

        'public' => [
            'driver' => 'local',
            'root' => storage_path('app/public'),
            'url' => env('APP_URL').'/storage',
            'visibility' => 'public',
            // ===== permissionsを追加 =====
            'permissions' => [
                'dir' => [
                    'public'  => 0775 ,
                ],
                'file' => [
                    'public' => 0664 ,
                ],
            ],
            // ===== / permissionsを追加 =====
        ],

● 必要なパッケージを追加する

必要であれば以下のようなパッケージをインストールしておきます

# yaml
composer require symfony/yaml

# Debug Bar
composer require barryvdh/laravel-debugbar

# DB Backup
composer require spatie/laravel-db-snapshots

Laravel で DB のバックアップを簡単にとる (laravel-db-snapshots)|プログラムメモ

● 不要なデフォルトのミドルウェアを停止する

TrimStringsはフォーム入力の無駄な前後スペースを取り除きます。

不要ならコメントアウトしましょう app/Http/Kernel.php

    protected $middleware = [
        \App\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
// OFF        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        \App\Http\Middleware\TrustProxies::class,
    ];
No.1473
05/15 15:14

edit

blade テンプレートのひな型

● 継承元テンプレート

<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
    <title>{{$page_title or ''}}</title>
</head>
<body>
    @yield('content')
</body>
</html>

● 各ページテンプレート

{{-- 継承元 --}}
@extends('user.layout_user')


{{-- ページタイトル --}}
@php
    $page_title = '記事詳細'
@endphp


{{-- コンテンツ --}}
@section('content')
    <div>ページ内容</div>
@endsection
No.1472
04/03 17:46

edit

コントローラーの作成

● artisan コマンドによるコントローラーのひな形作成

(先頭は大文字です)

php artisan make:controller InfoController

app/Http/Controllers/InfoController.php が自動で作成されます。

No.1471
04/03 18:15

edit

TCPDF で 外字使用してPHPからPDF出力をする

● 外字フォントの用意

1. ファイルのリネーム( tte を ttf にリネームする)

例: 外字ファイルが eudc.tte の場合

「eudc.tte」→「eudc.ttf」

2. 任意のフォルダで tcpdfをダウンロード(git clone)する

git clone https://github.com/tecnickcom/tcpdf

3. フォントファイル(eudc.ttf)を( tcpdf/tools )へコピーする

4. コンバートの実行

cd tcpdf/tools
php ./tcpdf_addfont.php -b -t eudc -f 32 -i eudc.ttf

これでフォルダ tcpdf/fonts にファイル

eudc.ctg.z
eudc.php
eudc.z

が生成されます。

これらの3つのファイルをtcpdfを動作させるサーバの好きなディレクトリにコピーします。

● TCPDFで使用する

$pdf = new Fpdi\TcpdfFpdi();
$font_2 = $pdf->AddFont( "eudc", "", "/YOUR/SERVER/PATH/fonts/eudc.php", true );

これで

<span style="font-family:eudc">◆◆◆</span>

(◆ が外字 )

で表示されます。 外字文字のところだけ、このCSSをあててあげます。

● CSSを自動で当てる(Laravel)

Laravel の モデルにアクセサを登録します。

/**
 * アクセサー : PDF生成時に外字文字のみCSSを追加します。
 */
public function getPdfGaijiNameAttribute()
{
    if ( $this->attributes['name'] != null ){
        $text = $this->attributes['name'];
        $encoding = "UTF-8";
        $textLength = mb_strlen($text, $encoding);
        for($i = 0; $i < $textLength; $i++) {
            $m = mb_substr($text, $i, 1, $encoding);
            if (preg_match('/^(\xEE[\x80-\xBF])|(\xEF[\x80-\xA3])|(\xF3[\xB0-\xBF])|(\xF4[\x80-\x8F])/', $m)){
                echo '<span style="font-family:eudc">' . $m ."</span>";
            }
            else {
                echo $m;
            }

        }
    } else {
        return 'ERROR: getPdfGaijiNameAttribute()';
    }
}

使い方

{{$user->name}}

 ↓ の代わりに次のように記述します。

{{$user->pdf_gaiji_name}}

引用:https://goo.gl/AkQXfT

No.1468
03/20 18:56

edit

Laravel で プライマリキー(ID)を bigint にする

● Laravel で プライマリキー(ID)を bigint にする

            $table->bigIncrements('id');

これだけで unsigned, auto increment , primary key 設定になります。

No.1466
03/20 11:08

edit

Laravelでフォームパラメーター($request)の自動トリムをoffにする

● フォームパラメーター($request)の自動トリムをoff

1. app/Http/Kernel.php** の ミドルウェアを削除する

app/Http/Kernel.php
「TrimStrings」( フォーム入力値の前後の空白を自動的にトリムする)
「ConvertEmptyStringsToNull」( フォーム入力値の空文字をnullに自動的に変換する)
を削除します。

    protected $middleware = [
        \App\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        // コメントアウト \App\Http\Middleware\TrimStrings::class,
        // コメントアウト \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        \App\Http\Middleware\TrustProxies::class,
    ];
No.1464
03/19 13:36

edit

Laravel Mix を使用する

● Laravel Mix を使用する

1. Laravel アプリを作成する

composer create-project "laravel/laravel" my_app
cd my_app

2. package.json の確認

cat package.json

このような感じで自動生成されます

{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "npm run development -- --watch",
        "watch-poll": "npm run watch -- --watch-poll",
        "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "axios": "^0.18",
        "bootstrap": "^4.0.0",
        "cross-env": "^5.1",
        "jquery": "^3.2",
        "laravel-mix": "^4.0.7",
        "lodash": "^4.17.5",
        "popper.js": "^1.12",
        "resolve-url-loader": "^2.3.1",
        "sass": "^1.15.2",
        "sass-loader": "^7.1.0",
        "vue": "^2.5.17"
    }
}

3. nodeモジュールのインストール

npm install

4. ビルドする

テスト環境(ソースを圧縮せず)ビルドする

npm run dev

本番環境環境(ソースを圧縮して)ビルドする

npm run prod
No.1462
03/19 22:01

edit

Laravel で DB のバックアップを簡単にとる (laravel-db-snapshots)

laravel-db-snapshotsを使用すると、Laravel で DBの構造とデータをまとめてバックアップ / リストア することができます。 (データのみの取得はできないようです。)

● spatie/laravel-db-snapshots

composer コマンドでインストールします

composer require spatie/laravel-db-snapshots

● インストールの確認

インストールを確認します。

php artisan
 snapshot
  snapshot:create      Create a new snapshot.
  snapshot:delete      Delete a snapshot.
  snapshot:list        List all the snapshots.
  snapshot:load        Load up a snapshot.

● バックアップを取るディスクを設定する

config/filesystems.php

    'disks' => [

        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],

        // ここから追加
        'snapshots' => [
            'driver' => 'local',
            'root' => database_path('snapshots'),
        ],
        // ここまで追加

(実際のディレクトリはバックアップを取るときに自動作成されます)

● バックアップを取る

テストで database/snapshots/my-first-dump.sql を作成します

php artisan snapshot:create my-first-dump

ファイル名を日付にしてもいいと思います。

php artisan snapshot:create 2019_03_12

何度もとるなら時刻も入れておくといいと思います。

php artisan snapshot:create 2019_04_16__03_19_00

なお 同名のファイルの場合は上書き されますので注意してください。

● ファイル名自動でバックアップを取る

php artisan snapshot:create
Creating new snapshot...
Snapshot `2019-06-04_08-06-49` created (size: 1.37 MB)

2019-06-04_08-06-49 というフォーマットで自動的にファイル名を命名してバックアップを取ってくれます。

●バックアップファイルからリストア(データを流し込む)する

バックアップファイル一覧の確認

php artisan snapshot:list

一覧の Name を指定してリストアを実行します。

リストアの実行

php artisan snapshot:load <バックアップName>

● リストアエラー「 The "force" option does not exist. 」が出る場合

本番環境 (.env に APP_ENV=production が設定されている場合)ではリストアはエラーとなります。

一時的に戻します

.env

APP_ENV=production

 ↓

APP_ENV=local

これで実行できます。 .env ファイルの中身は戻しておきましょう

No.1459
06/27 12:06

edit

Laravel で back URL を持ち回る

● Laravel で back URL を持ち回る

管理画面の編集完了後にリダイレクトするページを複数にしたい時、 戻る URL を次のようにして 持ちまわると便利です。

● _back_url を(1画面だけ有効な)セッションに保存

use Illuminate\Support\Facades\Session;
\Session::flash('_back_url', $request->fullUrl());

● _back_url を経過するコントローラーで(1画面だけ有効なセッションを)保持

use Illuminate\Support\Facades\Session;
if (\Session::has('_back_url')) { \Session::keep('_back_url'); }

● データをUPDATEするコントローラーでもセッションを保持しつつ、リダイレクト

セッションがある時とない時で処理を分けます。

use Illuminate\Support\Facades\Session;
if (\Session::has('_back_url')) { \Session::keep('_back_url'); }
if ( \Session::get('_back_url') ){
    return redirect( \Session::get('_back_url') )->with([ 'message' => 'success !' ]);
}
else {
    return redirect()->route("admin.data.index")->with([ 'message' => 'success !' ]);
}

● 全てのコントローラーに適用したい場合は

httpミドルウェアを使用しましょう。
https://readouble.com/laravel/5.8/ja/middleware.html

No.1455
04/16 10:54

edit

Laravel の バージョン( Ver )をソースコード、コマンド、Bladeテンプレートから調べる

● Laravel の バージョンをソースコードから調べる

vendor/laravel/framework/src/Illuminate/Foundation/Application.php を調べます

	/**
	 * The Laravel framework version.
	 *
	 * @var string
	 */
	const VERSION = '5.0.31';

● Laravel の バージョンをコマンドから調べる

php artisan -V

● Laravel の バージョンを Blade テンプレートから調べる

{{ App::VERSION() }}
No.1454
06/11 09:32

edit

Blade
artisan

Laravel の ユーザー認証の ハッシュ方式を任意のものに変更する

● Laravel の ユーザー認証の ハッシュ方式を任意のものに変更する

例) として aes256(キー固定)に変更してみます。

● 1.CustomHasher.php の作成

app/Libs/CustomHash/CustomHasher.php を以下の内容で作成する

<?php
 namespace App\Libs\CustomHash;
 
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
 
class CustomHasher implements HasherContract {

    public function info($hashedValue)
    {
        return $this->driver()->info($hashedValue);
    }
 
    public function make($value, array $options = array()) {
        $key = env('CUSTOM_HASHER_AES256_KEY', false);
	    return openssl_encrypt($value,'aes-256-ecb',$key);
    }

    public function unmake($value, array $options = array()) {
	    $key = env('CUSTOM_HASHER_AES256_KEY', false);
	    return openssl_decrypt($value,'aes-256-ecb',$key);
    }
 
    public function check($value, $hashedValue, array $options = array()) {
        return $this->make($value) === $hashedValue;
    }
 
    public function needsRehash($hashedValue, array $options = array()) {
        return false;
    }
 
}

● 2. CustomHashServiceProvider.php の作成

app/Providers/CustomHashServiceProvider.php を以下の内容で作成する

<?php
namespace App\Providers;
 
use Illuminate\Hashing\HashServiceProvider;
use App\Libs\CustomHash\CustomHasher as CustomHasher;
 
class CustomHashServiceProvider extends HashServiceProvider
{
    public function register()
    {
        $this->app->singleton('hash', function () {
            return new CustomHasher;
        });
    }
}

● 3.config/app.php の変更

config/app.php の変更

    'providers' => [
		・・・・・
        App\Providers\CustomHashServiceProvider::class ,    // 追加
        // Illuminate\Hashing\HashServiceProvider::class,    // コメントアウト
		・・・・・

● 4. .env に追加

CUSTOM_HASHER_AES256_KEY=my_aes256key

● 5. bcrypt で記述しているシーダーがあれば修正

            'password'            => bcrypt('my-pass-word') ,

  ↓

            'password'            => \Illuminate\Support\Facades\Hash::make('my-pass-word') ,
No.1453
03/07 14:35

edit

bcrypt
Hasher
Hashing

Laravel の 多対多リレーション

● Laravel全リレーション

1対1
1対多
多対多
Has Many Through
1対1(ポリモーフィック)
1対多(ポリモーフィック)
多対多(ポリモーフィック)

これらのうち 多対多 リレーションを操作してみます。

● Laravel の 多対多リレーションのDB構造

とても簡単です。2つのテーブルをつなぐピボットテーブルを作成すればOKです。

・users
・practitioners

というテーブルを多対多でつなぐ時は
テーブル ↓

・user_practitioner

を作成します。( practitioner_user でも良い。 アルファベット順に並べると規則がはっきりして良いですね。単数形 をアンダースコアでつなげます。)
中身は

テーブル「practitioner_user」の構造

id                  (primary key)
user_id             (integer,unsigned)
practitioners_id    (integer,unsigned)

とします。 マイグレーションファイルの up() メソッドは次のようになります。

    public function up()
    {
        Schema::create('practitioner_user', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('practitioner_id');
            $table->integer('user_id');
        });
    }

● Laravel の 多対多リレーション(belongsToMany)をモデルに設定する

多対多リレーションある意味シンプルです。
これを両方のテーブルに(メソッド名は適宜変更して)定義します。
例)Userモデルに設定

    /**
     * 多対多 リレーション
     * ピボットテーブル「practitioner_user」
     *
     * @return \Illuminate\Database\Eloquent\Relations\belongsToMany
     */
    public function practitioners()
    {
        return $this->belongsToMany('App\Practitioner','practitioner_user');
    }

●多対多リレーションのIDリストを取得する

$model = User::findOrFail($id);
dump( $model->practitioners()->allRelatedIds() );   // (注意)Laravel 5.4以前は getRelatedIds() という名前でした

●多対多リレーションの項目名( カラム名 = practitioner_name )をカンマ区切りで取得する

ユーザ1 , ユーザ2 , ユーザ3 の様な文字列を取得します

$model = User::findOrFail($id);
dump( $model->practitioners()->implode('practitioner_name' , ' , ' ) );

bladeテンプレートに記述するときは以下のようにします。

{!! $consentform->patient->managers->pluck('name')->implode('<br>') !!}

このようにも記述できます。( ↑ と同じです。)

{!! $consentform->patient->managers->implode('name','<br>') !!}

●多対多リレーションの項目名へのリンクを作成する

@php
	$consentform->patient->managers->each(function ($item) {
		$route_manager = route('admin.managers.show', $item->id);
		print <<< DOC_END
			<a href="{$route_manager}" target="_blank">{$item->name}</a><br>
		DOC_END;
	});
@endphp

●多対多リレーションのデータ更新(追加)

$model = User::findOrFail($id);
$model->practitioners()->attach([5,6,7]);    // ピボットテーブルに(すでにあるデータは消さずに)データを追加

●多対多リレーションのデータ更新(書き換え)

$model = User::findOrFail($id);
$model->practitioners()->sync([11,22,33]);    // ピボットテーブルを指定した配列のデータで更新(すでにあるデータを書き換え)
No.1452
06/17 10:28

edit

Laravel の 1対1リレーション

● Laravel全リレーション

1対1
1対多
多対多
Has Many Through
1対1(ポリモーフィック)
1対多(ポリモーフィック)
多対多(ポリモーフィック)

これらのうち 1対1 リレーションを操作してみます。

● Laravel の 1対1リレーション(belongsTo)

    /**
     * 1対1リレーション(belongsTo) : ->mt_branch で営業支店の情報を取得できるようにする
     *
     */
    public function mt_branch()
    {
        return $this->belongsTo('App\MtBranch','branch_id')->withDefault();
    }

● Laravel の 1対1リレーション(hasOne)

    /**
     * 1対1リレーション(hasOne) : ->created_user で作成したユーザーの情報を取得できるようにする
     *
     * @return \Illuminate\Database\Eloquent\Relations\hasOne
     */
    public function created_user()
    {
        return $this->hasOne('App\User', 'id', 'created_user_id')->withDefault();
    }
No.1450
04/16 17:19

edit

Laravel で fill を通さない DBデータINSERT

(管理画面で初期マスタデータをクライアントに登録してもらう時などに使用します)

● 通常の INSERT(その1)

$insert_data = [
    'name'    => '代入 太郎' ,
];
$practitioner = \App\Practicioner::create($insert_data);

● 通常の INSERT(その2)(その1と同じです)

$insert_data = [
    'name'    => '代入 太郎' ,
];
$practitioner = \App\Practicioner::fill($insert_data)->save();

● fill を通さない INSERT

$insert_data = [
    'id'      => 123456 ,
    'name'    => '代入 太郎' ,
];
$practitioner = \App\Practitioner::insert($insert_data);
No.1449
03/05 11:46

edit

Laravelで id またはメールアドレスでログインする

● Laravelで id またはメールアドレスでログインする

1. コントローラーを修正

(パラメータ名「email_or_id」を受けて、メールアドレスの場合はメールアドレスとして認証。それ以外の場合はidとして認証に行きます。)

app/Http/Controllers/Auth/LoginController.php に以下を追加します

    function username()
    {
        return 'email_or_id';
    }

    function attemptLogin(\Illuminate\Http\Request $request)
    {
        $email_or_id = $request->input($this->username());
        $password = $request->input('password');

        if (filter_var($email_or_id, \FILTER_VALIDATE_EMAIL)) {
            $credentials = ['email' => $email_or_id, 'password' => $password];
        } else {
            $credentials = ['id' => $email_or_id, 'password' => $password];
        }
        return $this->guard()->attempt($credentials, $request->filled('remember'));
    }

2. ビューを修正

パラメータ名を「email」 →「email_or_id」に変更します resources/views/auth/login.blade.php を以下のように変更します

<input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" autofocus>

<input id="email" type="text" class="form-control" name="email_or_id" value="{{ old('email_or_id') }}" autofocus>

以上で id またはメールアドレスでログインする事ができます

引用元 : https://goo.gl/Wodfh1

No.1448
02/22 09:21

edit

Laravel アプリで WordPress 自動整形機能(wpautop) を使用する

● wptrait

https://github.com/akat03/wptrait

● 準備 ( Model )

class Mymodel extends Model
{
    use WpTrait;
}

● 使い方 ( Blade テンプレート)

{!! $mymodel->wpautop($mymodel->contents)  !!}

● 使い方 ( Voyager BREAD )

カラム「text_name」にのみ適用します

@if ( $row->field == 'text_name' )
    @php
        echo $dataTypeContent->wpautop($dataTypeContent->text_name);
    @endphp
@else
   <p>{!! $dataTypeContent->{$row->field} !!}</p>
@endif
No.1445
02/15 11:47

edit

Laravel 「No application encryption key has been specified.」エラーの対処法

● Laravel 「No application encryption key has been specified.」エラー

.env.example からリネームして .env を作成した時に主に出現します。
「application encryption key」がないですよ、と言う事ですので作成しましょう。

php artisan key:generate
No.1441
02/12 10:38

edit

Laravel で lang ファイルを使って多言語化する

● 言語ファイル格納場所とファイル名

英語の場合は「resources/lang/en」ディレクトリ内に言語ファイルを格納します(元からあるはずです) 日本語の場合は「resources/lang/en」ディレクトリを作成します。

ファイル名の例(myapp)

resources/lang/ja/myapp.php

● 言語ファイルの書式

return [
    'list'        => '一覧',
    'edit'        => '編集',
    'delete'      => '削除',
    'print'       => '印刷',
];

● Bladeビューでの使い方

こちらの記法がオススメです

@lang('excrud.search')

こういう書き方もできます。

{{ __('messages.welcome') }}

● Bladeビュー @php ブロック内での使い方

@php
    $page_title = \Lang::get('myapp.edit');
@endphp
No.1439
02/09 14:51

edit

Laravel Voyager を使用する

● Voyager

オリジナルのCMSや管理画面を作りたい時に、面倒な色々の準備をやってくれるのが Voyager です。
必要最低限の機能がかなりのクォリティで用意されています。

https://github.com/the-control-group/voyager

● Voyager のインストラクションビデオ

( 必ず見るようにしましょう。 簡潔に説明してくれています。)

https://laravelvoyager.com/academy/configurations/

● Voyager のインストール

Laravel コマンドでアプリを作成した後に次のコマンドを入力します

・1. laravelコマンドでアプリを作成

composer create-project "laravel/laravel=5.7.*" my_app
cd my_app

・2. composer で Voyagerをインストール

composer require tcg/voyager

・2-B. インストールした Laravel , Voyager のバージョンを確認

composer show

laravel と voyager だけ表示させる

composer show | grep -e laravel/framework -e tcg/voyager

リストの中の次のバージョンを確認する(何か問題が発生した時はバージョンを考慮して検索しましょう)

laravel/framework                     v5.7.28 
tcg/voyager                           v1.1.12

・3-A. .env に DB設定を書き込む

適宜変更します

https://YOUR-SERVER-NET
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

・3-B. Laravel の varcharのデフォルト文字数を191文字にして(191*4 = 764バイト) 767バイトより小さくする

app\Providers\AppServiceProvider.php

// ↓ この行を追加
use Illuminate\Support\Facades\Schema;

    public function boot()
    {
        // ↓ この行を追加
        Schema::defaultStringLength(191);
    }

・4. php artisan voyager コマンドからインストールする

・ダミーデータも一緒にインストールする場合
php artisan voyager:install --with-dummy

(↑ このコマンドでDBデータも自動作成されます)

・管理ユーザーを設定してインストールする場合
php artisan voyager:install
php artisan voyager:admin your@email.com --create

・5. Voyagerにアクセスします

https://<your-site>/admin

admin@admin.com
password

● nginx で Voyager を動作させる

Voyager 1.2 以降から

{{ voyager_asset('lib/css/responsive.dataTables.min.css') }}

の様な形で voyager_asset が追加されました。 「今まで public ディレクトリ以下にファイルをコピーしていた代わりに内部ファイルを返す」 といったものです。これが標準の nginx では動作しない可能性があります。

・nginx設定ファイルに以下を追加

location ~* .(js|css|jpg|png|gif|svg|woff|ttf)$ {
	try_files $uri $uri/ /index.php?$args;
}
nginx -s reload

これで読み込まれます。

 

● 管理画面の見た目のカスタマイズ

・1. 管理画面を日本語にローカライズする

右上のメニューから「Profile」 →「Edit My Profile」→「Locale を ja にセットする」

・2. 管理画面のローディングアイコンを変更する

「Settings」→「Admin」→「Admin Loader」に画像をアップロードする

・3. 管理画面のログイン画面のメイン画像を変更する

こちらの画像ファイルを変更します。

/public/vendor/tcg/voyager/assets/images/bg.jpg

デフォルトでは画像サイズ「1800ox * 1200px 」となっています。

・4. 管理画面のBREDのテンプレートビューを変更する

管理画面のBREDのテンプレートビューを変更するには次の位置に Bladeテンプレートファイルを作成します。

(詳細表示 : browse)を変更する場合

/resources/views/vendor/voyager/<テーブル名>/browse.blade.php

元の管理画面を参考に変更したい場合は次のファイルの内容をコピーします。

vendor/tcg/voyager/resources/views/bread/browse.blade.php

解説: https://laravelvoyager.com/academy/views/

・5. 管理画面のBREDのレイアウトテンプレートを変更する

vendor/tcg/voyager/resources/master.blade.php

 ↓ コピーする

resources/views/vendor/voyager/master.blade.php

・4. Voyager 管理画面のBREDのテンプレートビュー(Blade)内で権限により処理を変える

例: BREADのリスト表示で
「admin の role を持つ場合は表示させる」
「user の role の場合は Policy(別途作成が必要)により TCG\Voyager\Actions\EditAction が可能な場合は表示させる」
を Bladeテンプレートに記述します。

@if (Auth::user()->hasRole('admin'))
    <!-- admin -->
@else
    @php
        $edit_action = new TCG\Voyager\Actions\EditAction($dataType, $data);
    @endphp
    @can($edit_action->getPolicy(), $data)
        @php echo '<!-- user (edit可能です)-->'; @endphp
    @else
        @php echo '<!-- user (edit ×不可能です)-->'; @endphp
        @continue
    @endcan
@endif

・6. 管理画面のBREDのコントローラを変更する

管理画面のBREDのコントローラーを変更するには次の位置に コントローラーファイルを作成します。

例: (EstimateController)を変更する場合

app/Http/Controllers/EstimateController.php

app/Http/Controllers/EstimateController.php を次のようにします。( VoyagerBaseController を継承して中身が空のコントローラを作成 )

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use TCG\Voyager\Database\Schema\SchemaManager;
use TCG\Voyager\Events\BreadDataAdded;
use TCG\Voyager\Events\BreadDataDeleted;
use TCG\Voyager\Events\BreadDataUpdated;
use TCG\Voyager\Events\BreadImagesDeleted;
use TCG\Voyager\Facades\Voyager;
use TCG\Voyager\Http\Controllers\Traits\BreadRelationshipParser;

class  EstimateController extends \TCG\Voyager\Http\Controllers\VoyagerBaseController
{
}

 
元の管理画面を参考に変更したい場合は次のコントローラーファイルの内容をコピーします。

vendor/tcg/voyager/src/Http/Controllers/VoyagerBaseController.php

最後にVoyager の BREAD から 対象となるDBテーブルの「コントローラー名」に「\App\Http\Controllers\EstimateController」を指定します。 (必須です) これで作成したコントローラが使用されます。

● Voyager に 独自cssを追加する

1. /config/voyager.php の以下を変更します。

    'additional_css' => [
        'storage/css/voyager_custom.css',
    ],

storage/app/public/css/voyager_custom.css にcssファイルを置きます

2. css を設置します

<My-APP>/public/css/voyager_custom.css

● Voyager チートシート

https://voyager-cheatsheet.ulties.com/

● Google Analytics API を使用する

https://goo.gl/JrtvkG

● 設定ファイル

/config/voyager-hooks.php
/config/voyager.php

● WordPressデータをインポートしたい

https://github.com/thedevdojo/wordpress-import

● 辞書ファイルの場所

辞書ファイル(日本語)はこちらにあります。

/vendor/tcg/voyager/publishable/lang/ja

● Voyager の ユーザーモデルを変更する

app/User.php

<?php
namespace App\Models;
use TCG\Voyager\Models\User as VoyagerUser;
class User extends VoyagerUser {
    // add custom mutators and other code in here
}

app/config/voyager.php

'user' => [
    'add_default_role_on_register' => true,
    'default_role'                 => 'user',
    'admin_permission'             => 'browse_admin',
    'namespace'                    => App\User::class,
],

● BREADの options を使用する

BREADのオプションに任意のパラメータを設定した場合は次のように $row->details から参照できます。

例)編集画面にコメントを表示させる
resources/views/vendor/voyager/<BREAD名>/edit-add.blade.php

{{-- コメント表示 --}}
@php 
if ( @$row->details->comment ){
    echo '<small>';
    echo $row->details->comment;
    echo '</small>';
}
@endphp
{{-- / コメント表示 --}}

なお、編集時に項目の見出しをつけるには

{
    "legend": {
        "text": "○○編集エリア"
    }
}

のように指定すると見出しが表示されます。

引用 : https://goo.gl/ydJEd6

● BREAD画面でリレーションにリンクをつける

https://github.com/the-control-group/voyager/issues/2008

● Select Dropdown を使った BREAD のリレーション設定方法

・1. 入力タイプを「Select Dropdown」を選択する

・2. オプション詳細を次のように記述する

{
    "relationship": {
        "key": "id",
        "label": "name"
    }
}
No.1438
04/10 11:38

edit

Laravel の モデルで リレーション先のカラムで親データをソートする

● Laravel の モデルで リレーション先のカラムで親データをソートする

少しややこしい表現になりますが、
リレーション先の複数のカラムをソートする のではなく、
リレーション先のカラムを使って親データをソート します

\App\Shirt::with('size')
    ->select(‘shirts.*', \DB::raw('(SELECT sort FROM sizes WHERE shirts.size_id = sizes.id limit 1 ) as sort'))
    ->orderBy('sort')
    ->get();  // または paginate( $limit ); とかですね。

注意

limit 1 をつけないと、複数行ある時に 「Subquery returns more than 1 row」エラーが返ります

● Laravelのサブクエリ用メソッド

Laravel 5.6.19 から は DB::raw を使用する代わりに joinSub()、leftJoinSub()、rightJoinSub()が追加されたようです。

DB::table('table')->joinSub('select * from "subtable"', 'sub', ...);
DB::table('table')->leftJoinSub(function ($q) { $q->from('subtable'); }, 'sub', ...);
DB::table('table')->rightJoinSub(DB::table('subtable')->where('foo', 'bar'), 'sub', ...);

引用元 : https://goo.gl/2UPi1E

No.1436
02/07 13:28

edit

Eloquent
DB

Laravel で ファイルをアップロードする

● Blade テンプレートに以下を記述してフォームタグを生成

{{ Form::file('myfile', ['class' => $class_name]) }}

( Form::text の場合は 2番目の引数に値をセットしますが、Form::file はセットしません。 )

● ファイル名を「お任せ」で保存する

コントローラーに以下を記述

$file_store_dir = 'img/';
$file_store_disk = 'local';  // local または public または s3
$file_name = $request->myfile->store($file_store_dir, $file_store_disk );

● ファイル名を指定して保存する

コントローラーに以下を記述

$ext = pathinfo($request->myfile->hashName(), PATHINFO_EXTENSION);	// ファイル名から拡張子を取得
$file_store_dir = 'img/';
$file_store_file_name = $id.".{$ext}"; // IDに拡張子をつけたものを保存ファイル名とする
$file_store_disk = 'local';  // local または public または s3
$file_name = $request->myfile->storeAs($file_store_dir, $file_store_file_name, $file_store_disk );  	// ディレクトリ, ファイル名, ディスク
No.1434
02/01 17:39

edit

Laravel の モデル で 生年月日から 和暦(昭和45年6月27日)を返すアクセサーを定義する

    /**
     * アクセサー : 「->patient_birth_date_wareki」 で 値「昭和45年6月27日」のフォーマットで誕生日を返す
     */
    public function getPatientBirthDateWarekiAttribute()
    {
        if ( $this->attributes['patient_birth_date'] != null ){
            $c = new \Carbon\Carbon($this->attributes['patient_birth_date']);
            setlocale(LC_TIME, 'ja_JP.utf8');
            $format = '%EC%Ey年%-m月%-d日';
            return $c->formatLocalized($format);
        } else {
            return 'ERROR: getPatientBirthDateWarekiNengoAttribute()';
        }
    }


    /**
     * アクセサー : 「->patient_birth_date_wareki_nengo」 で 値「昭和」を返す
     */
    public function getPatientBirthDateWarekiNengoAttribute()
    {
        if ( $this->attributes['patient_birth_date'] != null ){
            $c = new \Carbon\Carbon($this->attributes['patient_birth_date']);
            setlocale(LC_TIME, 'ja_JP.utf8');
            $format = '%EC';
            return $c->formatLocalized($format);
        } else {
            return 'ERROR: getPatientBirthDateWarekiNengoAttribute()';
        }
    }


    /**
     * アクセサー : 「->patient_birth_date_wareki_nengo」 で 年号以降の和暦の誕生日を返す
     */
    public function getPatientBirthDateWarekiNengappiAttribute()
    {
        if ( $this->attributes['patient_birth_date'] != null ){
            $c = new \Carbon\Carbon($this->attributes['patient_birth_date']);
            setlocale(LC_TIME, 'ja_JP.utf8');
            $format = '%Ey年%-m月%-d日';
            return $c->formatLocalized($format);
        } else {
            return 'ERROR: getPatientBirthDateWarekiNengoAttribute()';
        }
    }

・使い方

dump($model->patient_birth_date); // DB に入っている誕生日
dump($model->patient_birth_date_wareki);
dump($model->patient_birth_date_wareki_nengo);
dd($model->patient_birth_date_wareki_nengappi);

・結果

Carbon @1548926428 {#558 ▼
  date: 2019-01-31 18:20:28.0 Asia/Tokyo (+09:00)
}
"平成31年1月31日"
"平成"
"31年1月31日"
No.1433
01/31 18:22

edit

Laravelでリレーション先のデータを少なくとも1つ以上持つデータを取得する

https://readouble.com/laravel/5.7/ja/eloquent-relationships.html

// 最低1つのコメントを持つ全ポストの取得…
$posts = App\Post::has('comments')->get();
// 3つ以上のコメントを持つ全ポストの取得
$posts = App\Post::has('comments', '>=', 3)->get();
// 最低1つのコメントと、それに対する評価を持つポストの取得
$posts = App\Post::has('comments.votes')->get();
No.1431
01/30 17:36

edit

LaravelでDBのトランザクションを使用する

● LaravelでDBのトランザクションを使用する

これで、DB処理にエラーがあるときは ROLLBACK されます。

// ========== トランザクション ==========
DB::transaction(function () use ($params) {

    // DB 処理(例です。適宜書き換えてください。)
    DB::table('users')->update($params);
    DB::table('posts')->delete();

});
// ========== / トランザクション ==========
No.1428
04/16 09:20

edit

Laravelのモデルで明示的にIDの値を指定して INSERT する

$insert_data = [
    'id'         => 1001 ,
    'user_name'  => 'テスト太郎' 
];

IDがガードされている場合、次のようにすると user_name のみ INSERTするSQL文が実行されます。

・ id に値をセットしないで INSERT

$model = new MyModel();
$model->fill($insert_data)->save();

 ↓ 明示的に ID にも値を入れて INSERT する場合はこのようにします。

・ id に値をセットして INSERT

$model = new MyModel();
$model->insert($insert_data);

ただし この方法では自動的に created_at にインサート時刻が入りません。 そこで明示的に現在時刻を渡してあげます。

$insert_data['created_at'] = new \Carbon\Carbon();
No.1427
02/01 14:45

edit

Eloquent
DB

Laravel の ディスク・ファイルシステム Storage , Filesystem を使用する

● ディスクの種類

local : ローカルディスク(一般公開しないファイル)
public : ローカルディスク(一般公開するファイル。コマンド aritizan storage:link を実行すると公開することができる。 )
s3 : Amazon S3
ftp :FTP (別途パッケージのインストールが必要)

など。

● publicディスクへのシンボリックリンクを作成する

publicディスクを使用するときは次のコマンドを事前に実行しておきましょう。

php artisan storage:link

● ディスクの設定記述場所

config/filesystems.php

    'disks' => [
        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],
        'public' => [
            'driver' => 'local',
            'root' => storage_path('app/public'),
            'url' => env('APP_URL').'/storage',
            'visibility' => 'public',
        ],
        's3' => [
            'driver' => 's3',
            'key' => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
            'region' => env('AWS_DEFAULT_REGION'),
            'bucket' => env('AWS_BUCKET'),
            'url' => env('AWS_URL'),
        ],
    ],

● ディスク設定にパーミッションを設定する

        'public' => [
            'driver' => 'local',
            'root' => storage_path('app/public'),
            'url' => env('APP_URL').'/storage',
            'visibility' => 'public',
            // ===== permissions =====
            'permissions' => [
                'dir' => [
                    'public'  => 0775 ,
                ],
                'file' => [
                    'public' => 0664 ,
                ],
            ],
            // ===== / permissions =====
        ],

● ディスク(Local )への移動の例

次のようなファイル移動を行うとします。

<アプリのトップディレクトリ>/storage/app/tmp/test.csv
 ↓
<アプリのトップディレクトリ>/storage/app/csv/123456789.csv

注意: Diskをまたいだコピーや移動は move()メソッドだけではできません
参考 : http://bit.ly/2Lk5Qw7

Laravel Storage を使って次の様に記述します。

$disk = \Storage::disk('local');
$disk->move("tmp/test.csv", "csv/12345679.csv" );

簡単ですね。 おすすめです。

● Laravel Storage を使ってファイルのパスを表示させる

dump( $disk->path(false) );    // パスのみの表示
dump( $disk->path("csv/test.csv") );    // ファイル名をフルパスで表示

 ↓ 表示例

/var/www/laravel/my_app/storage/app/
/var/www/laravel/my_app/storage/app/test.csv

● public のディスクの保存したファイルにアクセスする

url(\Storage::disk('public')->url($image_name))

blade

<img src="{{ url(\Storage::disk('public')->url($image_name)) }}">

.env を次のように修正しておきましょう

APP_URL=http://localhost

 ↓

APP_URL=https://YOUR-SITE.TLD/

● Laravel Disk を使ってローカルの pdf や画像を表示する

例えばコントローラに次のように記述するとローカルファイルのデータを表示できます。

        $pdf_file_path = 'pdf/125_01.pdf';
        $disk = \Storage::disk('local');
        $mimetype = $disk->mimeType($pdf_file_path);
        return response($disk->get($pdf_file_path))->header('Content-Type', $mimetype);

● Storageのメソッド

$contents = Storage::get('file.jpg');
$exists = Storage::disk('s3')->exists('file.jpg');

// ファイルをダウンロードさせる
return Storage::download('file.jpg');
return Storage::download('file.jpg', $name, $headers);

// ファイル情報
$url = Storage::url('file.jpg');
$size = Storage::size('file.jpg');
$time = Storage::lastModified('file.jpg');

// ファイル操作
Storage::put('file.jpg', $contents);
Storage::copy('old/file.jpg', 'new/file.jpg');
Storage::move('old/file.jpg', 'new/file.jpg');

// ディスク外のディレクトリにあるファイルをコピー
$tmp_file_fullpath_name = "/tmp/test.jpg";
$d = file_get_contents( $tmp_file_fullpath_name );
\Storage::disk($file_store_disk)->put("{$file_store_dir}/{$image_name}", $d);


// 公開状態かどうか
Storage::setVisibility('file.jpg', 'public')

// ファイルの削除
Storage::delete('file.jpg');
Storage::delete(['file.jpg', 'file2.jpg']);
Storage::disk('s3')->delete('folder_path/file_name.jpg');

// ファイル/ディレクトリ一覧の取得
$files = Storage::files($directory);
$files = Storage::allFiles($directory);
$directories = Storage::directories($directory);
$directories = Storage::allDirectories($directory);

// ディレクトリ操作
Storage::makeDirectory($directory);
Storage::deleteDirectory($directory);

● Filesystemのメソッド

// ディレクトリ内のファイルやディレクトリを削除して 「ディレクトリの中身を空」にする
\File::cleanDirectory( storage_path().'/app/zip' );

// ディレクトリを パーミッション 0777 で作成する
umask( 0 );
\File::makeDirectory($path, '0777');

● 戻り値などはソースを確認しましょう

https://github.com/illuminate/filesystem/blob/master/Filesystem.php

No.1426
07/12 13:56

edit

Laravel の ルーティングで Route::resource() で生成されるルート名の先頭に 文字列を加える

Route::group(['prefix' => 'admin', 'middleware' => 'admin', 'namespace' => 'Admin'], function () {
    Route::resource("consentforms","ConsentformController");
});

とするとルート名は

| GET|HEAD  | admin/consentforms/create              | consentforms.create  | 
| GET|HEAD  | admin/consentforms/{consentform}       | consentforms.show    | 
| PUT|PATCH | admin/consentforms/{consentform}       | consentforms.update  | 
  ... (以下続く)

と、なりますが
次の様に 'as' => 'admin.' を使うと 名前の先頭に admin. が追加されます

・'as' => 'admin. を追加

Route::group(['prefix' => 'admin', 'middleware' => 'admin', 'namespace' => 'Admin', 'as' => 'admin.'], function () {
    Route::resource("consentforms","ConsentformController");
});

 ↓ この様なルート名になります

| GET|HEAD  | admin/consentforms/create              | admin.consentforms.create  | 
| GET|HEAD  | admin/consentforms/{consentform}       | admin.consentforms.show    | 
| PUT|PATCH | admin/consentforms/{consentform}       | admin.consentforms.update  | 
  ... (以下続く)

No.1425
01/25 17:35

edit

ルーティング

Laravel の Blade でテンプレートファイルの格納ディレクトリを変更(追加する)

● Laravel の Blade でテンプレートファイルの格納ディレクトリを変更(追加する)

1. app/resources/pdf を追加し、 Pdf:: としてアクセスできるようにします

use View;
View::addNamespace('Pdf', base_path().'/resources/pdf' );

2. app/resources/pdf/my_template.blade.php を表示する

return View::make('Pdf::my_template');
No.1420
01/18 11:15

edit

Laravelで Bladeテンプレートのレンダリング結果を文字列として取得する

● Laravelで Bladeテンプレートのレンダリング結果を文字列として取得する

レンダリングするファイルが Views 以下にある場合はこちらでOKです。

$html = view('welcome', compact('user'))->render();
dd( $html );

Views 以外のディレクトリにあるテンプレートファイルをレンダリングして変数に代入するには

    /**
     * views 以外にあるbladeテンプレート( *.blade.php )を描画して変数とし受け取る
     *
     * @param   string      $template_full_path      テンプレートhtmlファイル名(フルパス)
     * @param   string      $compact                 compact() で受け取るテンプレートパラメーター
     *
     * @return  string      htmlテンプレート描画内容
     */
    private function getViewRender( string $template_full_path ,  array $compact )
    {
        $template_path     = pathinfo($template_full_path, PATHINFO_DIRNAME);
        $templatefile_name = pathinfo($template_full_path, PATHINFO_FILENAME);

        $app = app();
        $paths = [$template_path];
 
        // もとの設定を取得
        $originalFinder = \Illuminate\Support\Facades\View::getFinder();
         $finder = new \Illuminate\View\FileViewFinder($app['files'], $paths);
        \Illuminate\Support\Facades\View::setFinder($finder);
 
            $html = view($templatefile_name, $compact )->render();
            dd($html);

        // もとの設定に戻す
        \Illuminate\Support\Facades\View::setFinder($originalFinder);
 
        return $html;
    }

使い方

        $html = $this->getViewRender( $template_html, compact('param') );

引用: https://goo.gl/nTfMmR

No.1419
01/31 15:20

edit

artisan migrate コマンドを本番サーバで安易に実行しないようにする

● artisan migrate コマンドを本番サーバで安易に実行しないようにする

.env を 以下のように設定します。

APP_ENV=production

APP_ENV=production の設定がある時に、migrate コマンドを実行すると

$ artisan migrate:fresh --seed

次のような確認入力が表示されます。
これで本番環境で安易なマイグレーションの実行を抑止することができます。

**************************************
*     Application In Production!     *
**************************************
 Do you really wish to run this command? (yes/no) [no]:
No.1415
01/16 11:51

edit

artisan

Laravelでリレーション先のカラムを文字列で検索する

● Laravelでリレーション先のカラムを文字列で検索する

1対1のリレーションに有効です。
1対多のリレーションの場合は Slow Query になる可能性があるようです。必ず生成されるSQL文を確認しましょう。

● モデル

    /**
     * 1対1リレーション (従属の関係)
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function user() // 単数形
    {
        return $this->belongsTo('App\User');
    }

● コントローラー

(モデルの中に記述してもいいです。お好みで。)

whereHasメソッド または orWhereHasメソッド を使用します。

// ● リレーション先のユーザー名「太郎」でも検索
$q = '太郎';
$model->orWhereHas('user', function ($query) use ($q) {	// リレーション名 user を渡す
    $query->where('name', 'LIKE', "%{$q}%");
});

● 実行されるSQL

WHERE
exists(select * from users
    where articles.user_id = users.id
    and name LIKE '%太郎%')

exists を使ってサブクエリを呼び出します。

● 1対多の場合は 最適化されないクエリで呼ばれるようです

EloquentのwhereHasメソッドは辛い - Qiita

No.1397
12/19 15:57

edit

Laravel で 全ての View でモデルのカウント数を表示する

全ての View で 何かの件数を表示したい時、ミドルウェアを作ったり、コントローラーを継承した親コントローラーに 共通処理を書いてもいいのですが、直接モデルオブジェクトを呼ぶという方法もあります。

● 全ての Bladeビューでモデルのカウント数を表示させる

Blade の ビューファイル から直接呼び出します。

自分の記事数 : {{ \App\MyArticle::count() }}
自分のユーザー数 : {{ \App\MyUser::count() }}

● 全ての Bladeビューから変数を読み込む

同様に static なメソッドを作成すれば、どこからでも呼ぶことができます。

app/Http/Controllers/MyController.php

	public static function getMyCount() {
		// ここに何かの処理
		$result = 99999;
		return $result;
	}

ビューからはこのように呼び出せます。

{{ \App\Http\Controllers\MyController::getMyCount() }}
No.1394
12/15 10:30

edit

モデル

Laravel で pdfテンプレートとhtmlを使ってpdfを出力する

● Laravel で pdfテンプレートとhtmlを使ってpdfを出力する

pdfを出力する時に、全てをhtmlで書いてもいいのですが、ロゴなどはpdfテンプレートで使い回すという方法も便利なので紹介します。

1. composer パッケージ「fpdi」「tcpdf」「html-compress 」のインストール

composer require setasign/fpdi
composer require tecnickcom/tcpdf
composer require wyrihaximus/html-compress 

2. pdfテンプレートとhtmlをディレクトリに保存

格納場所 resources/pdf を作成します。

mkdir resources/pdf

ここに pdf と html をコピーします。以下のファイル名とします。

template_01.pdf
template_01.pdf.html

3. 日本語フォントファイル「源真ゴシック」をこちらからダウンロードする

http://jikasei.me/font/genshin/

格納場所 resources/fonts を作成します。

mkdir resources/fonts

ここに 拡張子が .ttf のフォントファイルをコピーします。

4. pdfテンプレートとhtmlを読み込んで出力

Laravelのコントローラーからpdf 出力

use setasign\Fpdi;
use TCPDF_FONTS;
	public function tcpdf()
	{
        $pdf = new Fpdi\TcpdfFpdi();
		// $pdf = new \TCPDF("L", "mm", "A4", true, "UTF-8" );	// pdf テンプレートを使わない場合はこちら

		$pdf->setPrintHeader(false);
		$pdf->setPrintFooter(false);
		$pdf->AddPage();

		// テンプレートPDFファイル読み込み
		$pdf->setSourceFile(resource_path('pdf/template_01.pdf'));
		$page = $pdf->importPage(1);
		$pdf->useTemplate($page);

		// フォント
		$font = new TCPDF_FONTS();

		// フォント:源真ゴシック
		// $font_1 = $font->addTTFfont( resource_path('fonts/ipag.ttf') );
		$font_1 = $font->addTTFfont( resource_path('fonts/GenShinGothic-Medium.ttf') );
		$pdf->SetFont($font_1 , '', 10,'',true);

		// テンプレートhtmlファイル読み込み
		$html = \File::get( resource_path('pdf/template_01.pdf.html') );
		$pdf->writeHTML( $html, $ln=false, $fill=0, $reseth=false, $cell=false, $align="L" );

	 	$pdf->Output("output.pdf", "I");
	 }

5. tcpdf について調べるなら

このサイトがとても便利です

http://tcpdf.penlabo.net/

6. tcpdf の 改行や空白スペースがスペースとして認識されてずれる問題

htmlをminifyしましょう

composer require wyrihaximus/html-compress 
$parser = \WyriHaximus\HtmlCompress\Factory::construct();
$html = $parser->compress($html);

7. TCPDF で使用できるCSSプロパティ

以下のcssプロパティが使用できます。

font-family
font-size
font-weight
font-style
color
background-color
text-decoration
width
height
text-align

ではレイアウトはどうすれば良いのか? いにしえのテーブルレイアウトを使うのがいいでしょう。
例:

<html><body>
<table border="0">
	<tr>
		<td style="width:30px;"></td>
		<td style="width:350px; height:75px;"></td>
		<td></td>
	</tr>
	<tr>
		<td></td>
		<td></td>
		<td>平成31年1月25日</td>
	</tr>
</table>
</body></html>

● pdfフォームの例

https://tcpdf.org/examples/example_014/

No.1393
03/11 13:48

edit

Laravelの Blade でドロップダウンリスト(selectボックス)の任意の項目だけ選択不可能にする

● 1. Laravelの Blade でドロップダウンリスト(selectボックス)の全体を選択不可能にする

LaravelCollective の Form::select の 4番目の引数に配列を渡す事で実現できます。

{{ Form::select($name, $select_loop, $selected_value, ['class' => 'my_css_class', 'disabled' => 'disabled']) }}
{{ Form::select('size', ['L' => 'Large', 'S' => 'Small'], 'S', ['disabled' => 'disabled']) }}

引数4番目の配列に 'disabled' => 'disabled' を指定するだけでOKです。
これだけで、ドロップダウンリスト全体が disabled になります。

● 2. Laravelの Blade でドロップダウンリスト(selectボックス)の任意の項目だけ選択不可能にする

全体じゃなくて特定の <option>項目だけ選択できないようにしたいという時がたまにあります。 その場合は以下のようにフォームマクロを作成すると簡単にできます。

2-1. FormMacroServiceProvider の作成

次のコマンドを実行します

php artisan make:provider FormMacroServiceProvider

コマンドが実行されると app/Providers/FormMacroServiceProvider.php が自動生成されます。

2-2. FormMacroServiceProvider.phpにファイルを追記する

boot() メソッド内に以下を追加します

    public function boot()
    {
        // この行を追記する ↓
        require base_path() . '/resources/macros/selectbox.php';
    }

2-3. config/app.php の providers に登録する

  'providers' => [
        // この行を追記する ↓
        App\Providers\FormMacroServiceProvider::class,
  ]

2-4. macros ディレクトリを作成する

mkdir ./resources/macros

2-5. ファイル /resources/macros/selectbox.php を以下の内容で保存する

<?php
Form::macro('mySelectBox', function ($name, $list = [], $selected = null, array $selectAttributes = [], array $optionsAttributes = []) {
    $html = '<select name="' . $name . '"';
    foreach ($selectAttributes as $k => $v) {
        $html .= ' ' . $k . '="' . $v . '"';
    }
    $html .= ">\n";

    foreach ($list as $value => $text) {
        $html .= '<option value="' . $value . '"';
        if (strcmp($value, $selected) == 0) {
            $html .= ' selected="selected"';
        }
        if (isset($optionsAttributes[$value])) {
            $html .= ' ' . $optionsAttributes[$value];
        }
        $html .= '>' . $text . "</option>\n";
    }
    $html .= '</select>';
    return $html;
});

2-6. Bladeテンプレートに記述する

今まではこのように記述してドロップダウンリストを生成していたと思いますが次のように書き換えます

{{Form::select('size', ['L' => 'Large', 'M' => 'Medium', 'S' => 'Small'], 'S')}}

   ↓

{!! Form::mySelectBox('size', ['L' => 'Large', 'M' => 'Medium', 'S' => 'Small'], 'S', [], ['L' => 'disabled']) !!}

このようなドロップダウンリストが生成されます。 (Largeだけ選択出来ないようになりました)

添付ファイル1
No.1392
12/13 15:02

edit

添付ファイル

Laravel artisan の makeコマンド

● Laravel artisan の makeコマンド

コントローラーなどの各モジュールを作成するときにもちろん既存のファイルのコピペでもいいのですが、 artisan の make コマンドを使うと、エラーのない中身が空のひな形ファイルが作成されます。

● Laravel artisan でコントローラーを作成する(make:controller)

0. コントローラー作成コマンドのヘルプを表示

php artisan make:controller -h

例 : コントローラー「HomeController」を作成する

php artisan make:controller HomeController

成功すると app/Http/Controllers/HomeController.php が作成されます。

● その他のLaravel artisan の make系コマンド

以下、同様に次の make コマンドがあります。

 make:auth             Scaffold basic login and registration views and routes
  make:channel          Create a new channel class
  make:command          Create a new Artisan command
  make:controller       Create a new controller class
  make:event            Create a new event class
  make:exception        Create a new custom exception class
  make:factory          Create a new model factory
  make:job              Create a new job class
  make:listener         Create a new event listener class
  make:mail             Create a new email class
  make:middleware       Create a new middleware class
  make:migration        Create a new migration file
  make:model            Create a new Eloquent model class
  make:notification     Create a new notification class
  make:observer         Create a new observer class
  make:policy           Create a new policy class
  make:provider         Create a new service provider class
  make:request          Create a new form request class
  make:resource         Create a new resource
  make:rule             Create a new validation rule
  make:scaffold         Create a scaffold with bootstrap 3
  make:seeder           Create a new seeder class
  make:test             Create a new test class

● よく使う make系コマンド

種類 ヘルプ表示コマンド
コントローラー php artisan make:controller -h
モデル(DBデータ操作) php artisan make:model -h
マイグレーション(DBデータ構造) php artisan make:migration -h
シーダー(DBデータ作成) php artisan make:seeder -h
No.1387
12/05 10:11

edit

Laravelのモデル(Eloquent)の結果セット(Collection)に任意のカラムを追加する。またアクセサーで書式を変更する

● Laravelのモデルの結果セットに「任意のカラム」を追加する(自動)

モデルファイルに $appends プロパティをセットします

    // SELECTされるデータセットに次の独自カラムを追加する
    protected $appends = ['_editable_flag' , '_email_aisatsu' ];

● Laravelのモデルの結果セットに「任意のカラム」を追加する(手動)

Laravelのモデル(Eloquent)の結果セット(Collection)に手動で任意のカラムを追加するには map() を使用します。

// コレクションのすべてのデータにurl = http://your.url/here を追加
$collection->map(function ($v) {
    $v['url'] = 'http://your.url/here';
    return $v;
});
// コレクションそれぞれに count=xxx (任意の値) を追加
$collection->map(function ($v) {
    $v['count'] = <計算ロジック>;
    return $v;
});

● Laravelのモデルの結果セットに書式を変える「Accessor /Mutator」を追加する

少し書式を変えたいときは Accessor /Mutator を使いましょう

例1: is_starred=1 の時に ☆ を表示するアクセサ

モデルファイルに以下を記述

    /**
     * アクセサー : is_starred=1 の時に ☆ を表示する
     */
    public function getStarMarkAttribute()
    {
        if ($this->attributes['is_starred'] == 1){
            return '<div class="text-warning">★</div>';
        }
    }

呼び出し方

$model->star_mark

例2: 「dispatch_date」が存在する時にフォーマットして表示する。存在しない場合は未発送を返す アクセサ

    /**
     * アクセサー : 「->dispatch_date_ja」 で 値「dispatch_date」が存在する時にフォーマットして表示する。存在しない場合は未発送を返す。
     */
    public function getDispatchDateJaAttribute()
    {
        if ( $this->attributes['dispatch_date'] != null ){
            $c = new \Carbon\Carbon($this->attributes['dispatch_date']);
            return $c->format('m/d');
        } else {
            return '<span class="text-danger">未発送</span>';
        }
    }

呼び出し方

$model->dispatch_date_ja
No.1384
03/19 10:29

edit

モデル
Eloquent
DB

Laravel で Laravel Excel と LibreOfficeを使ってファイルを開いて pdf 出力する

● Laravel で Excel ファイルを開いてダウンロードする

Laravel-Excel ver 3 では まだ現時点では import が使えないようなので ver 2 を入れます。( 参考: https://goo.gl/wxHLE7

● Laravel Excelのインストール

composer で インストールします

composer require "maatwebsite/excel:~2.1.0"

● インストールされたモジュールのバージョン確認

インストールされたモジュールのうち excel 関連のバージョンを調べて置きます

composer show | grep excel
maatwebsite/excel                     2.1.30   Supercharged Excel exports in Laravel
phpoffice/phpexcel                    1.8.2    PHPExcel - OpenXML - Read, Create and Write Spreadsheet ...

Laravel Excel の 2.1.30phpexcel1.8.2 がインストールされています。
ググる時にはこれらのバージョンを参考にしましょう。

● Laravel Excel で テンプレートとなるエクセルファイルを読み込んで表示する

1. 元となるエクセルファイルを storage/excel/test.xls にアップロードする

( storage/excel/ )は存在しないので作成します。

2. routes/web.php に以下を追加する

Route::get('/test/excel', 'TestController@excel');

3. app/Http/Controllers/TestController.php を以下の内容で新規作成する

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;

class TestController extends Controller
{
	public function excel()
	{
		$excel_file = storage_path('excel/test.xls');
		Excel::load($excel_file, function($reader) {
			// 1番目のシートを選択
			$reader->sheet(0, function($sheet) {
				// セルA3に現在の日付を書き込み
				$sheet->cell('A3', function($cell) {
				    $cell->setValue( now()->format('Y/m/d') );
				});		    
			});		    
		})->export('xlsx');
	}
}

4. ブラウザでアクセスして エクセルファイルがダウンロードされることを確認する

https://YOUR-APP.COM/test/excel

にアクセスすると、エクセルファイルがダウンロードされます。
最初のシートの「A3」に今日の日付が書き込まれていることを確認します。
まずこれで Laravel Excel の 動作確認の完了です。

● エクセルファイルをpdfに変換する

PHPでするよりLibreOfficeを使用しましょう。再現性が上がります。(それでも80点ぐらいの再現度ですが。)

1. Libreofficeのインストール

yum -y install libreoffice libreoffice-langpack-ja

インストール後 バージョンを確認します。

libreoffice --version

もし libreoffice が見つからない場合は こちらから検索します。

find / -name soffice.bin

2. IPAフォントをインストール

wget https://ipafont.ipa.go.jp/old/ipafont/IPAfont00303.php -O IPAfont00303.zip
unzip IPAfont00303.zip
cd IPAfont00303
mv *.ttf /usr/share/fonts
cd ..
rm -rf IPAfont00303
rm -f IPAfont00303.zip

3. 源真ゴシックをインストール

mkdir genshingothic
cd genshingothic
wget https://osdn.jp/downloads/users/8/8637/genshingothic-20150607.zip genshingothic-20150607.zip
unzip genshingothic-20150607.zip
mv *.ttf /usr/share/fonts
cd ..
rm -rf genshingothic
rm genshingothic-20150607.zip

4. フォントがインストールされていることを確認

fc-list | grep IPA

5. libreoffice を使ってコンバート

コマンドラインから以下のコマンドを実行します。

libreoffice --headless --convert-to pdf --outdir /home/kusanagi/pdf test.xls

パスは絶対パスで指定しておくと確実です。

No.1383
12/02 22:46

edit

Laravel で DBモデル(データベース)のカラムを変更(追加)する

1. テーブル変更のパッケージを追加する

composer require doctrine/dbal

2. テーブル「articles」を変更するマイグレーションファイル「add_columns_articles_table」を生成する

add_columns_articles_table は任意の命名でOKですが「作業内容_テーブル名_table」としておくとテーブル作成時のファイルと命名が揃います

php artisan make:migration add_columns_articles_table  --table=articles

3. 生成されたファイル「2018_xx_xx_xxxxxx_add_columns_articles_table.php」にテーブル追加の命令を記述する

例:「articles」テーブルに以下のカラムを追加します

・「status_id」カラムの後ろにint型の「recruit_flg」を追加します
・「recruit_flg」カラムの後ろにint型の「recruit_date」を追加します
    public function up()
    {
        Schema::table('articles', function (Blueprint $table) {
            $table->integer('recruit_flg')->default(0)->after('status_id');    // この行を追加
            $table-> dateTime('recruit_date')->nullable()->after('recruit_flg');    // この行を追加
        });
    }

注意:SQLiteでは任意の位置にカラム追加が出来ないようです
回避策 : https://goo.gl/a2atCx

4. マイグレーションを戻す処理を down()メソッドに記述します

    public function down()
    {
        Schema::table('articles', function (Blueprint $table) {
            $table->dropColumn(['recruit_date','recruit_flg']);
        });
    }

5. カラム追加のマイグレーション実行

php artisan migrate

6. 実行したマイグレーションを戻す

php artisan migrate:rollback

以上で、既存のデータベースのデータを削除することなく、カラムを追加できます。

No.1381
05/10 11:16

edit

モデル
artisan

LaravelでCSVファイルをインポートする

● LaravelでCSVファイルをインポートする

ガリガリ書いてもいいですが、 fast-excelを使ってやるとさっとできます

https://github.com/rap2hpoutre/fast-excel

https://github.com/rap2hpoutre/fast-excel

fast-excelのインストール

composer require rap2hpoutre/fast-excel
use Rap2hpoutre\FastExcel\FastExcel;
$csv = (new FastExcel)->importSheets('data.csv');
dd($csv);

これだけで「data.csv」を読み込んで $csv にハッシュの配列形式で格納します。

● 日本語の文字コードが化ける問題への対応

文字コードは utf-8 以外の場合文字化けします。 csvファイルは sjis なことが多いので、事前に変換しておきましょう。

    //========================================== convertFileEncode
    protected function convertFileEncode($infname="", $incode='sjis-win', $outfname="", $outcode='UTF-8', $nl="\r\n") {
        if ( ! is_file($infname) ) {
            die("変換失敗:{$infname} が見つかりません.");
        }
        $tmp_filename = getmypid().'.tmp';
        $outfp = fopen($tmp_filename, 'wb');
        if ($outfp === FALSE) {
            die("変換失敗:{$tmp_filename} に書き込むことができません.");
        }
        $fp = fopen($infname,'r') or die("ファイル({$infname})のオープンに失敗しました");
        while ( ($line = fgets($fp,999999)) !== false ) {
            $outstr = mb_convert_encoding($line, $outcode, $incode);
            $outstr = preg_replace("/\r\n|\r|\n/", $nl, $outstr);
            fwrite($outfp, $outstr);
        }
        fclose($fp);
        fclose($outfp);
        rename($tmp_filename, $outfname);
        chmod($outfname, 0666);
        return true;
    }

エラー処理は適宜書き換えてください。(とりあえず die() していますが、例外を投げた方がいいでしょう。)

No.1379
11/27 18:23

edit

Laravelで try catch する

Laravel では以下のコードでは catch できません。

try {
    // 何かしらの処理
} catch (Exception $e) {
    dd($e);
}

 ↓ このように変更します

try {
    // 何かしらの処理
} catch (\Exception $e) {
    dd($e);
}

\Exception と表記します)

No.1373
11/22 22:05

edit

Laravelのモデルで複数のAND条件のクエリーを実行する

● クロージャを使ってLaravelのモデルで複数のAND条件のクエリーを実行する

例えば「日付が 2019/01/01」かつ「 report_name_1に何か入っている または report_name_2に何か入っている または report_name_3に何か入っている」
という条件はクロージャを使って以下のように記述できます。

$data_loop = \App\Report::where('kigen_date','=','2019-01-01')
            ->where(function($query) {
                $query->orWhereNotNull('report_name_1')
	                  ->orWhereNotNull('report_name_2')
	                  ->orWhereNotNull('report_name_3');
            })
->get();

● スコープを使ってLaravelのモデルで複数のAND条件のクエリーを実行する

ローカルスコープを使うのもおすすめです
スコープを使うと SQL文で言う所の 「AND ( 何かしらのSQL文 )」 を発行することができます。

例えば次のような単純なSQL文もスコープにしてしまうと簡単です。

AND ( feed_id = 100 )

モデルファイル( 例:User モデルの場合 ) app/User.php

    /**
     * ローカルスコープ:inFeed:フィードIDに限定するスコープ
     */
    public function scopeInFeed($query, $feed_id)
    {
        return $query->where('feed_id','=', $feed_id);
    }

コントローラファイルに記述

$model->inFeed( 100 );	// ローカルスコープ適用
No.1370
06/28 19:22

edit

Laravelのモデルでリレーションに条件をつける

次のようにリレーションがあった場合

    /**
     * 1対1リレーション
     */
    public function mt_status()
    {
        return $this->belongsTo('App\MtStatus');
    }

 ↓ 次のようにして条件をつけることができます ( is_only_admin = 0 )

    /**
     * 1対1リレーション
     */
    public function mt_status()
    {
        return $this->belongsTo('App\MtStatus')->where('is_only_admin', '=', 0);
    }
No.1365
11/16 14:47

edit

Laravelのモデルで自分で設定した日付型カラムで format メソッドを使用する

Laravelで自分で作成した

Laravelのモデルで自分で設定した日付型カラムで

$touroku_date->format('Y/m/d')

のようなformat メソッドを使用すると
以下のようなエラーとなります

Call to a member function format() on string 

このエラーを出さないようにするにはモデルファイルに登録します

app/モデル.php

    // dates(formatメソッドを使用できるようにする)
    protected $dates = [
        'created_at',
        'updated_at',
        'touroku_date' // 追加する
    ];
No.1364
11/27 14:58

edit

Laravelで指定したIPアドレスからしかアクセスできないように制限をかける

● Laravelで指定したIPアドレスからしかアクセスできないように制限をかける

https://goo.gl/mzAAiv

こちらの方法がとてもよかったので引用させていただきます。
変更点としては アクセスを許可するIP を .env ファイルに記述しています(後から見返したときに見通しをよくするため)

1. ミドルウェア(IpLimit.php)を作成する

app/Http/Middleware/IpLimit.php


<?php

/**
 * IpLimit.php
 *
 * クライアントのリアルIPがホワイトリストに存在するかチェックするためのミドルウェア
 *
 * @version  0.2		[fix] (int)に正しく型キャストするよう修正
 *
 */

namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Log;

class IpLimit {

	/**
	 * Handle an incoming request.
	 * @param  \Illuminate\Http\Request  $request
	 * @param  \Closure  $next
	 * @return mixed
	 */
	public function handle($request, Closure $next) {
		$config = \Config::get('ip_limit');
		if ($config['enable'] !== true) {
			return $next($request);
		}
		if ($config['isProxy'] === true) {
			$request->setTrustedProxies([$request->ip()]);
		}
		if ($this->isAllow($request->ip(), $config['allowIps']) === false) {
			$error_message = 'cannot access from : ' . $request->ip();
			Log::debug($error_message);
			abort(404, $error_message);
		}
		return $next($request);
	}

	private function isAllow(string $remoteIp, array $accepts) {
		foreach ($accepts as $accept) {
			if ($this->isIn($remoteIp, $accept)) {
				return true;
			}
		}
		return false;
	}

	private function isIn(string $remoteIp, string $accept) {
		if (strpos($accept, '/') === false) {
			return ($remoteIp === $accept);
		}
		list($acceptIp, $mask) = explode('/', $accept);
		$acceptLong = ip2long($acceptIp) >> (32 - (int) $mask);
		$remoteLong = ip2long($remoteIp) >> (32 - (int) $mask);
		return ($acceptLong == $remoteLong);
	}

}

2. Kernel に登録する

app/Http/Kernel.php に以下を追加

    protected $routeMiddleware = [
        'iplimit' => \App\Http\Middleware\IpLimit::class,    // この行を追加する

3. 設定ファイルを作成する

config/ip_limit.php

<?php
return [
    'enable'   => env('IP_LIMIT_ENABLE', false),
    'isProxy'  => env('IP_LIMIT_PROXY',  false),
    'allowIps' => [
        env('LOCALHOST_IP', '127.0.0.1'),
	    env('IP_LIMIT_ENABLE_ADDRESS_01', false) ,
	    env('IP_LIMIT_ENABLE_ADDRESS_02', false) ,
	    env('IP_LIMIT_ENABLE_ADDRESS_03', false) ,
	    env('IP_LIMIT_ENABLE_ADDRESS_04', false) ,
	    env('IP_LIMIT_ENABLE_ADDRESS_05', false) ,
    ],
];

4. .env にアクセスを許可する IP を記述する

.env

IP_LIMIT_ENABLE=true		
# IP_LIMIT_PROXY: Laravelがバランサー配下に設置されている場合にtrueにすると、Real IPを取得する
IP_LIMIT_PROXY=false
IP_LIMIT_ENABLE_ADDRESS_01=xxx.xxx.xxx.xxx/24
IP_LIMIT_ENABLE_ADDRESS_02=yyy.yyy.yyy.yyy
IP_LIMIT_ENABLE_ADDRESS_03=
IP_LIMIT_ENABLE_ADDRESS_04=
IP_LIMIT_ENABLE_ADDRESS_05=

5. .ルーターにミドルウェアを追加する

routes/web.php

ミドルウェアをかませます

Route::get('/register', 'RegisterController@showRegistrationForm')->name('register');

 ↓

Route::group(['middleware' => 'iplimit'], function () {
    Route::get('/register', 'RegisterController@showRegistrationForm')->name('register');
});

以上です。

No.1362
05/03 13:12

edit

Laravelで独自のエラーページ(404 , 403 , 500)をカスタマイズして作成する

● Laravelで独自のエラーページ(404 , 403 , 500)をカスタマイズして作成する

Laravelの標準のエラーページをカスタマイズするには

/resources/views/errors/404.blade.php にファイルを置くだけです。

1. ディレクトリ errors を作成する

2. ファイルを作成する

ファイル名は

403.blade.php
404.blade.php
500.blade.php

とすると、404エラーの時は 「404.blade.php」を見に行きます。

● Laravelでエラーページ(404 , 403 , 500)に独自メッセージを表示させる

エラー発生時にエラーメッセージを追加する

abort( 404, '独自のエラーメッセージ' );

Bladeテンプレートでエラーメッセージを表示

{{ $exception->getMessage() }}

これだけで、エラーページにメッセージが表示されます。

● Laravelの独自のエラーページをデフォルトのエラーページと同じようなデザインにする

デフォルトのデザイン ↑ にしたい場合は次のようなコードにします

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Page Not Found</title>
    <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet" type="text/css">
    <style>
    html,
    body {
        background-color: #fff;
        color: #636b6f;
        font-family: 'Nunito', sans-serif;
        font-weight: 100;
        height: 100vh;
        margin: 0;
    }

    .full-height {
        height: 100vh;
    }

    .flex-center {
        align-items: center;
        display: flex;
        justify-content: center;
    }

    .position-ref {
        position: relative;
    }

    .content {
        text-align: center;
    }

    .title {
        font-size: 36px;
        padding: 20px;
    }
    </style>
</head>

<body>
    <div class="flex-center position-ref full-height">
        <div class="content">
            <div class="title">
                Sorry, the page you are looking for could not be found.
            </div>
        </div>
    </div>
</body>
</html>

● エラーページにエラーメッセージを表示させてデバッグしやすくする

以下のようにすると .envAPP_DEBUG=1 の時だけエラーメッセージを表示させることができます。

            @if(env('APP_DEBUG') == 1)
                {{ $exception->getMessage() }}
            @endif

例:
Laravelエラーページにエラーメッセージを表示させる

添付ファイル1
添付ファイル2
No.1361
12/20 22:33

edit

添付ファイル

Laravel のデバッグを楽にする laravel-debugbar を使用する

Laravel のデバッグパッケージといえば laravel/telescope とlaravel-debugbar の2つが有名ですが、ここでは laravel-debugbar の使い方を紹介いたします。

● laravel-debugbarのインストール

composer require barryvdh/laravel-debugbar

● laravel-debugbarのインストール( Laravel 5 〜 Laravel 5.4 を使っている場合)

composer require barryvdh/laravel-debugbar:~2.4

● 使い方

.env の設定が以下になっていることを確認します。

APP_DEBUG=true

● laravel-debugbar の起動方法

Google Chrome で Laravelアプリを起動すると、

  1. 左下に Laravelの赤いアイコンが表示されていますのでそれをクリックします。
  2. 画面したの一番右から2番目のアイコンをクリックするとウィンドウ幅が上に大きくなって表示されます。

● laravel-debugbar の debug() メソッド

laravel-debugbar を インストールすると debug() メソッドが使用できるようになります。
これは dump() メソッドの出力を laravel-debugbarのウィンドウ内に表示するものです。

dump('test);        // 通常のダンプ
 ↓
debug('test);        // debug-bar に表示させるダンプ 

● (APP_DEBUG=true)にしたままlaravel-debugbarを無効にする

次のように設定すると laravel-debugbarのみ無効 にできます

APP_DEBUG=true
DEBUGBAR_ENABLED=false # laravel-debugbarを無効

● laravel-debugbar を一時的にオフにする

laravel-debugbar は 実行するSQL文が多いと重くなるので、ページごとに オンオフを切り替えたい時があります。
次のように オン/オフ します。

\Debugbar::enable();
\Debugbar::disable();
No.1360
08/12 10:45

edit

LaravelでFactoryとFakerとSeederを使ってダミーデータを作成する

● LaravelでFactoryとFakerとSeederを使ってダミーデータを作成する

PHPのFakerです。Faker Senpai ではないです。
Laravelだと標準でFakerがインストールされ、とても簡単に扱えるのでデータを作成する際には是非利用しましょう。
(Laravelアプリのインストール、モデルファイルはすでに用意してある前提で進めます。 )

Factoryを日本語で使用する

config/app.php の一番下に以下を追加

'faker_locale' => 'ja_JP',

先ずはダミーデータがどのようなデータになるか確認する

routes/web.php に以下を追加

Route::get('/faker', function () {
	$faker = Faker\Factory::create('ja_JP');
	$dummyData = [
		'name'                     => $faker->name,
		'password'                 => $faker->password,
		'country'                  => $faker->country,
		'prefecture'               => $faker->prefecture,
		'city'                     => $faker->city,
		'postcode'                 => $faker->postcode,
		'address'                  => $faker->address,
		'streetAddress'            => $faker->streetAddress,
		'phoneNumber'              => $faker->phoneNumber,
		'email'                    => $faker->email,
		'safeEmail'                => $faker->safeEmail, // (実在しないアドレスのため処理とかで使っても安心)
		'company'                  => $faker->company,
		'iso8601'                  => $faker->iso8601($max = 'now'),
		'dateTimeBetween'          => $faker->dateTimeBetween($startDate = '-110 years', $endDate = 'now')->format('Y年m月d日'),
		'numberBetween'            => $faker->numberBetween($min = 100, $max = 200),
		'title'                    => $faker->title,
		'realText'                 => $faker->realText($maxNbChars = 50, $indexSize = 2),
		'randomNumber'             => $faker->randomNumber($nbDigits = NULL),
		'randomFloat'              => $faker->randomFloat($nbMaxDecimals = NULL, $min = 0, $max = NULL),
		'randomElement'            => $faker->randomElement($array = ['男性', '女性']),
		'lexify'                   => $faker->lexify($string = '??????'),
		'hexcolor'                 => $faker->hexcolor,
		'ipv4'                     => $faker->ipv4,
		'url'                      => $faker->url,
		'imageUrl'                 => $faker->imageUrl($width = 640, $height = 480, $category = 'cats', $randomize = true, $word = null),
		'userAgent'                => $faker->userAgent,
		'creditCardType'           => $faker->creditCardType,
		'creditCardNumber'         => $faker->creditCardNumber,
		'creditCardExpirationDate' => $faker->creditCardExpirationDate,
		'isbn13'                   => $faker->isbn13,
		'isbn10'                   => $faker->isbn10,
	];
	dump($dummyData);
	exit();
});

http://YOUR-APP.TLD/faker にアクセスして表示させます。 次のようなダミーデータが表示されます。

array:31 [▼
  "name" => "浜田 舞"
  "password" => "sPz?uT[rr"
  "country" => "ドミニカ国"
  "prefecture" => "埼玉県"
  "city" => "廣川市"
  "postcode" => "9926575"
  "address" => "1202087  大阪府加藤市西区原田町廣川1-8-9"
  "streetAddress" => "若松町山岸5-1-2"
  "phoneNumber" => "05-4265-9978"
  "email" => "mitsuru67@gmail.com"
  "safeEmail" => "chiyo.kanou@example.net"
  "company" => "株式会社 喜嶋"
  "iso8601" => "1984-04-25T21:15:23+0000"
  "dateTimeBetween" => "1974年08月07日"
  "numberBetween" => 125
  "title" => "Dr."
  "realText" => "るしていただおじぎを捕とりと歴史れきしになって、と思ってすうりんどんどん流ながら上着うわぎのりを川。"
  "randomNumber" => 55
  "randomFloat" => 6539745.6
  "randomElement" => "男性"
  "lexify" => "znkbep"
  "hexcolor" => "#fb573b"
  "ipv4" => "136.204.203.254"
  "url" => "http://wakamatsu.jp/delectus-aspernatur-unde-quae-explicabo-aut-nisi"
  "imageUrl" => "https://lorempixel.com/640/480/cats/?97142"
  "userAgent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2) AppleWebKit/5330 (KHTML, like Gecko) Chrome/37.0.841.0 Mobile Safari/5330"
  "creditCardType" => "Visa"
  "creditCardNumber" => "4485419150999"
  "creditCardExpirationDate" => DateTime @1634115758 {#207 ▼
    date: 2021-10-13 09:02:38.0 UTC (+00:00)
  }
  "isbn13" => "9793648060130"
  "isbn10" => "7424451421"
]

引用: https://goo.gl/VmSXqV

artisanコマンドから Factory を作成する

モデル「Client.php (DBテーブル名:client)」に対する「ClientFactory」を作成します。

php artisan make:factory ClientFactory

完了すると database/factories/ClientFactory.php が作成されています

デフォルトでは

$factory->define(Model::class, function (Faker $faker) {
    return [
        //
    ];
});

となっているのでここに設定を記述して行きます。

    return [
		'client_name'    =>  $faker->name ,
		'addr_name'      =>  $faker->address,
    ];

これでOKです。

Seederファイルを作成する

以下の内容で database/seeds/ClientsSeeder.php を作成する

<?php

use Illuminate\Database\Seeder;

class ClientsSeeder extends Seeder {

    public function run()
    {
    	// 10件作成
      factory(App\Client::class, 10)->create();
    }

}

シーダー実行ファイルに記述してあげます

database/seeds/DatabaseSeeder.php

    public function run()
    {
        $this->call(ClientsSeeder::class);
    }

artisanからシーダーを実行する

まずキャッシュを削除する

php artisan cache:clear; php artisan config:clear; php artisan route:clear; php artisan view:clear; composer dump-autoload

データを全て作り直し、シーダーを実行します

php artisan migrate:fresh --seed
No.1359
11/13 16:09

edit

LaravelのBladeテンプレートでルーターのプレフィックスを使う

● LaravelのBladeテンプレートでルーターのプレフィックスを使う

ルーターで

Route::group(['prefix' => 'admin'], function () {

のように、プレフィクスをつけている場合に Bladeでその値を取得する方法。

・Bladeでプレフィクスを取得する

    @php
        $prefix = Request::route()->getPrefix()
    @endphp

としておいてから

{{URL::to($prefix.'/articles/search')}}

このようにも書けます

{{ url("$prefix/articles/search") }}

http://YOUR-SITE.TLD/admin/articles/search

もちろん、わざわざこんなことをせずに素直に

{{ route('articles.search') }}

と書くのがいいです。

No.1357
11/10 11:04

edit

Laravelのメッセージを日本語化する

https://github.com/caouecs/Laravel-lang/tree/master/src/ja

1. 多言語リソースファイルをダウンロードする

https://github.com/caouecs/Laravel-lang

2. /resources/lang/に「ja」 ディレクトリをアップロードする。

3. config/app.php の設定を変更する

    'locale' => 'en',

  ↓

    'locale' => 'ja',

4. timezone も合わせて変更しておく

'timezone' => 'UTC',

 ↓

'timezone' => 'Asia/Tokyo',

以上です。

No.1356
03/12 15:22

edit

Laravelでエラーログをファイルに保存しつつメールで送信する

● Laravelでエラーログをファイルに保存しつつメールで送信する

ログにはレベルがあります。( PSR-3 )
PSR-3: Logger Interface: https://www.php-fig.org/psr/psr-3/

(危険な順)

8. EMERGENCY
7. ALERT
6. CRITICAL
5. ERROR
4. WARNING
3. NOTICE
2. INFO
1. DEBUG

このログレベルを利用して

・ログレベルが ERROR 以上の時はログに保存しつつメールで送信
・ログレベルが WARNING 以下の時はログに保存

という運用ができるように設定してみます。

コントローラーのコンストラクタに以下を記述

protected $monolog;
public function __construct()
{
    // umask。適宜書き換えてください。
    umask(0000);

	$this->monolog = Log::getLogger();	// laravel 5.6以降

	// 1. monolog - mail
	$transport = new \Swift_SendmailTransport('/usr/sbin/sendmail -t');
	$mailer    = new \Swift_Mailer($transport);
	$message   = new \Swift_Message('monolog ERROR');
	$message->setFrom('メールアドレス');
	$message->setTo('メールアドレス');
	$this->monolog->pushHandler(new \Monolog\Handler\SwiftMailerHandler($mailer, $message, \Monolog\Logger::ERROR, false));

	// 2. monolog - file - rotation
	$formatter = new \Monolog\Formatter\LineFormatter(null, null, true);
	$handler = new \Monolog\Handler\RotatingFileHandler(storage_path('logs').DIRECTORY_SEPARATOR.'error.log', 10, \Monolog\Logger::ERROR );
	$handler->setFormatter($formatter);
	$this->monolog->pushHandler($handler);
}

次のメソッドでログに記録します。

ログファイルに記録

$this->monolog->debug('1. debug');
$this->monolog->info('2. info');
$this->monolog->notice('3. notice');
$this->monolog->warning('4. warning');

ログファイルに記録(ファイル名と行番号)

$this->monolog->info('ログメッセージ', ['file' => basename(__FILE__), 'line' => __LINE__]); // ファイル名(フルパス)
$this->monolog->info('ログメッセージ', ['file' => basename(__FILE__), 'line' => __LINE__]); // ファイル名のみ

ログファイルに記録 + メール送信

$this->monolog->error('5. error');
$this->monolog->critical('6. critical');
$this->monolog->alert('7. alert');
$this->monolog->emergency('8. emergency');
No.1355
03/27 10:59

edit

Laravelでログを出力する

● Laravelでログを出力する

cron実行時などは手動でログを出力して保存しておくと後からのデバッグが楽になります

use Log;
// $monolog = Log::getMonolog(); // Laravel 5.5以前
$monolog = Log::getLogger();	// laravel 5.6以降

ログの出力(下に行くほど深刻)

// DEBUG
$monolog->debug($message, $context);

// INFO
$monolog->info($message, $context);

// NOTICE
$monolog->notice($message, $context);

// WARNING
$monolog->warning($message, $context);

// ERROR
$monolog->error($message, $context);

// CRITICAL
$monolog->critical($message, $context);

// ALERT
$monolog->alert($message, $context);

// EMERGENCY
$monolog->emergency($message, $context);

● Laravelのログにファイル名やメソッド名を自動的に追加する

引用: https://goo.gl/NtbtSa

use Log;
$monolog = Log::getLogger();
$ip = new \Monolog\Processor\IntrospectionProcessor(
    \Monolog\Logger::DEBUG,
    [
        'Monolog\\',
        'Illuminate\\',
    ]
);
$monolog->pushProcessor($ip);

このようなログになります

[2018-11-09 01:52:35] local.WARNING: テーブルからデータを取得できません  {"file":"/home/app/Http/Controllers/TestController.php","line":231,"class":"App\\Http\\Controllers\\TestController","function":"postarticle"}

とても便利なので是非利用しましょう。

● ログの時刻がおかしい時の修正方法

config/app.php を以下のように変更します

    'timezone' => 'Asia/Tokyo',
No.1354
11/09 11:04

edit

Laravelの命名規約(または命名法則)

● Laravel命名規約

LaravelのコーディングスタイルはPSR-2に準拠。

PSR-2 スタイルの特徴

    PSR-1のコーディング規約には従わなければなりません。
    インデントには4つのスペースを利用しなければなりません。タブは使用してはいけません。
    1行の長さに制限はありませんが、120文字以下が望ましいです。できれば80文字以下にして下さい。
    クラス・メソッドの波括弧の前には改行を入れなければなりません。
    メソッドやプロパティの定義は最初にabstract/final、次にpublic/protected/private、最後にstaticを書かなければなりません。
    制御構文開始の波括弧の前には改行を入れません。
    制御構文の(の後、)の前にはスペースを入れません。

引用 : https://goo.gl/Fchriz

単数形複数形には注意する事。

http://www.infiniteloop.co.jp/docs/psr/psr-2-coding-style-guide.html

種類 単数 or 複数 ケース
モデル
(ファイル名)
単数形 パスカルケース(先頭大文字) Post.php
MsCountry.php
テーブル名 複数形 スネークケース(小文字) posts
ms_countries
コントローラ
(ファイル名)
どちらもOK パスカルケース(先頭大文字) PostController.php
MsCountryController.php
クラス どちらもOK パスカルケース(先頭大文字) PostController
MsCountryController
メソッド --- キャメルケース(先頭小文字) public function searchUser()
変数 --- スネークケース(小文字) $user_name

● Laravel DB命名規約

名前が決まっているカラム

カラム名 何を表すか?
id 主キー
created_at 登録日時
updated_at 更新日時
No.1353
12/05 11:56

edit

Laravelでフォーム送信時の先頭と最後のスペースや改行の自動削除を停止する

● Laravelでフォーム送信時の先頭と最後のスペースや改行の自動削除を停止する

Laravelではフォーム送信時に先頭と最後のスペース(改行も。)は自動削除されます。
これを停止するには Http/Kernel.php の 次の行をコメントアウトします。

protected $middleware = [
    \App\Http\Middleware\CheckForMaintenanceMode::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    // \App\Http\Middleware\TrimStrings::class, // この行をコメントアウトする
No.1352
11/08 22:03

edit

Laravel + nginx をサブディレクトリで動作させる

● Laravel + nginx で動作しているアプリをサブディレクトリで動作させる

例: /my_app/ で Laravelアプリを動作させる

/etc/nginx/conf.d/YOUR-SITE.conf

	location /my_app/ {
		try_files $1 /my_app/index.php?$query_string;
	}

nginx -s reload で nginx をリスタートすればOKです。

my_app に シンボリックリンクを貼ってください。

● kusanagi を使用している場合

KUSANAGIを使っている場合は設定ファイルが2つに分かれている事があります YOUR-SITE_http.conf , YOUR-SITE_ssl.conf の2ファイルを編集しましょう

参考: https://goo.gl/fcmdT4

● うまくいかないときは Laravel 公式の 設定ファイルをチェックする

こちらに公式の設定ファイルがあるので、手元の設定ファイルと比較して揃えておきましょう https://laravel.com/docs/5.8/deployment#nginx

No.1349
03/15 18:22

edit

Laravelで admin / user のMulti-Auth を素早く作成する

管理者側テーブル「admin」を利用した認証とユーザー側テーブル「users」を利用した認証を作成する
「素早く」がテーマなので composer パッケージを利用します。
Laravel 5.6 でのやり方です。

「Laravelアプリの作成」「DB接続設定」は設定完了しているものとします。

● Hesto/multi-auth

https://github.com/Hesto/multi-auth

・パッケージのインストール

composer require hesto/multi-auth

・認証ファイルのインストール(小文字、単数形で命名します)

php artisan multi-auth:install admin -f
php artisan multi-auth:install user -f

・管理者アカウントをシーダーに登録する

database/seeds/DatabaseSeeder.php

    public function run()
    {
        // この行を追加 ↓
        $this->call(AdminsSeeder::class);
    }

database/seeds/DatabaseSeeder.php

<?php
use Illuminate\Database\Seeder;
class AdminsSeeder extends Seeder {
    public function run()
    {
        DB::table("admins")->insert([
            'name'                => 'YOUR-NAME' ,
            'email'               => 'YOUR-EMAIL ,
            'password'            => Hash::make('YOUR-PASSWORD') ,
        ]);
    }
}

・DBの作成

php artisan migrate

以上です。

・早速使う

管理者ログイン

http://YOUR-SITE.TLD/admin/login

ユーザーログイン

http://YOUR-SITE.TLD/user/login

・Bladeでの認証記述方法

Bladeテンプレートで adminまたはuserでログインしているかどうかを判別する

@if ( Auth::guard('admin')->check() )
<h1>adminとしてログイン済みです</h1>
@endif
@if ( Auth::guest() )
<h1>管理者ログイン前のguestです</h1>
@endif

・Bladeテンプレートでログイン後のユーザー名を表示する

user の場合

{{ Auth::guard('user')->user()->name }}

admin の場合

{{ Auth::guard('user')->admin()->name }}

・コントローラでログイン後のユーザー名を表示する

dump( \Illuminate\Support\Facades\Auth::guard('user')->user()->name );

・コントローラでユーザーを強制ログアウトさせる

// 強制ログアウト
Auth::guard('user')->logout();

● コントローラで認証チェックを使用する

app/Http/Kernel.php には以下のような記述が増えています

    protected $routeMiddleware = [
        'user' => \App\Http\Middleware\RedirectIfNotUser::class,
        'user.guest' => \App\Http\Middleware\RedirectIfUser::class,
        'admin' => \App\Http\Middleware\RedirectIfNotAdmin::class,
        'admin.guest' => \App\Http\Middleware\RedirectIfAdmin::class,
........

なのでこれを使用しましょう。

コントローラのコンストラクタに以下のように記述します

	function __construct(){
		// admin ログイン認証
		$this->middleware('admin');
	}

● ルーターで認証チェックを使用する

routes/web.php に次のように 'middleware' => 'admin' を追加します

// admin ログインが必要なページ
Route::group(['prefix' => 'admin', 'middleware' => 'admin'], function () {
            Route::get("articles/index", "ArticleController@index")->name("articles.index");
});

● 管理者、ユーザー毎にログアウトした時のリダイレクト先を設定する

ログアウトした時のリダイレクト先はコントローラーで設定します
管理者用、ユーザー用のAuthコントローラーは
/app/Http/Controllers/AdminAuth/LoginController.php
/app/Http/Controllers/UserAuth/LoginController.php
にあるので、ここに記述します。
vendor/hesto/multi-auth/src/Traits/LogsoutGuard.php のトレイトをオーバーライドします )

    /**
     * 
     * ログアウト後のリダイレクト先を「/admin/login」に設定する
     *
     */
    public function logoutToPath() {
        return '/admin/login';
    }

● /user/home , /admin/home など homeアクションの動作をカスタマイズする

デフォルトでは routes/user.php

Route::get('/home', function () {
    $users[] = Auth::user();
    $users[] = Auth::guard()->user();
    $users[] = Auth::guard('admin')->user();
    return view('admin.home');
})->name('home');

という風にクロージャで /user/home へのルーティングが記述されています。 これらをコメントアウトで消してしまってroutes/web.php に記述していくと見通しがいいと思います。

● パスワードリマインダーのメールテキストを日本語に変更する(方法1)

・1. 独自のテンプレートを使用するように変更する

app/Notifications/UserResetPassword.php を以下のように変更

        return (new MailMessage)
            ->line('You are receiving this email because we received a password reset request for your account.')
            ->action('Reset Password', url('user/password/reset', $this->token))
            ->line('If you did not request a password reset, no further action is required.');

↓ テンプレート (resources/views/email/password_reset.blade.php) を使ってメール送信するように変更する

        return (new MailMessage)
            ->from($email_address, $email_name)
            ->view( 'email.password_reset' , [
                    'shop'      => $shop ,
                    'reset_url' => url('user/password/reset', [$shop->id, $this->token]) ,
            ]);

メール送信者はデフォルトで .env でしたいしたアドレスになるので、明示的に変更したい場合は ->from() メソッドで書き換えます 独自のパタメーターは配列で渡します。( 上の例では $shop を渡している)
'reset_url は適宜書き換えてください。

テンプレート例 (resources/views/email/password_reset.blade.php に保存)

<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
    <body>
        <style>
        body{
            font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';
            box-sizing:border-box;
        }
        </style>

        <div style="background-color:#f8fafc;color:#74787e;height:100%;line-height:1.4;margin:0;width:100%!important;word-break:break-word">
        <table width="100%" cellpadding="0" cellspacing="0" style="background-color:#f8fafc;margin:0;padding:0;width:100%">
        <tbody>
        <tr>
        <td align="center">
        <table width="100%" cellpadding="0" cellspacing="0" style="margin:0;padding:0;width:100%">
        <tbody>
        <tr>
        <td style="padding:25px 0;text-align:center">
        <a href="{{ url('/user/login', $shop->id) }}" style="color:#bbbfc3;font-size:19px;font-weight:bold;text-decoration:none" target="_blank" >
        {{ $shop->name }}
        </a>
        </td>
        </tr>
        <tr>
        <td width="100%" cellpadding="0" cellspacing="0" style="background-color:#ffffff;border-bottom:1px solid #edeff2;border-top:1px solid #edeff2;margin:0;padding:0;width:100%">
        <table align="center" width="570" cellpadding="0" cellspacing="0" style="background-color:#ffffff;margin:0 auto;padding:0;width:570px">
        <tbody>
        <tr>
        <td style="padding:35px">
        <p style="color:#3d4852;font-size:16px;line-height:1.5em;margin-top:0;text-align:left">「パスワード再設定」<wbr>ボタンを押してパスワードを再設定してください。</p>
        <table align="center" width="100%" cellpadding="0" cellspacing="0" style="margin:30px auto;padding:0;text-align:center;width:100%">
        <tbody>
        <tr>
        <td align="center">
        <table width="100%" border="0" cellpadding="0" cellspacing="0">
        <tbody>
        <tr>
        <td align="center">
        <table border="0" cellpadding="0" cellspacing="0">
        <tbody>
        <tr>
        <td>
        <a href="{{ $reset_url }}" style="border-radius:3px;color:#fff;display:inline-block;text-decoration:none;background-color:#3490dc;border-top:10px solid #3490dc;border-right:18px solid #3490dc;border-bottom:10px solid #3490dc;border-left:18px solid #3490dc" target="_blank" >パスワード再設定</a>
        </td>
        </tr>
        </tbody>
        </table>
        </td>
        </tr>
        </tbody>
        </table>
        </td>
        </tr>
        </tbody>
        </table>
        <p style="color:#3d4852;font-size:16px;line-height:1.5em;margin-top:0;text-align:left">もしこのメッセージに心当たりがない場合は破棄してください。</p>
        <table width="100%" cellpadding="0" cellspacing="0" style="border-top:1px solid #edeff2;margin-top:25px;padding-top:25px">
            <tbody>
                <tr>
                    <td>
                        <p style="color:#3d4852;line-height:1.5em;margin-top:0;text-align:left;font-size:12px">もし上の "パスワード再設定" ボタンを押してもうまく動作しない時はこちらのURLをブラウザ<wbr>に貼り付けてアクセスしてください。
                            <a href="{{ $reset_url }}" style="color:#3869d4" target="_blank">
                                {{ $reset_url }}
                            </a>
                        </p>
                    </td>
                </tr>
            </tbody>
        </table>
        </td>
        </tr>
        </tbody>
        </table>
        </td>
        </tr>
        <tr>
        <td>
        <table align="center" width="570" cellpadding="0" cellspacing="0" style="margin:0 auto;padding:0;text-align:center;width:570px">
            <tbody>
                <tr>
                    <td align="center" style="padding:35px">
                        copyright (c)2019 YOUR-SITE.COM
                    </td>
                </tr>
            </tbody>
        </table>
        </td>
        </tr>
        </tbody>
        </table>
        </td>
        </tr>
        </tbody>
        </table>
        </div>
    </body>
</html>


● パスワードリマインダーのメールテキストを日本語に変更する(方法2)

・1. モデルファイルにパスワードリマインダーのメソッドをオーバーライドする

モデルが User の場合は /app/User.php に以下を追加

    /**
     * パスワード再設定メールの送信
     *
     * @param  string  $token
     * @return void
     */
    public function sendPasswordResetNotification($token)
    {
        $this->notify( new \App\Notifications\UserResetPassword($token) );
    }

・2. メッセージを日本語化する

app/Notifications/UserResetPassword.php を以下のように変更

            // OFF  ->line('You are receiving this email because we received a password reset request for your account.')
            // OFF  ->action('Reset Password', url('user/password/reset', $this->token))
            // OFF  ->line('If you did not request a password reset, no further action is required.');
            ->line('「パスワード再設定」ボタンを押してパスワードを再設定してください。')
            ->action('パスワード再設定', url('user/password/reset', $this->token))
            ->line('もしこのメッセージに心当たりがない場合は破棄してください。');

・3. htmlメールのヘッダフッタを日本語に変更する

php artisan vendor:publish --tag=laravel-mail
php artisan vendor:publish --tag=laravel-notifications

コマンドを実行すると

resources/views/vendor/mail/(複数のテンプレートファイル)
resources/views/vendor/notifications/email.blade.php

ファイルが自動生成されます。 変更する箇所は次の画像の通りです。

↓ すべて日本語化すると次のようになります

● ログインせずにログイン認証が必要なページを表示させようとした時のリダイレクト先を変更する

app/Http/Middleware/RedirectIfNotUser.php

	public function handle($request, Closure $next, $guard = 'user')
	{
	    if (!Auth::guard($guard)->check()) {
	        return redirect('user/login');  // ここを書き換えます
	    }
添付ファイル1
添付ファイル2
添付ファイル3
No.1348
06/21 15:31

edit

添付ファイル

LaravelのValidatorで独自のチェックを行った後独自のエラーメッセージを表示させる

● LaravelのValidatorで独自のチェックを行った後独自のエラーメッセージを表示させる

Laravelでフォーム入力値のバリデーションを行った後、独自のチェックを行って、エラーが発生した場合 エラーメッセージと共に入力画面へ戻したい。といったことがあるかと思います。

次のようにして好きなメッセージでエラーメッセージを設定できます。

use Validator;
// 通常のバリデーション
$validator = Validator::make($request->all(), [
	'feed_url'  => 'required',
]);
$validator->validate();

// 追加で入力チェックを行う
if ( エラーがある場合 ) {
$validator->errors()->add('feed_url', 'このURLにはRSSフィードが含まれていません。');
return back()->withInput()->withErrors($validator);
}

エラーメッセージのセット方法は次のように記述してもOKです。

return back()->withInput()->withErrors(array('feed_url' => 'このURLにはRSSフィードが含まれていません。'));
No.1345
11/10 09:55

edit

LaravelでRSSフィードを読み込む

● awjudd/feed-reader

ざっと見たところ、「simplepie/simplepie」のLaravel5用ラッパーです。

● awjudd/feed-reader のインストール

composer require awjudd/feed-reader

config/app.php の編集

    'providers' => [
        .....
        Awjudd\FeedReader\FeedReaderServiceProvider::class, // この行を追加
    'aliases' => [
        .....
        'FeedReader' => Awjudd\FeedReader\Facade::class,, // この行を追加

● 設定ファイルの作成

php artisan vendor:publish

(  [1 ] Provider: Awjudd\FeedReader\FeedReaderServiceProvider )を選択します。

● Laravelコントローラーから使用する

use Awjudd\FeedReader\Facade as FeedReader;
$feed = FeedReader::read('https://RSS-FEED-SITE-URL');

if ( $feed->error() ) {
    echo $feed->error();
}

foreach ($feed->get_items() as $item) {
    $hash = [];
    $hash['site_title'] = $item->get_feed()->get_title();
    $hash['title'] = trim($item->get_title());
    $hash['permalink'] = trim($item->get_permalink());
    $hash['link'] = trim($item->get_link());
    $hash['date'] = $item->get_date('Y-m-d H:i:s');
    $hash['content'] = $item->get_content();
    dump($hash);
}

中身は「simplepie/simplepie」なので下記を参照してください。

https://github.com/simplepie/simplepie
https://goo.gl/ma6j9T

No.1344
11/08 17:43

edit

Laravelでsqliteを使用する / sqliteデータベースファイルを指定する

● Laravelでsqliteを使用する

Laravelでデータベース sqlite を使用します。データベースファイルは database/database.sqlite になります。

1. .env にsqlite設定を記述

mysqlの設定を # でコメントアウトして、sqlite設定を記述します。

# DB_CONNECTION=mysql
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=homestead
# DB_USERNAME=homestead
# DB_PASSWORD=secret

DB_CONNECTION=sqlite

2. 中身がからのデータベースファイルを作成する

touch database/database.sqlite

3. マイグレーション実行

php artisan migrate

以上です。簡単ですね。

● Laravelでデータベースファイルを指定して sqlite を使用する

.envフルパスでDBファイルを指定します。

例: /PATH/TO/YOUR/APP/database/production.sqliteを指定する

DB_DATABASE=/PATH/TO/YOUR/APP/database/production.sqlite 
No.1342
11/07 13:35

edit

Laravelで最速でソースコードを色づけしながらMarkdownを使用する

● Laravelで最速でソースコードを色づけしながらMarkdownを使用する「gitdown」

● gitdown

https://github.com/calebporzio/gitdown

1. gitdown のインストール

composer require calebporzio/gitdown

2. Bladeの記述を変更する

{{ $memo->text_name }}

 ↓

{!! GitDown::parseAndCache($memo->text_name) !!}

これだけでマークダウンでパースされます。

3. ソースコードに色づけする

@gitdown

以上です。最速。

● laravelで markdown をライトに使用する「laravel-markdown」

1. laravel-markdown のインストール

composer require andreasindal/laravel-markdown

2. Bladeの記述を変更する

{{ $memo->text_name }}

 ↓

@markdown($memo->text_name)

これだけでマークダウンでパースされます。

No.1341
03/12 16:59

edit

Laravelで指定したGETデータ(またはPOSTデータ)を取得する

● Laravelで指定したGETデータ(またはPOSTデータ)を取得する

Laravelで httpの全てのGETデータやPOSTデータは

$request->all();

で取得しますが、この時、取得したい項目を指定することができます。

「user_name」「email_name」を取得

$request->all(['user_name','email_name']);

なので、EloquentモデルでデータのUPDATEを行う時

$user->fill($request->all())->save();

 ↓

$user->fill( $request->all(['user_name','email_name']) )->save();

と書くことができます。 便利ですね。

No.1338
10/31 18:30

edit

LaravelのモデルにDBに存在しない独自のカラム(プロパティ)を追加する

● LaravelのモデルにDBに存在しない独自のカラム(プロパティ)を追加する

例としてあるモデル(User)に独自カラム「_editable_flag」を値「normal」で追加する。

app/User.php に以下の記述を追加する

    // 独自カラム
    // protected $appends = array('editable_flag');
    protected $appends = array('_editable_flag'); // このようにアンダースコア始まりのカラムも作成できます。(メソッド名は変更せずでOK)

    // 独自カラムのアクセサ
    public function getEditableFlagAttribute()
    {
        return 'normal';
    }

No.1337
10/31 13:35

edit

LaravelのBladeビューでテンプレートファイル名を表示させる

デバッグ時にどのBladeビューファイルが使用されているかを確認したい時があります。 そんな時は

● LaravelのBladeビューでテンプレートファイル名を変数に代入する( .env の APP_DEBUG=true の時のみ )

それぞれのテンプレートファイル名に配置

@if(env('APP_DEBUG') == 1)
    @php($template_filename = 'show.blade.php')
    @php($compiled_template_filename = __FILE__)
@endif

( show.blade.php はファイルごとに適宜書き換えてください。 )

● LaravelのBladeビューで変数を表示する( .env の APP_DEBUG=true の時のみ )

@if(env('APP_DEBUG') == 1)
<!-- {{$template_filename or '' }} -->
<!-- {{$compiled_template_filename or '' }} -->
@endif

レイアウトファイルに記述しておきます。

No.1336
10/31 09:30

edit

Laravelのログをローテーションさせる

● Laravelのログをローテーションさせる

Laravelのログはデフォルトでは1つのファイルに追記を繰り返していきます。
ローテーションさせましょう。

.envファイルのデフォルト値「stack」を「daily」に変更します。

.env

LOG_CHANNEL=stack

 ↓

LOG_CHANNEL=daily

これだけでローテーションできるようになります。

その他以下のような設定が可能です。

名前 説明
stack 「マルチチャンネル」チャンネルを作成するためのラッパー機能
single シングルファイル/パスベースのロガーチャンネル(StreamHandler
daily RotatingFileHandlerベースの毎日ファイルを切り替えるMonologドライバ
slack SlackWebhookHandlerベースのMonologドライバ
syslog SyslogHandlerベースのMonologドライバ
errorlog ErrorLogHandlerベースのMonologドライバ
monolog サポートしているMonologハンドラをどれでも使用できる、Monologファクトリドライバ
custom チャンネルを生成するため、指定したファクトリを呼び出すドライバ

monolog を選択して、深刻なエラーの場合はメールなり通知を送信するという運用が実用的かと思われます。

● cronを使っている場合に cron実行ユーザーの権限でログを作成されてしまうので permission denied エラーとなる場合の対処法

/config/logging.php に permission 項目を記述できます。 (Laravel version 5.6.10 以降)

        'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
            'days' => 7,
            'permission' => 0666,
        ],
No.1332
10/30 13:26

edit

LaravelのEloquentに追加したいパッケージ

● Laravelで権限(Role)を管理するパッケージ

● zizaco/entrust(★5919)

https://packagist.org/packages/zizaco/entrust
https://itsolutionstuff.com/post/laravel-52-user-acl-roles-and-permissions-with-middleware-using-entrust-from-scratch-tutorialexample.html

● laravel/socialite(★3507)

https://packagist.org/packages/laravel/socialite

● LaravelのEloquentでタグを管理するパッケージ

● rtconner/laravel-tagging(★679)

https://packagist.org/packages/rtconner/laravel-tagging

● cviebrock/eloquent-taggable(★266)

https://packagist.org/packages/cviebrock/eloquent-taggable

● rinvex/laravel-tags(★11)

https://packagist.org/packages/rinvex/laravel-tags

No.1326
10/27 15:27

edit

LaravelのBladeビューで現在のURLを取得する

● LaravelのBladeビューで現在のURLを取得する

・現在のURLを取得(GETパラメーター( ? 以降の文字列)も取得します。)

{{ request()->fullUrl() }}

例: http://test.server.tld/users/search?q=test

・現在のURLを取得(GETパラメーター( ? 以降の文字列)は取得しません)

{{ url()->current() }}

例: http://test.server.tld/users/search

・現在のURLを相対で取得(GETパラメーター( ? 以降の文字列)も取得します。)

{{ str_replace(url('/'),"",request()->fullUrl()) }}

例: /search?q=test

・リクエストURIの取得

{{ request()->path() }}

例: users/search

・リクエストのURIが指定されたパターンにマッチするか

@if ( request()->is('*users*') )
        マッチします<br>
@endif

・完全なURLを取得(クエリ文字列なし)

{{ request()->url() }}

例: http://test.server.tld/users/search

・リクエストメソッドの取得

{{ request()->method() }}

  ↓

GET

・リクエストメソッドが指定したものにマッチするか

@if( request()->isMethod('get') )
     getメソッドです<br>
@endif

引用: https://goo.gl/tojhBs

No.1325
06/28 16:33

edit

LaravelのBladeテンプレートでcsrfトークン、PUT/PATCH/DELETE メソッドを埋め込む。

● LaravelのBladeテンプレートで擬似的なPUT/PATCH/DELETE メソッドを埋め込む

例: PUT メソッドを埋め込みます

@method('PUT')

● LaravelのBladeテンプレートでcsrfトークンを埋め込む

@csrf

● LaravelのBladeテンプレートでcsrfトークンを手動で埋め込む。

<input type="hidden" name="_token" value="{{ csrf_token() }}"
No.1324
03/19 11:19

edit

LaravelのBladeテンプレートで変数の存在確認を行う

● LaravelのBladeテンプレートで変数の存在確認を行う

LaravelのBladeテンプレートで未定義の変数を使用するとエラーとなります。 事前に isset で 確認しましょう。

@if (isset( $text ))
<p>$test</p>
@endif

変数が未定義の場合に null をセットする

@if ( ! isset($v->flag) )
<?php $v->flag = null; ?>
@endif

または @ をつけて未定義エラーを回避します

@if ( $q['data_id'] )

 ↓

@if ( @$q['data_id'] )

● LaravelのBladeテンプレートで変数が存在しない場合に null (または空文字)を表示させる

変数が存在しない場合に null (または空文字)表示でいいのなら

{{ @$hoge }}
No.1323
04/12 13:28

edit

LaravelのコントローラーでHTTPのGETパラメーターを受け取る

LaravelのコントローラーでHTTPのGETパラメーターを受け取る

1. use Illuminate\Http\Request; の追加

use Illuminate\Http\Request;

2. 使用したいメソッドで $request を受け取る

	public function show($id)
	{

 ↓ Request型の $request をコントローラーのメソッドで受け取るようにします。

	public function show(Request $request, $id)
	{

3. 使う

URL https://YOUR-SERVER.TLD/test/action?file=001 でアクセスする時

echo $request->input('file') ;

次のように出力されます

001
No.1322
12/13 10:36

edit

Laravelのbladeテンプレート内で vue.js を使用する

Laravelのbladeテンプレート、vue.jsのテンプレート、どちらも {{ }} で変数を囲う記法なので、混在するとLaravelでエラーとなります。 そこで対応方法が2つあるようです。

● {{ の 前に @ をつける

    <div>
        {{ message }}
    </div>

 ↓

    <div>
        @{{ message }}
    </div>

● vue.js側のデリミタ {{ }} を (% %) に変更する

こちらの方法がオススメです。

Vue.config.delimiters = ['(%', '%)']; でデリミタを変更して使用します。

var vm = new Vue({
    el: '#myApp',
    data: {
    }
});

  ↓

var vm = new Vue({
    delimiters: ["(%","%)"] ,
    el: '#myApp',
    data: {
    }
});

引用: https://goo.gl/Y7QqBz

No.1321
10/29 09:45

edit

LaravelのBladeテンプレートで現在のアクション(URL, メソッド名)を取得する

● LaravelのBladeテンプレート内現在のコントローラーを取得する

<?php $current_controller_name = explode('.', Route::currentRouteName())[0]; ?>
現在のコントローラー名は {{ $current_controller_name }}

引用: https://goo.gl/9WmwRR

● LaravelのBladeテンプレート内で現在のルーティングを取得する

記法 戻り値(例)
{{ Route::currentRouteName() }} projects.edit

● LaravelのBladeテンプレート内でURLを取得する

記法 戻り値(例)
{{ Request::url() }} https://MY-SERVER.TLD/projects/3/edit
{{ Request::url("/") }} https://MY-SERVER.TLD/projects/3/edit
{{ Request::root() }} https://MY-SERVER.TLD
{{ Request::fullUrl() }} https://MY-SERVER.TLD/projects/3/edit
{{ Request::path() }} projects/3/edit
{{ Request::decodedPath() }} projects/3/edit

● FORMの hidden などで渡す場合は urlencode します。

{{ urlencode(request()->fullUrl()) }}

● LaravelのBladeテンプレート内でパスを取得する

記法 戻り値(例)
{{ url("") }} https://MY-SERVER.TLD
{{ url('/') }} https://MY-SERVER.TLD
{{ app_path() }} /var/www/vhosts/MY-SERVER.TLD/laravel/my_app/app
{{ base_path() }} /var/www/vhosts/MY-SERVER.TLD/laravel/my_app
{{ config_path() }} /var/www/vhosts/MY-SERVER.TLD/laravel/my_app/config
{{ database_path() }} /var/www/vhosts/MY-SERVER.TLD/laravel/my_app/database
{{ storage_path() }} /var/www/vhosts/MY-SERVER.TLD/laravel/my_app/storage
{{ resource_path() }} /var/www/vhosts/MY-SERVER.TLD/laravel/my_app/resources
No.1318
05/28 17:21

edit

LaravelのBladeでドロップダウンリスト<select>を簡単に作成する

laravelcollective/html を使用してドロップダウンリスト( select, option リスト) を簡単に作成します。

● laravelcollective/html のインストール

https://laravelcollective.com/docs/master/html

composer require "laravelcollective/html":"^5.4.0"

● ベタがきでドロップダウンリストを生成する

@php
    $job_name_loop = [
        ''      => '選択してください' ,
        '公務員' => '公務員' ,
        '医師'   => '医師' ,
        '弁護士' => '弁護士' ,
    ];
@endphp
{{ Form::select('job_name', $job_name_loop, old('job_name'), ['class' => 'my_class']) }}

● ドロップダウンリストの配列を取得する

モデルから一覧を取得してきて、それを (key/value)方式に変換します。
コントローラーの好きなところに以下を記述します。

$clients = Client::select('id', 'client_name')->get();

// key,value ペアに直す
$client_id_loop = $clients->pluck('client_name','id');

● LaraelのBladeテンプレートにデータを渡す

return view('projects.create', compact('client_id_loop') );

● Bladeテンプレート内で Form::select を呼び出す

フォーム名「FORM_NAME」  CSSクラス名「my_class」 なドロップダウンリストを生成します。

{{ Form::select('FORM_NAME', $client_id_loop, null, ['class' => 'my_class']) }}

次のようなドロップダウンリストが生成されます

<select class="my_class" name="FORM_NAME">
    <option value="1">テスト1</option>
    <option value="2">テスト2</option>
    <option value="3">テスト3</option>
</select>

● ↑ こんなめんどくさいことをせずに Bladeのビューに1行で記述する

一撃で記述したい場合はこのように記述します。
bladeテンプレート内に記述
3つ目の引数に値を渡すと選択済みになります。null を渡すと最初の項目が選択済みになります

{{ Form::select('FORM_NAME', \App\Client::select('id', 'client_name')->get()->pluck('client_name','id')->prepend( "選択してください", ""), null, ['class' => 'form-control']) }}

● 値をを選択済み(selected)のドロップダウンリストを生成する

3つめの引数に値をセットすると selected になります

{{ Form::select('FORM_NAME', $client_id_loop, 2, ['class' => 'my_class']) }}

 ↓ 次のようなドロップダウンリストが生成されます

<select class="my_class" name="FORM_NAME">
    <option value="1">テスト1</option>
    <option value="2" selected="selected">テスト2</option>
    <option value="3">テスト3</option>
</select>

●ドロップダウンリストに「選択してください」項目を追加する

key が null の値を登録します。

{{ Form::select('FORM_NAME',  [null=>'選択してください']+$client_id_loop, 2, ['class' => 'my_class']) }}

または prepend() メソッドを使って先頭に追加します。
prepend() メソッドを使用するときは 空文字 "" を使用します。( null を渡すと 連想配列から普通の配列になります。)
また 空文字 "" のところに 0 を渡すと、配列のキーが数字の場合 キーが 0,1,2,3,4,5.... という風にリナンバーされてしまうので注意してください。 (複数人数で開発する時は prepend() メソッドは使わずに、 foreach でベタに書くのもいいと思います。)

{{ Form::select('FORM_NAME', \App\Client::select('id', 'client_name')->get()->pluck('client_name','id')->prepend( "選択してください", ""), null, ['class' => 'form-control']) }}

 ↓ 次のようなドロップダウンリストが生成されます

<select class="my_class" name="FORM_NAME">
    <option value="">選択してください</option>
    <option value="1">テスト1</option>
    <option value="2" selected="selected">テスト2</option>
    <option value="3">テスト3</option>
</select>

disabled な値を追加するにはこちら
https://goo.gl/cBJVaM

No.1317
08/12 22:51

edit

Laravelで1対1のリレーションを複数回取得する

Laravelでテーブルが2つ「clients」「users」あって、「clients」テーブル内に登録者IDと更新者IDが格納されている場合に 更新者の名前を取得する方法。

● モデルに1対1 リレーションを設定

app/Client.php

DBカラムの

「clients.created_user_id」と「users.id」と同じデータがあれば取得します。
「clients.updated_user_id」と「users.id」と同じデータがあれば取得します。
    /**
     * 1対1リレーション
     *
     * @return \Illuminate\Database\Eloquent\Relations\hasOne
     */
    public function created_user()
    {
        return $this->hasOne('App\User', 'id', 'created_user_id')->withDefault();
    }


    /**
     * 1対1リレーション
     *
     * @return \Illuminate\Database\Eloquent\Relations\hasOne
     */
    public function updated_user()
    {
        return $this->hasOne('App\User', 'id', 'updated_user_id')->withDefault();
    }

->withDefault() がミソですね。存在しないときに中身が空のオブジェクトを返します。

● with メソッドの引数を複数指定する

$clients = Client::with('created_user','updated_user')->get();

● コントローラーから取得する時に with メソッドを2回投げる。

app/Http/Controllers/ClientController.php

	public function index( Request $request )
	{
		$clients = Client::with('created_user')
							->with('updated_user')
							->orderBy('id', 'desc')->paginate( 10 );
    }

引用: https://goo.gl/6h6LEC

No.1316
03/05 16:37

edit

LaravelのCRUD操作のメソッドとルーティング一覧

LaravelのCRUD操作のメソッドとルーティング一覧

例 : teams モデルの場合

HTTPメソッド URL例 ルーティング名 メソッド名
データの一覧表示
GET,HEAD teams teams.index App\Http\Controllers\TeamController@index
データの詳細表示
GET,HEAD teams/123456 teams.show App\Http\Controllers\TeamController@show
データの新規作成
GET,HEAD teams/create teams.create App\Http\Controllers\TeamController@create
POST teams teams.store App\Http\Controllers\TeamController@store
データの更新
GET,HEAD teams/123456/edit teams.edit App\Http\Controllers\TeamController@edit
PUT,PATCH teams/123456 teams.update App\Http\Controllers\TeamController@update
データの削除
DELETE teams/123456 teams.destroy App\Http\Controllers\TeamController@destroy

● クロージャで path_info のパラメーターを渡す

Route::get('user/{id}', function ($id) {
    return 'User '.$id;
});

● クロージャで Request と パラメータ id を渡す

use \Illuminate\Http\Request;
Route::get("/{id}", function (Request $request, $id) {
    return App\Http\Controllers\HomeJaController::index( $request, $id ); }
})->where([ 'id' => '[0-9]+' ]);

( id は 正規表現で数字のみに限定しておきます。 )

● ルーターの記述方法(個別)

/routes/web.php

メソッド: 「PUT」
URL: 「teams/{id}/myteamupdate」
を ↓ 
コントローラー「TeamController」の メソッド「myteamupdate」
にルーティングする

Route::put("teams/{id}/myteamupdate", "TeamController@myteamupdate")->name('teams.myteamupdate'); // Add this line in routes.php

● ルーターの記述方法(CRUD一括)

/routes/web.php

clients のCRUD関連メソッドを一括でルーティングする

Route::resource("clients","ClientController");

● ルーターの記述方法(CRUDから一部を除外)

CRUDから一部を除外する方法です

/routes/web.php

Route::resource("clients","ClientController");

 ↓ 「SHOWメソッド」「DELETE メソッド」を除外します

Route::resource('clients', 'ClientController', ['except' => ['show', 'delete'] ]);

● ルーティング変更を確認する

コマンドラインから以下のコマンドでルーティングを確認します。
peco コマンドがある場合は peco を通しましょう。

php artisan route:list | peco
No.1315
02/12 16:32

edit

ルーティング

Laravel mailable クラスを使ってメールを送信する

Laravelにはメールを送信するクラス(mailable)が最初から用意されています。
これを使って管理者宛にメールを送信してみます。

● Laravel mailableを artisan から生成する

今回管理者宛にメール送信するプログラムなので名前を「Admin」とします。(命名は自由です好きに書き換えてください)

app/Mail/Admin.php というファイルを次のコマンドで生成します。

php artisan make:mail Admin

app/Mail/Admin.php が生成されました。 以下のように修正します。

public function build() の中を書き換えます
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class Admin extends Mailable
{
    use Queueable, SerializesModels;
    private $message;
    /**
     * Create a new message instance.
     * @return void
     */
    public function __construct( $m )
    {
        $this->message = $m;
    }
    /**
     * Build the message.
     * @return $this
     */
    public function build()
    {
        // ここを書き換えます ↓
        return $this->from('FROM-ADDRESS@YOUR-DOMAIN.COM')
                    ->subject( "エラーのお知らせ" )
                    ->view('mails.admin')
                    ->with([
                        'user_name' => 'テスト 太郎' ,
                        'my_text'   => $this->message ,
                    ]);
        // ここを書き換えます ↑
    }
}

● メール本文のテンプレートファイル resources/views/mails/admin.blade.php を作成する

まず、 resources/views へ移動し、ディレクトリ mails/ を作成します。 そしてその中にファイル admin.blade.php を以下の内容で作成します

こんにちは{{ $user_name }} !!!<br>
テストメールです<br>
{!! $my_text !!}

● コントローラーからメールを送信する

コントローラーの好きな所に記述します。

use Illuminate\Support\Facades\Mail;
use App\Mail\Admin;
// メール送信
$t = '任意のテキストをここに記述します';
Mail::to('TO-ADDRESS@YOUR-DOMAIN.COM')->send( new Admin($t) );

● .env ファイルのメールの設定を確認する

正しくメール送信が行える設定になっているか .env ファイルを確認します。
ローカルサーバではなくインターネット上にあるサーバの場合はとりあえずは以下の設定でメール送信が可能です。

MAIL_FROM_ADDRESS=<メールアドレス>
MAIL_FROM_NAME=<メールアドレスの横に表示させる名前>

MAIL_DRIVER=sendmail
MAIL_HOST=localhost
MAIL_PORT=
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_ENCRYPTION=

● メール送信を記述したコントローラにアクセスしてメールを送信する

メール送信を記述したコントローラにアクセスしてメールを送信してみます。
このようなメールが到着します

● Laravelのメールドライバの種類

.env の MAIL_DRIVER には次の指定ができるようです。

MAIL_DRIVERの値 説明 補足
sendmail PHPのmail関数で送信する(一番簡単)
smtp SMTPサーバーへログインして送信する(id,passが必要)
mailgun MailgunというAPIベースのメール配信サービスから送信する
mandrill MailgunというAPIベースのメール配信サービスから送信する
ses Amazon AWSが提供するAmazon SESから送信する
sparkpost SparkPostというAPIベースのメール配信サービスから送信する
log 送信は行わず、ログファイルに内容を書き込む storage/logs/laravel.log に内容が記述されます
array ロジックは通りますが、送信はされません

引用: https://goo.gl/fjREcG

添付ファイル1
No.1312
05/06 10:42

edit

添付ファイル

Laravelのモデルで更新日(updated_at)のみ変更する

● Laravelのモデルで更新日(updated_at)のみ変更する

$model->touch(); 

これだけです、これだけで下記のようなSQL文が実行されます

            [query] => update `MY-TABLE` set `updated_at` = ? where `id` = ?
            [bindings] => Array
                (
                    [0] => 2018-10-17 22:44:43
                    [1] => 16090
                )
No.1311
10/17 22:47

edit

Laravel

Laravelで .env config ファイルに値を保存し取り出す

● .env ファイルに設定情報を保存する

MYAPP_URL=http://localhost

● .env ファイルから設定情報を取り出す

$aaa = env(MYAPP_URL);

設定がない場合にデフォルト値をセットすることもできます

$aaa = env(MYAPP_URL, 'default_value');

● config/xxxxx.php ファイルに設定情報を保存する

例: config/myfile.php に値を保存します

<?php
return [
	'data1' => "設定情報です" ,
];

KEY, VALUE 形式だけでなく 配列形式でも保存できます。

● config/xxxxx.php ファイルから設定情報を取り出す

次の2つのうちどちらでも取り出すことが出来ます。

config('myfile.data1');
\Config::get('myfile.data1');

● configファイルから値がとりだせない / 取り出した値が NULL になる時は

configファイルから値がとりだせない / 取り出した値が NULL になる時は次のコマンドを実行します

php artisan config:clear;

● .env ファイルに設定情報を保存する

No.1310
10/17 21:58

edit

LaravelでCLIから呼び出す自作コマンドを作成する。コマンドをcronで定期実行する

● LaravelでCLIから呼び出す自作コマンドを作成する

フレームワークによってはコントローラーを直接CLIから叩けるものもありますが、 Laravelの場合はコマンドを用意する必要があるようです。 (とはいえ artisan コマンドが用意されているので簡単です。)

● 作成するコマンド名を考える

コマンド名は

make:auth
make:migration

 のように(makeグループの中のauth)みたいな感じで、グルーピングされていますので、
自作コマンドもグルーピングしておくと、コマンドが増えた時に一覧表示で見やすくなります。

今回作成するコマンドは

myapp:print

とします。

● コマンドファイルを artisan で作成する

myapp:print コマンドを作成する時には次のように入力します

php artisan make:command  MyappPrint

するとファイル app/Console/Commands/MyappPrint.php が自動生成されます。

● 自動生成されたファイルを編集する

app/Console/Commands/MyappPrint.php を以下のようにします

protected $signature = 'myapp:print'; にコマンド名をセットします。
protected $description = 'MYAPP:にコマンドの説明をセットします。

<?php

namespace App\Console\Commands;
use Illuminate\Console\Command;

class MyappPrint extends Command
{
    /**
     * The name and signature of the console command.
     * @var string
     */
    protected $signature = 'myapp:print';


    /**
     * The console command description.
     * @var string
     */
    protected $description = 'MYAPP: ハローと表示します';


    /**
     * Create a new command instance.
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }


    /**
     * Execute the console command.
     * @return mixed
     */
    public function handle()
    {
        // ここにロジックを記述
        echo 'Hello Myapp Command !!!' . "\n";
    }
}

● ターミナルから実行する

php artisan myapp:print

結果

Hello Myapp Command !!!

● コマンドラインで引数を受け取る

1. シグネイチャを変更します

    protected $signature = 'myapp:print';

 ↓

    protected $signature = 'myapp:print {id}';

と変更します。

「引数なし」を許可するには

    protected $signature = 'myapp:print {id?}';

とします。

2.handle()メソッド内で引数を受け取ります

    public function handle()
    {
        // ここにロジックを記述
        $id = $this->argument('id');
        echo 'Hello Myapp Command !!!' . "\n";
        echo $id;
    }

ターミナルから実行時に引数を渡します

php artisan myapp:print

● Laravelでコマンドをcron定期実行する(タスクスケジュール)

Laravel で定期実行させるにはまず cron で毎分ごとにLaravelのスケジューラを実行させ、その中でLaravelで設定した時間ごとにコマンドを自動実行します。

1. crontab に設定する

crontab -e

crontabの書式に沿って以下のように記述します

* * * * * php7 /YOUR/APP/PATH/artisan schedule:run >> /dev/null 2>&1

2. app/Console/Kernel.php にコマンドを記述

コマンド「myapp:getdata」を1分ごとに起動するように設定します。

    protected function schedule(Schedule $schedule)
    {
        // RSSからデータを取得 (1分ごと)
        $schedule->command('myapp:getdata')->everyMinute();
    }

以上です。 ログを見て定期実行が行われているか確認します。

スケジュールは以下のように設定できます。

メソッド 説明
->cron('* * * * * *'); CRON記法によるスケジュール
->everyMinute(); 毎分タスク実行
->everyFiveMinutes(); 5分毎にタスク実行
->everyTenMinutes(); 10分毎にタスク実行
->everyFifteenMinutes(); 15分毎にタスク実行
->everyThirtyMinutes(); 30分毎にタスク実行
->hourly(); 毎時タスク実行
->hourlyAt(17); 一時間ごと、毎時17分にタスク実行
->daily(); 毎日深夜12時に実行
->dailyAt('13:00'); 毎日13:00に実行
->twiceDaily(1, 13); 毎日1:00と13:00時に実行
->weekly(); 毎週実行
->monthly(); 毎月実行
->monthlyOn(4, '15:00'); 毎月4日の15:00に実行
->quarterly(); 四半期ごとに実行
->yearly(); 毎年実行
->timezone('America/New_York'); タイムゾーン設定

● php artisan schedule:run で動作を確認する

cronでコマンドが呼ばれているかを確認するには

php artisan schedule:run

としますが、あらかじめ メソッドの修正が必要です!(重要)

1. schedule メソッドの実行間隔を 1分に変更する

1分に変更しないと、No scheduled commands are ready to run. が出て終了してしまいます。
また、重複起動を回避するメソッド withoutOverlapping() も外しておきましょう。

    protected function schedule(Schedule $schedule)
    {
        $schedule->command('myapp:getdata')->everyMinute();

2. schedule:run を実行する

php artisan schedule:run

とします。

これで必ず設定されたタスクが走るので、ログを見て動作を確認します。

● withoutOverlapping() メソッドはデッドロックを自動解除しない?

どうやら withoutOverlapping() はデッドロックを自動で解除できないようです。

https://goo.gl/mVchaN

No.1309
11/26 14:47

edit

Laravel
CLI
コマンド

Laravel マイグレーション時の「Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes"」の対処法

● varcharのデフォルト文字数を191文字にして(191*4 = 764バイト) 767バイトより小さくする

app\Providers\AppServiceProvider.php

// ↓ この行を追加
use Illuminate\Support\Facades\Schema;

    public function boot()
    {
        // ↓ この行を追加
        Schema::defaultStringLength(191);
    }

No.1307
10/16 16:11

edit

Laravel のコントローラーのコンストラクタで Authを使い、リダイレクトする

● Laravel のコントローラーのコンストラクタでAuthを使う

	function __construct(){

		// コンストラクタ内で Auth を使う
		$this->middleware(function ($request, $next) {
			$user = Auth::user();
			// .....

			return $next($request);
		});
	}

● Laravel のコントローラーのコンストラクタ等で強制リダイレクトを行う

use Illuminate\Support\Facades\Redirect;
Redirect::route('myerror')->withErrors(['redirect'=>'エラー発生'])->throwResponse();

引用: https://goo.gl/8rkAu5

No.1306
10/15 16:17

edit

Laraelのモデルでグローバルスコープ、ローカルスコープを動的なパラメーターでセットする

● Laravelのモデルの「スコープ」 とは

Laravelのモデルのスコープとは簡単にいうと SQL文の「 WHERE aaa = 'bbb'」みたいなWHERE句 なのですが、

・「User」モデルの中の管理者フラグを持つものだけを取り扱う
・「User」モデルが既にあるときに、現在削除されてないユーザー( WHERE is_deleted = 0 )を「Activeuser」モデルとして作成する。

みたいなところで使います。
その時に使うのが モデルの「スコープ」です。

好きな時につけたり外したりできる「ローカルスコープ」と
基本的につけっ放しの「グローバルスコープ」があります。

● グローバルスコープの作成方法

例:自分(ログインしているユーザー)と同じチームIDを持つという条件を
( Inmyteam )というグローバルスコープとして作成して、モデルに適用します。

1. グローバルスコープの作成

/app/Scopes/Inmyteam.php

<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;

class Inmyteam implements Scope
{
    /**
     * 自分のチーム内のユーザーに限定するスコープ
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        return $builder->where('team_id', '=', Auth::user()->team_id);
    }
}

2. モデルファイルから呼び出す。

app/User.php のメソッドに下記の boot() メソッドを追加する

use App\Scopes\Inmyteam;
    protected static function boot()
    {
        parent::boot();
        // スコープ「Inmyteam」を適用
        static::addGlobalScope(new Inmyteam);
    }

以上です。簡単ですね。
なおグローバルスコープに変数は渡せないようなので、ダイナミックに変わる条件(動的なパラメーター)を指定したい場合はセッションなど別のルートから取って来ましょう。
取れない場合はローカルスコープで設定します。

引用: https://goo.gl/Sk2F26

● ローカルスコープの作成方法

引用: https://goo.gl/Wfvuka

1. ローカルスコープの作成

モデルファイルの中に直接書けばOK。 ローカルスコープはメソッドに引数を渡せます。

例) あるショップ内の商品に限定するスコープを作成する

app/Items.php

    /**
     * ローカルスコープ : ->inShop(<id>) で あるショップ内の商品に限定する
     *
     * @param    \Illuminate\Database\Eloquent\Builder    $query
     * @return   \Illuminate\Database\Eloquent\Builder
     */
     public function scopeInShop($query, $shop_id)
     {
         return $query->where('shop_id', '=', $shop_id);
     }

2. ローカルスコープの呼び出し

shop_id が 99 な商品を全件取得

Item::inShop(99)->all()

実は

Item::inShop(99)
Item::inshop(99)

どちらも使うことができますが、同じようにキャメルケースで使用することをお勧めします。

No.1305
04/24 13:50

edit

Laravel でリレーションを設定し、リレーション先のテーブルを取得する

LaravelでEloquentを使ってリレーションを設定し、リレーション先のテーブルを取得する方法です。

● テーブル例

次のような2つのテーブルがあるとします
・「チーム」(teams)
・「ユーザー」(users)

このようにチームの中に複数のユーザーが所属するとします

 ─── マイチーム
     ├── 鈴木 一郎
     ├── 山田 太郎
     ├── 中村 二郎

● リレーションの設定

モデル /app/Team.php

    /**
     * 1対多リレーション
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
public function users() // 複数形(users)にする
{
    // 「is_deleted = 0」のデータを「idの大きい順」で取得する
    return $this->hasMany('App\User')->where('is_deleted', 0)->orderBy('id', 'DESC');
}

(取得条件やソート順を指定することができます。)

モデル /app/User.php

public function team() // 単数形(team)にする
{
    return $this->belongsTo('App\Team');
}

● リレーションのデータの取得

・1. チーム一覧を所属するユーザー一覧とともに取得する

use App\Team;
$all_teams = Team::with('users')->get();
dd( $all_teams->toArray() );

(実は with() メソッドを指定しなくても、Bladeテンプレートの中で リレーションオブジェクトを呼び出そうとすると自動取得されます。 ただ、自動取得が100回あると100回SQLクエリが投げられるので非効率です。with()メソッドだと in句 で一撃で取得してきます。)

・2. ログイン中のユーザーデータを(チームIDに加えて)チーム名とともに取得する

方法1: with() を使ったやり方

$user = User::with('team')->find( Auth::user()->id );
dd( $user->toArray() );

実行されるSQL文

select * from `users`";
select * from `teams` where `teams`.`id` in (?); // ? は プレースホルダ

 

方法2: LEFT JOIN を使ったやり方

$user = User::leftJoin('teams','teams.id','=','users.team_id')->find( Auth::user()->id );
Mydump::dump( $user->toArray() );

実行されるSQL文

select * from `users` left join `teams` on `teams`.`id` = `users`.`team_id` where `users`.`id` = ? limit 1

・3. 全ユーザー一覧を(チームIDに加えて)チーム名とともに取得する

$all_users = DB::table('users')
                ->leftJoin('teams','teams.id','=','users.team_id')
                ->get();
Mydump::dump( $all_users );

その他リレーションの参考: https://laravel-news.com/eloquent-tips-tricks

No.1304
01/30 15:32

edit

DB
Eloquent
モデル

LaravelでDBのシーダーを使ってデフォルトのデータをセットする

マイグレーションをやり直した時に、DBデータも自動で登録できるようにシーダーを使ってデータを作成しておくと マイグレーションのやり直しがとても楽にできます。

● DBのシーダーファイルを作る

テーブル名「clients」の場合「ClientsSeeder」や「ClientsTableSeeder」といった名前をつけて作成します。

(例: clients テーブル用のシーダーファイルを作成する )

php artisan make:seeder ClientsSeeder

database/seeds/ClientsSeeder.php が作成されます )

● 作成されたDBのシーダーファイルを編集する

database/seeds/ClientsSeeder.php

<?php
use Illuminate\Database\Seeder;
class ClientsSeeder extends Seeder
{
    /**
     * Run the database seeds.
     * @return void
     */
    public function run()
    {
        DB::table("clients")->insert([
			'id'           => 1 ,
			'client_name'  => 'テスト商事' ,
			'tel_name'     => '012-345-6789' ,
			'fax_name'     => '012-345-6780',
        ]);
        DB::table("clients")->insert([
			'id'           => 2 ,
			'client_name'  => 'てすとの商事' ,
			'tel_name'     => '112-345-6789' ,
			'fax_name'     => '112-345-6780',
        ]);
    }
}

● 呼び出し元ファイル(DatabaseSeeder.php)に記述

database/seeds/DatabaseSeeder.php に作成したシーダーファイルを記述して呼び出します

<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     * @return void
     */
    public function run()
    {
        $this->call([
          ClientsSeeder::class ,		// 追加
        ]);
    }
}

● シーダーの実行

php artisan db:seed

● Class XXXXXSeeder does not exist エラーが出る場合

composer の autoload を再読み込みしてから実行するとうまく実行できます。

composer dump-autoload
php artisan db:seed
No.1303
10/23 14:43

edit

DB

Laravelのパンくずリストlaravel-breadcrumbsを使用してページタイトルとパンくずを表示させる

● laravel-breadcrumbsのインストール

composer require davejamesmiller/laravel-breadcrumbs:5.x

● パンくずリストのデータを定義する

routes/breadcrumbs.php を以下の内容で作成します

<?php

// Home
Breadcrumbs::for('home', function ($trail) {
    $trail->push('Home', route('home'));
});

// Home > About
Breadcrumbs::for('about', function ($trail) {
    $trail->parent('home');
    $trail->push('About', route('about'));
});

● 設定ファイルを生成する

次の設定ファイルを生成コマンドを実行します

php artisan vendor:publish --provider="DaveJamesMiller\Breadcrumbs\BreadcrumbsServiceProvider"

● パンくずリストを表示する

ビューファイル(XXXXX.blade.php)に以下のように記述します

{{ Breadcrumbs::render('home') }}

もしくは、Route::currentRouteName() で現在のルーティングが取得できるので

{{ Breadcrumbs::render(Route::currentRouteName()) }}

としておくとビューファイルは触らなくてもいいので楽です。(レイアウトファイルにパンくずを設置してある場合はこちらがおすすめです。)

● パンくずリストをカスタマイズする

自作のパンくずリストテンプレートを使用するには config/breadcrumbs.php を編集します

25行目を次のように書き換えます

###    'view' => 'breadcrumbs::bootstrap4',
    'view' => 'my_breadcrumbs',

すると、テンプレートファイルviews/breadcrumbs.blade.phpを見に行くようになります。

テンプレートファイルを用意する

views/breadcrumbs.blade.php

(以下は例です。適宜書き換えてください。)

@if (count($breadcrumbs))
    <ol class="navbar__breadcrumb breadcrumb d-none d-sm-flex">
        @foreach ($breadcrumbs as $breadcrumb)
            @if ($breadcrumb->url && !$loop->last)
                <li class="breadcrumb-item"><a href="{{ $breadcrumb->url }}">{{ $breadcrumb->title }}</a></li>
            @else
                <li class="breadcrumb-item active">{{ $breadcrumb->title }}</li>
            @endif
        @endforeach
    </ol>
@endif

以上です。 とても簡単にパンくずリストが出来るのでLaravelを使っている場合は必須ともいえるでしょう。

● パンくずの一番後ろのテキストをページタイトルとして表示する

これも便利です。blade.php ファイルにページタイトルを記述しなくても自動的にセットされます。

    <title>{{ ($breadcrumb = Breadcrumbs::current()) ? $breadcrumb->title : 'No Name' }}</title>
No.1302
11/13 16:43

edit

Laravel

Laravelのキャッシュクリア

● Laravelのファイル更新が反映されない?時はキャッシュクリアを行いましょう

Laravelで「ファイルを更新したのに更新されてない?」
という時はキャッシュが残っている可能性が大です。
こちらのコマンドでキャッシュを削除しましょう。

php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan view:clear
composer dump-autoload

・1行で書いてコピペして実行!

php artisan cache:clear; php artisan config:clear; php artisan route:clear; php artisan view:clear; composer dump-autoload
No.1283
10/12 16:21

edit

Laravel

Laravel で自作パッケージを簡単に作成する

PackageCreator がとても便利です

● PackageCreator

https://github.com/SUKOHI/PackageCreator

・インストール

composer require sukohi/package-creator

インストールすると「make:package コマンド」が使用できるようになります

・パッケージの作成( php artisan make:package コマンド )

php artisan  make:package   (ベンダー名)   (パッケージ名)   (保存するフォルダ名(アプリケーションからの相対パス) )  

例 )

php artisan  make:package  myname  my-package  test_packages 

自動生成されるファイル

./test_packages/Myname/MyPackage/src/Facades/MyPackage.php
./test_packages/Myname/MyPackage/src/MyPackage.php
./test_packages/Myname/MyPackage/src/MyPackageServiceProvider.php
./test_packages/Myname/MyPackage/composer.json

● パッケージ作成例

例として mydump クラスを作成してみます。

1. コマンドの実行

php artisan  make:package  akato0315  mydump  mypackages 

2. クラスの実装

APP/mypackages/Akato0315/Mydump/src/Mydump.php を編集して以下の内容にします

<?php 
namespace Akato0315\Mydump;
class Mydump {
    public static function dump( $mix )
    {
  		print "\n".'<pre style="text-align:left;display:block;padding:9.5px;margin:10px;font-size:13px;line-height:1.4;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px;">'."\n";
  		print '<span style="color:#999;">TYPE: ' . gettype($mix) . "</span>\n";
  		print_r($mix);
  		print "\n</pre>\n\n";
    }

    public static function dump2( $mix )
    {
      print "\n"."<!--"."\n";
  		print "\n".'<pre style="text-align:left;display:block;padding:9.5px;margin:10px;font-size:13px;line-height:1.4;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px;">'."\n";
  		print '<span style="color:#999;">TYPE: ' . gettype($mix) . "</span>\n";
  		print_r($mix);
  		print "\n</pre>\n\n";
      print "\n"."-->"."\n";
    }
}

3. configファイル と composer.json を編集

APP/config/app.php の「providers」と「aliases」に以下を追加します

    'providers' => [
        ..................... 
        Akato0315\Mydump\MydumpServiceProvider::class,
    'aliases' => [
        ..................... 
        'Mydump' => Akato0315\Mydump\Facades\Mydump::class,

composer.json を以下のように修正します

        "psr-4": {
            "App\\": "app/" 
        }

        ↓

        "psr-4": {
            "App\\": "app/" ,
            "Akato0315\\Mydump\\": "mypackages/Akato0315/Mydump/src"
        }

4. コマンドラインから次のコマンドを実行

composer dumpautoload -o
php artisan config:cache

5. Laravelのコントローラーから使用する

use Mydump;

$mix = [
    'aaa' => 'bbb' ,
    'ccc' => 'ddd' ,
];
Mydump::dump( $mix );

5. 結果

添付ファイル1
mydump.png ( 22.5 KBytes ) ダウンロード
No.1282
10/05 09:52

edit

添付ファイル

Laravel
composer

Laravelのコントローラーからビューへの値の渡し方

● with

複数データを渡すときは連想配列で渡します

$data = [
 "data1" => $data1 ,  
 "data2" => $data2 ,  
];
return view('mytemplate')->with($data);

またはwithメソッドを2回呼んでもOKです。

return view('mytemplate')->with('data1',$data1)->with('data2',$data2);

● compact

すっきりと書きたい場合は compact を使って以下のように書くことができます

return view('mytemplate',compact('data1', 'data2'));

● ページネーションにパラメーターを渡す

コントローラーから次のように渡します。

$pagination_params = [
    "aaa" => 1 ,
    "bbb" => 2 ,
];
return view('mytemplate', compact('pagination_params'));

ビューでは次のようにして呼び出します
mytemplate.blade.php

{{ $model->appends($pagination_params)->links() }}

次のようなリンクがページネーションにつきます
( 3ページ目へのリンクにつく文字列 )

?&aaa=1&bbb=2&page=3

● ビューで渡された値の展開

foreach でオブジェクトを回す

<ul>
    @foreach($data_obj as $v)
    <li><a href="#">{{$v->data_name}}</a></li>
    @endforeach
</ul>

foreach で配列を回す

<ul>
    @foreach($data_loop as $v)
    <li><a href="#">{{$v['data_name']}}</a></li>
    @endforeach
</ul>

● ビューからコントローラーへのリンクを表示する

<a href="{{ route('tweets.index') }}">Tweets</a>

またはこのようにも書けます

<a href="{{ url("/tweets") }}">Tweets</a>
No.1279
10/09 16:17

edit

Laravel のページャー(ページネーション)の表示とカスタマイズ

● Laravel paginate の実行

Eloquent モデルクエリビルダに対して paginate() メソッドを 実行することができます。

Eloquent モデルに対してpaginate()を実行する

$users = User::where('votes', '>', 100)->paginate(15);
return view('user.index', ['users' => $users]);

クエリビルダーに対してpaginate()を実行する

$users = DB::table('users')->paginate(15);
return view('user.index', ['users' => $users]);

● 結果セットCollectionに対して paginate() する

Laravelの 結果セットに対してpaginate() を 行うこともできます。
複数のテーブルから検索して結合した後にページネーションを付けたいという場合にとても有効です。
メソッド名が変わるので注意してください。

$collection = collect([1,2,3,4,5,6,7,8,9,0]);
$items = $collection->forPage($_GET['page'], 5);

● Laravelのページャー(ページネーション / pagination)の表示

Bladeテンプレート内で次のように記述します

{!! $tweets->render() !!}

links() というエイリアスもあります。(機能は同じ)

{{ $model->links() }}

● 検索結果ページなどパラメーターを引き継ぐ

検索結果ページでは「検索文字列」「1ページあたりの表示数」などのパラメーターを引き継ぐ必要があります。
その時は次のように appends() メソッドを呼びます。

コントローラー pagination_params をコントローラーから渡します

$pagination_params = [
// パラメーターセット(連想配列)
];

return view('users.index', compact(pagination_params'));

bladeテンプレート内

    {!! $tweets->appends($pagination_params)->links('pagination.default') !!}

● その他便利なパラメーター(次のページがあるかどうか? など)

現在のページに表示されている件数: {{ $data->count() }}
現在のページ数: {{ $data->currentPage() }}
現在のページの最初の要素: {{ $data->firstItem() }}
次のページがあるかどうか: {{ $data->hasMorePages() }}
現在のページの最後の要素: {{ $data->lastItem() }}
最後のページ数: {{ $data->lastPage() }}
次のページのURL: {{ $data->nextPageUrl() }}
1ページに表示する件数: {{ $data->perPage() }}
前のページのURL: {{ $data->previousPageUrl() }}
合計件数: {{ $data->total() }}
指定ページのURL: {{ $data->url(4) }}

引用: http://bit.ly/2w8GKa8

● ページャー(ページネーション)のカスタマイズ

ページネーションをカスタマイズして「First Page」「Last Page」のリンクを追加してみましょう。

ページネーションの生成方法を次のように書き換えます

{!! $tweets->render() !!}
 ↓
{!! $tweets->links('pagination.default') !!}

resources/views/pagination/default.blade.php を以下の内容で新規作成します

@if ($paginator->lastPage() > 1)
<ul class="pagination">
    <li class="page-item {{ ($paginator->currentPage() == 1) ? ' disabled' : '' }}">
        <a class="page-link" href="{{ $paginator->url(1) }}">First Page</a>
     </li>
    <li class="page-item {{ ($paginator->currentPage() == 1) ? ' disabled' : '' }}">
        <a class="page-link" href="{{ $paginator->url(1) }}">
            <span aria-hidden="true">«</span>
            {{-- Previous --}}
        </a>
    </li>
    @for ($i = 1; $i <= $paginator->lastPage(); $i++)
        <li class="page-item {{ ($paginator->currentPage() == $i) ? ' active' : '' }}">
            <a class="page-link" href="{{ $paginator->url($i) }}">{{ $i }}</a>
        </li>
    @endfor
    <li class="page-item {{ ($paginator->currentPage() == $paginator->lastPage()) ? ' disabled' : '' }}">
        <a class="page-link" href="{{ $paginator->url($paginator->currentPage()+1) }}" >
            <span aria-hidden="true">»</span>
            {{-- Next --}}
        </a>
    </li>
    <li class="page-item {{ ($paginator->currentPage() == $paginator->lastPage()) ? ' disabled' : '' }}">
        <a class="page-link" href="{{ $paginator->url($paginator->lastPage()) }}">Last Page</a>
    </li>
</ul>
@endif

● カスタマイズした結果


         ↓

● 1ページしかない時にもページネーションを表示させる

Laravel の ページャーはデフォルトでは 1ページしかない時は表示されません
それではデザイン的にさみしい時は次のようにして表示させます。

{{-- paginate --}}
{!! $data_loop->links('pagination.front') !!}
{{-- / paginate --}}

  ↓ このように変更します

{{-- paginate --}}
@if ( $data_loop->hasPages() )
    {!! $data_loop->links('pagination.front') !!}
@else
    <div class="g_pager">
        <a class="prev"></a>
        <a class="current" href="">1</a>
        <a class="next"></a>
    </div>
@endif
{{-- / paginate --}}
添付ファイル1
添付ファイル2
No.1278
08/09 13:40

edit

添付ファイル

Laravel で DB構造取得と最後に実行したSQL文を取得する

● Laravel の Schema クラス

use Illuminate\Support\Facades\Schema;

category テーブルのカラムを配列で取得する

$columns = Schema::getColumnListing('category');
dump($columns);

● 最後に実行したSQL文を取得する

・方法その1

$data = $model->orderBy('id', 'desc')->paginate( 10 );
dump( $model->toSql() );

・方法その2

use DB;
\DB::enableQueryLog();
$data = $model->orderBy('id', 'desc')->paginate( 10 );
dump(\DB::getQueryLog());
No.1277
04/09 09:44

edit

Laravel