Erste Antwort: Eine Schlüsselrolle des Modells ist die Aufrechterhaltung der Integrität. Die Verarbeitung von Benutzereingaben liegt jedoch in der Verantwortung eines Controllers.
Das heißt, der Controller muss Benutzerdaten (die meistens nur Zeichenfolgen sind) in etwas Sinnvolles übersetzen. Dies erfordert eine Syntaxanalyse (und hängt möglicherweise vom Gebietsschema ab, da es beispielsweise verschiedene Dezimaloperatoren usw. gibt).
Die eigentliche Validierung, wie in "Sind die Daten korrekt aufgebaut?", Sollte also von der Steuerung durchgeführt werden. Allerdings ist die Überprüfung, wie in "Sind die Daten sinnvoll?" sollte innerhalb des Modells durchgeführt werden.
Um dies an einem Beispiel zu verdeutlichen:
Angenommen, Sie können in Ihrer Anwendung Entitäten mit einem Datum hinzufügen (z. B. ein Problem mit einer Frist). Möglicherweise verfügen Sie über eine API, in der Datumsangaben als reine Unix-Zeitstempel dargestellt werden. Wenn Sie von einer HTML-Seite stammen, handelt es sich um eine Reihe unterschiedlicher Werte oder eine Zeichenfolge im Format MM / TT / JJJJ. Sie möchten diese Informationen nicht im Modell haben. Sie möchten, dass jeder Controller einzeln versucht, das Datum herauszufinden. Wenn das Datum dann an das Modell übergeben wird, muss das Modell jedoch die Integrität beibehalten. Beispielsweise kann es sinnvoll sein, Termine in der Vergangenheit oder Termine an Feiertagen / Sonntagen usw. nicht zuzulassen.
Ihr Controller enthält Eingaberegeln (Verarbeitungsregeln). Ihr Modell enthält Geschäftsregeln. Sie möchten, dass Ihre Geschäftsregeln immer durchgesetzt werden, egal was passiert. Angenommen, Sie hätten Geschäftsregeln im Controller, dann müssten Sie diese duplizieren, falls Sie jemals einen anderen Controller erstellen sollten.
Zweite Antwort: Der Ansatz ist sinnvoll, die Methode könnte jedoch leistungsfähiger gemacht werden. Anstatt dass der letzte Parameter ein Array ist, sollte es sich um eine Instanz handeln, IContstraint
die wie folgt definiert ist:
interface IConstraint {
function test($value);//returns bool
}
Und für Zahlen könnte man so etwas haben
class NumConstraint {
var $grain;
var $min;
var $max;
function __construct($grain = 1, $min = NULL, $max = NULL) {
if ($min === NULL) $min = INT_MIN;
if ($max === NULL) $max = INT_MAX;
$this->min = $min;
$this->max = $max;
$this->grain = $grain;
}
function test($value) {
return ($value % $this->grain == 0 && $value >= $min && $value <= $max);
}
}
Ich sehe auch nicht, was 'Age'
gemeint ist, um ehrlich zu sein. Ist es der tatsächliche Name der Immobilie? Unter der Annahme, dass es standardmäßig eine Konvention gibt, kann der Parameter einfach an das Ende der Funktion gehen und optional sein. Wenn nicht festgelegt, wird standardmäßig der Wert to_camel_case des DB-Spaltennamens verwendet.
So würde der Beispielaufruf aussehen:
register_property('age', new NumConstraint(1, 10, 30));
Der Sinn der Verwendung von Schnittstellen besteht darin, dass Sie im Laufe der Zeit immer mehr Einschränkungen hinzufügen können, und diese können so kompliziert sein, wie Sie möchten. Damit eine Zeichenfolge mit einem regulären Ausdruck übereinstimmt. Für einen Termin mindestens 7 Tage voraus sein. Und so weiter.
Dritte Antwort: Jede Model-Entität sollte eine Methode wie haben Result checkValue(string property, mixed value)
. Die Steuerung sollte es vor dem Einstellen der Daten aufrufen . Sie Result
sollten alle Informationen darüber haben, ob die Überprüfung fehlgeschlagen ist, und in diesem Fall Gründe angeben, damit der Controller diese an die Ansicht entsprechend weitergeben kann.
Wenn ein falscher Wert an das Modell übergeben wird, sollte das Modell einfach durch Auslösen einer Ausnahme reagieren.
Ich bin mit "back2dos" nicht ganz einverstanden: Ich empfehle, immer eine separate Formular- / Validierungsschicht zu verwenden, mit der der Controller die Eingabedaten validieren kann, bevor sie an das Modell gesendet werden.
Theoretisch gesehen basiert die Modellvalidierung auf vertrauenswürdigen Daten (interner Systemstatus) und sollte im Idealfall zu jedem Zeitpunkt wiederholbar sein, während die Eingabevalidierung explizit einmal auf Daten angewendet wird, die aus nicht vertrauenswürdigen Quellen stammen (abhängig vom Anwendungsfall und den Benutzerrechten).
Diese Trennung ermöglicht es, wiederverwendbare Modelle, Steuerungen und Formulare zu erstellen, die durch Abhängigkeitsinjektion lose gekoppelt werden können. Stellen Sie sich die Eingabevalidierung als Whitelist-Validierung vor („als gut bekannt akzeptieren“) und die Modellvalidierung als Blacklist-Validierung („als schlecht bekannt ablehnen“). Die Validierung von Whitelists ist sicherer, während die Validierung von Blacklists verhindert, dass Ihr Modell-Layer zu sehr auf bestimmte Anwendungsfälle beschränkt wird.
Ungültige Modelldaten sollten immer dazu führen, dass eine Ausnahme ausgelöst wird (andernfalls kann die Anwendung weiter ausgeführt werden, ohne dass der Fehler bemerkt wird), während ungültige Eingabewerte aus externen Quellen nicht unerwartet, sondern häufig auftreten (es sei denn, Sie haben Benutzer, die niemals Fehler machen).
Siehe auch: https://lastzero.net/2015/11/why-im-using-a-separate-layer-for-input-data-validation/
quelle
Ja, das Modell sollte validiert werden. Die Benutzeroberfläche sollte auch die Eingabe validieren.
Es liegt eindeutig in der Verantwortung des Modells, gültige Werte und Zustände zu bestimmen. Manchmal ändern sich solche Regeln oft. In diesem Fall würde ich das Modell aus Metadaten füttern und / oder dekorieren.
quelle
Gute Frage!
Was die Entwicklung des World Wide Web angeht, was ist, wenn Sie auch Folgendes fragen?
"Wenn einer Steuerung eine falsche Benutzereingabe von einer Benutzerschnittstelle aus übermittelt wird, sollte die Steuerung die Ansicht in einer Art zyklischen Schleife aktualisieren, um zu erzwingen, dass Befehle und Eingabedaten genau sind, bevor sie verarbeitet werden ? Wie? Wie wird die Ansicht unter normalen Bedingungen aktualisiert Bedingungen Ist eine Ansicht eng an ein Modell gekoppelt? Ist die Kerngeschäftslogik der Benutzereingabevalidierung des Modells oder ist sie vorläufig und sollte daher innerhalb des Controllers erfolgen (da Benutzereingabedaten Teil der Anforderung sind)?
(Kann und sollte eine Instanziierung eines Modells tatsächlich verzögert werden, bis eine gute Eingabe erfolgt?)
Meiner Meinung nach sollten Modelle einen reinen und makellosen Umstand (so weit wie möglich) handhaben, der nicht durch die grundlegende Validierung der HTTP-Anforderungseingaben beeinträchtigt wird , die vor der Modellinstanziierung (und definitiv bevor das Modell Eingabedaten erhält) erfolgen sollte. Da das Verwalten von Statusdaten (persistent oder anderweitig) und API-Beziehungen die Welt des Modells ist, können grundlegende Überprüfungen der HTTP-Anforderungseingaben im Controller erfolgen.
Zusammenfassend.
1) Überprüfen Sie Ihre Route (aus der URL analysiert), da der Controller und die Methode vorhanden sein müssen, bevor etwas anderes ausgeführt werden kann. Dies sollte auf jeden Fall im Front-Controller-Bereich (Router-Klasse) geschehen, bevor Sie zum wahren Controller gelangen. Duh. :-)
2) Ein Modell kann viele Quellen für Eingabedaten haben: eine HTTP-Anfrage, eine Datenbank, eine Datei, eine API und ja, ein Netzwerk. Wenn Sie Ihre gesamte Eingabevalidierung in das Modell einfügen möchten, betrachten Sie die Eingabevalidierung für HTTP-Anforderungen als Teil der Geschäftsanforderungen für das Programm. Fall abgeschlossen.
3) Es ist jedoch kurzsichtig, die Ausgaben für die Instanziierung vieler Objekte zu durchlaufen, wenn die HTTP-Anforderungseingabe nicht gut ist! Sie können feststellen, ob die Eingabe von ** HTTP-Anforderungen ** in Ordnung ist ( die mit der Anforderung eingegangen ist ), indem Sie sie validieren, bevor Sie das Modell und alle seine Komplexitäten instanziieren (ja, vielleicht noch mehr Validatoren für API- und DB-Eingabe- / Ausgabedaten).
Testen Sie Folgendes:
a) Die HTTP-Anforderungsmethode (GET, POST, PUT, PATCH, DELETE ...)
b) Minimale HTML-Steuerelemente (haben Sie genug?).
c) Maximale HTML-Steuerelemente (haben Sie zu viele?).
d) Richtige HTML-Steuerelemente (haben Sie die richtigen?).
e) Eingabecodierung (normalerweise UTF-8?).
f) Maximale Eingabegröße (ist eine der Eingaben unzulässig?).
Denken Sie daran, dass Sie möglicherweise Zeichenfolgen und Dateien abrufen, sodass das Warten auf die Instanziierung des Modells sehr teuer werden kann, wenn Anforderungen Ihren Server erreichen.
Was ich hier beschrieben habe, trifft auf die Absicht, dass die Anforderung über den Controller eingeht. Wenn Sie die Überprüfung der Absicht auslassen, ist Ihre Anwendung anfälliger. Absicht kann nur gut sein (nach deinen Grundregeln spielen) oder schlecht (außerhalb deiner Grundregeln gehen).
Die Absicht für eine HTTP-Anfrage ist alles oder nichts. Alles ist bestanden oder die Anfrage ist ungültig . Sie müssen nichts an das Modell senden.
Diese Grundstufe der HTTP - Anforderung Absicht hat nichts mit normalen Benutzereingabefehler und Validierung zu tun. In meinen Anwendungen muss eine HTTP-Anforderung auf die oben genannten fünf Arten gültig sein, damit ich sie berücksichtigen kann. In einer Verteidigung-in-Tiefe Art zu sprechen, erhalten Sie nie auf Benutzereingaben Validierung auf der Server-Seite , wenn alle diese fünf Dinge fehlschlagen.
Ja, dies bedeutet, dass auch die Dateieingabe Ihren Front-End-Versuchen entsprechen muss, um den Benutzer zu verifizieren und ihm die maximal akzeptierte Dateigröße mitzuteilen. Nur HTML? Kein JavaScript? Gut, aber der Benutzer muss über die Konsequenzen des Hochladens von zu großen Dateien informiert werden (hauptsächlich, dass sie alle Formulardaten verlieren und aus dem System geworfen werden).
4) Bedeutet dies, dass die Eingabedaten für HTTP-Anforderungen nicht Teil der Geschäftslogik der Anwendung sind? Nein, es bedeutet nur, dass Computer endliche Geräte sind und Ressourcen mit Bedacht eingesetzt werden müssen. Es ist sinnvoll, böswillige Aktivitäten früher und nicht später einzustellen. Sie zahlen mehr in Rechenressourcen für das Warten, um es später zu stoppen.
5) Wenn die HTTP-Anforderungseingabe fehlerhaft ist, ist die gesamte Anforderung fehlerhaft . So sehe ich es. Die Definition einer guten HTTP-Anforderungseingabe wird von den Geschäftsanforderungen des Modells abgeleitet, es muss jedoch einen gewissen Punkt für die Abgrenzung der Ressourcen geben. Wie lange werden Sie eine schlechte Anfrage noch leben lassen, bevor Sie sie töten und sagen: "Oh, hey, macht nichts. Schlechte Anfrage."
Das Urteil ist nicht einfach, dass der Benutzer einen vernünftigen Eingabefehler begangen hat, sondern dass eine HTTP-Anfrage so unzulässig ist, dass sie als böswillig eingestuft und sofort gestoppt werden muss.
6) Für mein Geld ist die HTTP-Anfrage (METHODE, URL / Route und Daten) entweder ALLES in Ordnung oder NICHTS anderes kann fortgesetzt werden. Ein robustes Modell muss sich bereits mit Validierungsaufgaben befassen, aber ein guter Ressourcenschäfer sagt: "Mein Weg oder der hohe Weg. Kommt richtig oder kommt gar nicht."
Es ist jedoch Ihr Programm. "Es gibt mehr als einen Weg, dies zu tun." Manche Wege kosten mehr Zeit und Geld als andere. Ein späteres Validieren von HTTP-Anforderungsdaten (im Modell) sollte über die Lebensdauer einer Anwendung (insbesondere beim Vergrößern oder Verkleinern) höhere Kosten verursachen.
Wenn Ihre Validatoren modular aufgebaut sind, sollte die Validierung der grundlegenden * HTTP-Anforderungseingabe ** im Controller kein Problem darstellen. Verwenden Sie einfach eine strategische Validator-Klasse, in der Validatoren manchmal auch aus spezialisierten Validatoren bestehen (E-Mail, Telefon, Formular-Token, Captcha, ...).
Einige halten dies für völlig falsch, aber HTTP steckte noch in den Kinderschuhen, als die Viererbande Entwurfsmuster schrieb : Elemente wiederverwendbarer objektorientierter Software .
================================================ =======================
Da es sich nun um die normale Überprüfung von Benutzereingaben handelt (nachdem die HTTP-Anforderung als gültig eingestuft wurde), wird die Ansicht aktualisiert, wenn der Benutzer Fehler macht, über die Sie nachdenken müssen! Diese Art der Benutzereingabevalidierung sollte im Modell erfolgen.
Sie haben keine Garantie für JavaScript im Front-End. Das heißt, Sie können keine asynchrone Aktualisierung der Benutzeroberfläche Ihrer Anwendung mit Fehlerstatus garantieren. Eine echte progressive Verbesserung würde auch den synchronen Anwendungsfall abdecken.
Den synchronen Anwendungsfall zu berücksichtigen, ist eine Kunst, die immer mehr verloren geht, weil einige Leute nicht die Zeit und Mühe auf sich nehmen wollen, den Status aller ihrer UI-Tricks zu verfolgen (Steuerelemente ein- / ausblenden, Steuerelemente deaktivieren / aktivieren) , Fehleranzeigen, Fehlermeldungen) im Back-End (in der Regel durch Statusverfolgung in Arrays).
Update : Im Diagramm sage ich, dass das auf
View
das verweisen sollModel
. Nein. Sie sollten Daten anView
das übergebenModel
, um eine lose Kopplung zu erhalten.quelle