0 follower

Skapa modell

Innan HTML-koden som ett formulär erfordrar skrivs, behöver vi avgöra vilken slags data vi förväntar oss att slutanvändare skriver in samt vilka regler dessa data behöver följa. En modellklass kan användas till att registrera denna information. En modell är, enligt definition i underavsnittet Model, den centrala platsen för att hålla användarinmatad data samt för validering av denna.

Beroende på hur vi använder oss av inmatade data, kan två olika typer av modeller skapas. Om inmatningen hämtas in och används för att sedan slängas, skapas lämpligen en formulärmodell; om användarinmatningen hämtas in för att sparas i en databas, används lämpligen en active record-modell i stället. Båda typerna av modell härstammar från samma basklass, CModel, vilken definierar det gemensamma gränssnittet ett formulär behöver.

Märk: I exemplen i detta avsnitt används huvudsakligen formulärmodeller. Samma förfarande kan emellertid även appliceras på active record-modeller.

1. Definiera en modellklass

Nedan skapas en modellklass, LoginForm, som används för att samla in användarinmatning på en loginsida. Eftersom logininformationen bara används till att autentisera användaren och inte behöver sparas , skapas LoginForm som en formulärmodell.

class LoginForm extends CFormModel
{
    public $username;
    public $password;
    public $rememberMe=false;
}

Tre attribut deklareras i LoginForm: $username, $password samt $rememberMe. De används för att hålla inmatat användarnamn och lösen, samt det frivilliga alternativet huruvida logininformationen skall kommas ihåg. Eftersom $rememberMe har ett standardvärde, false, kommer det motsvarande alternativet, när det initialt visas i loginformuläret, att vara omarkerat .

Info: I stället för att kalla dessa medlemsvariabler för propertyn, används här termen attribut för att särskilja dem från vanliga propertyn. Ett attribut är en property som huvudsakligen används till att lagra data som härrör från användarinmatning eller från en databas.

2. Deklarera valideringsregler

När en användare väl postar sina inmatningar och modellen tilldelats dessa, behöver vi säkerställa att inmatningarna är giltiga innan de används. Detta sker genom validering av inmatningarna mot en uppsättning regler. Valideringsregler specificeras i metoden rules(), vilken skall returnera en array bestående av regelkonfigurationer.

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())  // we only want to authenticate when no input errors
        {
            $identity=new UserIdentity($this->username,$this->password);
            if($identity->authenticate())
            {
                $duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days
                Yii::app()->user->login($identity,$duration);
            }
            else
                $this->addError('password','Incorrect password.');
        }
    }
}

Ovanstående kod specificerar att både username och password är obligatorisk inmatning, samt att password skall autentiseras.

Varje regel som returneras från rules() måste vara på följande format:

array('AttributeList', 'Validator', 'on'=>'ScenarioList', ...additional options)

där AttributeList är en sträng bestående av kommaseparerade attributnamn vilka behöver valideras enligt regeln; Validator specificerar vilket slags validering som skall utföras; on-parametern är frivillig och specificerar en lista med scenarier där regeln skall appliceras; additional options är namn- värdepar som används till att initialisera motsvarande validators propertyvärden.

Validator kan specificeras på tre sätt i en valideringsregel. För det första kan Validator vara namnet på en metod i modellklassen, som authenticate i ovanstående exempel. Valideringsmetoden måste ha följande signatur:

/**
 * @param string the name of the attribute to be validated
 * @param array options specified in the validation rule
 */
public function ValidatorName($attribute,$params) { ... }

För det andra kan Validator vara namnet på en validerarklass. När regeln appliceras, kommer en instans av validerarklassen att skapas för att utföra den aktuella valideringen. De ytterligare alternativen (additional options) i regeln används till att initialisera instansens attributvärden. En validerarklass måste ärva från och utvidga CValidator.

Märk: När regler specificeras för en active recordmodell, kan ett speciellt alternativ vid namn on användas. Detta alternativs värden kan vara antingen 'insert' eller 'update' så att regeln bara appliceras vid insättning resp. uppdatering av posten. Om alternativet ej anges, kommer regeln att appliceras i båda fallen när metoden save() anropas.

För det tredje kan Validator vara ett fördefinierat aliasnamn för en validerarklass. I ovanstående exempel är namnet required ett alias för CRequiredValidator, vilken säkerställer att attributvärdet som valideras inte är tomt. Nedan följer den kompletta förteckningen över validerarklassers aliasnamn:

  • boolean: alias för CBooleanValidator, garanterar att attributet har ett värde som är antingen CBooleanValidator::trueValue eller CBooleanValidator::falseValue.

  • captcha: alias för CCaptchaValidator, garanterar att attributet överensstämmer med verifieringskoden som visades i CAPTCHA.

  • compare: alias för CCompareValidator, garanterar att attributet har samma värde som ett annat attribut eller en konstant.

  • email: alias för CEmailValidator, garanterar att attributet är en giltig email-adress.

  • default: alias för CDefaultValueValidator, tilldelar specificerade attribut ett standardvärde.

  • exist: alias för CExistValidator, säkerställer att attributvärdet kan återfinnas i den specificerade tabellkolumnen.

  • file: alias för CFileValidator, garanterar att attributet innehåller namnet på en uppladdad fil.

  • filter: alias för CFilterValidator, transformerar attributet med hjälp av ett filter.

  • in: alias för CRangeValidator, garanterar att data håller sig inom ett fördefinierat intervall (lista) av värden.

  • length: alias för CStringValidator, garanterar att längden av data faller inom ett angivet intervall.

  • match: alias för CRegularExpressionValidator, garanterar att data matchar ett reguljärt uttryck (regexp).

  • numerical: alias för CNumberValidator, garanterar att data är ett giltigt tal.

  • required: alias för CRequiredValidator, garanterar att attributet ej är tomt.

  • type: alias för CTypeValidator, garanterar att attributet är av en specifik datatyp.

  • unique: alias för CUniqueValidator, garanterar att data är unikt för en kolumn i en databastabell.

  • url: alias för CUrlValidator, garanterar att data är en giltig URL.

Nedan listas några exemepl på användning av de fördefinierade aliasnamnen för validerarklasser:

// username är obligatoriskt
array('username', 'required'),
// username måste vara mellan 3 och 12 tecken långt
array('username', 'length', 'min'=>3, 'max'=>12),
// i register-scenariet endast, måste password matcha password2
array('password', 'compare', 'compareAttribute'=>'password2', 'on'=>'register'),
// i login-scenariet endast, måste password vara autentiserat
array('password', 'authenticate', 'on'=>'login'),

3. Säkra upp attributtilldelningar

Märk: scenariebaserade attributtilldelningar har funnits tillgängliga fr o m version 1.0.2.

När en modellinstans har skapats, behöver dess attribut ofta tilldelas värden inskickade av slutanvändare. Detta kan lämpligen utföras med hjälp av följande massiva tilldelning:

$model=new LoginForm;
$model->scenario='login';
if(isset($_POST['LoginForm']))
    $model->attributes=$_POST['LoginForm'];

Märk: Propertyn scenario har varit tillgänglig fr o m version 1.0.4. Den massiva tilldelningen utgår från värdet i denna propertty för att avgöra vilka attribut som kan tilldelas massivt. I version 1.0.2 och 1.0.3, behövde vi använda följande sätt för att utföra massiv tilldelning i ett specifikt scenario:

$model->setAttributes($_POST['LoginForm'], 'login');

Den sista programraden innebär en massiv tilldelning av varje fält i $_POST['LoginForm'] till motsvarande modellattribut i login-scenariet. Detta är ekvivalent med följande tilldelning:

foreach($_POST['LoginForm'] as $name=>$value)
{
    if($name is a safe attribute)
        $model->$name=$value;
}

Uppgiften att avgöra huruvida en datainmatning är säker eller inte baseras på returvärdet från en metod med namnet safeAttributes samt det specificerade scenariet. Som standard returnerar denna metod alla publika medlemsvariabler som säkra attribut till CFormModel, medan den returnerar alla tabellkolumner utom primärnyckeln som säkra attribut till CActiveRecord. Denna metod kan åsidosättas i enlighet med scenarier, för att begränsa de säkra attributen. Till exempel, en modell för användare kan innehålla många attribut, men i scenariet login erfordras endast attributen username och password. Denna begränsning kan specificeras som följer:

