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:
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
- Presenters - Presenters create ViewModels
- Twig Integration - Templates consume ViewModels