Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel View Models Laravel Package

spatie/laravel-view-models

Move complex view-prep logic out of controllers into dedicated Laravel view model classes. Extend Spatie\ViewModels\ViewModel to transform data for views, expose computed properties, and keep templates clean and focused.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Pros:

    • Aligns with separation of concerns by encapsulating view logic in dedicated classes, reducing controller bloat.
    • Promotes reusability of view preparation logic across routes/controllers.
    • Complements Laravel’s dependency injection and service container patterns.
    • Enables type safety (via PHP 8+ typed properties) and IDE support (autocompletion, refactoring).
    • Works seamlessly with Blade templates, Livewire, and API responses (via JSON serialization).
    • Supports nested view models for complex UI hierarchies (e.g., dashboards with modular components).
  • Cons:

    • Adds indirection (view model classes vs. direct controller logic), which may feel verbose for simple views.
    • Requires discipline to avoid over-engineering trivial cases (e.g., single-property models).
    • Performance overhead negligible for most use cases, but could matter in high-throughput APIs (e.g., 10K+ requests/sec).

Integration Feasibility

  • Laravel Compatibility:
    • Officially supports Laravel 10+ (PHP 8.1+). Backward compatibility with older versions may require adjustments.
    • Integrates with Laravel’s service container (bindings, singleton/scoped instances).
    • Works with Blade, Inertia.js, and API responses (via toArray()/toJson()).
  • Non-Laravel Stacks:
    • Not applicable outside Laravel (e.g., Symfony, native PHP). Requires Laravel’s routing, service container, and Blade.
  • Database/ORM:
    • Agnostic to ORM (works with Eloquent, Query Builder, or raw SQL). View models can hydrate data from any source.
    • Supports eager loading patterns to optimize N+1 queries.

Technical Risk

  • Low-Medium:
    • Dependency Risk: Spatie is a trusted vendor with a strong track record. MIT license mitigates legal concerns.
    • Breaking Changes: Last release in 2026 suggests active maintenance, but Laravel version pinning is critical.
    • Learning Curve: Team must adopt new class-based patterns (vs. procedural view logic). Requires training for junior devs.
    • Testing Impact:
      • View models introduce new testable units (unit tests for model logic, feature tests for rendering).
      • May require mocking adjustments in existing tests (e.g., controllers no longer directly return data).
  • Mitigation:
    • Start with pilot routes (e.g., admin dashboard) to validate the pattern.
    • Use Laravel’s make:view-model artisan command to scaffold boilerplate.
    • Enforce type hints and IDE checks to catch integration issues early.

Key Questions

  1. Adoption Scope:
    • Will this replace all view logic, or only complex components? (Avoid overkill for simple CRUD.)
    • How will it interact with existing view composers? (Deprecate composers or migrate incrementally?)
  2. Performance:
    • Are there hot paths (e.g., API endpoints) where view model instantiation could add latency?
    • Will serialization (e.g., toArray()) become a bottleneck for large payloads?
  3. Team Buy-In:
    • How will the team adapt to class-based view logic vs. traditional controller methods?
    • Are there legacy constraints (e.g., monolithic controllers) that complicate migration?
  4. Testing Strategy:
    • How will view models be unit tested (e.g., data transformation logic) vs. integration tested (rendering)?
    • Will mocking be needed for dependencies (e.g., repositories, APIs)?
  5. Long-Term Maintenance:
    • How will view models evolve if Blade is replaced (e.g., with Livewire or Inertia)?
    • Will the package’s Laravel version support align with the project’s roadmap?

Integration Approach

Stack Fit

  • Primary Fit:
    • Laravel 10+ applications with Blade templates, APIs, or Inertia.js frontends.
    • Projects using Eloquent/Query Builder for data access (view models can hydrate any data source).
    • Teams prioritizing clean architecture, testability, or modular UI components.
  • Partial Fit:
    • Legacy Laravel apps with tightly coupled controllers/views (requires incremental migration).
    • API-first projects where view models are used only for response shaping (not Blade).
  • Non-Fit:
    • Non-Laravel PHP stacks (Symfony, Lumen, native PHP).
    • Serverless/edge-rendered apps (e.g., Cloudflare Workers) without Laravel’s service container.

Migration Path

  1. Assessment Phase:
    • Audit top 20% most complex controllers (by lines of code or logic) for migration candidates.
    • Identify repeated view logic (e.g., dashboard headers, product cards) to prioritize.
  2. Pilot Phase:
    • Create 1–2 view model classes for a non-critical route (e.g., /admin/settings).
    • Replace controller logic with view model instantiation and pass to Blade.
    • Example:
      // Before
      public function showDashboard() {
          return view('dashboard', [
              'stats' => $this->fetchStats(),
              'recentActivity' => Activity::recent()->get(),
          ]);
      }
      
      // After
      public function showDashboard(DashboardViewModel $viewModel) {
          return view('dashboard', ['model' => $viewModel]);
      }
      
  3. Incremental Rollout:
    • Phase 1: Migrate read-heavy routes (e.g., dashboards, listings).
    • Phase 2: Refactor write-heavy routes (e.g., forms) using view models for validation/preparation.
    • Phase 3: Deprecate view composers in favor of view models (if using both).
  4. Tooling:
    • Use make:view-model to generate boilerplate.
    • Leverage IDE refactoring to move logic from controllers to view models.
    • Add PHPStan/Psalm rules to enforce view model usage where applicable.

Compatibility

  • Blade Templates:
    • View models can be passed directly to Blade and accessed as objects:
      {{ $model->stats->revenue }}
      
    • Supports collection view models for iterable data (e.g., product lists).
  • API Responses:
    • Implement JsonSerializable or toArray() for API-friendly output:
      public function toArray(): array {
          return [
              'id' => $this->product->id,
              'name' => $this->product->name,
              'price' => $this->formattedPrice,
          ];
      }
      
  • Livewire/Inertia:
    • Works seamlessly with Livewire properties or Inertia page props.
    • Example (Inertia):
      return Inertia::render('Dashboard', [
          'dashboard' => new DashboardViewModel(),
      ]);
      
  • Service Container:
    • Bind view models as singletons (for shared state) or scoped (per request):
      $this->app->bind(DashboardViewModel::class, function () {
          return new DashboardViewModel(StatsRepository::fetch());
      });
      

Sequencing

  1. Pre-requisites:
    • Upgrade to Laravel 10+ and PHP 8.1+ (if not already).
    • Ensure composer and PHPUnit are configured for dependency management.
  2. Core Integration:
    • Install the package:
      composer require spatie/laravel-view-models
      
    • Publish config (if customizing defaults):
      php artisan vendor:publish --provider="Spatie\ViewModels\ViewModelsServiceProvider"
      
  3. Testing:
    • Write unit tests for view model logic (e.g., data transformation).
    • Update feature tests to assert view model behavior (e.g., Blade rendering).
  4. Deployment:
    • Roll out in feature flags or canary routes to monitor performance.
    • Monitor Blade render times and memory usage post-migration.

Operational Impact

Maintenance

  • Pros:
    • Decoupled logic: Easier to update view models without touching controllers or Blade.
    • Reusable components: View models for shared UI (e.g., headers, footers) reduce duplication.
    • Type safety: IDE autocompletion and static analysis (PHPStan) catch errors early.
    • Testability: Isolated view model logic is easier to mock and test.
  • Cons:
    • Additional classes: More
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport