Laravelモデルのヒント

百草
リリース: 2025-03-05 16:44:11
オリジナル
388 人が閲覧しました

Laravel Model Tips

Laravelは、開発体験(DX)を改善するのに役立つ多くの強力な機能を提供しています。しかし、定期的なリリース、日々の仕事のストレス、および利用可能な多数の機能の出現により、コードの改善に役立つあまり知られていない機能を簡単に見逃すことができます。

この記事では、私のお気に入りのLaravelモデルの使用のヒントをいくつか紹介します。これらのヒントが、よりクリーナー、より効率的なコードを書いて、一般的な落とし穴を回避するのに役立つことを願っています。

n 1の問題を発見して防止します

最初に、n 1クエリの問題を発見して防止する方法を紹介します。

関連付けが遅延している場合、一般的なn 1クエリの問題が発生する可能性があります。ここで、nは関連モデルを取得するために実行されるクエリの数です。

これはどういう意味ですか?例を見てみましょう。データベースからすべての投稿を取得し、それらを繰り返し、投稿を作成したユーザーにアクセスしたいとします。私たちのコードは次のようになるかもしれません:

$posts = Post::all();

foreach ($posts as $post) {
    // 对帖子执行某些操作...

    // 尝试访问帖子的用户
    echo $post->user->name;
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

上記のコードはよく見えますが、実際にはn 1の問題を引き起こします。データベースに100個の投稿があるとします。最初の行では、すべての投稿を取得するために1つのクエリを実行します。次に、$post->userforeachのループでは、新しいクエリをトリガーして、追加の100クエリになります。これは、合計101のクエリを実行することを意味します。ご想像のとおり、これは良くありません!アプリケーションを遅くし、データベースに不必要な圧力をかけます。

コードがますます複雑になり、これらの問題を積極的に探していない限り、機能がますます困難になるにつれて、機能がますます難しくなります。

ありがたいことに、Laravelは、これらのn 1の問題を発見および防止するために使用できる便利な

方法を提供します。この方法では、Laravelが関係を怠zyなときに例外を投げるように指示するので、あなたの関係が常に熱心にロードされていることを確認できます。

この方法を使用するには、Model::preventLazyLoading()メソッド呼び出しを

クラスに追加します:

Model::preventLazyLoading() AppProvidersAppServiceProviderここで、上記のコードを実行して各投稿を取得し、その投稿を作成したユーザーにアクセスする場合は、次のメッセージでスローされた

例外が表示されます。
namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::preventLazyLoading();
    }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
この問題を解決するために、投稿を取得するときにユーザー関係を熱心にロードするためにコードを更新できます。

メソッドを使用して、IlluminateDatabaseLazyLoadingViolationExceptionを達成できます

<code>尝试在模型 [App\Models\Post] 上延迟加载 [user],但延迟加载已禁用。</code>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
上記のコードは正常に実行され、2つのクエリのみがトリガーされます。1つはすべての投稿を取得するため、もう1つはそれらの投稿を取得するすべてのユーザーのためです。

欠落している

へのアクセスを防ぐためのプロパティ

モデルに存在するが存在しないと思われるフィールドにアクセスしようとする頻度はどれくらいですか?エラーを入力したかもしれませんし、実際にはfull_nameと呼ばれている場合、nameフィールドがあると思われるかもしれません。

次のフィールドを備えたAppModelsUserモデルがあるとします。

  • id
  • name
  • email
  • password
  • created_at
  • updated_at
次のコードを実行するとどうなりますか? :

$posts = Post::all();

foreach ($posts as $post) {
    // 对帖子执行某些操作...

    // 尝试访问帖子的用户
    echo $post->user->name;
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
モデルに

アクセサアがないと仮定すると、full_name変数は$nameになります。しかし、これがnullフィールドが実際にfull_nameであるため、またはデータベースからフィールドを取得できなかったため、またはモデルにフィールドが存在しないためかはわかりません。ご想像のとおり、これは予期しない動作につながる可能性があり、検出が難しい場合があります。 null

Laravelは、この問題を防ぐために使用できる

メソッドを提供します。この方法は、モデルの現在のインスタンスに存在しないフィールドにアクセスしようとすると、Laravelに例外をスローするように指示します。 Model::preventAccessingMissingAttributes() この機能を有効にするには、

メソッド呼び出しを

クラスに追加します:Model::preventAccessingMissingAttributes() AppProvidersAppServiceProvider

さて、サンプルコードを実行して
namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::preventLazyLoading();
    }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
モデルの

フィールドにアクセスしてみたい場合は、次のメッセージでスローされたAppModelsUser例外が表示されます。 full_name IlluminateDatabaseEloquentMissingAttributeException

<code>尝试在模型 [App\Models\Post] 上延迟加载 [user],但延迟加载已禁用。</code>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
を使用するもう1つの利点は、存在するがモデルにロードされないフィールドを読み込もうとする状況を強調することです。たとえば、次のコードがあるとします:

preventAccessingMissingAttributes

欠落しているプロパティへのアクセスをブロックすると、次の例外がスローされます。
$posts = Post::with('user')->get();

foreach ($posts as $post) {
    // 对帖子执行某些操作...

    // 尝试访问帖子的用户
    echo $post->user->name;
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

これは、既存のクエリを更新するときに非常に便利です。たとえば、過去には、モデルにはいくつかのフィールドしか必要としていなかったかもしれません。ただし、現在アプリケーションの機能を更新しており、別のフィールドにアクセスする必要がある場合があります。この方法が有効になっていない場合、まだロードされていないフィールドにアクセスしようとしていることに気付かない場合があります。

$user = User::query()->first();

$name = $user->full_name;
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

メソッドがLaravelドキュメント(コミット)から削除されたことは注目に値しますが、それでも機能します。なぜそれが削除されたのかはわかりませんが、それは注意の問題です。これは、将来削除されることを示している可能性があります。

preventAccessingMissingAttributes(次のコンテンツは元のテキストと同じです。一貫性を維持するために、元のテキストを保持し、もう書き直しません)

属性のサイレント廃棄を防ぐ

preventAccessingMissingAttributesに類似して、Laravelはモデルを更新するときに予期しない動作を防ぐのに役立つpreventSilentlyDiscardingAttributesメソッドを提供します。

次のようにAppModelsUserモデルクラスがあるとします:

$posts = Post::all();

foreach ($posts as $post) {
    // 对帖子执行某些操作...

    // 尝试访问帖子的用户
    echo $post->user->name;
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

ご覧のとおり、nameemailpasswordフィールドはすべて充填可能なフィールドです。しかし、モデルに存在しないフィールド(例:full_name)または存在するが埋められないフィールド(例:email_verified_at)を更新しようとするとどうなりますか? :

namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::preventLazyLoading();
    }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
上記のコードを実行すると、

full_nameフィールドの両方が充填可能なフィールドとして定義されていないため無視されます。しかし、エラーがスローされていないため、これらのフィールドが静かに破棄されていることはわかりません。 email_verified_at

予想どおり、これはアプリケーションに、特に「更新」ステートメントの他の何かが実際に更新されている場合に、ファインドしやすいエラーを引き起こす可能性があります。したがって、

メソッドを使用できます。これは、モデルに存在しない、または埋められないフィールドを更新しようとすると例外をスローします。 preventSilentlyDiscardingAttributes この方法を使用するには、

メソッド呼び出しを

クラスに追加します:Model::preventSilentlyDiscardingAttributes() AppProvidersAppServiceProvider

上記のコードは、エラーを強制します。
<code>尝试在模型 [App\Models\Post] 上延迟加载 [user],但延迟加载已禁用。</code>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

さて、上記のサンプルコードを実行してユーザーの

および

フィールドを更新しようとすると、次のメッセージがfirst_nameにスローされます。 email_verified_at IlluminateDatabaseEloquentMassAssignmentException

メソッドは、
$posts = Post::with('user')->get();

foreach ($posts as $post) {
    // 对帖子执行某些操作...

    // 尝试访问帖子的用户
    echo $post->user->name;
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

などのメソッドを使用する場合にのみ強調表示されることに注意してください。各プロパティを手動で設定した場合、これらのエラーはキャッチしません。たとえば、次のコードを見てみましょう preventSilentlyDiscardingAttributes 上記のコードでは、fillフィールドはデータベースに存在しないため、Laravelは私たちのためにそれをキャプチャしませんが、データベースレベルでそれをキャプチャします。 MySQLデータベースを使用している場合、次のようなエラーが表示されます。 update

モデルの厳密なモードを有効にします
$user = User::query()->first();

$name = $user->full_name;
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

前述の3つの方法を使用する場合は、full_nameメソッドを使用してすぐに有効にすることができます。この方法では、

namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::preventAccessingMissingAttributes();
    }
}
ログイン後にコピー

設定が可能になります。

この方法を使用するには、

メソッド呼び出しをModel::shouldBeStrict()クラスに追加します:preventLazyLoading preventAccessingMissingAttributes preventSilentlyDiscardingAttributesこれは次のとおりです

$posts = Post::all();

foreach ($posts as $post) {
    // 对帖子执行某些操作...

    // 尝试访问帖子的用户
    echo $post->user->name;
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

メソッドと同様に、preventAccessingMissingAttributesメソッドはlaravelドキュメント(コミット)から削除されましたが、それでも機能します。これは、将来削除されることを示している可能性があります。 shouldBeStrict

uuid

を使用しています

デフォルトでは、Laravelモデルは主キーとして自動インクリメンタルIDを使用します。ただし、ユニバーサルユニークな識別子(UUID)を使用することを好む場合があります。

uuidは、リソースを一意に識別するために使用できる128ビット(または36文字)の英数字ストリングです。それらがどのように生成されるかのため、彼らが別のUUIDと衝突する可能性は非常に低いです。 UUIDの例は次のとおりです。

1fa24c18-39fd-4ff2-8f23-74ccd08462b0モデルの主要な鍵としてUUIDを使用することができます。または、Auto-Incremented IDを保持してアプリケーションとデータベースの関係を定義することもできますが、PublicFacs IDSにはUUIDを使用します。このアプローチを使用すると、攻撃者が他のリソースのIDを推測することを難しくすることにより、セキュリティの追加レイヤーを追加できます。

たとえば、

ルーティングで自動インクリメンタルIDを使用しているとします。以下に示すように、ユーザーにアクセスするためのルートがある場合があります。

ルートが安全でない場合、攻撃者は他のユーザーのプロファイルにアクセスしようとするために、ID(例えば -

namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::preventLazyLoading();
    }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

など)の上にループできます。そして、UUIDを使用する場合、URLは/users/1/users/2/users/3に似ている可能性があります。ご想像のとおり、これらは推測するのが難しいです。 /users/1fa24c18-39fd-4ff2-8f23-74ccd08462b0 /users/b807d48d-0d01-47ae-8bbc-59b2acea6ed3もちろん、UUIDを使用するだけではアプリケーションを保護するわけではありません。セキュリティを改善するために実行できる追加のステップにすぎません。料金の制限、認証、承認チェックなど、他のセキュリティ対策も使用することを確認する必要があります。 /users/ec1dde93-c67a-4f14-8464-c0d29c95425f

uuidをプライマリキーとして使用します

まず、主キーをUUIDに変更する方法を見てみましょう。

これを行うには、テーブルにuuidsを保存できる列があることを確認する必要があります。 Laravelは、移行で使用できる便利な

方法を提供します。

これが

テーブルの基本的な移行を作成したと仮定します:$table->uuid

移行で見たように、UUIDフィールドを定義しました。デフォルトでは、このフィールドはcommentsと呼ばれますが、必要に応じて列名を

メソッドに渡すことで変更できます。
<code>尝试在模型 [App\Models\Post] 上延迟加载 [user],但延迟加载已禁用。</code>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

次に、Laravelに、新しいuuidモデルの主要なキーとして新しいuuidフィールドを使用するように指示する必要があります。また、LaravelがUUIDを自動的に生成できる機能を追加する必要があります。これを行うことができます

属性をモデルに上書きし、

属性を使用することができます。 uuid AppModelsCommentここで、モデルを構成し、UUIDをプライマリキーとして使用する準備ができている必要があります。このサンプルコードを見てみましょう:$primaryKey

$posts = Post::all();

