eigener Form-Validator mit Select-Feldern

Das Forum soll der Ablage von Lösungen für immer wieder auftauchende Problemstellungen dienen. // This forum contains solutions to problems that frequently occur.
Antworten
Benutzeravatar
dave
Beiträge: 903
Registriert: 04.02.2011, 19:03:57
Wohnort: Berlin
Kontaktdaten:

eigener Form-Validator mit Select-Feldern

Beitrag von dave » 28.07.2015, 17:51:18

Hi zusammen,

ich möchte mir einen eigenen Form-Validator bauen, mit dem ich select-Felder überprüfen kann.

Laut Doku (http://adventure-php-framework.org/Seit ... alidatoren) muss ich dazu den SelectFieldValidator nutzen. Wenn ich dies nun allerdings tue, und ein Select überprüfen möchte in der Art

Code: Alles auswählen

$form = & $this->control->getForm();
$Select1 = $form->getFormElementByName('select-markt')->getSelectedOption()->getValue();
 
erhalte ich nur einen Error, welcher darauf hindeutet, dass ich ein getValue() nicht darauf anwenden kann, da es sich nicht um ein Objekt handelt:
Call to a member function getValue() on a non-object in ...
Schaue ich mir einmal den SelectSelectFieldValidator an, bemerke ich, dass dieser leer ist, mit einem netten Kommentar, dass die Markierung nun über CSS-Klassen erfolgt.

Wie kann ich mir nun einfach einen eigenen Select-Validator bauen, mit dem ich die bekannten Methoden getSelectedOption() etc. verwenden kann?

PS: Den "SimpleSelectControlValidator" habe ich mir bereits angesehen, aber wie ich daraus nun mehrere Selects ableiten kann, ist mir nicht schlüssig.

Benutzeravatar
dr.e.
Administrator
Beiträge: 4527
Registriert: 04.11.2007, 16:13:53

Re: eigener Form-Validator mit Select-Feldern

Beitrag von dr.e. » 29.07.2015, 09:21:16

Hallo dave,
Laut Doku (http://adventure-php-framework.org/Seit ... alidatoren) muss ich dazu den SelectFieldValidator nutzen.
Ja und nein. Du kannst die Implementierung als Vorlage nutzen musst das aber nicht. Sofern du deinen eigenen Validator from-the-scratch implementierst kommen evtl. einfach nur ein paar Punkte mehr dazu, die du beachten solltest bzw. die zusätzlich zu implementieren sind.

Lass es uns Stück für Stück angehen. :)
erhalte ich nur einen Error, welcher darauf hindeutet, dass ich ein getValue() nicht darauf anwenden kann, da es sich nicht um ein Objekt handelt:
Korrekt. getSelectedOption() kann null zurück liefern, falls keine Option selektiert wurde. Insofern solltest du diesen Fall in deinem Validator abfangen.
Schaue ich mir einmal den SelectFieldValidator an, bemerke ich, dass dieser leer ist, mit einem netten Kommentar, dass die Markierung nun über CSS-Klassen erfolgt.
Der SelectFieldValidator ist Software-Design-technisch quasi eine Abstraktion und Klammer für alle SelectField-Validatoren. Du musst - wie oben beschrieben . allerdings nicht davon erben, sondern kannst auch einfach von AbstractFormValidator ausgehend starten. Um die Implementierung einfach zu halten ist es allerdings empfehlenswert von TextFieldValidator zu starten, da dort bereits die notwendige Infrastruktur für z.B. die Markierung von invaliden Feldern für dich fertig vorbereitet ist (z.B. notify()).

Code: Alles auswählen

$form = & $this->control->getForm();
$Select1 = $form->getFormElementByName('select-markt')->getSelectedOption()->getValue(); 
Validatoren werden als Observer direkt auf ein Feld registriert (entweder im Template oder (dynamisch) per Controller). Aus diesem Grund ist es empfehlenswert den Validator direkt auf dasjenige Feld zu hängen das es auch betrifft (z.B. select-markt) statt auf ein beliebiges Feld um darin dann ein anderes Feld zu validieren. Evtl. kenne ich jedoch auch deine kompletten Anforderungen nicht und liege daneben.

Lass mich wissen, ob dir das weiter hilft! :)
Viele Grüße,
Christian

Benutzeravatar
dave
Beiträge: 903
Registriert: 04.02.2011, 19:03:57
Wohnort: Berlin
Kontaktdaten:

