Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

ViewModels (ArgumentInterface) vs. klassische Block-Klassen - warum ViewModels bevorzugt werden

ViewModels (ArgumentInterface) vs. klassische Block-Klassen - warum ViewModels bevorzugt werden

~8 Min. Lesezeit Zuletzt aktualisiert am 9. August 2026

Klassisches Magento löst Datenversorgung von Templates häufig über eigene Block-Klassen, die \Magento\Framework\View\Element\Template erweitern. In Hyvä-Projekten - und generell als moderne Magento-2-Konvention - wird stattdessen ein ViewModel bevorzugt, das \Magento\Framework\View\Element\Block\ArgumentInterface implementiert.

Das Problem mit eigenen Block-Klassen

Eine eigene Block-Klasse erbt automatisch die gesamte Komplexität von Template - Caching-Logik, toHtml(), Kind-Block-Verwaltung und vieles mehr, was für reine Datenversorgung gar nicht gebraucht wird. Außerdem kann ein Template nur einen Block als $block haben - wer mehrere unabhängige Datenquellen braucht, verschachtelt entweder weitere Blocks oder injiziert Abhängigkeiten direkt in die Block-Klasse, was Tests erschwert.

Die ViewModel-Alternative

Ein ViewModel ist eine ganz normale PHP-Klasse mit Constructor-Injection, die ArgumentInterface implementiert - ein reines Marker-Interface ohne vorgeschriebene Methoden. Es kann beliebig viele davon pro Template geben, jedes mit eigenem, sprechendem Namen im Layout-XML.

app/code/Mironsoft/TeamPage/ViewModel/TeamMembers.php
<?php

declare(strict_types=1);

namespace Mironsoft\TeamPage\ViewModel;

use Magento\Framework\View\Element\Block\ArgumentInterface;

/**
 * Supplies team members and categories for the team page.
 */
class TeamMembers implements ArgumentInterface
{
    /**
     * @param TeamMemberRepositoryInterface $teamMemberRepository Data source for team members.
     */
    public function __construct(
        private readonly TeamMemberRepositoryInterface $teamMemberRepository,
    ) {
    }

    /**
     * Returns all active team members.
     *
     * @return array<int, array{name: string, role: string, category: string}>
     */
    public function getTeamMembers(): array
    {
        return $this->teamMemberRepository->getActive();
    }
}

Diese Klasse weiß nichts von HTML-Rendering, Caching oder Kind-Blocks - sie liefert reine Daten. Genau diese Trennung macht ViewModels leicht testbar: Ein Unit-Test instanziiert die Klasse mit einem Mock des Repositories, ganz ohne Magentos schwere Block-Infrastruktur mitschleppen zu müssen.

Bindung im Template

Im Template steht das ViewModel unter dem Argument-Namen zur Verfügung, der im Layout-XML vergeben wurde (siehe Kapitel 6):

Zugriff im Template
<?php
/** @var \Magento\Framework\Escaper $escaper */
/** @var \Magento\Framework\View\Element\Template $block */
/** @var \Mironsoft\TeamPage\ViewModel\TeamMembers $teamViewModel */
$teamViewModel = $block->getData('team_view_model');
?>

Mehrere ViewModels pro Block

Ein Block kann mehrere ViewModel-Argumente gleichzeitig binden - zum Beispiel ein ViewModel für Team-Daten und ein zweites für allgemeine Store-Konfiguration. Jedes bekommt einen eigenen argument name="..."-Wert im Layout-XML und wird im Template unter genau diesem Namen abgerufen.

Tipp: Faustregel für dieses Projekt: Neue Templates bekommen ein ViewModel, keine eigene Block-Klasse - außer es gibt einen sehr konkreten Grund, Template-Rendering-Verhalten selbst zu überschreiben (was ViewModels grundsätzlich nicht können, weil sie kein toHtml() haben).

Wann doch eine Block-Klasse?

Eine eigene Block-Klasse bleibt sinnvoll, wenn tatsächlich Rendering-Verhalten überschrieben werden muss - etwa eigenes Caching, eigene toHtml()-Logik oder das Verwalten vieler Kind-Blocks mit komplexer Sortierung. Für reine Datenversorgung, wie in praktisch allen Fällen dieser Serie, reicht ein ViewModel.