View Composers
Automatically injecting data into views with View Composers
View Composers allow you to automatically inject data into views. This pattern helps you centralize data sharing and avoid code repetition in controllers.
Types of View Composers:
1. Closure-based Composers: Simple composers with closure suitable for simple logic.
2. Class-based Composers: Class-based composers suitable for more complex and reusable logic.
Common Uses:
- Shared data across multiple views (like categories, menus)
- Navigation menus
- User settings
- Statistics and counters
- Sidebar content
- Footer data
- Global variables
Benefits of View Composers:
- Reduced code duplication in controllers
- Centralized data sharing
- Cleaner and more maintainable code
- Reusable logic
- Separation of concerns
- Easier for testing
Examples
Closure-based Composer
<?php
// In AppServiceProvider boot()
use Illuminate\Support\Facades\View;
View::composer('layouts.sidebar', function ($view) {
$view->with('categories', Category::all());
});
// Multiple views
View::composer(['layouts.sidebar', 'layouts.nav'], function ($view) {
$view->with('categories', Category::all());
});
// All views
View::composer('*', function ($view) {
$view->with('currentUser', auth()->user());
});
A simple composer that injects categories into sidebar.
Class-based Composer
<?php
namespace App\View\Composers;
use App\Models\Category;
use Illuminate\View\View;
class CategoryComposer
{
public function compose(View $view)
{
$view->with('categories', Category::all());
}
}
// Register in AppServiceProvider
View::composer('layouts.sidebar', CategoryComposer::class);
// Or with dependency injection
class CategoryComposer
{
public function __construct(
private CategoryRepository $repository
) {}
public function compose(View $view)
{
$view->with('categories', $this->repository->all());
}
}
A class-based composer.
Composer with Caching
<?php
namespace App\View\Composers;
use Illuminate\View\View;
use Illuminate\Support\Facades\Cache;
class CategoryComposer
{
public function compose(View $view)
{
$categories = Cache::remember('categories', 3600, function () {
return Category::all();
});
$view->with('categories', $categories);
}
}
Composer with caching for better performance.
Multiple Composers
<?php
// Multiple composers for same view
View::composer('layouts.app', CategoryComposer::class);
View::composer('layouts.app', MenuComposer::class);
View::composer('layouts.app', function ($view) {
$view->with('siteSettings', config('site'));
});
// All composers execute and merge data
Multiple composers for one view.
Composer Creators
<?php
// View creator (runs before view is created)
View::creator('layouts.app', function ($view) {
// This runs before view is created
// Can modify view data before rendering
$view->with('preloadData', [
'user' => auth()->user(),
'settings' => app('settings')
]);
});
// Difference:
// Composer: runs after view is created
// Creator: runs before view is created
View creator that runs before view is created.
Conditional Composer
<?php
namespace App\View\Composers;
use Illuminate\View\View;
class AdminComposer
{
public function compose(View $view)
{
if (auth()->check() && auth()->user()->isAdmin()) {
$view->with('adminMenu', $this->getAdminMenu());
$view->with('adminStats', $this->getAdminStats());
}
}
private function getAdminMenu()
{
return [
'users' => route('admin.users.index'),
'posts' => route('admin.posts.index'),
];
}
}
Composer with conditional logic.
Composer with Wildcards
<?php
// All views in users directory
View::composer('users.*', function ($view) {
$view->with('userCount', User::count());
});
// All views
View::composer('*', function ($view) {
$view->with('appName', config('app.name'));
});
// Multiple patterns
View::composer(['users.*', 'admin.*'], function ($view) {
$view->with('isAdminArea', true);
});
Using wildcards to match multiple views.
Testing Composers
<?php
namespace Tests\Unit;
use App\View\Composers\CategoryComposer;
use App\Models\Category;
use Illuminate\View\View;
use Tests\TestCase;
class CategoryComposerTest extends TestCase
{
public function test_composer_injects_categories()
{
Category::factory()->count(3)->create();
$view = $this->view('layouts.sidebar');
$composer = new CategoryComposer();
$composer->compose($view);
$this->assertArrayHasKey('categories', $view->getData());
$this->assertCount(3, $view->getData()['categories']);
}
}
Testing View Composers.
Use Cases
- Shared data across multiple views
- Navigation menus and sidebar content
- Global variables and settings
- User-specific data
- Statistics and counters
- Footer and header data
Common Mistakes
- Using composer for data only needed in one view
- Heavy operations in composer causing slow rendering
- Not using caching for expensive queries
- Composer for all views causing overhead
- Forgetting to register composer
- N+1 queries in composer
Best Practices
- Use composer for shared data
- Use caching for expensive queries
- Use eager loading for relationships
- Register composer in Service Provider
- Use class-based composer for complex logic
- Test composer
- Use wildcards with caution
Edge Cases
- Multiple composers for one view
- Composer with circular dependencies
- Composer in API responses
- Composer with very large datasets
- Conditional composers
- Composer with async operations
Performance Notes
- Composer overhead is usually low
- Using caching for expensive queries is important
- Composer for all views can have overhead
- Use eager loading for relationships
- Composer caching can improve performance
Security Notes
- Ensure sensitive data is not exposed in composer
- Use authorization checks in composer
- Ensure user input is validated
Interview Points
- What is the difference between composer and creator?
- When should you use View Composer?
- What is the difference between closure-based and class-based composer?
- How can you test composer?
- What are the benefits of using View Composers?
- How can you register composer for multiple views?
Version Notes
- Laravel 11.x: Improved performance in composer execution
- Laravel 11.x: Better support for composer caching
- Laravel 10.x: Improved composer registration
- Laravel 9.x: Improved composer creators