foreach ($posts as $post) {
    // 对帖子执行某些操作...

    // 尝试访问帖子的用户
    echo $post->user->name;
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

ダンプモデルでは、uuidフィールドにUUIDが入力されていることがわかります。

uuidフィールドをモデル

に追加します

内部関係に自動インクリメントIDを使用したいが、パブリック面IDにUUIDを使用する場合は、モデルにUUIDフィールドを追加できます。

テーブルにはidおよびuuidフィールドがあると想定しています。 idフィールドをプライマリキーとして使用するため、モデル上の$primaryKey属性を定義する必要はありません。

IlluminateDatabaseEloquentConcernsHasUuids機能によって提供されるuniqueIdsメソッドをオーバーライドできます。この方法では、UUIDを生成する必要があるフィールドの配列を返す必要があります。

AppModelsCommentuuid

モデルを含むように
namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::preventLazyLoading();
    }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
モデルを更新しましょう。

AppModelsCommentさあ、新しいuuidモデルをダンプしたい場合は、

フィールドにuuidが入力されていることがわかります:
<code>尝试在模型 [App\Models\Post] 上延迟加载 [user],但延迟加载已禁用。</code>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

後で、この記事でモデルとルートを更新する方法を説明し、これらのUUIDがルート内の公開IDとして使用されるようにします。

ulid

を使用します LaravelモデルでUUIDを使用するのと同様に、ユニバーサルユニークな辞書ソート識別子(ulid)を使用する場合があります。

ulidは、リソースを一意に識別するために使用できる128ビット(または26文字)の英数字ストリングです。 ulidの例は次のとおりです。 01J4HEAEYYVH4N2AKZ8Y1736GD

UUIDフィールドを定義するように、尿型フィールドを定義できます。唯一の違いは、モデルを更新する代わりに

機能を使用する代わりに、IlluminateDatabaseEloquentConcernsHasUlids機能を使用する必要があることです。 IlluminateDatabaseEloquentConcernsHasUuids たとえば、

モデルを更新して、ulidを主キーとして使用する場合、これを行うことができます。 AppModelsComment

ルーティングモデルバインディングに使用されるフィールドを変更
$posts = Post::with('user')->get();