Re: eigener Form-Validator mit Select-Feldern

Beitrag von dave » 29.07.2015, 18:43:42

dr.e. hat geschrieben:Validatoren werden als Observer direkt auf ein Feld registriert (entweder im Template oder (dynamisch) per Controller). Aus diesem Grund ist es empfehlenswert den Validator direkt auf dasjenige Feld zu hängen das es auch betrifft (z.B. select-markt) statt auf ein beliebiges Feld um darin dann ein anderes Feld zu validieren. Evtl. kenne ich jedoch auch deine kompletten Anforderungen nicht und liege daneben.
Jup, das ist soweit logisch. Ich habe als Vorlage dafür den FieldCompareValidator genutzt, dort wird es ähnlich gehandhabt, nur statt zwei Elementen, wie bei mir, wird nur eines genutzt. Ich habe mir daraus bereits einen eigenen Validator gebaut, der jedoch nur auf normale Input-Formular-Elemente schaut und das funktioniert einwandfrei. Nun wollte ich einen weiteren Validator bauen, der jedoch statt Inputs mit Selects arbeitet.
Was ich erreichen möchte ist folgendes: Es gibt insgesamt drei Select-Felder, wovon immer nur bei einem der drei Selects eine Auswahl getroffen werden darf. Wurde bei zwei oder drei Selects eine Option gewählt, muss eine Fehlermeldung kommen. Bisher habe ich das im Controller nach dem Senden des Formulares gelöst, finde das aber unschön, da dies wie alle anderen Validatoren auch schon vor dem eigentlich erfolgreichen Absenden des Formulares geschehen kann.

Ich glaube, wir müssen etwas weiter ausholen:

1. Der Validator wird erst beim Absenden des Formulares ausgeführt?
2. Ich befülle meine Selects dynamisch im Controller mit Inhalt. Kann es daher evtl. zu der Fehlermeldung
Call to a member function getAttribute() on a non-object
kommen?


Ich füge mal den Code meines Validators ein, vllt. kannst du anhand dessen meine Problematik besser verstehen:

Code: Alles auswählen

namespace WEB\pres\validator;

use APF\tools\form\validator\TextFieldValidator;
use APF\tools\form\taglib\AbstractFormControl;

class MarktSelectionValidator extends TextFieldValidator {

    protected $lebensmittelmarkt = null;
    protected $handelskette = null;

    public function __construct(AbstractFormControl &$control, AbstractFormControl &$button, $type = null) {
        $this->control = & $control;
        $this->button = & $button;
        $this->type = $type;

        $this->initializeFormElements();
    }

    public function validate($input) { //input kommt vom Stamm-Lebensmittelmarkt $form->getFormElementByName('select-stammlebensmittelmarkt')
        
        $selLebenmittelmarkt = $this->lebensmittelmarkt->getSelectedOption()->getValue();
        $selLebenmittelmarkt = $this->handelskette->getSelectedOption()->getValue();

        if ( /* wir überprüfen diverse Auswahl-Szenarien */ ) {
            return false; // False - Auswahl fehlerhaft
        } else {
            return true; // True - Auswahl Ok
        }
    }

    private function initializeFormElements() {
        $form = & $this->control->getForm();

        $this->lebensmittelmarkt = & $form->getFormElementByName('select-markt');
        $this->handelskette = & $form->getFormElementByName('select-handelskette');
    }

    public function notify() {
        $this->control->markAsInvalid();
        $this->lebensmittelmarkt->markAsInvalid();
        $this->handelskette->markAsInvalid();
        $this->markControl($this->control);
        $this->markControl($this->lebensmittelmarkt);
        $this->markControl($this->handelskette);
        $this->notifyValidationListeners($this->control);
        $this->notifyValidationListeners($this->lebensmittelmarkt);
        $this->notifyValidationListeners($this->handelskette);
    }
}
Wie gesagt, Vorlage ist der FieldCompareValidator gewesen ;)

Der Validator wird dann ganz einfach im Formular wie alle anderen auch, verwendet:

Code: Alles auswählen

<form:addvalidator
            class="WEB\pres\validator\MarktSelectionValidator"
            button="sendProduktPreisAdd"
            control="select-stammlebensmittelmarkt"
            />

Benutzeravatar
dr.e.
Administrator
Beiträge: 4527
Registriert: 04.11.2007, 16:13:53