public function safeAttributes()
{
    return array(
        parent::safeAttributes(),
        'login' => 'username, password',
    );
}

Formellt uttryckt, skall returvärdena från safeAttributes ha följande struktur:

array(
   // dessa attribut kan tilldelas massivt i varje scenario
   // som inte uttryckligen specificeras nedan
   'attr1, attr2, ...',
     *
   // dessa attribut kan endast tilldelas massivt i scenario 1
   'scenario1' => 'attr2, attr3, ...',
     *
   // dessa attribut kan endast tilldelas massivt i scenario 2
   'scenario2' => 'attr1, attr3, ...',
)

Om modellen okänslig för scenarier (dvs den används endast i ett scenario, eller alla scenarier delar samma uppsättning av säkra attribut), kan returvärdet förenklas till en enda sträng:

'attr1, attr2, ...'

I fråga om inmatningar som inte är säkra, behöver vi tilldela dem till motsvarande attribut med hjälp av individuella tilldelningssatser, som i följande exempel:

$model->permission='admin';
$model->id=1;

4. Sätta igång validering

När väl en modell försetts med användarinmatad data, kan metoden CModel::validate() anropas för att sätta igång datavalideringsprocessen. Metoden returnerar ett värde som indikerar huruvida valideringen lyckades eller inte. För CActiveRecord-modellen, kan validering även sättas igång automatiskt till följd av att dess metod CActiveRecord::save() anropas.

Vid anrop av CModel::validate() kan en scenarioparameter specificeras. Endast de valideringsregler som hänför sig till angivet scenario kommer att exekveras. En valideringsregel hänför sig till ett scenario om regelns on-alternativ ej har satts, alternativt innehåller det specificerade scenarionamnet. Om scenario ej specificeras i anropet av CModel::validate(), kommer enbart de regler köras vars on-alternativ ej satts.

Exempelvis exekveras följande sats för att genomföra valideringen vid registrering av en användare:

$model->scenario='register';
$model->validate();

Märk: Propertyn scenario har varit tillgänglig fr o m version 1.0.4. Valideringsmetoden utgår från detta propertyvärde för att avgöra vilka regler som skall användas för kontroll. I version 1.0.2 och 1.0.3, behövde vi använda följande tillvägagångssätt för att utföra scenariobaserad validering:

$model->validate('register');

Valideringsregler kan deklareras i en formulärmodellklass på följande sätt,

public function rules()
{
    return array(
        array('username, password', 'required'),
        array('password_repeat', 'required', 'on'=>'register'),
        array('password', 'compare', 'on'=>'register'),
    );
}

Resultatet blir att den första regeln appliceras i alla scenarier, medan de övriga två reglerna endast kommer att appliceras i scenariet register.

Märk: scenariobaserad validering har varit tillgänglig fr o m version 1.0.1.

5. Åtkomst till valideringsmeddelanden

Metoden CModel::hasErrors() kan användas för att kontrollera om det uppstått några valideringsfel, om så är fallet kan metoden CModel::getErrors() användas för att erhålla felmeddelandena. Båda metoderna kan användas för alla attribut eller för ett individuellt attribut.

6. Attributs ledtexter

Vid utformning av ett formulär behöver vi ofta presentera en ledtext för varje inmatningsfält. Ledtexten informerar användaren om vad slags information denne förväntas mata in i fältet. Även om en ledtext kan hårdkodas i vyn, erbjuds större flexibilitet och praktisk användbarhet om den kan specificeras i tillhörande modell.

Som standard lämnar CModel helt enkelt namnet på ett attribut som dess ledtext. Detta kan anpassas genom att åsidosätta metoden attributeLabels(). Som kommer att framgå i nästa avsnitt, tillåter specificering av ledtexter i modellen, oss att skapa formulär snabbare och mer kraftfullt.