20210907のlaravelに関する記事は6件です。

【Laravel】ルーティングの基本的な書き方

はじめに ルーティングとは 「ユーザーがこのURLにアクセスしたらこの機能を呼び出す」というような感じで、URLと機能を紐付ける工程のことを言います。 Laravelでは、ユーザーからリクエストが送信されたら、ルーティングにしたがって決められたコントローラーのアクション(メソッド)が起動するという流れになります。 ルーティングは、routesディレクトリ内のweb.phpにRouteファサードを使って記述していきます。 記述方法 (1)「/」にアクセスしたら、viewsのwelcome.blade.phpを表示する。 web.php Route::get('/', function () { return view('welcome'); }); (2)「/menu」にアクセスしたら、MenuControllerのindexアクションを実行し、menusディレクトリ内のindex.blade.phpを表示する。 web.php Route::get('/menu', 'MenuController@index'); MenuController.php public function index() { return view('menus.index'); } Laravel8.xでは web.php Route::get('/menu', [MenuController::class, 'index']); と記述するようになったみたいです。 おわりに ルーティングは先(上)に記述した方が優先されるということは覚えておきましょう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel Authでユーザー登録後の遷移先を分岐する。

View inputタグをhiddenをかける。 register_blade.php <form method="POST" action="{{ route('register') }}" enctype="multipart/form-data"> : <input id="name" type="hidden" name="company_register" value=1 > # 見えない要素にしておく。 : </form> Controller redirectPath()メソッドを用いて、ルーティングに分岐をかける。 RegisterController.php // protected $redirectTo = '/'; public function redirectPath() { if($_POST["company_register"] == 1){ return '/company/new'; } return '/'; }  ログイン後の遷移も同じ要領で行う。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

phpunitでテストコードを書く時に使うテンプレ集&ネタ集