Re: eigener Form-Validator mit Select-Feldern

Beitrag von dr.e. » 30.07.2015, 16:24:54

Hallo dave,

danke für deine Zusammenfassung der Anforderungen das hilft mir sehr!
1. Der Validator wird erst beim Absenden des Formulares ausgeführt?
Korrekt. Genauer: in der onAfterAppend()-Phase sprich bevor der Controller ausgeführt wird.
2. Ich befülle meine Selects dynamisch im Controller mit Inhalt. Kann es daher evtl. zu der Fehlermeldung

Code: Alles auswählen

Call to a member function getAttribute() on a non-object


kommen?
Absolut! Wenn du dein Feld im Controller dynamisch befüllst, kann zuvor ja noch nicht auf einen ausgewählten Eintrag validiert werden. Aus diesem Grund nutzt z.B. der SimpleSelectValidator den Request-Wert und nicht die Werte direkt. Wenn du das so implementieren möchtest, hänge den Validator doch einfach nach der Befüllung dynamisch auf das Feld im Controller. Das ist vom APF für dynamische Formulare ebenfalls unterstützt.

Ich denke insbesonders letzteres sollte dich zum Ziel führen.
Viele Grüße,
Christian

Benutzeravatar
dave
Beiträge: 903
Registriert: 04.02.2011, 19:03:57
Wohnort: Berlin
Kontaktdaten:

Re: eigener Form-Validator mit Select-Feldern

Beitrag von dave » 30.07.2015, 18:52:43

Hi Christian,
perfekt, langsam nähern wir uns :)

Die Validierung im Controller habe ich bisher drin, allerdings finde ich das Prinzip, einen Validator im HTML-Template zu definieren, um den ich mich nicht mehr weiter kümmern muss, absolut genial. Daher möchte ich gern jegliche Validierung aus dem Controller entfernen und auslagern. Zumal der Code des Controllers dadurch auch schlanker wird.

Ich schaue mir das ganze nochmal an und versuche mal direkt mit den Request-Werten zu arbeiten. Immerhin weiss ich nun, was ich bisher falsch gemacht habe ;) Ich melde mich nochmal!

EDIT
Ich habe es nun für mich sauber gelöst bekommen. Der Request hast mit wunderbar geholfen. Zur Vollständigkeit poste ich hier mal meinen ganezn Validator:

Code: Alles auswählen

namespace WEB\pres\validator;

use APF\tools\form\validator\SelectFieldValidator;

class MarktSelectionValidator extends SelectFieldValidator {

    public function validate($input) {

        $form = $this->control->getForm();

        $StammMarkt = $this->control->getAttribute('name');
        $Lebensmittelmarkt = $form->getFormElementByName('select-markt')->getAttribute('name');
        $Handelskette = $form->getFormElementByName('select-handelskette')->getAttribute('name');

        $selStammMarkt = self::getRequest()->getParameter($StammMarkt);
        $selLebenmittelmarkt = self::getRequest()->getParameter($Lebensmittelmarkt);
        $selHandelskette = self::getRequest()->getParameter($Handelskette);

        if ((/* Wir überprüfen diverse Selektions-Szenarien */)) {
            return false; // False - Auswahl fehlerhaft
        } else {
            return true; // True - Auswahl Ok
        }
    }

    public function notify() {
        $form = $this->control->getForm();

        $Lebensmittelmarkt = $form->getFormElementByName('select-markt');
        $Handelskette = $form->getFormElementByName('select-handelskette');

        $this->control->markAsInvalid();
        $Lebensmittelmarkt->markAsInvalid();
        $Handelskette->markAsInvalid();
        $this->markControl($this->control);
        $this->markControl($Lebensmittelmarkt);
        $this->markControl($Handelskette);
        $this->notifyValidationListeners($this->control);
        $this->notifyValidationListeners($Lebensmittelmarkt);
        $this->notifyValidationListeners($Handelskette);
    }
}
 
Danke Christian, du hast mich auf die richtige Spur geführt.

Benutzeravatar
dr.e.
Administrator
Beiträge: 4527
Registriert: 04.11.2007, 16:13:53

Re: eigener Form-Validator mit Select-Feldern

Beitrag von dr.e. » 30.07.2015, 22:55:22

Perfekt! :)
Viele Grüße,
Christian

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast