- 投稿日:2019-05-26T21:50:48+09:00
LaravelでクエリビルダのJoinを使って検索機能を作ろうとしたらハマった
当方、Laravel初心者です。
Eloquentモデル
をクエリビルダのjoin()
を使って関係するテーブルのカラムを使って絞り込んだら、
検索対象じゃないモデルのインスタンスが返ってきて小一時間悩みました。まとめ
Eloquentモデル
をクエリビルダのjoin()
を使ってインスタンスを取得したら、
id
というカラムが複数存在したため、
想定外のインスタンスが返ってきた。
↓
同じカラム名はLaravel内の処理で上書きされる。
Select()
で取得するカラムを絞ろう!詳細
たとえばこんなコード。
$searched_posts = Post::join('comments', 'posts.id', '=', 'comments.posts_id') ->where('comments.text', 'like', '%あいうえお%')->get();
posts
テーブルにもcomments
テーブルにも「id
」というカラムがある前提です。上記のコードをSQLに変換されると多分こんな感じになります。
select * from posts inner join comments on posts.id = comments.post_id where comments.text LIKE '%あいうえお%';仮にSQLの実行結果が以下のような感じだったとします。
id post_content id text 1 あああ 2 あいうえお 3 ううう 3 あいうえお 5 おおお 4 あいうえお これで
Post
モデルのインスタンスが3つ取れて、
post_content
はそれぞれ「あああ」「ううう」「おおお」
となるんだろうな とおもったら
なぜか全然違うPostが返ってきました。そうです。
id
カラムが重複して存在するため、
posts.id
をcomments.id
が上書きしてしまい、
id
が2
,3
,4
であるPost
がモデルインスタンスとして取得されてしまいました。解決策
selectで取ってくるカラムを絞る。
$searched_posts = Post::select('posts.*')->join('comments', 'posts.id', '=', 'comments.posts_id') ->where('comments.text ', 'like', '%あいうえお%')->get();
select('posts.*')
のように、取得するカラムを絞り込むことで、id
というカラムが重複しないようにしましょう。こういうハマりポイントは知っていればすぐ解決できるのに、知らないと結構はまってしまいますよね。
Laravelを覚えるにあたって先にハマりポイントを押さえておこうと思いましたそもそもクエリビルダのJoinを使って検索をするっていうのがイケてないっぽいので
よりよい方法があれば教えていただきたく思います。
whereHas()
を使うといいのかな?Post::whereHas('Comment', function($comment){ $comment->where('text', 'like', '%あいうえお%');以上、お役に立てれば幸いです
参考
laravelのクエリビルダでJOINしたら、同名カラムの値が上書きされるという事案発生
Laravel Eloquent でハマらないために知っておきたいこと
- 投稿日:2019-05-26T20:48:26+09:00
Laravel で Service 層を取り入れるときに検討したいこと
この記事について
普段何気なく使っている Service クラス(Service 層)について、書籍を中心にその役割や目的について書かれた資料を読みながら、Laravel 製のウェブアプリケーションに Service 層を取り入れる際の判断材料となるような情報や観点を、提供できればと思います。
以前にも調べたり考えたりしたんですが、そのときは明確な役割や使い方の提案ができなかったので、それの補遺的な位置づけになります。
Laravelでウェブアプリケーションをつくるときのベストプラクティスを探る (9) Service編 - Qiita
Service レイヤーとは
これ
出典: Martin Fowler's Bliki
https://martinfowler.com/eaaCatalog/serviceLayer.htmlどんなときに Service 層が必要になるか
Despite their different purposes, these interfaces often need common interactions with the application to access and manipulate its data and invoke its business logic.
そういった異なる目的(訳者注: 上図の Data Loaders、User Interfaces、Integration Gateway の目的)にかかわらず、これらのインタフェースには、データを操作したりビジネスロジックを実行し対するために、アプリケーションとの共通のやりとりが必要になるときがある。
ようするに、UI からだけでなく、CUIのプログラムとか他システムとの連携部分とかで、共通のロジックを呼ぶ必要があるときに、Service レイヤー越しにドメインロジックを処理すると、共通のインタフェースで操作できるようになるよね、ということと理解できます。
たとえば、
// via Web User Interface class SomeController extends Controller { public function someAction(Request $request) { $this->someService->doSomething($request->all()); } } // via Command class SomeCommand extends Command { public function handle() { $this->someService->doSomething($this->options()); } } // via Another Service class AnotherService { public function doSomething() { $this->someService->doSomething($params); } }このように処理をラップすることで、上記3つのクライアントがそれぞれ、引数の構築だけを担って、実際の処理を Service クラスに移譲することができるようになります。
Service クラスとは
Service には2種類ある
- Application Service: Application 層にある Service(何の説明にもなってないですが、後述します)
- Domain Service: Domain 層にある Service(何の(ry
Domain Service の定義
Domain といえば「ドメイン駆動設計」ですね。
「ドメイン駆動設計」では、巻末で以下のように定義されています:
SERVICE An operation offered as an interface that stands alone in the model, with no encapsulated state.
Evans, Eric. Domain-Driven Design
「サービス
モデルの中で独立したインタフェースとして提供される操作、カプセル化された状態を持たない。」ちょっとこれだけだとよく分からないので、もう少し詳細な説明を探してみます。
When a significant process or transformation in the domain is not a natural responsibility of an ENTITY or VALUE OBJECT, add an operation to the model as a standalone interface declared as a SERVICE.
「ドメインにおける重要な処理や変換が、エンティティや値オブジェクトの自然な責務ではない場合、サービスとして宣言された独立したインタフェースとしての操作をモデルに追加してください。」
さらに、以下のような記述もあります。
Unlike ENTITIES and VALUE OBJECTS, it is defined purely in terms of what it can do for a client.
「エンティティや値オブジェクトとは異なり、純粋に、クライアントに対してなにができるか、という観点でのみ定義されます。」
ドメインとはなにか、というのは下記の記事も参照してください。
ドメインモデル、ドメインロジックとは何かをコードを交えて考えてみる - Qiita
Application Service の定義
It can be harder to distinguish application SERVICES from domain SERVICES. The application layer is responsible for ordering the notification.
Evans, Eric. Domain-Driven Design
「Application Service と Domain Service を区別するのはもう少し難しいかもしれない。Application 層の責務は通知を命令することである。」
この文の前段で、銀行のシステムで口座の残高がある閾値を超えた場合にメールを送信する、というような例が紹介されていて、閾値のチェックは Domain 層、メールの送信を命令するのは Application 層、メールを送信するのは Infrastructure 層、という切り分けであると述べています。
また他の箇所では、
layer. For example, if the banking application can convert and export our transactions into a spreadsheet file for us to analyze, that export is an application SERVICE.
Evans, Eric. Domain-Driven Design
Spreadsheet へのエクスポート機能も Application Service と言っています。
明確な定義はないものの、Infrastructure 層(メールなどの通知系、ファイルやデータベースの操作、など)へ命令を下すのが Application Service である、と言えそうです。
よい Service の特徴
- The operation relates to a domain concept that is not a natural part of an ENTITY or VALUE OBJECT.
- The interface is defined in terms of other elements of the domain model.
- The operation is stateless.
Evans, Eric. Domain-Driven Design
- その操作が、エンティティや値オブジェクトの自然な一部でないようなドメインの概念に関連したものである
- そのインタフェースが、ドメインモデルの他の要素の観点から定義されている
- その操作が、状態を持たない
Laravel における Service
Service Providers のセクションに出てきます。
Your own application, as well as all of Laravel's core services are bootstrapped via service providers.
あまり深くは見ませんが、config/app.php で
providers
に登録されている様々な Service Provider の中身を見てみると、命名だったり、初期化の仕方だったり、を参考にできるかもしれません(ただし、後述しますが、アプリケーションで Service をつくるときは、必ずしもサービスコンテナに登録する必要はないと考えています)。Facade は一種の Service である(と言えるのではないか)
そうして見てみると、いくつかの Facade が Service Provider で登録されていることが分かりました。
そうでない Facade についても、たとえば Log の場合、
- ウェブアプリケーションフレームワークというドメインにおいて、ログ操作というのは、どのモデルにも属さない独立した操作である
- とはいえ、デバッグ、エラー、といった、アプリケーションの状態に関わるインタフェースがある
- 状態を持たない
といった特徴があり、よい Service クラスの特徴に合致しています。
「Facade は一種の Service である」と考えると、どういう機能を Service 化するのがいいのか、のヒントになるような気がします。
Application 層と Domain 層の境界
- Application 層
- UI
- Request(アプリケーション外部からの入力パラメータ)
- Job/Event(アプリケーションの外部に対する通知やコマンド実行)
- Response(アプリケーション外部への出力パラメータ)
- Command(php artisan CLI で実行されるコマンド)
- app/Http, app/Console, Exceptions, Events, Listeners, Jobs, Policies, Providers
- Domain 層
- Laravel に依存しない部分、DB に依存しない部分
- 厳密には上記の定義だが、Eloquent Model (Active Record) はドメインロジックを書く一方で、中で DB に依存した処理が含まれるものもあり、境界はあいまい
- Laravel ではどこに配置するかは決まっていない
- app 以下じゃなくてもいい
- Service 層
- Application 層と Domain 層の間に位置し、Application Service はアプリケーション層に、Domain Service は Domain 層に配置する
- Infrastructure 層
- DB
- Notification (mail, slack, etc.)
- Queue (database, redis, etc.)
Application Service の例
例1: Excel への Export
なんらかのデータを整形して Excel 形式のファイルに出力してダウンロードするというのは、Service 化がもっとも適した例だと思います。
$activeUsers = User::active()->get(); // 出力形式の他にテンプレートファイルを渡すのもいいかもしれません $exporter = Factory::factory(ExportType::Excel); // ファイルに保存するなら $exporter->toFile($activeUsers, $dir, $name); // Response として返すなら $exporter->toStream($activeUsers);例2: 複数のエンティティを一度に更新するようなケース
たとえば UI の都合で、複数のエンティティを一度に更新するといったケースでは、Controller から直接操作するよりも、Service を挟んだほうがいい気がします(UI が頻繁に変わる場合でも、Controller に影響が及ばないようにできます)。
エンティティを個別に操作するパターン
class SomeController { public function update(UpdateRequest $request) { $someModel->update($request->someAttributes()); $otherModel->update($request->otherAttributes()); } }Serivce を介して更新するパターン
class SomeController { public function update(UpdateRequest $request) { $this->updateSomeServce->update($request->validated()); } }Domain Service の例
例1: ECサイトにおける Recommendation
Recommend されるのは「商品」だが、「商品」に「レコメンド」の責務を持たせるのは不自然かな、と思ったら、Service クラスに切り出すことができるでしょう。
「おすすめ」インタフェースに対して複数の実装を持たせ、内部のアルゴリズムをインタフェース越しに差し替えることもできます。
class RecommendController { public function __invoke() { $user = Auth::user(); return $this->recommender->recommendTo($user); // Userに合わせたレコメンド } }例2: ホテルの予約サービスにおける Reservation
「予約」というエンティティがあるにはあるが、「予約」という振る舞いに対して、内部で複数のエンティティを連動して操作しなければいけないときに、Service クラスに切り出すことができるでしょう。
ロジックが巨大で複雑になるようなら、さらに「空き状況確認サービス」などといった処理ごとに別の Service に分解してもいいかもしれません。
class Reservation { public function invoke(Accommodation $accommodation) { if ($this->vacancyFinder->vacant($accommodation)) { throw new AlreadyOccupiedException('…'); } // ... } }Service 層を取り入れる際に検討したいこと
振る舞いを Entity に持たせるか Service に持たせるか
Service を使ったバージョン
class ReservationService { public function cancel(Reservation $reservation) { $reservation->is_cancelled = true; $reservation->save(); } } // Client $this->reservationService->cancel($reservation);エンティティにメソッドを持たせず、プロパティを直接変更しています。
Entity を使ったバージョン
class Reservation { public function cancel() { $this->is_cancelled = true; $this->save(); } } // Client $reservation->cancel();こちらは、プロパティの変更はエンティティ内で行い、クライアントはエンティティのメソッドを呼び出しています。
「キャンセル」という操作と、実際に更新されるデータが分離されているので、仮にデータ構造が変わり、更新する対象データが変わっても、クライアントに影響が及ぶことがありません(
is_cancelled
の代わりにcancelled_at
にキャンセル日時を入れるようにした場合、とか)委譲するかしないか
Service を使ったバージョン
class SomeService { public function create(SomeModel $model) { return $this->repository->create($model); } public function update(SomeModel $model) { return $this->repository->update($model); } }いわゆる Repository パターンを使った、Controller -> Service -> Repository という流れでのデータ操作の方法です。
Entity を使ったバージョン
$someModel->create($attributes); $someModel->update($attributes);単純に委譲しているだけなら直接 Model を書き換えることを検討してもいいと思います(無理に Service 層と Repository を経由する必要はないと思います)。
関連する操作をまとめるか分けるか
決済関連のメソッドをまとめるパターン
class PaymentService { public function doPayment() {} public function doRefund() {} }Service には状態がないので、いくつ公開メソッドをつくっても基本的には問題にはならないです。
1クラス1メソッドのパターン
class PaymentService { public function invoke() {} } class RefundService { public function invoke() {} }しかし、個々のメソッドの行数が長くなって見通しが悪くなってきた場合、クラスを分けてしまったほうがいいと思います。
まとめ
Service とは何かというところから、実際に Laravel にどう組み込んで使うかというところまで、ざっと見てみましたが、どのようなケースで Service 化するといいか、というのが少し見えてきた気がします。
他にもこういう処理は Service 化するといい、などの提案や、文中の定義や例の部分で改善点みたいなのがありましたら、ぜひコメント欄にてご指摘ください
- 投稿日:2019-05-26T15:35:55+09:00
paiza cloudのHTTPSの制限でハマった
概要
PaizaCloud
を使うと、簡単に開発環境を構築することができる。有料プランなら、常時公開もできるようになる。
https://paiza.cloud/ja/Laravel勉強用にPaizaCloudで開発環境を構築していたところ、
HTTPS周りのことでつまずいて、初心者はきっとハマると思うので誰か困った時に参考にしてもらえるように、メモ。詳しく
php artisan make:auth // ログイン認証画面を作成 php artisan migrate // DBに反映 php artisan serve --host=0.0.0.0これで、ログイン画面ができたので、
xxx.paiza-user.cloud:8000
にアクセス。
しかし、右上の
LOGIN
を押しても、
Please use HTTPS(SSL) instead of HTTP to access the URL.
と表示され、ログイン画面が表示されない…
ローカル環境ならちゃんと表示されるのに、なぜだ...なぜなのか
- ログイン画面へのリンクが、
http
で張られていたトップページが
https
で表示されているので、当然https
だと思ってリンクがhttp
なのに気が付かなかった・・・PaizaCloudで非SSLなアクセスがあった際、
解決策
[コメントを受け、追記]
ここでhttpsとならないのは、X_FORWARDED_PROTO を使った判定をしていないため。app/Http/Middleware/TrustProxies.php// 略 class TrustProxies extends Middleware { /** * The trusted proxies for this application. * * @var array|string */ protected $proxies = "*"; // ここに"*"を指定する /** * The headers that should be used to detect proxies. * * @var int */ protected $headers = Request::HEADER_X_FORWARDED_ALL; }こちらの記事で詳しく解説されている。
https://qiita.com/yamatox/items/8f3f481d88e807793ad5以下は、forceSchemeを使う方法。この方法では、扱うURLをhttpsに強制する。
AppServiceProvider bootメソッドでUrlGeneratorクラスforceSchemeメソッドを呼び出して、
アプリ内で扱われるURLを全てhttpsにする。
こうすることで、リンクがhttpsで出力されるようになる。app/Providers/AppServiceProvider.php<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Routing\UrlGenerator; class AppServiceProvider extends ServiceProvider { /** * Register any application services. * * @return void */ public function register() { // } /** * Bootstrap any application services. * * @return void */ public function boot(UrlGenerator $url) { // force to use HTTPS $url->forceScheme('https'); } }参考
[Laravel]常時SSLなアプリケーションでのURL生成のベストプラクティスを考える
https://qiita.com/hisash/items/4b3bb1ea47c38b0d8c86
- 投稿日:2019-05-26T15:22:49+09:00
Laravel で API コントローラのテストをする (FeatureTest 編)
Laravel で HTTP コントローラをテストするために FeatureTest を書く。サンプルプロジェクトは GitHub にあります。
UnitTest と FeatureTest の違い
Laravel には UnitTest(ユニット・テスト)と FeatureTest(フィーチャー・テスト)の2つのテストがある。
それぞれ保存されるディレクトリがtests/{Unit,Feature}
と違うだけで、テストの書き方は変わらない。違いはテストの 対象範囲 だけ。
UnitTest は小さなコードの一部をテストする。単体のモデルやモデルのメソッドを独立してテストする。
FeatureTest は複数のオブジェクトが関連した機能をテストする。主にコントローラのテストに使用する。テストを実行する
トップディレクトリで
phpunit
または./vendor/bin/phpunit
コマンドを実行するとテストが実行される。引数がなければtests/
ディレクトリにある全ての UnitTest と FeatureTest が実行される。$ phpunit # 全てのテストを実行 $ phpunit tests/Feature/UserControllerTest.php # 特定のテストを実行この他にも
--filter
オプションでテスト対象をフィルタリングできる。詳細はphpunit
のマニュアル参照。
phpunit
を実行すると結果が出力される。$ phpunit PHPUnit 7.5.11 by Sebastian Bergmann and contributors. .. 2 / 2 (100%) Time: 118 ms, Memory: 16.00 MB OK (2 tests, 2 assertions)最終行の
OK (2 tests, 2 assertions)
は2つのテストが実行されて 2つの検証(アサーション)にパスしたことが表示されている。テストの設定
phpunit
を実行すると Laravel のApp::environment()
はtesting
に設定される。.env
を読み込んだ後に.env.testing
で上書きされるので、変更したい値のみ設定することができる。テストに使用する DB のマイグレーションは
--env testing
を指定して実行する。# .env.testing で指定されたDBのマイグレーション $ php artisan migrate --env testing # DBのリセット $ php artisan migrate:fresh --env testingPHPUnit の設定は
phpunit.xml
で変更できる。テストの全体像
全てのテストクラスは PHPUnit の
TestCase
クラスを継承する。継承したクラスは「テストケース」と呼ばれ、複数の「テスト」メソッドを保持する。
phpunit
コマンドが実行されると、クラス名がTest
で終わっているクラスを読み込み、全てのtest
で始まるメソッドを実行する。DB はテスト毎にデータを初期化して空の状態で開始される。
Laravel には DB のトランザクションをロールバックするtrait DatabaseTransactions
があり、これを利用することでテスト実行後に DB を初期化することができる。テストケースの実行フロー
全てのテストメソッドに対して、以下のフローで繰り返し実行される。
TeseCase::setUp()
テストケースのセットアップメソッドを実行- DB のトランザクションを開始
TestCase::test*()
テストメソッドの実行
- 初期データの作成
- HTTP リクエスト送信
- レスポンス検証
- DB検証
- DB のロールバック
FeatureTest を作成する
実際にテストケースを作成して
User
モデルを API で操作するUserController
のテストを書いてみる。FeatureTest は
php artisan make:test
コマンドで作成できる。$ php artisan make:test UserControllerTest # パスを指定する $ php artisan make:test Http/Controllers/UserControllerTest作成されたテストクラスに DB 初期化用の
trait
とテスト前に必ず実行されるsetUp()
メソッドを追加する。use Illuminate\Foundation\Testing\DatabaseTransactions; class UserControllerTest extends TestCase { // データベースの初期化にトランザクションを使う use DatabaseTransactions; public function setUp(): void { parent::setUp(); } public function testIndex() { // 検証(assert) をココに書く } }実際のプロジェクトではベースとなる
TestCase
クラスを作成して共通化する
index
アクションのテスト
index
アクションの仕様はGET
リクエストを送信するとusers
テーブルのデータを JSON の配列で返す API を想定する。テストでは事前に1件のデータを作成して
GET
リクエストでデータが返ってくることを検証する。public function testIndex() { // `users` テーブルにデータを作成 (Tips参照) factory(User::class)->create([ 'email' => 'user1@example.com', ]); // GET リクエスト $response = $this->get(route('users.index')); // レスポンスの検証 $response->assertOk() # ステータスコードが 200 ->assertJsonCount(1) # レスポンスの配列の件数が1件 ->assertJsonFragment([ # レスポンスJSON に以下の値を含む 'email' => 'user1@example.com', ]); }
$this->get()
を呼び出すとGET
リクエストを送信することができる。レスポンス$response
を取得したら検証用のメソッドassert*
を呼び出して正しいレスポンスが返ってきていることを検証している。このテストを書いて
phpunit
を実行すると以下のように表示される。$ phpunit tests/Feature/UserControllerTest.php PHPUnit 7.5.11 by Sebastian Bergmann and contributors. . 1 / 1 (100%) Time: 130 ms, Memory: 18.00 MB OK (1 test, 3 assertions)1つのテストが実行されて3件のアサーションをパスした。
POST
DELETE
メソッドを使ったテストも追加する。public function testStore() { $data = [ # 登録用のデータ 'user' => [ 'email' => 'user@example.com', 'name' => 'Tanaka Taro', 'password' => '123456', ], ]; // POST リクエスト $response = $this->post(route('users.store'), $data); // レスポンス検証 $response->assertOk() # ステータスコードが 200 ->assertJsonFragment([ # レスポンス JSON に以下の値を含む 'email' => 'user@example.com', 'name' => 'Tanaka Taro', ]); } public function testDestroy() { // `users` テーブルにデータを作成 $user = factory(User::class)->create([ 'email' => 'user1@example.com', ]); // DELETE リクエスト $response = $this->delete(route('users.destroy', [$user->id])); // ステータスコード 200 $response->assertOk(); // `users` テーブルが0件になっている $this->assertEquals(0, User::count()); }
phpunit
を再実行する。$ phpunit tests/Feature/UserControllerTest.php PHPUnit 7.5.11 by Sebastian Bergmann and contributors. ... 3 / 3 (100%) Time: 174 ms, Memory: 20.00 MB OK (3 tests, 8 assertions)3件のテストが実行され、8件のアサーションをパスした。
検証 (アサーション)
1つのテストに複数のアサーションを書くことができる。アサーションが1つでも失敗すると、そのテストは
失敗(F)
として表示される。レスポンスクラスの
$response->assert*
メソッドはレスポンスを対象にした検証メソッドが実装されている。
TeseCase
クラスの$this->assert*
メソッドは値の一致、不一致、null
チェックなどレスポンスに依存しないメソッドが実装されている。また、上記の他に DB の内容を直接検証できるメソッドも存在する。
よく利用する検証メソッド
メソッド名 クラス 説明 assertEquals($a, $b)
TestCase
$a
と$b
が一致するassertTrue($b)
TestCase
$b
がtrue
assertNotNull($o)
TestCase
$o
がnull
ではないassertArraySubset($subset, $a)
TestCase
配列 $a
に部分配列$subset
を含むassertOk()
レスポンス ステータスコードが 200
assertJsonCount($n)
レスポンス(JSON) JSON配列レスポンスの件数が $n
件assertHeader($h, $v)
レスポンス レスポンスヘッダ $h
の値が$n
であるassertSee($t)
レスポンス(HTML) HTMLに文字列 $t
が存在するassertDatabaseHas($t, array $a)
TestCase
テーブル $t
に$a
に一致するレコードが存在するassertSoftDeleted($, array $a)
TestCase
テーブル $t
の$a
に一致するレコードが論理削除されているその他のアサーション
Tips
よく利用するイディオムや関連ツール。
モデルファクトリー
Laravel にはテストデータの作成を簡単にするファクトリーという機能がある。
事前に定義しておいた値で DB にデータを投入できる。データの定義
// database/factories/UserFactory.php // User モデルのファクトリクラス use Illuminate\Support\Str; use Faker\Generator as Faker; use App\User; // define() で事前データを定義する $factory->define(App\User::class, function (Faker $faker) { return [ 'name' => $faker->name, 'email' => $faker->unique()->safeEmail, 'email_verified_at' => now(), 'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret 'remember_token' => Str::random(10), ]; }); // データに名前を付けて複数定義することもできる $factory->state('user2')->define(...);データを作成するときは
factory()
関数にクラス名を渡す。use App\User; // DBに保存された User モデルが返る $user = factory(User::class)->create(); // 特定の値だけ上書きして作成する $user = factory(User::class)->create([ 'id' => 1, 'email' => 'tanaka@example.com', ]); // 10件作成 $user = factory(User::class, 10)->create(); // DBに保存せず new User() したモデルを取得 $user = factory(User::class)->make(); // 名前を付けたモデルを取得 $user = factory(User::class)->states('user2')->make();詳細は Laravel のマニュアル を参照。
認証ユーザ
認証されたユーザを使いたいときは
actingAs()
メソッドでユーザを指定することができる。// UserControllerTest.php - testIndex() $user = factory(User::class)->create(); $this->actingAs($user); # 認証済みユーザを指定 // UserController.php - index() $user = \Auth::user(); // actingAs() で指定したユーザになっているレスポンスのダンプ
レスポンスの内容を直接確認したいときは
$response->dump()
でダンプすることができる。例外のテスト
例外が発生することをテストしたいときはテストにアノテーションを指定する。
// UserNotFoundeException がスローされること /** * @expectedException \App\Exceptions\UserNotFoudException */ public function testIndex()モック
モックオブジェクトを使いたいときは Mockery を使用する。
参考
- 投稿日:2019-05-26T00:18:59+09:00
laravel manp 初期画面 localhost
laravelのインストールしたら
初期画面を出したいけど上手くいかない時の設定方法
laravelのインストールして、初期画面を出したいけど上手くいかない時
localhostとURLを入力しても上手く表示されない場合
manpの設定(preferences...)のWebSeverの中にある、Documents Root を、
{laravelのディレクトリー}¥public (例) C:\MAMP\htdocs\laravel\publicと設定すると上手くいく。
上記の例だとLaravelがMAMPの設定上だが本来はあまりお勧めされない。
理由はMAMPを消すとデータが消えるため。
MAMPのバージョンに依存しないフォルダーに保存しておくことが望ましい。