Skip to content

View Models

ViewModels are simple data structures holding exactly what a template needs to render.

Structure

ViewModels are readonly classes with public properties:

final readonly class ListBooksHtmlViewModel
{
    public function __construct(
        public array $books,
        public int $count,
        public bool $can_create_book = false
    ) {}
}

Design Principles

Flat Structure

Use primitives and arrays for easy template consumption:

final readonly class DetailBookHtmlViewModel
{
    public function __construct(
        public string $id,
        public string $title,
        public string $status,
        public string $statusClass,  // CSS class ready
        public bool $can_update_book = false
    ) {}
}

Display-Ready Data

All data should be formatted for display. Transform in the presenter, not the template.

Permission Flags

Include booleans for conditional UI elements:

public bool $can_create_book = false,
public bool $can_delete_book = false,

Template Usage

{% if can_create_book %}
<a href="/books/create" class="btn btn-primary">Add Book</a>
{% endif %}

{% for book in books %}
<tr>
    <td>{{ book.title }}</td>
    <td><span class="badge {{ book.statusClass }}">{{ book.status }}</span></td>
</tr>
{% endfor %}

Form ViewModels

Include values and errors for forms:

final readonly class CreateBookHtmlViewModel
{
    public function __construct(
        public array $formValues = [],
        public array $errors = []
    ) {}
}

Best Practices

  • Keep ViewModels immutable (readonly)
  • Use descriptive property names
  • Include all data the template needs
  • Use primitives, avoid complex objects
  • One ViewModel per view

See Also