- 投稿日:2021-02-27T20:07:00+09:00
[自分メモ]複数レコードを配列にして一括でattach()
- 投稿日:2021-02-27T15:55:37+09:00
OctoberCMS 管理画面実装テク:テキストフィールドの文字数制限を変更する
- 投稿日:2021-02-27T15:39:06+09:00
OctoberCMS 管理画面実装テク:フォームに非表示フィールドを作る
OctoberCMSの自作プラグインで管理画面を実装する際のテクニックのお話。
fields.yamlでフィールドを定義して管理画面のフォームを実装する際、
<input type="hidden">
のようなフィールドが意外と直感的に作れない。
hidden
プロパティでできそうだが、これだとPOSTデータに含まれなくなる。
readOnly
やdisabled
だと変更不可にはなるがページに表示されてしまう。そこで、
containerAttributes
プロパティを使用してdisplay: none
を当ててやる。containerAttributes: style: "display: none"これで、POSTデータに含まれるが表示されないフィールドが実装できる。
- 投稿日:2021-02-27T15:21:42+09:00
Laravelの構成概念 第1回 ライフサイクル編
Laravelフレームワークの全体の処理の流れやサービスコンテナ、サービスプロバイダーについて調べたことをまとめます。
シリーズ
- Laravelの構成概念 第1回 ライフサイクル編
- Laravelの構成概念 第2回 サービスコンテナ編(近日公開)
- Laravelの構成概念 第3回 サービスプロバイダ編(近日公開)
調べるきっかけ
こちらのイベントに参加するにあたって、読んでおかないと話についていけないだろうなぁと思って復習がてら読んでいきます。
初心者の方へ
ライフサイクル・サービスコンテナ・サービスプロバイダ周りは始めたばかりの人には難易度が高いですが、Laravelの処理の流れや初期設定などの仕組みを理解できるので概要だけでも把握できると良いです。
環境
- Laravel 8.5.11
参考
- Laravel 8.x ライフサイクル
- Laravel 8.x サービスコンテナ
- Laravel 8.x サービスプロバイダ
- Laravel 8.x ファサード
- (今回はあまり触れません)
- Laravel API 8.x
- Laravel フレームワーク
- Laravel コアフレームワーク
Laravelの構成概念については公式ドキュメントにより詳しい内容がまとまっているので詳細を知りたい方は上記の公式ドキュメントをご覧ください。
用語概要
用語: Laravel ライフサイクル
Laravelが起動して終了するまでのLaravel全体の処理の流れをライフサイクルといいます。
ちなみに入り口はHttpとConsoleの二つあります。用語: Laravel サービスコンテナ
クラスの依存関係を管理し、依存注入(DI)を実行するための機能です。
用語: Laravel サービスプロバイダ
Laravelアプリケーション全体の起動処理における初期起動処理を行っています。
サービスプロバイダからサービスコンテナへDIの設定(コンテナ結合)を行います。サービスプロバイダーでは、コンテナ結合以外にもイベントリスナ、フィルター、ルーティングの設定なども行います。
用語: DI(Dependency Injection)とは
Dependency Injectionは依存性の注入となります。
PHPを実行する際に抽象クラス(interface)を具象クラスに差し替えて実行できる。テストの時は、DBやAPIを実際にアクセスさせないために差し替えたり等テストコードが書きやすくなるメリットがあります。
本題: Laravelライフサイクル
http://localhost/foo/bar
等のHttp経由の場合、public/index.phpから始まります。
php artisan foo:bar
等のConsole経由の場合、artisanから始まります。それぞれファイルの中身を見てみましょう。
(補足のコメントを入れてます)public/index.php
Http経由の流れです。
public/index.php<?php use Illuminate\Contracts\Http\Kernel; use Illuminate\Http\Request; // タイマー開始。フレームワークの起動にかかる時間などを測れる define('LARAVEL_START', microtime(true)); // メンテナンスモードのファイルがあればメンテナンス画面を表示して終了する // https://github.com/laravel/framework/blob/8.x/src/Illuminate/Foundation/Console/stubs/maintenance-mode.stub if (file_exists(__DIR__.'/../storage/framework/maintenance.php')) { require __DIR__.'/../storage/framework/maintenance.php'; } // composer dump-autoload で生成されたオートローダーを読み込む // オートローダーとは外部にあるPHPファイルを自動的に読み込む仕組みです // https://genkiroid.github.io/2016/07/15/about-composer-autoload require __DIR__.'/../vendor/autoload.php'; // ここからLaravelのコアシステムが始まります // Illuminate\Foundation\Application のインスタンスを取得して $app に格納してます // サービスコンテナを生成してHttpカーネル、Consoleカーネル、例外ハンドラーのインスタンスの生成を行います // https://github.com/laravel/laravel/blob/8.x/bootstrap/app.php $app = require_once __DIR__.'/../bootstrap/app.php'; // 上の行で生成したHttpカーネルのインスタンスを取得してます(App\Http\Kernel) $kernel = $app->make(Kernel::class); // tapやsendの挙動がどうなっているのか怪しいですが... // 送信されてきたHttpリクエスト(GET, POSTの中身)をHttpカーネルへ渡してHttpレスポンスを取得してます $response = tap($kernel->handle( $request = Request::capture() ))->send(); // Laravelの終了処理 $kernel->terminate($request, $response);artisan
Console経由の流れです。
artisan#!/usr/bin/env php <?php // タイマー開始。Httpの時と同じ define('LARAVEL_START', microtime(true)); // オートローダーの読み込み。Httpの時と同じ require __DIR__.'/vendor/autoload.php'; // Illuminate\Foundation\Application インスタンスの取得。Httpの時と同じ $app = require_once __DIR__.'/bootstrap/app.php'; // サービスコンテナからコンソールカーネルのインスタンス(App\Console\Kernel)を取得している $kernel = $app->make(Illuminate\Contracts\Console\Kernel::class); // 引数入力インスタンスとコンソール出力インスタンスをコンソールカーネルへ渡して実行する // 実行結果のステータスを受け取る $status = $kernel->handle( $input = new Symfony\Component\Console\Input\ArgvInput, new Symfony\Component\Console\Output\ConsoleOutput ); // Laravelの終了処理 $kernel->terminate($input, $status); // $statusを出力して、スクリプトを終了する // https://www.php.net/manual/ja/function.exit.php exit($status);public/index.phpの補足
public/index.php$app = require_once __DIR__.'/../bootstrap/app.php';bootstrap/app.php
bootstrap/app.php ファイルの補足です。
bootstrap/app.php<?php // 新しいLaravelアプリケーションのインスタンスを生成してます $app = new Illuminate\Foundation\Application( $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__) ); // インターフェースに具象クラスをサービスコンテナにバインドしてます // Httpカーネルのバインド $app->singleton( Illuminate\Contracts\Http\Kernel::class, App\Http\Kernel::class ); // Consoleカーネルのバインド $app->singleton( Illuminate\Contracts\Console\Kernel::class, App\Console\Kernel::class ); // 例外ハンドラーのバインド $app->singleton( Illuminate\Contracts\Debug\ExceptionHandler::class, App\Exceptions\Handler::class ); return $app;Illuminate\Foundation\Applicationのインスタンスを生成してます。
Illuminate\Foundation\Application
はIlluminate\Container\Containerを継承してます。なのでサービスコンテナのインスタンスを作ってると言っても良いですね。
Illuminate\Foundation\Application
のコンストラクタを見てみましょう。Illuminate\Foundation\Applicationclass Application extends Container implements ApplicationContract, CachesConfiguration, CachesRoutes, HttpKernelInterface { public function __construct($basePath = null) { if ($basePath) { $this->setBasePath($basePath); } $this->registerBaseBindings(); $this->registerBaseServiceProviders(); $this->registerCoreContainerAliases(); } protected function registerBaseBindings() { static::setInstance($this); $this->instance('app', $this); $this->instance(Container::class, $this); $this->singleton(Mix::class); $this->singleton(PackageManifest::class, function () { return new PackageManifest( new Filesystem, $this->basePath(), $this->getCachedPackagesPath() ); }); } protected function registerBaseServiceProviders() { $this->register(new EventServiceProvider($this)); $this->register(new LogServiceProvider($this)); $this->register(new RoutingServiceProvider($this)); } public function registerCoreContainerAliases() { foreach ([ 'app' => [self::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class], 'auth' => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class], // ... 略 'view' => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class], ] as $key => $aliases) { foreach ($aliases as $alias) { $this->alias($key, $alias); } } } }この段階ではLaravelを起動するための最低限のクラスが読み込まれています。
深掘りしていくとキリがないのでここは気になったら詳しくみていけば良いかなと思います。続いて、
Illuminate\Contracts\Http\Kernelインターフェースをキーとして、Illuminate/Foundation/Http/Kernelクラスを登録してます。
Consoleカーネル、例外ハンドラーも同様に登録してますね。
最後に$app
を返してbootstrap/app.php
は終了です。public/index.php$kernel = $app->make(Kernel::class);先ほどサービスコンテナに登録した
Illuminate\Contracts\Http\Kernel
をキー使って、App\Http\Kernel
インスタンスを取得します。
App\Http\Kernel
のコンストラクタを見てみます。
このファイルはvendor
配下ではなく、app/Http/Kernel.php
と配置されてます。
また、Illuminate\Foundation\Httpを継承していて、ここのコンストラクタが実行されます。Illuminate\Foundation\Http\Kernel/** * Create a new HTTP kernel instance. * * @param \Illuminate\Contracts\Foundation\Application $app * @param \Illuminate\Routing\Router $router * @return void */ public function __construct(Application $app, Router $router) { $this->app = $app; $this->router = $router; $this->syncMiddlewareToRouter(); } protected function syncMiddlewareToRouter() { $this->router->middlewarePriority = $this->middlewarePriority; foreach ($this->middlewareGroups as $key => $middleware) { $this->router->middlewareGroup($key, $middleware); } foreach ($this->routeMiddleware as $key => $middleware) { $this->router->aliasMiddleware($key, $middleware); } }Httpカーネルクラスの初期処理でミドルウェアの設定が行われてますね。
どんなミドルウェアが登録されているかはApp\Http\Kernelを見るとわかります。public/index.php$response = tap($kernel->handle( $request = Request::capture() ))->send(); // Laravelの終了処理 $kernel->terminate($request, $response);
$_GET
,$_POST
などを元にIlluminate/Http/Request
のインスタンスを作っています。
$kernel->handle(...)
Httpカーネルのhandleメソッドを実行してIlluminate/Http/Request
インスタンスを渡して実行してます。
ルーティングやコントローラを通って、最終的にIlluminate\Http\Response
インスタンスを生成して返します。
Illuminate\Http\Response
のsend
メソッドを実行してます。
Illuminate\Http\Response
はSymfony\Component\HttpFoundation
を継承していて、Symfonyコンポーネントのメソッドを呼び出してます。
ここでは、Httpレスポンスヘッダーやレスポンスボディの出力を行ってます。
つまりはここで最終的なHTMLが出力されてる訳ですね。
tap
ヘルパーメソッドを使うと、メソッドチェーンで関数を実行しても、返り値はtap関数の第一引数に渡した変数が返ってきます。
つまりは、Illuminate\Http\Response
のインスタンスが$response
に入ります。最後にLaravelの終了部分です。
$kernel->terminate($request, $response);
Illuminate\Foundation\Http\Kernelpublic function terminate($request, $response) { $this->terminateMiddleware($request, $response); $this->app->terminate(); } protected function terminateMiddleware($request, $response) { $middlewares = $this->app->shouldSkipMiddleware() ? [] : array_merge( $this->gatherRouteMiddleware($request), $this->middleware ); foreach ($middlewares as $middleware) { if (! is_string($middleware)) { continue; } [$name] = $this->parseMiddleware($middleware); $instance = $this->app->make($name); if (method_exists($instance, 'terminate')) { $instance->terminate($request, $response); } } }Laravelの終了時にもミドルウェアを差し込めるようですね。
各種ミドルウェアにterminate
メソッドがあればそれを実行して終了処理を行っていきます。さいごに
今回はLaravel ライフサイクルについて詳しく見ていきました。
改めて調べるとまだまだ知らない部分が発見できてよかったです。サービスコンテナやサービスプロバイダについてもまとめて紹介しようと思いましたが、
流石に長くなるので別記事に分けて紹介しようと思います。
- 投稿日:2021-02-27T13:32:11+09:00
LaravelはRequestを使えと怒られたお話
LaravelではRequestを使おう!
はじめに
先輩「何この\$_POSTって、Requestを使わない理由は何?」
僕「え?りくえすと??\$_POSTと何が違うの??」
先日Laravelを初めて使用してサービスを作った際に先輩からご指摘をいただきました。
\$_POSTではなくRequestを?。。。はぁ?
調べてみるとなるほどな、納得納得。とまあこんな初心者レベルですが、備忘録として、あわよくば同じ立場の初心者さんのためにも残しておこうかと思います。
開発環境
PHP 7.3.25
Laravel 8.16.1Requestってなーに?
Laravelで、リクエスト(Request)というのは、ブラウザを通してユーザーから送られる情報をすべて含んでいるオブジェクトのことです。例えば、会員登録のフォームなら、画面でユーザーが入力したEメール、パスワード、名前、住所だけでなく、何のブラウザを使用したか(User Agent)、どのIPから送られたか、どのURLからアクセスしたかなど、また、会員ログイン後の画面なら、会員認証において保存されたクッキーもブラウザを介して、リクエストに含まれます。
引用:ララジャパンざっくりいうと、\$_POSTとか\$_GETとか、その他ユーザーが通信を行った情報を全てまるっとゴリっとまとめてくれたものか!
ちなみにこの\$_POSTとか\$_GETとかいうのは、PHPのスーパーグローバル変数の1つで、
これもブラウザからの情報を取得する際に使用できます。
詳細はこちらの記事を参考にするといいかも。ふむふむ、めちゃくちゃ便利じゃん!
でもなぜRequestを使った方がいいの?
例えばあなたの前に一般電卓と関数電卓があったとします。
四則演算の範疇に収まらない複雑な計算をするときに一般電卓でも出来ないわけではないですが、関数電卓があれば楽ちんに計算出来ますよね?そうです。
Requestの方が楽ちんなんです!
上記でも記載した通り、Requestには色々な情報がギュッと詰まっています。
ユーザーがブラウザからフォームで送信したデータはもちろん、
よく使うところの送信が行われたURLからユーザーのIPアドレスまでほんと色々。これは使わない手はないです。
他にも「型」にも違いがあります。
\$_POSTなどのハイパーグローバル変数は基本的に連想配列と文字列で構成されます。
それに比べてRequestはオブジェクト型で構成されます。さほど影響ないのでは?
果たしてそうでしょうか。。。取得データの扱いが変わります
まずは下記条件で実験してみましょう。
formデータ: // user_name→anomeme // test_data→空欄 <input name="user_name" class="form-control" type="text-input" value="anomeme"> <input name="test_data" class="form-control" type="text-input" value=""> $_POST array:2 [▼ "user_name" => "anomeme" "test_data" => "" ] request()->all() array:2 [▼ "user_name" => "anomeme" "test_data" => null ]お分かりいただけますでしょうか。
そう、test_dataのvalueが別物に変わってますよね?空白もnullも一緒じゃないか!と思う人がいるかもしれませんが、これは別物です。
・空白は文字列が0のデータ!
・nullは存在しないよ!
です。例えば isset() 関数でこれを見てみましょうか。
isset($_POST["test_data"]) → bool: true isset(request()->all()["test_data"]) → bool: false一緒のデータを使用しているのに結果が変わってしまいましたね?
(is_null() でも判定が変わりますね)長くなりましたが、requestは便利だけどこういった違いがありますよというお話でした。
終わりに
取れる値については他の人がさらに研究をしたりリファレンスを読み解いているので、こちらを参考にしてみるといいと思います。
PHPを勉強してきた人ならフォームデータを\$_XXXを取得したくなる気持ちは分かりますが、
一度に様々なデータが取得できるRequestを是非使ってみてください。
これは私からのリクエストです。
- 投稿日:2021-02-27T13:01:25+09:00
laravel6 メールのファイル添付機能で日本語のファイル名が文字化けした
目的
- laravel6のメールにファイル添付をする機能を作成したら日本語のファイル名が文字化けしたのて解決策をメモ的に紹介する。
環境
- ハードウェア環境
項目 情報 OS macOS Catalina(10.15.5) ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) プロセッサ 2 GHz クアッドコアIntel Core i5 メモリ 32 GB 3733 MHz LPDDR4 グラフィックス Intel Iris Plus Graphics 1536 MB
- ソフトウェア環境
項目 情報 備考 PHP バージョン 7.4.8 Homebrewを用いてこちらの方法で導入→Mac HomebrewでPHPをインストールする Laravel バージョン 6.X commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする 方法
- ファイル名指定部分にて
mb_encode_mimeheader()
を用いてファイル名を指定しエンコードを行うと正常に表示された。mb_encode_mimeheader(添付ファイル名)
とすることでエンコードすることができる。
- 投稿日:2021-02-27T12:13:47+09:00
【AWS】EC2インスタンスで作成したLaravelとRDS(MySQL)を連携させる方法
今回はAWSのRDS(MySQL)についてい書いていきます。
AWSにもDockerにも段々慣れてきたのですが、まだまだ知らない機能の方が多いですね。
さて、早速説明していきましょう。
はじめに
まず初めに前提条件として以下の条件を満たしている前提で話を進めめていきます。
・ECSで既にLaravelに関するコンテナの環境が構築済み
・EC2インスタンスへのSSH接続が可能上記2つの条件を満たしていな場合は下記の記事にすべてやり方が書いてあるので是非ご覧ください!
【AWS】AWS超初心者が、頑張ってDockerで作ったLaravelプロジェクトをECR、ECS、EC2を使ってAWS上で動かしてみた
RDSでMySQLのデータベースを作成
サービス検索欄から「RDS」と検索してください。
そして、「データベースの作成」をクリック。
するとこのような画面になると思います。
そしたら以下の条件を元にデータベースを作成してください。
データベースの作成方法 標準作成 エンジンのオプション MySQL バージョン 任意(大体8.*か5.7) テンプレート 本番稼働用 DBクラスター識別子 database-1 マスターユーザー名・マスターパスワード 任意 Virtual Private Cloud (VPC) 利用するEC2インスタンスと同じVPCを選択 パブリックアクセス可能 あり VPCセキュリティグループ 既存の選択 追加設定 最初のデータベース名(ローカル環境で使っていたデータベース名を入れるところ) 注意すべきポイントを2つ解説します。
1つ目は「Virtual Private Cloud (VPC)」です。
これは、書いてる通りEC2インスタンスと同じVPCを必ず選択してください。選択しないとEC2インスタンスへSSH接続したときにMySQLへアクセスできないのでくれぐれもご注意を。2つ目は追加設定の「最初のデータベース名」です。
「DBクラスター識別子」ではdatabase-1
と設定しましたが、これとは全く別物です。
例えばローカル環境でexample_database
という名前のデータベースを利用していた場合は、example_database
を「DBクラスター識別子」ではなく、「最初のデータベース名」に書いて下さい。また、ローカルでのデータベース名と本番環境用のデータベース名を分けたい場合でも「最初のデータベース名」に入力してください。
「データベースの作成」をクリックし、しばらくするとデータベースが作成されます。
SSH接続でMySQLのアクセス確認
次に、EC2インスタンスにSSH接続を行いMySQLへアクセスしてみます。
その前に先ほど作成したデータベースの画面へ行ってください。
「セキュリティ」の「VPCセキュリティグループ」をクリックしてください(sg-から始まるもの)
※注意 「ネットワーク」のVPCではございませんのでご注意を。
そしたらインバウンドルールの編集を行います。
SSH接続でMySQLにアクセスするために、利用するEC2インスタンスの「プライベート IPv4 アドレス」をコピーして、「すべてのトラフィック」で「IPv4アドレス/32」として追加してください。
例:10.0.0.0/32
また、LaravelからもMySQLのデータベースにアクセスできるようにタイプで「MYSQL/Aurora」を選んで「0.0.0.0/0」もしくはALBのセキュリティグループを選んでください。
そしてルールを保存してください。
これでSSH接続でMySQLにアクセスが可能になり、Laravelからもデータベースにアクセスすることができます。
試しにSSH接続でMySQLにアクセスしてみましょう!
ssh -i "C:~\zaemonia-ec2-key.pem" ec2-user@ec2-xxx.ap-northeast-1.compute.amazonaws.commysql -u{マスターユーザー名} -p -h{MySQLのエンドポイント} Enter password:{マスターパスワード} #パスワード入力は文字が出力されないのでコピペするのが良いかと無事MySQLにアクセス出来たら成功です!
これでアクセスできない場合は以下の事項を再確認してください。
・マスターユーザー名、マスターパスワード
・セキュリティグループのインバウンドルールこれら2つがしっかりと合っていれば必ずアクセスできます。
諦めずに頑張りましょう!!
以上、「【AWS】EC2インスタンスで作成したLaravelとRDS(MySQL)を連携させる方法」でした!
良ければ、LGTM、コメントお願いします。
また、何か間違っていることがあればご指摘頂けると幸いです。
他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい!!
あと、最近「ココナラ」で環境構築のお手伝いをするサービスを始めました。
気になる方はぜひ一度ご相談ください!
Thank you for reading
- 投稿日:2021-02-27T11:19:20+09:00
【Laravel6.x〜】デバッグするならdd()?いやいや、ddd()を使おう!!
概要
ZennやQiitaでLaravelの記事を色々見ていたらたまたま
ddd()
というデバッグ用のヘルパー関数を見つけたので実際に使ってみました。結論:今後は
ddd()
を使う!!環境
$ composer -V Composer version 1.10.20 2021-01-27 15:41:06 $ php artisan --version Laravel Framework 6.20.16dd()とddd()とは
どちらのデバッグ用のヘルパー関数です。
デバッグ関数 概要 dd() Laravel本体のヘルパー関数 ddd() facade/ignitionのヘルパー関数 (ヘルパー関数:PHPとは別にLaravelや各パッケージが用意している関数)
ddd()
はLaravel6.xから統合されたfacade/ignition
のヘルパー関数だそうです。Laravel Ignition Introduces the ddd() Helper
Laravel本体のヘルパー関数でないから
でも見つけることができませんでなかったわけですね。
※ddd()がfacade/ignitionのヘルパー関数であることはこの記事へのコメント、Twitterで教えていただきました。ありがとうございます?♂️(どちらもLaravel本体のヘルパー関数だと思っていました)
サンプルケース
記事投稿アプリで特定のidの記事の編集画面表示の処理とします。
ViewからControllerのアクションに記事(Article)クラスのインスタンス(=編集する記事データ)を渡している仕様とします。app/Http/Controllers/ArticleController.phpclass ArticleController extends Controller { // 略 /** * 記事編集画面表示 * * @param App\Article $article * @return \Illuminate\Http\Response */ public function edit(Article $article) { return view('articles.edit', compact('article'); } // 略 }dd()使用時の画面
app/Http/Controllers/ArticleController.phpclass ArticleController extends Controller { // 略 /** * 記事編集画面表示 * * @param App\Article $article * @return \Illuminate\Http\Response */ public function edit(Article $article) { // dd() dd($article); return view('articles.edit', compact('article'); } // 略 }モデルインスタンスの場合、多くの場合
- attributes:デバッグ対象のプロパティ
- relations:デバック対象のリレーション関係にある情報
を見るかと思いますし、
dd()
で取得できるのはそれくらいかと思います。ddd()使用時の画面
app/Http/Controllers/ArticleController.phpclass ArticleController extends Controller { // 略 /** * 記事編集画面表示 * * @param App\Article $article * @return \Illuminate\Http\Response */ public function edit(Article $article) { // ddd() ddd($article); return view('articles.edit', compact('article'); } // 略 }【Debugタブ(初期表示)】
これは
dd()
で表示される内容と同じですね。【Stack Traceタブ】
スタックトレースとは、こちらの記事でこう書かれています。
エラーが発生するまでに、どんな処理を、どの順番で呼び出したか表現したもの
こうは書いていますが、今回のように処理を中断した場合は中断したところまでの処理の流れを追えるようになっています。
今回の場合でいうと
public/index.php
の55行目がまずは実行されて、最終的にapp/Http/Controllers/ArticleController.php
の89行目(ddd($article);
)が実行されて処理が中断されているという流れがわかります。
(ここまでに計44個の工程があるんですね〜)【Requestタブ】
リクエストの情報が記載されています。
- GETであること
- CSRFトークンの値
- リクエストヘッダー
などが一目でわかります。
【App】
- Controller:実行したアクションメソッド
- Route name:ルーティング名
- Route Parameters:アクションメソッドに渡したパラメーター(引数にあたる)
- Middleware:ルーティングに設定したミドルウェア
こんな情報が一目で確認できます。
【User】
Userタブではログイン中のユーザーの情報が表示されます。
この情報は
dd(Auth::user());で取得できるUserクラスインスタンスのattributesプロパティから
password
の情報を除いたものです。(これはセキュリティの観点からなのかな...?)【Context】
- Repository:GitHubのリポジトリ
- Message:最新のコミットメッセージと
- Laravel version:Laravelのバージョン
- Laravel locale:言語設定
- Laravel config cache:設定ファイルのキャッシュをクリアしたか(※)
- PHP version:PHPのバージョン
(※)
この画像ではfalse
になっていますが、$ php artisan config:cache実行後に再度、
ddd($article);
するとtrue
に変わっていました。config系のキャッシュをクリアしてない(=config系の設定が反映されてない)ことに起因するエラーの発見もしやすくなりそうですね。
まとめ
ddd()
、めっちゃ良い!!
- UI(タブ切り替えでわかりやすい)
- 情報量(ログインユーザーや設定情報もすぐわかる)
の観点から完全に
dd()
の上位互換な印象ですね。
ddd()
ではなくdd()
を使う理由が見つからないので今後はddd()
使います。(もっと早く知りたかった...?♂️)
参考
- 投稿日:2021-02-27T00:46:32+09:00
もちろんバックエンドとのやり取りはCORS対策を行っていますよね???
皆さんバックエンドとのやり取りでCORS対策は行っていますか?
今回はLaravelでCORS対策を行うやり方を書いていこうかなと思います。
既にLaravelに触れたことのある方は
config\cors.php
を見たことがあるかと思います。config/cors.php<?php return [ 'paths' => ['*'], 'allowed_methods' => ['*'], 'allowed_origins' => ['*'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => true, ];実際はこんな感じに書いてあります。
ただ、これ注目し欲しいのが
allowed_origins
です。この中身を
*(アスタリスク)
にしてしまうと、全てのドメインから通信を行うことができてしまいます。便利かもしれませんが、本番環境でどのドメインからも通信を行うことができたら個人情報だだもれですね。
じゃあ対策をしてあげましょう!
ミドルウェアの作成
以下のコマンドを入力してミドルウェアを作成します。名前は適当に変えて下さい。今回はAPI通信用のCORS対策を行うので
ApiCors
としています。php artisan make:middleware ApiCorsそしたら
app\Http\Middleware\ApiCors(自分で決めた名前)
を開いてください。Middleware\ApiCors.php<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; class ApiCors { public function handle(Request $request, Closure $next) { if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { return $next($request) ->header('Access-Control-Allow-Origin', config('cors.allowed_origins')) ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS') ->header('Access-Control-Allow-Headers', ['X-Requested-With', 'Content-Type', 'Origin', 'Cache-Control', 'Authorization', 'Accept', 'Accept-Encoding']) ->header('Access-Control-Allow-Credentials', true); } else { return $next($request) ->header('Access-Control-Allow-Origin', config('cors.allowed_origins')) ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS') ->header('Access-Control-Allow-Headers', ['X-Requested-With', 'Content-Type', 'Origin', 'Cache-Control', 'Authorization', 'Accept', 'Accept-Encoding']); } } }
Access-Control-Allow-Origin
で通信を行うドメインを入力します。
config('cors.allowed_origins')
としているのは、環境変数としてローカルで開発をしている時と本番環境用に分けるためです。なんたって本番環境用にローカルホストのドメイン入力したら一発アウト。
Karnel.php
次に
Middleware\Kernel.php
に今作成したミドルウェアを登録します。Middleware\Karnel.phpprotected $routeMiddleware = [ 'apicors' => \App\Http\Middleware\ApiCors::class, 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, ];
'apicors' => \App\Http\Middleware\ApiCors::class
のようにします。
apicors
の部分はお好きな名前で。CORS対策の適用
routes\api.php
にCORS対策のミドルウェアを適用させます。routes\api.php<?php use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; use App\Http\Controllers\ApisController; /* |-------------------------------------------------------------------------- | API Routes |-------------------------------------------------------------------------- | | Here is where you can register API routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | is assigned the "api" middleware group. Enjoy building your API! | */ Route::middleware('apicors')->group(function() { Route::apiResource('/apis', ApisController::class); });こんな感じでCORS対策を行うことができます!
これでもまだセキュリティ対策は甘い方だと思います。
まぁでも一歩前進ということで。
以上、「もちろんバックエンドとのやり取りはCORS対策を行っていますよね???」でした!
良ければ、LGTM、コメントお願いします。
また、何か間違っていることがあればご指摘頂けると幸いです。
他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい!!
あと、最近「ココナラ」で環境構築のお手伝いをするサービスを始めました。
気になる方はぜひ一度ご相談ください!
Thank you for reading
- 投稿日:2021-02-27T00:22:11+09:00
npm install && npm run devした際のエラー
laravel8でnpm install && npm run devを実行し、npm ERR!というエラーが出た際に解決した方法を書きます。
下記コマンド実行
$ php artisan cache:clear実行結果
Cache cleared successfully下記コマンド実行
php artisan config:cache実行結果
Configuration cache cleared! Configuration cached successfully!再度下記コマンドを実行
npm install && npm run dev解決しました。