Validierung und Pflichtfelder bei EAV-Attributen
Validierung und Pflichtfelder bei EAV-Attributen
~6 Min. Lesezeit Zuletzt aktualisiert am 9. August 2026
Kapitel 13 hat title, points_cost und reward_type mit 'required' => true registriert - dieses Kapitel klärt, was diese Einstellung tatsächlich bewirkt, und wo sie an ihre Grenzen stößt.
Die eingebaute Validierung von AbstractEntity
Magento\Eav\Model\Entity\AbstractEntity bringt eine validate($object)-Methode mit, die bei jedem save() automatisch aufgerufen wird. Sie iteriert über alle Attribute des Entity Types, prüft für jedes Attribut mit is_required = 1, ob das Model einen nicht-leeren Wert dafür trägt, und sammelt für jedes fehlende Pflichtfeld einen Fehler ein. Am Ende wirft sie bei mindestens einem Fehler eine \Magento\Framework\Validator\Exception mit allen gesammelten Meldungen - ohne dass die Modul-Klassen dafür auch nur eine Zeile Code schreiben mussten.
$reward = $this->rewardFactory->create();
$reward->setDescription('Nur eine Beschreibung, kein Titel.');
try {
$this->rewardResource->save($reward);
} catch (\Magento\Framework\Validator\Exception $exception) {
foreach ($exception->getMessages() as $message) {
// "title" is a required field. (title, points_cost und reward_type
// fehlen alle drei - drei gesammelte Meldungen in einer Exception.)
}
}Tipp: Diese Basisvalidierung ist der Grund, warum Kapitel 13 required überhaupt gesetzt hat - ohne diese Einstellung ließe sich eine Prämie ohne Titel, ohne Punktepreis und ohne Typ speichern, und die Lücke fiele erst im Frontend auf, wenn ein Kunde eine leere Prämienkarte sieht.
Die Grenzen der eingebauten Validierung
is_required prüft nur "leer oder nicht leer" pro Attribut, isoliert von allen anderen Attributen. Eine geschäftliche Regel wie "discount_value ist nur dann Pflicht, wenn reward_type gleich RewardType::TYPE_DISCOUNT ist" kennt diese Basisvalidierung nicht - dafür braucht es zusätzliche, eigene Logik.
Eigene Validierung per beforeSave()
AbstractModel::save() ruft vor dem eigentlichen ResourceModel::save() die Methode beforeSave() auf - der richtige Ort für Regeln, die mehrere Attribute gleichzeitig betreffen. Eine LocalizedException an dieser Stelle stoppt den kompletten Speichervorgang, bevor auch nur eine Zeile in die Datenbank geschrieben wird.
<?php
declare(strict_types=1);
namespace Mironsoft\Loyalty\Model;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Model\AbstractModel;
use Mironsoft\Loyalty\Model\Reward\Source\RewardType;
use Mironsoft\Loyalty\Model\ResourceModel\Reward as RewardResource;
/**
* Reward EAV entity model, represents a single redeemable reward.
*/
class Reward extends AbstractModel
{
/**
* @var string
*/
public const ENTITY = 'mironsoft_loyalty_reward';
/**
* Binds the model to its resource model.
*
* @return void
*/
protected function _construct(): void
{
$this->_init(RewardResource::class);
}
/**
* Enforces the cross-attribute rule that a discount reward needs a discount value,
* a check the built-in is_required validation cannot express on its own.
*
* @return $this
* @throws LocalizedException
*/
public function beforeSave(): self
{
if ($this->getData('reward_type') === RewardType::TYPE_DISCOUNT
&& (string) $this->getData('discount_value') === ''
) {
throw new LocalizedException(
__('A discount value is required for rewards of type "discount".')
);
}
return parent::beforeSave();
}
}Achtung: beforeSave() läuft vor der eingebauten EAV-Pflichtfeldprüfung aus AbstractEntity::validate(), nicht danach - eine eigene Exception hier verhindert also zuverlässig, dass die teureren EAV-JOINs beim Speichern überhaupt erst versucht werden, wenn die Eingabe schon auf den ersten Blick ungültig ist.
Validierung im Admin-Formular
Im Admin-Formular (dessen UI-Component-XML die dedizierte Admin-Grids-Serie aus Kapitel 16 erklärt) übersetzt sich is_required automatisch in "validation": {"required-entry": true} auf dem jeweiligen Formularfeld - eine clientseitige Vorabprüfung, die die serverseitige Validierung aus diesem Kapitel ergänzt, aber niemals ersetzt. Die clientseitige Prüfung lässt sich umgehen (deaktiviertes JavaScript, direkter API-Aufruf); die serverseitige in AbstractEntity::validate() und beforeSave() nicht.
Mit sauber validierten Attributen schließt Kapitel 18 diesen Block mit der Frage ab, die Kapitel 10 bewusst offengelassen hat: wo genau die Performance-Grenzen von EAV liegen - und was zu tun ist, wenn sie erreicht werden.