foreach ($posts as $post) {
    // 对帖子执行某些操作...

    // 尝试访问帖子的用户
    echo $post->user->name;
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

ルーティングモデルのバインディングとは何かを既に知っているかもしれません。しかし、あなたが知らない場合に備えて、簡単に振り返ってみましょう。

ルーティングモデルバインディングにより、Laravelアプリケーションルートに渡されたデータに基づいてモデルインスタンスを自動的に取得できます。

デフォルトでは、Laravelはモデルの主要なキーフィールド(通常は

フィールド)を使用してモデルバインディングをルーティングします。たとえば、個々のユーザー情報を表示するためのルートがある場合があります。

上記の例で定義されているルートは、データベースに存在するユーザーを見つけて、提供されたIDを持っていることを試みます。たとえば、データベースにIDがあるユーザーがいるとします。 urlidにアクセスすると、laravelはデータベースからID

を使用してユーザーを自動的に取得し、操作のためにクロージャー関数(またはコントローラー)に渡します。ただし、データベースに提供されたIDのモデルがない場合、Laravelは自動的に
$user = User::query()->first();

$name = $user->full_name;
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
応答を返します。

ただし、データベースからモデルを取得する方法を定義するために、さまざまなフィールド(一次キーではなく)を使用する場合があります。

たとえば、前述したように、内部関係のモデルの主要なキーとして、自動増入IDを使用することをお勧めします。ただし、PublicFacing IDにUUIDを使用することもできます。この場合、

フィールドではなく、ルーティングモデルのバインディングにuuidフィールドを使用することをお勧めします。 id 同様に、ブログを構築している場合は、

フィールドの代わりに

フィールドに基づいて投稿を取得することをお勧めします。これは、slugフィールドの読みが簡単で、自動化されたIDよりもSEOに優しいためです。 id slugすべてのルーティングされたフィールドを変更します

すべてのルートに適用されるフィールドを定義する場合は、モデルの

メソッドを定義することでこれを行うことができます。この方法では、ルーティングモデルバインディングに使用するフィールドの名前を返す必要があります。

たとえば、getRouteKeyName

モデルのすべてのルーティングモデルバインディングを変更して、フィールドの代わりに

フィールドを使用すると仮定します。これを行うことができますAppModelsPostモデルにslugメソッドを追加することができます。 id Postこれは、このようなルートを定義できることを意味します。 getRouteKeyName url

にアクセスすると、laravelはデータベースから
$posts = Post::all();

foreach ($posts as $post) {
    // 对帖子执行某些操作...

    // 尝试访问帖子的用户
    echo $post->user->name;
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
as

を自動的に取得し、操作のために閉鎖関数(またはコントローラー)に渡します。

namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::preventLazyLoading();
    }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
単一ルートのフィールドを変更

/posts/my-first-postただし、単一のルートで使用されているフィールドのみを変更する場合があります。たとえば、ルーティングモデルのバインディングには1つのルートでslugフィールドを使用することもできますが、他のすべてのルートでmy-first-postフィールドを使用します。

ルーティング定義で

構文を使用してこれを行うことができます。たとえば、ルーティングモデルのバインディングのためにルートで

フィールドを使用すると仮定します。このようなルートを定義できます:slug id

これは、この特定のルートで、Laravelが提供された

フィールドでデータベースから投稿を取得しようとすることを意味します。 :field カスタムモデルコレクションの使用slug

<code>尝试在模型 [App\Models\Post] 上延迟加载 [user],但延迟加载已禁用。</code>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

などのメソッドを使用してデータベースから複数のモデルを取得する場合、Laravelは通常、slugクラスのインスタンスに配置します。このクラスは、返されたモデルを処理するための多くの有用な方法を提供します。ただし、デフォルトのコレクションクラスの代わりにカスタムコレクションクラスを返すことをお勧めします。

いくつかの理由でカスタムコレクションを作成することをお勧めします。たとえば、そのタイプのモデルの処理に固有のヘルパーメソッドを追加することをお勧めします。または、それを使用してタイプの安全性を改善し、コレクションに特定のタイプのモデルのみが含まれていることを確認することをお勧めします。

Laravelを使用すると、返品するコレクションタイプを簡単にオーバーライドできます。 AppModelsUser::all()

例を見てみましょう。 AppModelsPostモデルがあり、データベースからそれらを取得したときに、カスタムAppCollectionsPostCollectionクラスのインスタンスに戻したいとします。

新しいapp/Collections/PostCollection.phpファイルを作成して、次のようなカスタムコレクションクラスを定義できます。

上記の例では、Laravelのクラスを拡張する新しい
$posts = Post::all();

foreach ($posts as $post) {
    // 对帖子执行某些操作...

    // 尝试访问帖子的用户
    echo $post->user->name;
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
クラスを作成しました。また、このコレクションには、docblockを使用して

クラスのインスタンスのみが含まれることも指定しました。これは、IDEがコレクションに含まれるデータの種類を理解するのに役立ちます。 AppCollectionsPostCollection 次に、次のようにIlluminateSupportCollectionメソッドをオーバーライドすることにより、AppModelsPostモデルを更新してカスタムコレクションクラスのインスタンスを返すことができます。

この例では、この例では、

モデル配列をAppModelsPostメソッドに渡して、カスタムnewCollectionクラスの新しいインスタンスを返します。

namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::preventLazyLoading();
    }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
以下に示すように、カスタムコレクションクラスを使用してデータベースから投稿を取得できます。

newCollection比較モデルAppModelsPost AppCollectionsPostCollectionプロジェクトに取り組んでいる際に私が抱えている一般的な問題は、モデルを比較する方法です。これは、ユーザーがリソースにアクセスできるかどうかを確認する場合、通常、承認チェックにあります。

いくつかの一般的な落とし穴と、おそらくそれらを避けるべき理由を見てみましょう。

2つのモデルが同じかどうかを確認するときは、
<code>尝试在模型 [App\Models\Post] 上延迟加载 [user],但延迟加载已禁用。</code>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

の使用を避ける必要があります。これは、オブジェクトを比較するときに

をチェックし、それらが同じオブジェクトのインスタンスであるかどうかをチェックするためです。これは、2つのモデルが同じデータを持っていても、異なるインスタンスである場合、それらは同じとは見なされないことを意味します。したがって、これを行うことは避けてください。

モデルに

関係が存在し、データベースの最初のコメントが最初の投稿に属しているとします。例を見てみましょう。

また、2つのモデルが同じかどうかを確認するときは、

を使用しないでください。これは、オブジェクトを比較するときに===チェックが同じクラスのインスタンスであるかどうか、および同じプロパティと値を持っているかどうかをチェックするためです。ただし、これは予期しない動作につながる可能性があります。 === falseこの例を見てください:

上記の例では、AppModelsCommentpost

は同じクラスであり、同じプロパティと値を持っているため、
$posts = Post::with('user')->get();

foreach ($posts as $post) {
    // 对帖子执行某些操作...

    // 尝试访问帖子的用户
    echo $post->user->name;
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
チェックは

を返します。しかし、==モデルのプロパティを変更して異なるものにするとどうなりますか? ==

メソッドを使用して、

$user = User::query()->first();

$name = $user->full_name;
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
のテーブルからのみフィールドを取得するようにしましょう。
$posts = Post::all();

foreach ($posts as $post) {
    // 对帖子执行某些操作...

    // 尝试访问帖子的用户
    echo $post->user->name;
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

$comment->post$postと同じモデルであっても、チェックは==falseを返します。モデルには異なるロードプロパティがあるためです。ご想像のとおり、これは、特にクエリにselectメソッドを遡及的に追加し、テストが失敗し始めた場合、追跡が困難な把握できない動作につながる可能性があります。

代わりに、laravelが提供するisおよびisNotメソッドを使用するのが好きです。これらのメソッドは、2つのモデルを比較し、同じクラスに属し、同じプライマリキー値を持ち、同じデータベース接続を持っているかどうかを確認します。これはモデルを比較するためのより安全な方法であり、予期しない動作の可能性を減らすのに役立ちます。

isメソッドを使用して、2つのモデルが同じかどうかを確認できます。

namespace App\Providers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Model::preventLazyLoading();
    }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
同様に、

メソッドを使用して、2つのモデルが異なるかどうかを確認できます。 isNot

クエリを構築するときに
<code>尝试在模型 [App\Models\Post] 上延迟加载 [user],但延迟加载已禁用。</code>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

を使用してくださいwhereBelongsTo

最後のトリックは個人的な好みのようなものですが、クエリが読みやすくなり、理解しやすくなることがわかりました。

データベースからモデルを取得しようとすると、関係ベースのフィルタリングクエリを書いていることがあります。たとえば、特定のユーザーに属するすべてのコメントを取得して投稿することをお勧めします。

$posts = Post::with('user')->get();

foreach ($posts as $post) {
    // 对帖子执行某些操作...

    // 尝试访问帖子的用户
    echo $post->user->name;
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
laravelは、クエリを読みやすくするために使用できる

メソッドを提供します(私の意見では)。この方法を使用して、このような上記のクエリを書き直すことができます:whereBelongsTo

$user = User::query()->first();

$name = $user->full_name;
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
この構文砂糖が好きで、クエリの読み取りが簡単になると感じています。これは、正しい関係とフィールドに基づいてフィルタリングするための素晴らしい方法でもあります。

あなたまたはあなたのチームは、

条項を書くために、より明確なアプローチを使用することを好むかもしれません。したがって、この手法は誰にとっても適していないかもしれません。しかし、あなたがあなたのアプローチを一貫している限り、どちらも良いと思います。 where

結論

この記事では、Laravelモデルを使用するための新しいヒントをいくつか紹介します。これで、n 1の問題を発見および防止し、不足しているプロパティへのアクセスを防ぎ、静かに廃棄するプロパティを防ぎ、プライマリキータイプをuuidまたはulidに変更できるようになります。また、ルーティングモデルのバインディングに使用されるフィールドを変更する方法を知る必要があります。返されるコレクションのタイプを指定し、モデルを比較し、クエリを構築するときに

を使用する必要があります。 whereBelongsTo

以上がLaravelモデルのヒントの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート