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

Grid für Kundenstimmen bauen: Spalten, Filter, Massenaktionen

Grid für Kundenstimmen bauen: Spalten, Filter, Massenaktionen

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

Mit den Grundlagen aus Block 2 lässt sich der Testimonial-Grid jetzt zügig zusammensetzen - Controller, Layout, listing.xml und DataProvider folgen exakt dem Muster aus den Kapiteln 4 und 5, hier direkt vollständig für das echte Projekt.

DataProvider

app/code/Mironsoft/Testimonial/Ui/DataProvider/Listing/TestimonialDataProvider.php
<?php

declare(strict_types=1);

namespace Mironsoft\Testimonial\Ui\DataProvider\Listing;

use Magento\Ui\DataProvider\AbstractDataProvider;
use Mironsoft\Testimonial\Model\ResourceModel\Testimonial\CollectionFactory;

/**
 * Supplies testimonial rows to the admin grid.
 */
class TestimonialDataProvider extends AbstractDataProvider
{
    /**
     * @param string $name Component name, injected by the UI Component framework.
     * @param string $primaryFieldName Primary key column of the underlying collection.
     * @param string $requestFieldName Request parameter name carrying the current ID.
     * @param CollectionFactory $collectionFactory Factory building the testimonial collection.
     * @param array<string, mixed> $meta Additional UI Component meta configuration.
     * @param array<string, mixed> $data Additional UI Component data configuration.
     */
    public function __construct(
        string $name,
        string $primaryFieldName,
        string $requestFieldName,
        CollectionFactory $collectionFactory,
        array $meta = [],
        array $data = [],
    ) {
        parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
        $this->collection = $collectionFactory->create();
    }
}

listing.xml mit allen Spaltentypen aus Block 2

app/code/Mironsoft/Testimonial/view/adminhtml/ui_component/mironsoft_testimonial_listing.xml
<?xml version="1.0"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_components.xsd">
    <argument name="data" xsi:type="array">
        <item name="js_config" xsi:type="array">
            <item name="provider" xsi:type="string">mironsoft_testimonial_listing.mironsoft_testimonial_listing_data_source</item>
        </item>
        <item name="spinner" xsi:type="string">testimonial_columns</item>
        <item name="deps" xsi:type="string">mironsoft_testimonial_listing.mironsoft_testimonial_listing_data_source</item>
    </argument>

    <dataSource name="mironsoft_testimonial_listing_data_source">
        <argument name="dataProvider" xsi:type="configurableObject">
            <argument name="class" xsi:type="string">Mironsoft\Testimonial\Ui\DataProvider\Listing\TestimonialDataProvider</argument>
            <argument name="name" xsi:type="string">mironsoft_testimonial_listing_data_source</argument>
            <argument name="primaryFieldName" xsi:type="string">testimonial_id</argument>
            <argument name="requestFieldName" xsi:type="string">id</argument>
        </argument>
        <argument name="data" xsi:type="array">
            <item name="js_config" xsi:type="array">
                <item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
            </item>
        </argument>
    </dataSource>

    <listingToolbar name="listing_top">
        <filters name="listing_filters"/>
        <massaction name="listing_massaction"/>
        <paging name="listing_paging"/>
    </listingToolbar>

    <columns name="testimonial_columns">
        <column name="testimonial_id">
            <settings>
                <filter>text</filter>
                <label translate="true">ID</label>
                <sorting>desc</sorting>
            </settings>
        </column>
        <column name="image" component="Magento_Ui/js/grid/columns/thumbnail">
            <settings>
                <altField>customer_name</altField>
                <has_preview>1</has_preview>
                <label translate="true">Photo</label>
                <sortable>false</sortable>
            </settings>
        </column>
        <column name="customer_name">
            <settings>
                <filter>text</filter>
                <label translate="true">Customer</label>
            </settings>
        </column>
        <column name="company">
            <settings>
                <filter>text</filter>
                <label translate="true">Company</label>
            </settings>
        </column>
        <column name="rating">
            <settings>
                <filter>textRange</filter>
                <dataType>text</dataType>
                <label translate="true">Rating</label>
            </settings>
        </column>
        <column name="is_active">
            <settings>
                <options class="Mironsoft\Testimonial\Model\Source\IsActive"/>
                <filter>select</filter>
                <dataType>select</dataType>
                <label translate="true">Status</label>
            </settings>
        </column>
        <actionsColumn name="actions" class="Magento\Ui\Component\Listing\Columns\Actions">
            <settings>
                <indexField>testimonial_id</indexField>
                <resizeEnabled>false</resizeEnabled>
                <sortable>false</sortable>
            </settings>
        </actionsColumn>
    </columns>
</listing>

Die Spaltenauswahl kombiniert bewusst alles aus Kapitel 6: image als Thumbnail, rating mit textRange-Filter (eine Bewertung zwischen 3 und 5 filtern zum Beispiel), is_active als Select mit derselben IsActive-Source-Klasse wie im Übungsmodul.

Massenaktionen: Delete und Status

Die massaction-Deklaration und die MassDelete/MassStatus-Controller entsprechen eins zu eins Kapitel 8 - Filter::getCollection() übernimmt erneut die komplette Selektionslogik, nur Namensraum und Tabellenname ändern sich auf Testimonial.

Achtung: Beim Massenlöschen greift jetzt die onDelete="CASCADE"-Regel aus Kapitel 14: Jedes $testimonial->delete() löscht automatisch auch die zugehörigen Zeilen in mironsoft_testimonial_store. Ohne diese Kaskade müsste der MassDelete-Controller die Store-Relationen manuell vorher entfernen.

Die IsActive-Source-Klasse

Dieselbe kleine Klasse aus Kapitel 6 wird hier eins zu eins für das Testimonial-Modul wiederholt (eigener Namespace Mironsoft\Testimonial\Model\Source) - Grid-Filter und Formular-Select (Kapitel 16) greifen später auf dieselbe Quelle zurück.