Files
yii/docs/guide/de/form.model.txt
2009-11-01 17:58:27 +00:00

445 lines
16 KiB
Plaintext

Erstellen des Models
====================
Bevor wir den HTML-Code für ein Formular schreiben, sollten wir entscheiden,
welche Daten wir vom Endbenutzer erwarten und welche Regeln diese Daten
erfüllen sollen. Eine Model-Klasse kann genutzt werden um diese Informationen
aufzunehmen. Wie im Abschnitt [Model](/doc/guide/basics.model)
definiert, ist ein Model ein zentraler Ort zur Aufbewahrung und
Gültigkeitsprüfung von Benutzereingaben.
Je nachdem, wie wir die Benutzereingaben weiterverwenden, können wir zwischen
zwei Model-Typen wählen. Wenn Benutzereingaben erfasst, verarbeitet und dann verworfen
werden sollen, erstellen wir ein [Formular-Model](/doc/guide/basics.model).
Wenn die Benutzereingaben erfasst und in einer Datenbank gespeichert werden,
verwenden wir stattdessen einen [ActiveRecord](/doc/guide/database.ar).
Beide Model-Typen benutzen die gleiche Basisklasse [CModel], in der die
gemeinsame Schnittstelle zu einem Formular definiert ist.
> Note|Hinweis: In den Beispielen dieses Abschnitts benutzen wir hauptsächlich
Formular-Models. Genausogut könnte ein [ActiveRecord](/doc/guide/database.ar)
verwendet werden.
Definieren der Model-Klasse
---------------------------
Unten erzeugen wir die Model-Klasse `LoginForm`, um die Benutzereingaben
einer Anmeldeseite zu erfassen. Da die Anmeldeinformationen nur dazu benutzt
werden, den Benutzer zu authentifizieren und nicht gespeichert werden müssen,
erstellen wir `LoginForm` als Formular-Model.
~~~
[php]
class LoginForm extends CFormModel
{
public $username;
public $password;
public $rememberMe=false;
}
~~~
`LoginForm` deklariert drei Attribute: `$username` (Benutzername),
`$password` (Passwort) und `$rememberMe` (sinngem.: Angemeldet bleiben).
Sie dienen zum Speichern des eingegebenen Benutzernamens, des Passworts und der
Option "Angemeldet bleiben". Da `$rememberMe` den Standardwert `false` hat,
wird die entsprechende Option beim ersten Aufruf des Anmeldeformulars
nicht markiert.
> Info|Info: Anstatt "Eigenschaften" benutzen wir für Klasseneigenschaften
den Begriff *Attribute*, um sie von normalen Eigenschaften zu unterscheiden. Ein
Attribut ist eine Eigenschaft, die hauptsächlich dazu benutzt wird, Daten aus
Benutzereingaben oder aus der Datenbank zu speichern.
Angeben der Regeln zur Gültigkeitsprüfung
-----------------------------------------
Sobald der Benutzer seine Eingaben abschickt und das Model befüllt
wird, müssen wir sicherstellen, dass die Daten gültig sind, bevor wir sie
weiterverwenden. Das geschieht durch eine Gültigkeitsprüfung (engl.:
validation) anhand eine Reihe von Regeln. Wir legen diese Regeln mit der Methode
`rules()` fest, die ein Array von Regelkonfigurationen zurückgeben sollte.
~~~
[php]
class LoginForm extends CFormModel
{
public $username;
public $password;
public $rememberMe=false;
public function rules()
{
return array(
array('username, password', 'required'),
array('password', 'authenticate'),
);
}
public function authenticate($attribute,$params)
{
if(!$this->hasErrors()) // wir wollen nur bei fehlerfreier Eingabe identifizieren
{
$identity=new UserIdentity($this->username,$this->password);
if($identity->authenticate())
{
$duration=$this->rememberMe ? 3600*24*30 : 0; // 30 Tage
Yii::app()->user->login($identity,$duration);
}
else
$this->addError('password','Falsches Passwort.');
}
}
}
~~~
Der obige Code legt fest, dass sowohl `username` als auch `password` zwingend erforderlich
sind und `password` authentifiziert werden soll.
Jede der Regeln, die von `rules()` zurückgegeben werden, muss folgendem Format entsprechen:
~~~
[php]
array('AttributListe', 'Validator', 'on'=>'SzenarienListe', ...Zusätzliche Optionen)
~~~
wobei `AttributListe` eine durch Kommas getrennte Reihe von zu Attributnamen ist,
die entsprechend der Regel auf Gültigkeit geprüft werden sollen. `Validator` (sinngem.:
Gültigkeitsprüfer) legt fest, welche Überprüfung durchgeführt werden soll. Der
`on` (bei) Parameter ist optional und definiert eine Liste von Szenarien, in denen die Regel
angewendet werden soll. `Zusätzliche Optionen` sind Namen-Werte-Paare, die dazu dienen,
die entsprechenden Eigenschaftswerte des Validators zu initialisieren.
Es gibt drei Arten, um einen `Validator` in einer Prüfregel anzugeben. Erstens
kann `Validator` der Name einer Methode der Model-Klasse sein, wie `authenticate`
im obigen Beispiel. Diese Prüfmethode muss folgendem Muster entsprechen:
~~~
[php]
/**
* @param string der Name des Attributs, das geprüft werden soll
* @param array Optionen der Prüfregel
*/
public function ValidatorName($attribute,$params) { ... }
~~~
Zweitens kann `Validator` der Name einer Klasse zur Gültigkeitsprüfung sein. Wenn die
Regel angewendet wird, wird eine Instanz dieser Klasse erzeugt, um
die jeweilige Gültigkeitsprüfung durchzuführen. Die zusätzlichen Optionen der Regel
werden dazu benutzt, die Eigenschaftswerte dieser Instanz zu initialisieren.
Eine Klasse zur Gültigkeitsprüfung muss von [CValidator] abgeleitet werden.
> Note|Hinweis: Beim Festlegen der Regeln für einen ActiveRecord können
wir eine spezielle Option `on` verwenden. Der Wert dafür kann entweder `'insert'`
oder `'update'` sein. Die Regel wird dann beim Einfügen bzw. Aktualisieren
des Datensatzes angewendet. Falls nicht gesetzt, wird die Regel beim Aufruf
von `save()` in beiden Fällen angewendet.
Drittens kann `Validator` eine vordefinierter Alias für eine Prüfklasse sein.
Im obigen Beispiel ist der Name `required` (benötigt) ein Alias zu [CRequiredValidator].
Damit ist sichergestellt, dass der Wert des zu prüfenden Attributs nicht leer ist.
Nachfolgend die komplette Liste der vordefinierten Validatoraliase:
- `boolean`: Alias für [CBooleanValidator], garantiert dass das Attribut
entweder den Wert [CBooleanValidator::trueValue] oder
[CBooleanValidator::falseValue] hat.
- `captcha`: Alias für [CCaptchaValidator], garantiert die Übereinstimmung des Attributs
mit dem angezeigten [CAPTCHA](http://de.wikipedia.org/wiki/Captcha) Verifikationscode.
- `compare`: Alias für [CCompareValidator], garantiert die Gleichheit mit einem anderen
Attribut oder einer Konstanten.
- `email`: Alias für [CEmailValidator], garantiert eine gültige E-Mail Adresse.
- `default`: Alias für [CDefaultValueValidator], Zuweisung eines Standardwertes für
das angegebene Attribut.
- `exist`: Alias für [CExistValidator], garantiert, dass der Wert des
Attributs in der entsprechenden Tabellenspalte vorhanden ist.
- `file`: Alias für [CFileValidator], garantiert dass der Attributwert den Namen einer
hochgeladenen Datei enthält.
- `filter`: Alias für [CFilterValidator], Umformung des Attributs durch einen Filter.
- `in`: Alias für [CRangeValidator], garantiert, dass die Daten mit einem Wert in
einer vordefinierten Liste übereinstimmen.
- `length`: Alias für [CStringValidator], garantiert, dass die Länge der Daten
innerhalb eines bestimmten Bereichs liegen.
- `match`: Alias für [CRegularExpressionValidator], garantiert, dass die Daten
einem regulären Ausdruck entsprechen.
- `numerical`: Alias für [CNumberValidator], garantiert, dass das Attribut
eine gültige Zahl ist.
- `required`: Alias für [CRequiredValidator], garantiert, dass das Attribut nicht
leer ist.
- `type`: Alias für [CTypeValidator], garantiert, dass das Attribut einem bestimmten
Datentyp entspricht.
- `unique`: Alias für [CUniqueValidator], garantiert, dass das Attribut nur
einmal in einer Datenbankspalte vorkommt.
- `url`: Alias für [CUrlValidator], garantiert, das die Daten eine gültige
URL enthalten.
Nachfolgend sind einige Beispiele für die Verwendung von vordefinierten
Validatoren aufgelistet:
~~~
[php]
// `username` ist erforderlich
array('username', 'required'),
// `username` muss 3 bis 12 Zeichen lang sein
array('username', 'length', 'min'=>3, 'max'=>12),
// Bei einem `register`-Szenario: `password` muss mit `password2` übereinstimmen
array('password', 'compare', 'compareAttribute'=>'password2', 'on'=>'register'),
// Bei einem `login`-Szenario, `password` muss authentifiziert werden
array('password', 'authenticate', 'on'=>'login'),
~~~
Absichern von Attributzuweisungen
---------------------------------
Nachdem ein Model instanziiert wurde, müssen wir seine Attributwerte oft mit
Daten befüllen, die von Endbenutzern geliefert werden. Das kann bequem über
folgende Massenzuweisung geschehen:
~~~
[php]
$model=new LoginForm;
if(isset($_POST['LoginForm']))
$model->attributes=$_POST['LoginForm'];
~~~
Die letzte Anweisung ist eine *Massenzuweisung*, bei der jeder Eintrag in
`$_POST['LoginForm']` dem entsprechenden Model-Attribut zugewiesen wird.
Dies ist äquivalent zu folgender Zuweisung:
~~~
[php]
foreach($_POST['LoginForm'] as $name=>$value)
{
if($name ist ein sicheres Attribut)
$model->$name=$value;
}
~~~
Es ist von entscheidender Bedeutung, die sicheren Attribute zu bestimmen.
Würden wir zum Beispiel den Primärschlüssel einer Tabelle als sicher
ausweisen, könnte ein Angreifer diesen möglicherweise bei einem gegebenen
Record verändern und sich so evtl. Zugang zu Daten verschaffen, zu denen er
nicht autorisiert ist.
Die Regeln anhand derer entschieden wird, ob ein Attribut sicher ist oder nicht,
unterscheiden sich zwischen Version 1.0 und 1.1. Daher beschreiben wir
im Folgenden beide Versionen.
***Sichere Attribute in 1.1
In Version 1.1 gilt ein Attribut als sicher, wenn es dafür eine
Validierungsregel im gegebenen Szenario gibt. Zum Beispiel:
~~~
[php]
array('username, password', 'required', 'on'=>'login, register'),
array('email', 'required', 'on'=>'register'),
~~~
Im Szenario `login` sind hier die Attribute `username` und `password` zwingend
erforderlich, im Szenario `register` die Attribute `username`, `password` und
`email`. Führen wir also eine Massenzuweisung im Szenario `login` durch,
werden nur `username` und `password` zugewiesen, da dies die einzigen
Attribute sind, die auch Validierungsregeln in diesem Szenario haben.
Im Szenario `register` können hingegen alle drei Attribute per Massenzuweisung
befüllt werden.
~~~
[php]
// Im Szenario login
$model=new User('login');
if(isset($_POST['User']))
$model->attributes=$_POST['User'];
// Im Szenario register
$model=new User('register');
if(isset($_POST['User']))
$model->attributes=$_POST['User'];
~~~
Warum gehen wir davon aus, dass diese Attribute als sicher gelten?
Hintergedanke war, dass wir uns um Attribute, die bereits eine oder mehrere
Validierungsregeln haben, keine Gedanken mehr machen müssen.
Man bedenke, dass Validierungsregeln dazu da sind, um Benutzerdaten zu prüfen,
nicht Daten, die wir per Code generieren (z.B. Zeitstempel, autogenerierte
Primärschlüssel). Fügen Sie daher KEINE Validierungsregeln für jene Attribute
hinzu, die keine Daten von Endbenutzern erwarten.
Manchmal möchten wir ein Attribut als sicher definieren, obwohl es keine
spezielle Regel dafür gibt. Ein Beispiel könnte z.B. das Attribut inhalt eines
Artikels sein, für das jede Benutzereingabe gültig sein soll. Dazu können wir
die spezielle Regel `safe` verwenden:
~~~
[php]
array('inhalt', 'safe')
~~~
Der Vollständigkeit halber gibt es auch eine `unsafe`-Regel, die ein Attribut
explizit als `nicht sicher` deklariert:
~~~
[php]
array('erlaubnis', 'unsafe')
~~~
Diese Regel wird nur selten verwendet. Sie ist eine Ausnahme zu unserer
vorhergehenden Definition sicherer Attribute.
***Sichere Attribute in 1.0
In Version 1.0 basierte die Entscheidung, ob ein Attribut sicher ist oder nicht,
auf dem Rückgabewert der Methode `safeAttributes` (sichere Attribute) und
dem angegebenen Szenario.
Als Standardwert liefert diese Methode für [CFormModel] alle als public deklarierten
Attribute und für [CActiveRecord] alle Tabellenspalten außer dem
Primärschlüssel als sichere Attribute zurück. Wir können diese Methode
überschreiben, um die je nach Szenario sicheren Attribute einzuschränken.
Ein Benutzer-Model kann zum Beispiel viele Attribute enthalten,
im `login`-Szenario brauchen wir aber nur die Attribute `username` und
`password`. Wir können diese Einschränkung wie folgt festlegen:
~~~
[php]
public function safeAttributes()
{
return array(
parent::safeAttributes(),
'login' => 'username, password',
);
}
~~~
Genauer gesagt, sollte der Rückgabewert von `safeAttributes` folgendem
Aufbau entsprechen:
~~~
[php]
array(
// Diese Attribute können per Massenzuweisung in jedem Szenario befüllt
// werden, das unten nicht explizit angegeben wird
'attr1, attr2, ...',
*
// Diese Attribute können nur in `szenario1` per Massenzuweisung befüllt werden
'szenario1' => 'attr2, attr3, ...',
*
// Diese Attribute können nur in `scenario2` per Massenzuweisung befüllt werden
'Scenario2' => 'attr1, attr3, ...',
)
~~~
Wenn ein Model keine Unterscheidung nach Szenarien braucht (es also nur
in einem Szenario benutzt wird oder in allen Szenarien die selben Attribute
als sicher gelten) kann der Rückgabewert zu einer einzelnen Zeichenkette
vereinfacht werden:
~~~
[php]
'attr1, attr2, ...'
~~~
Eingegebenene Daten, die nicht sicher sind, müssen wir dem entsprechenden
Attribut wie im Folgenden von Hand zuweisen:
~~~
[php]
$model->permission='admin';
$model->id=1;
~~~
Auslösen der Gültigkeitsprüfung
-------------------------------
Sobald ein Model mit den vom Benutzer übermittelten Daten befüllt ist, können
wir [CModel::validate()] aufrufen, um die Gültigkeitsprüfung durchzuführen.
Der Rückgabewert dieser Methode zeigt an, ob die Prüfung erfolgreich war
oder nicht. Für das [CActiveRecord]-Model wird die Gültigkeitsprüfung automatisch
ausgelöst, wenn wir dessen Methode [CActiveRecord::save()] aufrufen.
Beim Aufruf von [CModel::validate()], können wir einen Szenario-Parameter
angeben. Dabei werden nur die in diesem Szenario geltenden Prüfregeln ausgeführt.
Eine Regel gilt für ein Szenario, wenn die `on` Option der Regel entweder nicht gesetzt ist,
oder den Namen dieses Szenarios enthält.
Wenn wir kein Szenario beim Aufruf von [CModel::validate()] angeben,
werden nur die Regeln, bei denen die `on` Option nicht gesetzt ist ausgeführt.
Zur Gültigkeitsprüfung der Anmeldung eines Benutzers führen wir beispielsweise folgende
Anweisung aus:
~~~
[php]
$model->scenario='register';
$model->validate();
~~~
> Note|Hinweis: Die Eigenschaft [scenario|CModel::scenario] ist seit Version
> 1.0.4 verfügbar. Die Prüfmethode verwendet diese Eigenschaft, um
> festzustellen, gegen welche Regeln geprüft werden muss. In den Versionen
> 1.0.2 und 1.0.3 mussten wir die szenarienbasierte Prüfung wie folgt
> durchführen:
>
> ~~~
> [php]
> $model->validate('register');
> ~~~
Wir können die Prüfregeln im Formular-Model wie folgt angeben:
~~~
[php]
public function rules()
{
return array(
array('username, password', 'required'),
array('password_repeat', 'required', 'on'=>'register'),
array('password', 'compare', 'on'=>'register'),
);
}
~~~
Demzufolge wird die erste Regel in allen Szenarien angewendet, während
die beiden nächsten Regeln nur im Szenario `register` zum Einsatz kommen.
> Note|Hinweis: Die szenarienbasierte Gültigkeitsprüfung ist seit Version 1.0.1
verfügbar.
Abfragen von Fehlern bei der Gültigkeitsprüfung
-----------------------------------------------
Um zu ermitteln, ob bei der Gültigkeitsprüfung ein Fehler aufgetreten ist,
können wir [CModel::hasErrors()] verwenden. Falls ja, erhalten wir mit
[CModel::getErrors()] die Fehlermeldung. Beide Methoden können für alle oder
ein einzelnes Attribut verwendet werden.
Attribut-Label
--------------
Beim Entwurf eines Formulars ist es oft erforderlich, für jedes Eingabefeld ein
Label (Beschriftung) anzuzeigen. Dieses Label informiert den Benutzer über die Art der
Information, die er in das Feld eintragen soll. Obwohl wir ein Label fest in
einem View hinterlegen können, wäre es flexibler und bequemer, es im entsprechenden
Model anzugeben.
Als Standardwert gibt [CModel] einfach den Namen des Attributs als Label zurück.
Dies kann durch Überschreiben der Methode [attributeLabels()|CModel::attributeLabels]
angepasst werden. Wie wir in den folgenden Kapiteln sehen werden, erlaubt
uns die Angabe von Labels im Model, ein Formular schneller und wirkungsvoller zu
erstellen.
<div class="revision">$Id: form.model.txt 1425 2009-09-28 03:28:17Z qiang.xue $</div>