(jp) =
ビュー モデルは、コントローラーとモデル コードを単純化するための抽象化です。 ビュー モデルは、データをビューに提供する役割を果たします。それ以外の場合は、コントローラーまたはモデルから直接取得されます。 それらは、関心のより良い分離を可能にし、開発者により多くの柔軟性を提供します。
本質的に、ビュー モデルは、いくつかのデータを取得し、それをビューで使用できるものに変換する単純なクラスです。 この投稿では、パターンの基本原則を紹介し、それらが Laravel プロジェクトにどのように統合されるかを見ていき、最後に、Spatie の会社のプロジェクトの 1 つでパターンを使用する方法を示します。 .
始めましょう。 カテゴリを含むブログ投稿を作成するフォームがあるとします。 ビューの選択ボックスにカテゴリ オプションを入力する方法が必要です。 コントローラーはそれらを提供する必要があります。
public function create()
return view('blog.form', [
'categories' => Category::all(),
]);
上記の例は create メソッドで機能しますが、既存の投稿も編集できる必要があることを忘れないでください。
public function edit(Post $post)
return view('blog.form', [
'post' => $post,
'categories' => Category::all(),
]);
次に、新しいビジネス要件があります。ユーザーが投稿できるカテゴリを制限する必要があります。つまり、ユーザーに基づいてカテゴリの選択を制限する必要があります。
return view('blog.form', [
'categories' => Category::allowedForUser(
current_user()
)->get(),
]);
このアプローチはスケーリングしません。 両方のコードを変更する必要があります create
と edit
方法。 投稿にタグを追加する必要がある場合、何が起こるか想像できますか? または、投稿を作成および編集するための別の特別な管理フォームがある場合は?
次の解決策は、次のように、投稿モデル自体にカテゴリを提供させることです。
class Post extends Model
public static function allowedCategories(): Collection
return Category::query()
->allowedForUser(current_user())
->get();
これが悪い考えである理由はたくさんありますが、Laravel プロジェクトではよく起こります。 私たちのケースに最も関連する問題に焦点を当てましょう: それでも重複が許されます。
新しいモデルがあると言う News
同じカテゴリの選択も必要です。 これにより、再び重複が発生しますが、コントローラーではなくモデル レベルで発生します。
別のオプションは、メソッドを User
モデル。 これは最も理にかなっていますが、メンテナンスも難しくなります。 前述のようにタグを使用していると想像してください。 ユーザーに依存しません。 ここで、ユーザー モデルからカテゴリを取得し、別の場所からタグを取得する必要があります。
モデルをビューのデータ プロバイダーとして使用することも特効薬ではないことは明らかだと思います。
要約すると、どこからカテゴリを取得しようとしても、コードの重複が常にあるようです。 これにより、コードの保守と推論が難しくなります。
ここで、ビュー モデルの出番です。 このロジックはすべてカプセル化されているため、さまざまな場所で再利用できます。 ビューに正しいデータを提供するという 1 つの責任しかありません。
class PostFormViewModel
public function __construct(
User $user,
Post $post = null
)
$this->user = $user;
$this->post = $post;
public function post(): Post
return $this->post ?? new Post();
public function categories(): Collection
return Category::allowedForUser($this->user)->get();
このようなクラスの主な機能をいくつか挙げてみましょう。
- すべての依存関係が注入されます。これにより、外部に最大限の柔軟性がもたらされます。
- ビュー モデルは、ビューで使用できるいくつかのメソッドを公開します。
- によって提供される新しい投稿または既存の投稿があります。
post
投稿を作成するか編集するかによって異なります。
コントローラは次のようになります。
class PostsController
public function create()
$viewModel = new PostFormViewModel(
current_user()
);
return view('blog.form', compact('viewModel'));
public function edit(Post $post)
$viewModel = new PostFormViewModel(
current_user(),
$post
);
return view('blog.form', compact('viewModel'));
最後に、次のようにビューで使用できます。
<input value=" $viewModel->post()->title " />
<input value=" $viewModel->post()->body " />
<select>
@foreach ($viewModel->categories() as $category)
<option value=" $category->id ">
$category->name
</option>
@endforeach
</select>
ビュー モデルを使用する利点は次の 2 つです。
- それらはロジックをカプセル化します
- それらは複数のコンテキストで再利用できます
# Laravel でモデルを表示
前の例では、いくつかのメソッドを持つ単純なクラスを示しました。 パターンを使用するにはこれで十分ですが、Laravel プロジェクト内には、さらにいくつかの機能を追加できます。
たとえば、ビュー モデルを直接 view
ビューモデルが実装する場合の関数 Arrayable
.
public function create()
$viewModel = new PostFormViewModel(
current_user()
);
return view('blog.form', $viewModel);
ビューは、次のようなビュー モデルのプロパティを直接使用できるようになりました。 $post
と $categories
. 前の例は次のようになります。
<input value=" $post->title " />
<input value=" $post->body " />
<select>
@foreach ($categories as $category)
<option value=" $category->id ">
$category->name
</option>
@endforeach
</select>
実装することで、ビュー モデル自体を JSON データとして返すこともできます。 Responsable
. これは、AJAX 呼び出しを介してフォームを保存していて、呼び出しが完了した後に最新のデータを再入力したい場合に役立ちます。
public function update(Request $request, Post $post)
return new PostFormViewModel(
current_user(),
$post
);
ビュー モデルと Laravel リソースの間には類似点が見られるかもしれません。 ビュー モデルが必要なデータを提供する場合、リソースはモデル上で 1 対 1 でマップされることに注意してください。
私たちのプロジェクトの 1 つでは、実際にビュー モデルでリソースを使用しています。
class PostViewModel
public function values(): array
return PostResource::make(
$this->post ?? new Post()
)->resolve();
最後に、このプロジェクトでは、JSON データを必要とする Vue フォーム コンポーネントを使用しています。 魔法の getter を呼び出すときに、オブジェクトや配列の代わりにこの JSON データを提供する抽象化を行いました。
abstract class ViewModel
public function __get($name): ?string
$name = Str::camel($name);
$values = $this->$name();
if (! is_string($values))
return json_encode($values);
return $values;
ビュー モデル メソッドを呼び出す代わりに、それらのプロパティを呼び出して JSON を取得できます。
<select-field
label=" __('Post category') "
name="post_category_id"
:options=" $postViewModel->post_categories "
></select-field>
# ちょっと待って、ビュー コンポーザーはどうするの?
私はあなたを聞く! そのトピックに関するまったく別のブログ投稿があります。 ここで読むことができます。
要約すると、ビュー モデルは、コントローラーでデータを直接操作するための実行可能な代替手段になる可能性があります。 再利用性が向上し、コントローラーに属さないロジックがカプセル化されます。
また、フォームを使用するときにフォームに限定されません。 Spatie では、ユーザーが現在作業している複雑なコンテキストに基づいて、ファセット フィルター オプションを設定するためにもそれらを使用しています。
このパターンを試してみることをお勧めします。 ちなみに、始めるのに何も必要ありません。 上記の Laravel ギミックはすべてオプションであり、ユースケースに応じて追加できます。
Laravel ギミックを使用したい場合に備えて、spatie/laravel-view-models というパッケージがあります .