# Laravel View Models Laravel View Models is a package by Spatie that provides a clean way to encapsulate complex view logic into dedicated classes. Instead of cluttering controllers with data preparation code, view models take raw data and transform it into something directly usable by views, keeping controllers thin and focused on their primary responsibility. The package offers automatic exposure of public methods and properties to views, support for returning JSON responses for AJAX requests, callable methods with parameters for use in Blade templates, and an artisan command for generating new view models. View models implement both `Arrayable` and `Responsable` interfaces, making them seamlessly integrate with Laravel's view system and response handling. ## Installation Install the package via Composer to add view model support to your Laravel application. ```bash composer require spatie/laravel-view-models ``` ## Creating a ViewModel Class Extend the base `ViewModel` class to create a view model that automatically exposes all public methods and properties to your views. Methods without parameters are executed and their return values are exposed, while methods with parameters become callable closures in the view. ```php user = $user; $this->post = $post; $this->indexUrl = action([PostsController::class, 'index']); } // Methods without parameters: return value is exposed as $post public function post(): Post { return $this->post ?? new Post(); } // Return value is exposed as $categories public function categories(): Collection { return Category::canBeUsedBy($this->user)->get(); } } ``` ## Using ViewModel in Controllers Pass the view model directly to the `view()` helper. Laravel automatically converts it to an array, making all public methods and properties available in the view. ```php title }}" /> {{-- Loop through collection returned by categories() method --}} {{-- Access public property directly --}} Back to Posts ``` ## Ignoring Methods Use the `$ignore` property to prevent specific public methods from being exposed to the view. Magic methods starting with `__` are automatically ignored. ```php helperMethod(); } // This method will NOT be available in the view public function ignoredMethod() { return 'This is hidden from the view'; } // This helper is also hidden from the view public function helperMethod() { return Post::with('author')->find($this->postId); } } ``` ## Returning ViewModel as Response Return a view model directly from a controller to get a JSON response by default. This is useful for AJAX requests and API endpoints. ```php update($request->validated()); // Returning ViewModel directly outputs JSON return new PostViewModel($post); } // Response when Accept: application/json header is present: // { // "post": {"id": 1, "title": "Updated Title", "body": "Content..."}, // "categories": [{"id": 1, "name": "Tech"}, {"id": 2, "name": "News"}], // "indexUrl": "/posts" // } } ``` ## Returning View with ViewModel Use the `view()` method to specify which Blade template to render. The response type automatically switches between HTML and JSON based on the request's `Accept` header. ```php view('posts.show'); } public function edit(Post $post) { // Pass additional data to the view return (new PostViewModel(current_user(), $post)) ->view('posts.form', ['editing' => true]); // If request has Accept: application/json header, // JSON is returned instead of the rendered view } } ``` ## Exposing Callable Methods Methods with parameters are exposed as callable closures in the view, allowing you to pass arguments directly in your Blade templates. ```php post = $post; } // Method with parameter becomes a callable in the view public function formatDate(Carbon $date): string { return $date->format('F j, Y'); } // Another callable method example public function truncate(string $text, int $length = 100): string { return strlen($text) > $length ? substr($text, 0, $length) . '...' : $text; } } ``` ```blade {{-- Call methods with parameters directly in Blade --}}

Published: {{ $formatDate($post->created_at) }}

Updated: {{ $formatDate($post->updated_at) }}

{{-- Use the truncate callable --}}

{{ $truncate($post->body, 150) }}

``` ## Snake Case Property Names Enable snake_case conversion for property and method names by setting `$snakeCase = true`. This converts camelCase names to snake_case when exposing them to views. ```php first(); } public function relatedPosts() { return Post::related($this->article)->get(); } } // In Blade template, use snake_case names: // $published_date (instead of $publishedDate) // $featured_article (instead of $featuredArticle) // $related_posts (instead of $relatedPosts) ``` ## Artisan Make Command Use the built-in artisan command to generate new view model classes with the correct namespace and directory structure. ```bash # Create a view model in app/ViewModels/HomepageViewModel.php php artisan make:view-model HomepageViewModel # Create in a custom subdirectory: app/Blog/ViewModels/PostsViewModel.php php artisan make:view-model "Blog/PostsViewModel" # Force overwrite if file exists php artisan make:view-model HomepageViewModel --force ``` Generated file structure: ```php toArray(); // Result: // [ // 'user' => User {...}, // 'post' => Post {...}, // 'indexUrl' => '/posts', // 'categories' => Collection {...}, // 'formatDate' => Closure {...} // Callable methods become closures // ] // Test that expected keys exist assert(array_key_exists('post', $data)); assert(array_key_exists('categories', $data)); assert(is_callable($data['formatDate'])); ``` ## Summary Laravel View Models provides an elegant solution for organizing complex view logic in Laravel applications. The primary use case is separating data preparation from controller logic, making controllers thinner and more maintainable. View models excel at handling forms with multiple data sources (like a post edit form needing categories, tags, and user permissions), dashboard views with computed statistics, and any view requiring data transformation before display. Integration with Laravel is seamless through the `Arrayable` and `Responsable` interfaces. View models can be passed directly to views, returned as JSON responses for AJAX, or converted to arrays for testing. The automatic exposure of public methods and properties, combined with callable method support and the snake_case option, provides flexibility for various coding styles. The artisan generator command ensures consistent file structure across the project, making view models a natural extension of Laravel's conventions.