When working with .NET Framework MVC applications, I used to use bound view models, which let me use classes on the Razor templates very easily with the autocomplete feature. This was a default feature provided for .NET Framework by Visual Studio IDE. In the Razor views, we had to define a class as a model on top, and on the other hand, in the controller, we were forced to pass the instance of that class to the view. If passed a different class instance, it would throw an error telling this view required the instance of the defined class. Once this was done, we were able to access class with a variable called Model. This gave the autocomplete feature within Razor view.
I was looking for the same thing in the Laravel ecosystem, but I found none. So I practiced a pattern I call ViewModels and kept using it for many years. What is ViewModel in Laravel? Let me explain.
What is ViewModel?
In my view, a ViewModel is a class that fulfills the requirements of a page.
To further explain, let’s assume a scenario. Say we have to display a list of products with some filters above. The filters can be a list of categories and brands in dropdowns. Users can select a category and apply a filter to fetch products of a specific category. Users can do the same with brands. Thus, the ViewModel for the page will look something like this.
Defining ViewModel Class
<?php
namespace App\ViewModels;
class ProductsViewModel {
public $products;
public $categories;
public $brands;
}
So this class will have 3 properties to hold the required data for categories, brands, and products.
Let’s assume another example. This time we need a ViewModel for the e-commerce home page. The home page will have banners and some category sections.
class ProductsViewModel {
public $banners;
public $sections = [];
}
Each section in the array can have the following:
class Section {
public $title;
public $products = [];
}
Filling ViewModel with Data (Using AQC)
Now let’s move forward. We have defined the ViewModel class. Now we need to fill it with data to view. I am going to use the AQC design pattern here to get data. If you haven’t heard about it, you can read my post here.

namespace App\ViewModels;
use App\AQC\Products\GetAllProducts;
use App\AQC\Category\GetAllCategories;
use App\AQC\Brand\GetAllBrands;
class ProductsViewModel {
public $products;
public $categories;
public $brands;
public function handle($params)
{
$this->brands = GetAllBrands::handle();
$this->categories = GetAllCategories::handle();
$this->products = GetAllProducts::handle();
return $this;
}
}
And we are done. Now let’s move towards the controller and see how we use it.
Using ViewModels in Controllers
<?php
namespace App\Http\Controllers;
use App\Http\Requests\GetAllProductsRequest;
use App\ViewModels\ProductsViewModel;
use App\Helpers\ResponseHelper;
class ProductController extends Controller
{
public function index(GetAllProductsRequest $request)
{
$params = $request->all();
$productsViewModel = new ProductsViewModel();
$response = $productsViewModel->handle($params);
return ResponseHelper::handle('index', [ 'model' => $response ]);
}
}
<h1>{{ $model->product->title }}</h1>
Comparing Controller Approach
Using the ViewModel, we are passing a single data key to view. If we aren’t using ViewModel, our code looks like this.
<?php
namespace App\Http\Controllers;
use App\Http\Requests\GetAllProductsRequest;
use App\AQC\Products\GetAllProducts;
use App\AQC\Category\GetAllCategories;
use App\AQC\Brand\GetAllBrands;
class ProductController extends Controller
{
public function index(GetAllProductsRequest $request)
{
$params = $request->all();
$brands = GetAllBrands::handle($params);
$categories = GetAllCategories::handle($params);
$products = GetAllProducts::handle($params);
$data = [
'brands' => $brands,
'categories' => $categories,
'products' => $products
];
return view('index', $data);
}
}
You can see instead of passing a single data key model, we are now passing much more data to view, which we will have to remember when accessing in the blade template. This is only a sample. Imagine your page required much more data, so your controller will get fat.
By moving all the required data to a ViewModel class, our controller is lean and our logic is simple.
What Are We Lacking?
Even though we have simplified our controller, many IDEs currently lack the autocomplete feature in blade templates. But gluing the required data to a class and passing it as a model to view is still a good improvement.
In the Laravel ecosystem so far, I have found this package by Spatie, which does the same, but I like my own implementation. If you want to take a look, here it is.
If you found this post helpful, consider supporting my work — it means a lot.