最近は、Laravelで開発されたアプリケーションのテストコードをphpunitで書いています。 今回は、テストをするときに使いまわせる部分だけ抜き出してまとめてみました。 リクエストクラスのバリデーションをテストしたい キーワード:request, rules(), dataProvider, データプロバイダ ■ポイント ・データプロバイダを使うと複数のパラメータパターンのテストが書きやすい&見やすい ・テストを実行するメソッドのアノテーションに@dataProvider を記載する。 ・テストケース名は「どのような値か 型 成功(success)or失敗(error)」でつけると分かりやすい。 テンプレ ... use App\Http\Requests\MyProfile\UserRegisterRequest; use Illuminate\Support\Facades\Validator; use Tests\TestCase; ...(略) /** * @test * @dataProvider dataproviderValidation */ public function validationCheck(array $params, bool $expected): void { $request = new UserRegisterRequest(); $rules = $request->rules(); $validator = Validator::make($params, $rules); $result = $validator->passes(); $this->assertEquals($expect, $result); } /** * バリデーションチェック用データ */ public function dataproviderValidation() { return [ 'email string success' => [ [ 'email' => "test@t.com", ], true, ], 'email null error' => [ [ 'email' => null, ], false, ], ]; } 説明あり(理解用) ... use App\Http\Requests\MyProfile\UserRegisterRequest; use Illuminate\Support\Facades\Validator; use Tests\TestCase; ...(略) /** * @test // テスト対象であることを示すアノテーション * @dataProvider {データを返すメソッド} // このアノテーションは必須 */ public function validationCheck(array $params, bool $expected): void { $request = new {テスト対象のリクエストクラス}; $rules = $request->rules(); $validator = Validator::make($params, $rules); $result = $validator->passes(); // true/falseが返る $this->assertEquals($expect, $result); } /** * バリデーションチェック用データ */ public function dataproviderValidation() { return [ '{テストケース名}' => [ // ケース失敗時にどのケースか分かりやすくなる [ '{パラメータ名}' => '{パラメータ}', ], {結果}, ], 'email null error' => [ [ '{パラメータ名}' => '{パラメータ}', ], {結果}, ], ]; } 参考: ・2. PHPUnit 用のテストの書き方 https://phpunit.readthedocs.io/ja/latest/writing-tests-for-phpunit.html#writing-tests-for-phpunit-data-providers ・【Laravel】フォームリクエストバリデーションのテストコード作成 https://qiita.com/n_mogi/items/57a946205df2a69889c2 リクエストクラスのバリデーションメッセージもテストしたい キーワード:request, rules(), dataProvider, データプロバイダ, message() ■ポイント ・関数の引数に array $messages を追加。setCustomMessages() でリクエストのmessages()を呼び出す。 ・assertSameでメッセージ内容をテスト。 テンプレ ... use App\Http\Requests\MyProfile\UserRegisterRequest; use Illuminate\Support\Facades\Validator; use Tests\TestCase; ...(略) /** * @test * @dataProvider dataproviderValidation */ public function validationCheck(array $params, array $messages, bool $expected): void { $request = new UserRegisterRequest(); $rules = $request->rules(); $validator = Validator::make($params, $rules); $validator = $validator->setCustomMessages($request->messages()); // 追記 $result = $validator->passes(); $this->assertEquals($expect, $result); $this->assertSame($messages, $validator->errors()->messages()); // 追記。メッセージをassert。 } /** * バリデーションチェック用データ */ public function dataproviderValidation() { return [ 'email null' => [ [ 'email' => null ], [ // メッセージのパラメータ配列を追加。パラメータの「array $messages」に対応。 'email' => [ 'Eメールを入力してください。', ], ], true ], ]; } リクエストクラスのwithValidator()もテストしたい キーワード:request, rules(), dataProvider, データプロバイダ, withValidator() ■ポイント ・$request->withValidator($validator); を追記する。 テンプレ ... use App\Http\Requests\MyProfile\UserRegisterRequest; use Illuminate\Support\Facades\Validator; use Tests\TestCase; ...(略) /** * @test * @dataProvider dataproviderValidation */ public function validationCheck(array $params, bool $expected): void { $request = new UserRegisterRequest(); $rules = $request->rules(); $validator = Validator::make($params, $rules); $request->withValidator($validator); // 追記 $result = $validator->passes(); $this->assertEquals($expect, $result); } /** * バリデーションチェック用データ */ public function dataproviderValidation() { return [ 'email string success' => [ [ 'email' => "test@t.com", ], true, ], 'email null error' => [ [ 'email' => null, ], false, ], ]; } ログ出力をテストしたい キーワード:log, 'logging.channels.stderr.level', getLogger(), popProcessor() ■ポイント ・setup()で現在のログレベル設定を取得。tearDown()で元の設定に戻す。 ・各テストケースの冒頭でログレベルを'debug'に設定する。 テンプレ ... use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Log; use Tests\TestCase; ...(略) private string $logLevel; protected function setUp(): void { parent::setUp(); $this->testTarget = new TestTargetLog(); $this->logLevel= Config::get('logging.channels.stderr.level'); } protected function tearDown(): void { parent::tearDown(); Config::set('logging.channels.stderr.level', $this->logLevel); } /** * @test * 【正常系】操作ログ:メッセージのログ出力を確認 */ public function operationSuccess() { Config::set('logging.channels.stderr.level', 'debug'); $content = []; $logMessage = "logTest Message"; Log::getLogger()->pushProcessor(function ($record) use (&$content) { $content[] = $record['message']; $content[] = $record['context']; return $record; }); $this->testTarget->operation($logMessage); Log::getLogger()->popProcessor(); $this->assertSame($content[0], $logMessage); $this->assertSame($content[1], ["operation" => true]); } 説明あり(理解用) ... use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Log; use Tests\TestCase; ...(略) private string $logLevel; // ログレベルバックアップ用変数 protected function setUp(): void { parent::setUp(); $this->testTarget = new TestTargetLog(); $this->logLevel= Config::get('logging.channels.stderr.level'); // 現在のログレベルを取得 } protected function tearDown(): void { parent::tearDown(); Config::set('logging.channels.stderr.level', $this->logLevel); // ログレベルを元に戻す } /** * @test * 【正常系】操作ログ:メッセージのログ出力を確認 */ public function operationSuccess() { Config::set('logging.channels.stderr.level', 'debug'); // ログレベルを'debug'に設定 $content = []; // ログを入れるための配列 $logMessage = "logTest Message"; Log::getLogger()->pushProcessor(function ($record) use (&$content) { // ログ取得処理 $content[] = $record['message']; $content[] = $record['context']; return $record; }); {"テスト対象の処理"} Log::getLogger()->popProcessor(); // ログ取得終わり $this->assertSame($content[0], $logMessage); $this->assertSame($content[1], ["operation" => true]); } protected, privateメソッドをテストしたい キーワード:protected, private, プロテクト, プライベート, Reflection ■ポイント ・ReflectionClassを使う テンプレ /** * @test */ public function Validation(): void { $params= [1]; $target = new TestTargetClass(); $reflection = new \ReflectionClass($target); $method = $reflection->getMethod('getMessages'); $method->setAccessible(true); $method->invokeArgs($target , [$params]); } 説明有り(理解用) /** * @test */ public function Validation(): void { $target = new {テスト対象のクラス}(); $reflection = new \ReflectionClass($target); $method = $reflection->getMethod({テスト対象のprotectedメソッド}); $method->setAccessible(true); $method->invokeArgs($target , [{メソッドに引数が必要な場合はここに書く}]); } モック作成には2種類ある キーワード:mock, createMock(), mockery, mock() ■ポイント ・「phpunitのcreateMock()」と「mockeryの\Mockery::mock()」の2種類 ・mockeryはモックのフレームワーク ・mockeryの方ができることが多い(?)  ex)mockeryはfinal, private, staticのモックが作成できる テンプレ // phpunitのモック $sampleMock = $this->createMock(SomeClass::class); $sampleMock->method('getNubmer') ->willReturn('123'); // Mockeryのモック $sampleMock = \Mockery::mock('SomeClass'); $sampleMock->shouldReceive('getNubmer') ->andReturn('123'); ちなみに... ・mockeryはuseでエイリアスを記載しておけばシンプルに書ける。 use Mockery as m; ... // Mockeryのモック $sampleMock = m::mock('SomeClass'); 参考 8. テストダブル https://phpunit.readthedocs.io/ja/latest/test-doubles.html 静的なメソッドをモックしたい キーワード:静的, モック, mockery ■ポイント ・mockeryのaliasを使う。 テンプレ $mockReplaceService = \Mockery::mock("alias:" . ReplaceServiceClass::class); $mockReplaceService->shouldReceive("getMemberName") ->andReturn("taro"); テストをスキップしたいとき キーワード:スキップ, skip, mark ■ポイント ・markTestSkipped()を使う。 ・元ソースに間違いがある時等に使う ・メッセージは任意。 ・結果が「S」と表示される。 テンプレ $this->markTestSkipped('ルール修正が必要.'); テストのログレベルを変更したいとき キーワード:ログレベル ■ポイント .ent.testing の LOG_STDERR_LEVEL=critical を変更する。 error に設定するとより詳細なログメッセージが確認できる。 最後に 他にもあれば随時更新していきます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelのAuthでユーザー登録時に、画像を登録したい。

Model やること $fillableを記述する。 User.php protected $fillable = [ 'name', 'email', 'password', 'avatar_file_name',// ⬅追加(画像のパス名カラム) ];  前知識として Eloquentモデルにおけるfillable属性 ホワイトリストのこと。 指定したカラムのみが、Modelに持たせることができる。 見れば分かる$fillableの機能⬇ protected $fillable = ['title', 'body']; $book = new Book([ 'name' => 'Soseki Natsume', 'title' => '猫', 'body' => '吾輩は猫である', 'published' => '1990' ]); $book->getAttributes(); ['name' => 'Soseki Natsume', 'title' => '猫',] $bookには$fillableで指定したカラム以外は入っていないことが分かる。 使い所 //この一文でfillabeに指定しているカラムは全て格納される。 //idなどは、書かなくてよいはず Book::create($request->all()); 参考 属性 機能 説明  $guard ブラックリスト 禁止したもの以外は入れる。 $fillable ホワイトリスト 許可したもの以外は入れない。 View やること formタグに、enctype="multipart/form-data"を追加する。 (form要素で enctype属性の値を"multipart/form-data"にする。) ただのURLエンコード➡マルチパート(メディア送信に対応) register_blade.php <form method="POST" action="{{ route('register') }}" enctype="multipart/form-data"> @csrf 前知識として form要素は、enctype属性を指定できる。 enctype属性で、送信時のMIMEタイプを指定できる。 MIMEタイプ=メディアタイプ Multipurpose Internet Mail Extensions 文書、ファイル、またはバイト列の性質や形式を示す標準 値 概要 application/x-www-form-urlencoded URLエンコード (デフォルト) multipart/form-data マルチパート URLエンコード:(あ → %E3%81%82) Controller やること 使用するクラスを増やす。 RegisterController.php : : use Illuminate\Http\File; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Storage; use Intervention\Image\Facades\Image; : : 画像保存用のメソッドを追加する。 RegisterController.php private function saveAvatar(UploadedFile $file): string { $tempPath = $this->makeTempPath(); Image::make($file)->fit(200, 200)->save($tempPath); $filePath = Storage::disk('public') ->putFile('avatars', new File($tempPath)); return basename($filePath); } private function makeTempPath(): string { $tmp_fp = tmpfile(); $meta = stream_get_meta_data($tmp_fp); return $meta["uri"]; } バリデーターを追記する。 RegisterController.php return Validator::make($data, [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 'password' => ['required', 'string', 'min:8', 'confirmed'], 'introduction' =>['required', 'string', 'max:255'], 'avatar' => ['required', 'image'], ]); createアクション内に画像保存の処理を追加する。 RegisterController.php protected function create(array $data) { $fileName = $this->saveAvatar($data['avatar']); //⬅privateで定義したメソッド呼び出し return User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => Hash::make($data['password']), 'avatar_file_name' => $fileName, //⬅カラムに画像名追加 ]); }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】Xdebugを導入する(mac × MAMP)

VSCodeの拡張機能のインストール PHP Debugをインストールする。 (VSCoedeの拡張機能のところで、felixfbecker.php-debugと検索) Xdebugのインストールと設定 macのMAMPにはXebugがデフォルトでインストールされれている。 Xdebugがインストールされているか確認する方法 適当なファイル(例:phpinfo.php)を作成し、以下のように記述する。 phpinfo.php <?php phpinfo(); ?> このページをブラウザで開き、Xdebugの記述があればインストールされている。 Xdebugについての記述が無い場合は、インストールを行う。 Xdebugのインストール方法(Xdebug3の場合) Xdebug Wizardを開く。 https://xdebug.org/wizard 先ほどのブラウザに表示されたphpinfoを全てコピーし、Xdebug Wizardのテキスト欄に貼り付ける。 「Analyse my phpinfo() output」をクリック。 InstructionsのところにダウンロードするべきXdebugが表示されるので、リンクをクリックしてダウンロードする。 Instructionの「2. Move the downloaded file to ~~~~」のパスをコピーし、エクスプローラーを開いて貼り付け、このパスまで移動する。ここに、4.でダウンロードしたファイルをドラッグ&ドロップする。 Instructionの「3. Edit ~~~~」のパスを辿り、php.iniを開く。「add the line」以下の「zend_extension = 」をphp.iniの一番下に追記する。(xdebug.mode=debugにしておく) サーバーを再起動し、phpinfoを開いてXdebugの記述があるか確認する。 インストール済みの場合の設定方法 phpinfoの「Configuration File (php.ini) Pathのconfの前までをコピー。Finderでこのパスまで移動する。/lib/php/extensions/no-debug~~/xdebug.so この「xdebug.so」が対象のファイルなので、このファイルまでのフルパスをコピーする。 phpinfoの「Configuration File (php.ini) Pathのconf/php.iniに、[Xdebug]の設定を追記する。 //Xdebug ver3の場合 [XDebug] xdebug.mode=debug,develop,trace xdebug.start_with_request = yes zend_extension = C:\MAMP\bin\php\php7.4.1\ext\php_xdebug-3.0.0-7.4-vc15.dll ※zend_extensionはXdebug Wizardでコピーした値 //Xdebug ver2、またはMacの場合 [XDebug] xdebug.remote_enable = 1 xdebug.remote_autostart = 1 xdebug.remote_port = 9010     zend_extension = C:\MAMP\bin\php\php7.4.1\ext\php_xdebug-2.0.0-7.4-vc15.dll ※Windowsの場合:zend_extensionはXdebug Wizardでコピーした値 ※Macの場合:xdebug.soまでのパス 3.サーバーを再起動して、設定を反映させる。 VSCodeの設定 デバッグの設定(サイドバーの虫のアイコン)より、「launch.json ファイルを作成します。」をクリック。「PHP」を選択する。 .vscode/launch.jsonが作成されるので、以下の通り編集する。これより下は不要なので削除する。 vscode/launch.json.php { // IntelliSense を使用して利用可能な属性を学べます。 // 既存の属性の説明をホバーして表示します。 // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Listen for Xdebug", "type": "php", "request": "launch", "port": 9010,                     //php.iniのポートと同じに。 "stopOnEntry": true }, ] } PHPのワーニングを画面表示する ※ワーニングエラーも、開発環境では確認できる方がよいので。 php.iniを開き、「display_errors」と検索する。 「display_errors = On」に変更する。 サーバーを再起動して、設定を反映させる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【laravel】laravel+Reactを使ってSPAにしてみる

初書:2021/09/06 mac : 11.5.2 php:v8.0.6 laravel:v8.57.0 前書き 最近Reactを知ったのでせっかくならLaravelでも使ってみよう、というメモ。 前提 Laravelインストール済み。 素のPHPしか触ってなかった人がlaravelを触ってみる - Qiita インストール まずはuiをインストール % composer require laravel/ui その後はuiをreactに変更 % php artisan ui react インストールとmix % npm install && npm run dev もし、Please run Mix again.と言われた場合はもう一度npm run devします。 以上 Typescriptにする ReactといえばTypescript…と、勝手に思ってるので、Typescriptで書けるように追加していく。 インストール まずは必要なものをインストール % npm install --save-dev ts-loader typescript react-router-dom @types/react @types/react-dom @types/react-router-dom react-router-domと@types/react-router-domはSPAを作る場合。laravel側でルーティングする場合は不要。 でもこの記事では使います。 tsconfig.jsonの設定 % npx tsc --init これでtsconfig.jsonが生成される。 設定は好みだが、一応今設定しているものを置いておく。 tsconfig.json { "compilerOptions": { "target": "ES2020", "lib": [ "ES2020", "DOM", ], "jsx": "react-jsx", "module": "AMD", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true }, "include": [ "resources/ts/**/*" ] } targetはES2020を選択。頻繁なアプデを好まない層(IEとか古いiOSとか)がこないサイトなら最新のものでいいと思う。 moduleはAMDを選択した。es2020とかとの違いはあんまり分かってない。(非同期で読み込める点?でものちに1ファイルにまとめる・・・。) 各ブラウザの対応状況:ECMAScript 2016+ compatibility table ページを作成する 今回はメインページとサブページを作る。 laravelでtsを置くのは基本的にresourcesディレクトリなので、この下に作成する。 resources/ts/app.tsx import ReactDOM from "react-dom"; import { BrowserRouter, Route, Switch } from "react-router-dom"; import main from "./main"; import sub from "./sub"; function App() : JSX.Element { return ( <BrowserRouter> <Switch> <Route exact path="/" component={main} /> <Route exact path="/sub" component={sub} /> </Switch> </BrowserRouter> ); } ReactDOM.render(<App />, document.getElementById("root")); resources/ts/main.tsx import React from "react"; import { Link } from "react-router-dom"; const element = (): JSX.Element => { return ( <div> <p>メインページです。</p> <Link to="/sub">サブページへ</Link> </div> ); }; export default element; resources/ts/sub.tsx import React from "react"; const element = (): JSX.Element => { return <p>サブページです。</p>; }; export default element; React、最近は関数型の書き方の方が良いって聞いたので関数型を使ってみた。 基盤となるapp.tsxとページを表示するmainとsubを作成。 これが出来れば、それを表示するためのwelcome.blade.phpを変更する resources/views/welcome.blade.php <!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Laravel</title> </head> <body class="antialiased"> <div id="root"> </div> </body> <script src="{{ mix('js/app.js') }}"></script> </html> 表示用のdivと、読み込みスクリプトがあれば後は自由。 ページは以上 laravel mixを使う そのままではapp.jsなるファイルは存在していないので、作成する。 普通にインストールしていると、webpack.mix.jsが既に存在しているので、これを編集する。 webpack.mix.js const mix = require('laravel-mix'); mix.js('resources/ts/app.tsx', 'public/js') .react() .webpackConfig({ module: { rules: [ { test: /\.tsx?$/, loader: 'ts-loader', exclude: /node_modules/, }, ], }, resolve: { extensions: ['*', '.js', '.jsx', '.ts', '.tsx'], }, }) .version(); react()が何するのかよく分かってない。誰か教えてください(他人頼り) これで、npm run devを実行すると、先ほど作ったapp.tsx関連がapp.jsにまとめられる。 一度アクセスしてみる これで一度アクセスしてみる。 php artisan serveでサーバーを立て、http://127.0.0.1:8000/にアクセスすると、先程のメインページですが表示されているはず。 また、サブページへを押すと、http://127.0.0.1:8000/subにアクセスされ、サブページですが表示される。 一見これでいいように見えるが、直接http://127.0.0.1:8000/subにアクセスすると、laravel側からurlが存在していないと言われる。 これは、subページがReact内だけで作成されているだけのため。 この先は仕様次第だが、今回はReact側でアクセス処理を任せることにする 全てのアクセスをapp.tsxにまとめる アクセスはroutes/web.phpで管理しているので、ここを変える routes/web.php Route::get('/{any}', function () { return view('welcome'); })->where('any', '.*'); 元々あった/を/{any}に変え、条件を全てに変更した。 where文があるのは、/もanyに含まれるようにするため。 これで、直接http://127.0.0.1:8000/subにアクセスしても、サブページですが表示される。 終わりに この後ブラウザとサーバー側でデータのやりとりをするため、APIの設定等をしないといけないが、長くなりそうなので今回は一旦ここで切り上げ。 まだ試行錯誤段階なので、やり方異なってたり、よりいい方法とかあれば更新する…かも。 参考サイト React.JS + Laravel 8 + MySQL + API REST でCRUDを作ってみた。 【環境構築】LaravelでReactとTypescriptを使う方法 - Qiita 【Typescript×React】tsconfig.jsonの設定項目を詳しく紹介 - Qiita laravel-mixでtypescript + reactをビルドする - Qiita
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む