Dmitry Naumenko
9 years ago
6 changed files with 1013 additions and 1 deletions
@ -0,0 +1,649 @@
|
||||
Walidacja danych wejściowych |
||||
================ |
||||
|
||||
Jedna z głównych zasad mówi, że nigdy nie powinno ufać się danym otrzymanym od użytkowników oraz zawsze je walidować przez użyciem. |
||||
|
||||
Mamy [model](structure-models.md) wypełniony danymi od użytkownika. Możemy go zwalidować przez wywołanie metody [[yii\base\Model::validate()|validate()]]. |
||||
Metoda zwróci wartość `boolean` wskazującą, czy walidacja się powiodła, czy nie. Jeśli nie, możesz pobrać informacje o błędach za pomocą właściwości [[yii\base\Model::errors|errors]]. |
||||
Dla przykładu, |
||||
|
||||
```php |
||||
$model = new \app\models\ContactForm(); |
||||
|
||||
// uzupełniamy model danymi od użytkownika |
||||
$model->load(\Yii::$app->request->post()); |
||||
// ten zapis jest tożsamy z poniższą metodą |
||||
// $model->attributes = \Yii::$app->request->post('ContactForm'); |
||||
|
||||
if ($model->validate()) { |
||||
// akcja w przypadku poprawnej walidacji |
||||
} else { |
||||
// akcja w przypadku niepoprawnej walidacji. Zmienna $errors jest tablicą zawierającą wiadomości błędów |
||||
$errors = $model->errors; |
||||
} |
||||
``` |
||||
|
||||
|
||||
## Deklaracja zasad <span id="declaring-rules"></span> |
||||
|
||||
Aby metoda [[yii\base\Model::validate()|validate()]] naprawdę zadziałała, powinieneś zadeklarować zasady walidacji dla atrybutów, które mają jej podlegać. |
||||
Powinno zostać to zrobione przez nadpisanie metody [[yii\base\Model::rules()|rules()]]. Poniższy przykład pokazuje jak zostały zadeklarowane zasady walidacji dla modelu `ContactForm`: |
||||
|
||||
```php |
||||
public function rules() |
||||
{ |
||||
return [ |
||||
// atrybuty name, email, subject oraz body są wymagane |
||||
[['name', 'email', 'subject', 'body'], 'required'], |
||||
|
||||
// atrybut email powinien być poprawnym adresem email |
||||
['email', 'email'], |
||||
]; |
||||
} |
||||
``` |
||||
|
||||
Metoda [[yii\base\Model::rules()|rules()]] powinna zwracać tablicę zasad, gdzie każda zasada jest tablicą w następującym formacie: |
||||
|
||||
```php |
||||
[ |
||||
// wymagane, określa atrybut który powinien zostać zwalidowany przez tę zasadę. |
||||
// Dla pojedyńczego atrybutu możemy użyć bezpośrednio jego nazwy, bez osadzania go w tablicy |
||||
['attribute1', 'attribute2', ...], |
||||
|
||||
// wymagane, określa typ tej zasady walidacji |
||||
// Może to być nazwa klasy, alias walidatora lub nazwa metody walidacji |
||||
'validator', |
||||
|
||||
// opcjonalny, określa, w którym scenariuszu/scenariuszach ta zasada powinna zostać użyta |
||||
// w przypadku nie podania żadnego argumentu zasada zostanie zaaplikowana do wszystkich scenariuszy |
||||
// Możesz również skonfigurować opcję "except" jeśli chcesz użyć tej zasady dla wszystkich scenariuszy. oprócz tych wymienionych przez Ciebie |
||||
'on' => ['scenario1', 'scenario2', ...], |
||||
|
||||
// opcjonalny, określa dodatkowe konfiguracje do obiektu walidatora |
||||
'property1' => 'value1', 'property2' => 'value2', ... |
||||
] |
||||
``` |
||||
|
||||
Dla każdej z zasad musisz określić co najmniej jeden atrybut, którego ma ona dotyczyć, oraz należy określić typ tej zasady. |
||||
Możesz określić typ zasady jako jedną z następujących form: |
||||
|
||||
* alias walidatora podstawowego, np. `required`, `in`, `date` itd. Zajrzyj do sekcji [Podstawowe walidatory](tutorial-core-validators.md) aby uzyskać pełną listę walidatorów podstawowych. |
||||
* nazwa metody walidacji w klasie modelu, lub funkcja anonimowa. Po więcej szczegółów zajrzyj do sekcji [Inline Validators](#inline-validators). |
||||
* pełna nazwa klasy walidatora. Po więcej szczegółów zajrzyj do sekcji [Standalone Validators](#standalone-validators). |
||||
|
||||
Zasada może zostać użyta do walidacji jednego lub wielu atrybutów, a atrybut może być walidowany przez jedną, lub wiele zasad. |
||||
Zasada może zostać użyta dla konkretnych [scenariuszy](structure-models.md#scenarios) przez określenie opcji `on`. |
||||
Jeśli nie określisz opcji `on` oznacza to, że zasada zostanie użyta w każdym scenariuszu. |
||||
|
||||
Kiedy zostaje wywołana metoda [[yii\base\Model::validate()|validate()]] zostają wykonane następujące kroki w celu wykonania walidacji: |
||||
|
||||
1. Określenie które atrybuty powinny zostać zwalidowane przez pobranie listy atrybutów z [[yii\base\Model::scenarios()|scenarios()]] używając aktualnego |
||||
[[yii\base\Model::scenario|scenario]]. Wybrane atrybuty nazywane są *atrybutami aktywnymi*. |
||||
2. Określenie które zasady walidacji powinny zostać użyte przez pobranie listy zasad z [[yii\base\Model::rules()|rules()]] używając aktualnego [[yii\base\Model::scenario|scenario]]. |
||||
Wybrane zasady nazywane są *zasadami aktywnymi*. |
||||
3. Użycie każdej aktywnej zasady do walidacji każdego aktywnego atrybutu, który jest powiązany do konkretnej zasady. Zasady walidacji są wykonywane w kolejności w jakiej zostały zapisane. |
||||
|
||||
Odnosząc się do powyższych kroków walidacji, atrybut zostanie zwalidowany wtedy i tylko wtedy, gdy jest on aktywnym atrybutem zadeklarowanym w |
||||
[[yii\base\Model::scenarios()|scenarios()]] oraz jest powiązany z jedną lub wieloma aktywnymi zasadami zadeklarowanymi w [[yii\base\Model::rules()|rules()]]. |
||||
|
||||
|
||||
### Dostosowywanie wiadomości błedów <span id="customizing-error-messages"></span> |
||||
|
||||
Większość walidatorów posiada domyślne wiadomości błędów, które zostaną dodane do poddanego walidacji modelu, kiedy któryś z atrybutów nie przejdzie walidacji. |
||||
Dla przykładu, walidator [[yii\validators\RequiredValidator|required]] doda wiadomość "Username cannot be blank." do modelu, jeśli atrybut `username` nie przejdzie walidacji tej zasady. |
||||
|
||||
Możesz dostosować wiadomość błędu danej zasady przez określenie właściwości `message` przy deklaracji zasady. |
||||
Dla przykładu, |
||||
|
||||
```php |
||||
public function rules() |
||||
{ |
||||
return [ |
||||
['username', 'required', 'message' => 'Proszę wybrać login.'], |
||||
]; |
||||
} |
||||
``` |
||||
|
||||
Niektóre walidatory mogą wspierać dodatkowe wiadomości błedów, aby bardziej precyzyjnie określić problemy przy walidacji. |
||||
Dla przykładu, walidator [[yii\validators\NumberValidator|number]] dodaje [[yii\validators\NumberValidator::tooBig|tooBig]] oraz [[yii\validators\NumberValidator::tooSmall|tooSmall]] |
||||
do opisania sytuacji, kiedy liczba jest za duża lub za mała podczas walidacji. Możesz skonfigurować te wiadomości tak, jak pozostałe właściwości walidatorów w zasadzie walidacji. |
||||
|
||||
|
||||
### Zdarzenia walidacji <span id="validation-events"></span> |
||||
|
||||
Podczas wywołania metody [[yii\base\Model::validate()|validate()]] zostaną wywołane dwie metody, które możesz nadpisać, aby dostosować proces walidacji: |
||||
|
||||
* [[yii\base\Model::beforeValidate()|beforeValidate()]]: domyślna implementacja wywoła zdarzenie [[yii\base\Model::EVENT_BEFORE_VALIDATE|EVENT_BEFORE_VALIDATE]]. Możesz nadpisać tę |
||||
metodę lub odnieść się do zdarzenia, aby wykonać dodatkowe operacje przed walidacją. Metoda powinna zwracać wartość `boolean` wskazującą, czy walidacja powinna zostać wykonana, czy nie. |
||||
* [[yii\base\Model::afterValidate()|afterValidate()]]: domyślna implementacja wywoła zdarzenie [[yii\base\Model::EVENT_AFTER_VALIDATE|EVENT_AFTER_VALIDATE]]. Możesz nadpisać tę metodę |
||||
lub odnieść się do zdarzenia, aby wykonać dodatkowe operacje po zakończonej walidacji. |
||||
|
||||
|
||||
### Walidacja warunkowa <span id="conditional-validation"></span> |
||||
|
||||
Aby zwalidować atrybuty tylko wtedy, gdy zostaną spełnione pewne założenia, np. walidacja jednego atrybutu zależy od wartości drugiego atrybutu, możesz użyć właściwości |
||||
[[yii\validators\Validator::when|when]] aby zdefiniować taki warunek. Dla przykładu, |
||||
|
||||
```php |
||||
[ |
||||
['state', 'required', 'when' => function($model) { |
||||
return $model->country == 'USA'; |
||||
}], |
||||
] |
||||
``` |
||||
|
||||
Właściwość [[yii\validators\Validator::when|when]] pobiera możliwą do wywołania funkcję PHP z następującą definicją: |
||||
|
||||
```php |
||||
/** |
||||
* @param Model $model model, który podlega walidacji |
||||
* @param string $attribute atrybut, który podlega walidacji |
||||
* @return boolean wartość zwrotna; czy reguła powinna zostać zastosowana |
||||
*/ |
||||
function ($model, $attribute) |
||||
``` |
||||
|
||||
Jeśli potrzebujesz również wsparcia walidacji warunkowej po stronie użytkownika, powinieneś skonfigurować właściwość [[yii\validators\Validator::whenClient|whenClient]], |
||||
która przyjmuje wartość `string` reprezentującą funkcję JavaScript, zwracającą wartość `boolean`, która będzie określała, czy zasada powinna zostać zastosowana, czy nie. |
||||
Dla przykładu, |
||||
|
||||
```php |
||||
[ |
||||
['state', 'required', 'when' => function ($model) { |
||||
return $model->country == 'USA'; |
||||
}, 'whenClient' => "function (attribute, value) { |
||||
return $('#country').val() == 'USA'; |
||||
}"], |
||||
] |
||||
``` |
||||
|
||||
|
||||
### Filtrowanie danych <span id="data-filtering"></span> |
||||
|
||||
Dane od użytkownika często muszą zostać przefiltrowane. Dla przykładu, możesz chcieć wyciąć znaki spacji na początku i na końcu pola `username`. |
||||
Aby osiągnąć ten cel, możesz użyć zasad walidacji. |
||||
|
||||
Poniższy przykład pokazuje, jak wyciąć znaki spacji z pola oraz zmienić puste pole na wartość `NULL` przy użyciu podstawowych walidatorów [trim](tutorial-core-validators.md#trim) oraz |
||||
[default](tutorial-core-validators.md#default): |
||||
|
||||
```php |
||||
[ |
||||
[['username', 'email'], 'trim'], |
||||
[['username', 'email'], 'default'], |
||||
] |
||||
``` |
||||
|
||||
Możesz użyć również bardziej ogólnego walidatora [filter](tutorial-core-validators.md#filter), aby przeprowadzić bardziej złożone filtrowanie. |
||||
|
||||
Jak pewnie zauważyłeś, te zasady walidacji tak naprawdę nie walidują danych. Zamiast tego przetwarzają wartości, a następnie przypisują je do atrybutów, które zostały poddane walidacji. |
||||
|
||||
|
||||
### Obsługa pustych danych wejściowych <span id="handling-empty-inputs"></span> |
||||
|
||||
Kiedy dane wejściowe są wysłane przez formularz HTML, często zachodzi potrzeba przypisania im domyślnych wartości jeśli są puste. |
||||
Możesz to osiągnąć przez użycie walidatora [default](tutorial-core-validators.md#default). Dla przykładu, |
||||
|
||||
```php |
||||
[ |
||||
// ustawia atrybuty "username" oraz "email" jako `NULL` jeśli są puste |
||||
[['username', 'email'], 'default'], |
||||
|
||||
// ustawia atrybut "level" równy "1" jeśli jest pusty |
||||
['level', 'default', 'value' => 1], |
||||
] |
||||
``` |
||||
|
||||
Domyślnie pole uważane jest za puste, jeśli jego wartość to pusty string, pusta tablica lub `NULL`. |
||||
Możesz dostosować domyślną logikę wykrywania pustych pól przez skonfigurowanie parametru [[yii\validators\Validator::isEmpty|isEmpty]], przekazując mu funkcję PHP. |
||||
Dla przykładu, |
||||
|
||||
```php |
||||
[ |
||||
['agree', 'required', 'isEmpty' => function ($value) { |
||||
return empty($value); |
||||
}], |
||||
] |
||||
``` |
||||
|
||||
> Note: Większość walidatorów nie obsługuje pustych pól, jeśli ich właściwość [[yii\base\Validator::skipOnEmpty|skipOnEmpty] przyjmuje domyślnie wartość `true`. |
||||
Zostaną one po prostu pominięte podczas walidacji, jeśli ich powiązany atrybut otrzyma wartość uznawaną za pustą. |
||||
Wśród [podstawowych walidatorów](tutorial-core-validators.md), tylko walidatory `captcha`, `default`, `filter`, `required` oraz `trim` obsługują puste pola. |
||||
|
||||
## Walidacja "Ad Hoc" <span id="ad-hoc-validation"></span> |
||||
|
||||
Czasami potrzebna będzie walidacja *ad hoc* dla wartości które nie są powiązane z żadnym modelem. |
||||
|
||||
Jeśli potrzebujesz wykonać tylko jeden typ walidacji (np. walidacja adresu email), możesz wywołać metodę [[yii\validators\Validator::validate()|validate()]] wybranego walidatora, tak |
||||
jak poniżej: |
||||
|
||||
```php |
||||
$email = 'test@example.com'; |
||||
$validator = new yii\validators\EmailValidator(); |
||||
|
||||
if ($validator->validate($email, $error)) { |
||||
echo 'Email is valid.'; |
||||
} else { |
||||
echo $error; |
||||
} |
||||
``` |
||||
|
||||
> Note: Nie każdy walidator wspiera tego typu walidację. Dla przykładu, podstawowy walidator [unique](tutorial-core-validators.md#unique) został zaprojektowany do pracy wyłącznie z modelami. |
||||
|
||||
Jeśli potrzebujesz przeprowadzić wielokrotne walidacje, możesz użyć [[yii\base\DynamicModel|DynamicModel]], który wspiera deklarację atrybutów oraz zasad walidacji "w locie". |
||||
Dla przykładu, |
||||
|
||||
```php |
||||
public function actionSearch($name, $email) |
||||
{ |
||||
$model = DynamicModel::validateData(compact('name', 'email'), [ |
||||
[['name', 'email'], 'string', 'max' => 128], |
||||
['email', 'email'], |
||||
]); |
||||
|
||||
if ($model->hasErrors()) { |
||||
// validation fails |
||||
} else { |
||||
// validation succeeds |
||||
} |
||||
} |
||||
``` |
||||
|
||||
Metoda [[yii\base\DynamicModel::validateData()|validateData()]] tworzy instancję `DynamicModel`, definiuje atrybuty używając przekazanych danych (`name` oraz `email` w tym przykładzie), |
||||
a następnie wywołuje metodę [[yii\base\Model::validate()|validate()]] z podanymi zasadami walidacji. |
||||
|
||||
Alternatywnie, możesz użyć bardziej "klasycznego" zapisu to przeprowadzenia tego typu walidacji: |
||||
|
||||
```php |
||||
public function actionSearch($name, $email) |
||||
{ |
||||
$model = new DynamicModel(compact('name', 'email')); |
||||
$model->addRule(['name', 'email'], 'string', ['max' => 128]) |
||||
->addRule('email', 'email') |
||||
->validate(); |
||||
|
||||
if ($model->hasErrors()) { |
||||
// validation fails |
||||
} else { |
||||
// validation succeeds |
||||
} |
||||
} |
||||
``` |
||||
|
||||
Po walidacji możesz sprawdzić, czy przebiegła ona poprawnie lub nie, przez wywołanie metody [[yii\base\DynamicModel::hasErrors()|hasErrors()]], |
||||
a następnie pobrać błędy walidacji z właściwości [[yii\base\DynamicModel::errors|errors]], tak jak w normalnym modelu. |
||||
Możesz również uzyskać dostęp do dynamicznych atrybutów tej instancji, np. `$model->name` and `$model->email`. |
||||
|
||||
|
||||
## Tworzenie walidatorów <span id="creating-validators"></span> |
||||
|
||||
Oprócz używania [podstawowych walidatorów](tutorial-core-validators.md) dołączonych do wydania Yii, możesz dodatkowo utworzyć własne: wbudowane lub niezależne. |
||||
|
||||
### Walidatory wbudowane <span id="inline-validators"></span> |
||||
|
||||
Wbudowany walidator jest zdefiniowaną w modelu metodą lub funkcją anonimową. Jej definicja jest następująca: |
||||
|
||||
```php |
||||
/** |
||||
* @param string $attribute atrybut podlegający walidacji |
||||
* @param mixed $params wartość parametru podanego w zasadzie walidacji |
||||
*/ |
||||
function ($attribute, $params) |
||||
``` |
||||
|
||||
Jeśli atrybut nie przejdzie walidacji, metoda/funkcja powinna wywołać metodę [[yii\base\Model::addError()|addError()]] do zapisania wiadomości błędu w modelu, |
||||
aby mogła ona zostać później pobrana i zaprezentowana użytkownikowi. |
||||
|
||||
Poniżej znajduje się kilka przykładów: |
||||
|
||||
```php |
||||
use yii\base\Model; |
||||
|
||||
class MyForm extends Model |
||||
{ |
||||
public $country; |
||||
public $token; |
||||
|
||||
public function rules() |
||||
{ |
||||
return [ |
||||
// Wbudowany walidator zdefiniowany jako metoda validateCountry() w modelu |
||||
['country', 'validateCountry'], |
||||
|
||||
// Wbudowany walidator zdefiniowany jako funkcja anonimowa |
||||
['token', function ($attribute, $params) { |
||||
if (!ctype_alnum($this->$attribute)) { |
||||
$this->addError($attribute, 'Token musi zawierać litery lub cyfry.'); |
||||
} |
||||
}], |
||||
]; |
||||
} |
||||
|
||||
public function validateCountry($attribute, $params) |
||||
{ |
||||
if (!in_array($this->$attribute, ['USA', 'Web'])) { |
||||
$this->addError($attribute, 'Wybrany kraj musi być jednym z: "USA", "Web".'); |
||||
} |
||||
} |
||||
} |
||||
``` |
||||
|
||||
> Note: Domyślnie wbudowane walidatory nie zostaną zastosowane, jeśli ich powiązane atrybuty otrzymają puste wartości lub wcześniej nie przeszły którejś z zasad walidacji. |
||||
> Jeśli chcesz się upewnić, że zasada zawsze zostanie zastosowana, możesz skonfigurować właściwość [[yii\validators\Validator::skipOnEmpty|skipOnEmpty]] i/lub |
||||
> [[yii\validators\Validator::skipOnError|skipOnError]] przypisując jej wartość `false` w deklaracji zasady walidacji. Dla przykładu: |
||||
> |
||||
> ```php |
||||
> [ |
||||
> ['country', 'validateCountry', 'skipOnEmpty' => false, 'skipOnError' => false], |
||||
> ] |
||||
> ``` |
||||
|
||||
|
||||
### Walidatory niezależne <span id="standalone-validators"></span> |
||||
|
||||
Walidator niezależy jest klasą rozszerzającą [[yii\validators\Validator|Validator]] lub klasy po nim dziedziczące. |
||||
Możesz zaimplementować jego logikę walidacji przez nadpisanie metody [[yii\validators\Validator::validateAttribute()|validateAttribute()]]. |
||||
Jeśli atrybut nie przejdzie walidacji, wywołaj metodę [[yii\base\Model::addError()|addError()]] do zapisania wiadomości błędu w modelu, tak jak w |
||||
[walidatorach wbudowanych](#inline-validators). |
||||
|
||||
|
||||
Dla przykładu, poprzedni wbudowany walidator mógłby zostać przeniesiony do nowej klasy `components/validators/CountryValidator`. |
||||
|
||||
```php |
||||
namespace app\components; |
||||
|
||||
use yii\validators\Validator; |
||||
|
||||
class CountryValidator extends Validator |
||||
{ |
||||
public function validateAttribute($model, $attribute) |
||||
{ |
||||
if (!in_array($model->$attribute, ['USA', 'Web'])) { |
||||
$this->addError($model, $attribute, 'Wybrany kraj musi być jednym z: "USA", "Web".'); |
||||
} |
||||
} |
||||
} |
||||
``` |
||||
|
||||
Jeśli chcesz, aby walidator wspierał walidację wartości bez modelu, powinieneś nadpisać metodę [[yii\validators\Validator::validate()|validate()]]. |
||||
Możesz nadpisać także [[yii\validators\Validator::validateValue()|validateValue()]] zamiast `validateAttribute()` oraz `validate()`, |
||||
ponieważ domyślnie te dwie metody są implementowane użyciem metody `validateValue()`. |
||||
|
||||
Poniżej znajduje się przykład, jak mógłbyś użyć powyższej klasy walidatora w swoim modelu. |
||||
|
||||
```php |
||||
namespace app\models; |
||||
|
||||
use Yii; |
||||
use yii\base\Model; |
||||
use app\components\validators\CountryValidator; |
||||
|
||||
class EntryForm extends Model |
||||
{ |
||||
public $name; |
||||
public $email; |
||||
public $country; |
||||
|
||||
public function rules() |
||||
{ |
||||
return [ |
||||
[['name', 'email'], 'required'], |
||||
['country', CountryValidator::className()], |
||||
['email', 'email'], |
||||
]; |
||||
} |
||||
} |
||||
``` |
||||
|
||||
|
||||
## Walidacja po stronie klienta <span id="client-side-validation"></span> |
||||
|
||||
Walidacja po stronie klienta bazująca na kodzie JavaScript jest wskazana, kiedy użytkownicy dostarczają dane przez formularz HTML, |
||||
ponieważ pozwala na szybszą walidację błędów, a tym samym zapewnia lepszą ich obsługę dla użytkownika. Możesz użyć lub zaimplementować walidator, który wspiera walidację po stronie |
||||
klienta *dodatkowo do* walidacji po stronie serwera. |
||||
|
||||
> Info: Walidacja po stronie klienta nie jest wymagana. Głównym jej celem jest poprawa jakości korzystania z formularzy przez użytkowników. |
||||
Podobnie do danych wejściowych pochodzących od użytkowników, nigdy nie powinieneś ufać walidacji po stronie klienta. Z tego powodu, |
||||
powinieneś zawsze przeprowadzać walidację po stronie serwera wywołując metodę [[yii\base\Model::validate()|validate()]], tak jak zostało to opisane w poprzednich sekcjach. |
||||
|
||||
### Używanie walidacji po stronie klienta <span id="using-client-side-validation"></span> |
||||
|
||||
Wiele [podstawowych walidatorów](tutorial-core-validators.md) domyślnie wspiera walidację po stronie klienta. Wszystko, co musisz zrobić, to użyć widżetu |
||||
[[yii\widgets\ActiveForm|ActiveForm]] do zbudowania formularza HTML. Dla przykładu, model `LoginForm` poniżej deklaruje dwie zasady: jedną, używającą podstawowego walidatora |
||||
[required](tutorial-core-validators.md#required), który wspiera walidację po stronie klienta i serwera, oraz drugą, w której użyto walidatora wbudowanego `validatePassword`, który |
||||
wspiera tylko walidację po stronie klienta. |
||||
|
||||
```php |
||||
namespace app\models; |
||||
|
||||
use yii\base\Model; |
||||
use app\models\User; |
||||
|
||||
class LoginForm extends Model |
||||
{ |
||||
public $username; |
||||
public $password; |
||||
|
||||
public function rules() |
||||
{ |
||||
return [ |
||||
// atrybuty username oraz password są wymagane |
||||
[['username', 'password'], 'required'], |
||||
|
||||
// atrybut password jest walidowany przez validatePassword() |
||||
['password', 'validatePassword'], |
||||
]; |
||||
} |
||||
|
||||
public function validatePassword() |
||||
{ |
||||
$user = User::findByUsername($this->username); |
||||
|
||||
if (!$user || !$user->validatePassword($this->password)) { |
||||
$this->addError('password', 'Nieprawidłowa nazwa użytkownika lub hasło.'); |
||||
} |
||||
} |
||||
} |
||||
``` |
||||
|
||||
Formularz HTML zbudowany przez następujący kod zawiera dwa pola: `username` oraz `password`. |
||||
Jeśli wyślesz formularz bez wpisywania jakichkolwiek danych, otrzymasz komunikaty błędów o ich braku, bez konieczności przeprowadzania komunikacji z serwerem. |
||||
|
||||
```php |
||||
<?php $form = yii\widgets\ActiveForm::begin(); ?> |
||||
<?= $form->field($model, 'username') ?> |
||||
<?= $form->field($model, 'password')->passwordInput() ?> |
||||
<?= Html::submitButton('Login') ?> |
||||
<?php yii\widgets\ActiveForm::end(); ?> |
||||
``` |
||||
|
||||
"Za kulisami", widżet [[yii\widgets\ActiveForm|ActiveForm]] odczyta wszystkie zasady walidacji zadeklarowane w modelu i wygeneruje odpowiedni kod JavaScript |
||||
dla walidatorów wspierających walidację po stronie klienta. Kiedy użytkownik zmieni wartość w polu lub spróbuje wysłać formularz, zostanie wywołana walidacja po stronie klienta. |
||||
|
||||
Jeśli chcesz wyłączyć kompletnie walidację po stronie klienta, możesz ustawić właściwość [[yii\widgets\ActiveForm::enableClientValidation|enableClientValidation]] na `false`. |
||||
Możesz również wyłączyć ten rodzaj walidacji dla konkretnego pola, przez ustawienie jego właściwości |
||||
[[yii\widgets\ActiveField::enableClientValidation|enableClientValidation]] na `false`. Jeśli właściwość `enableClientValidation` zostanie skonfigurowana na poziomie pola formularza i w |
||||
samym formularzu jednocześnie, pierwszeństwo będzie miała opcja określona w formularzu. |
||||
|
||||
|
||||
### Implementacja walidacji po stronie klienta <span id="implementing-client-side-validation"></span> |
||||
|
||||
Aby utworzyć walidator wspierający walidację po stronie klienta, powinieneś zaimplementować metodę [[yii\validators\Validator::clientValidateAttribute()|clientValidateAttribute()]], |
||||
która zwraca kod JavaScript, odpowiedzialny za przeprowadzenie walidacji. W kodzie JavaScript możesz użyć następujących predefiniowanych zmiennych: |
||||
|
||||
- `attribute`: nazwa atrybutu podlegającego walidacji. |
||||
- `value`: wartość atrybutu podlegająca walidacji. |
||||
- `messages`: tablica używana do przechowywania wiadomości błędów dla danego atrybutu. |
||||
- `deferred`: tablica, do której można dodać zakolejkowane obiekty (wyjaśnione w późniejszej podsekcji). |
||||
|
||||
W poniższym przykładzie, tworzymy walidator `StatusValidator`, który sprawdza, czy wartość danego atrybutu jest wartością znajdującą się w zbiorze statusów w bazie danych. |
||||
Walidator wspiera obydwa typy walidacji: po stronie klienta oraz serwerową. |
||||
|
||||
```php |
||||
namespace app\components; |
||||
|
||||
use yii\validators\Validator; |
||||
use app\models\Status; |
||||
|
||||
class StatusValidator extends Validator |
||||
{ |
||||
public function init() |
||||
{ |
||||
parent::init(); |
||||
$this->message = 'Niepoprawna wartość pola status.'; |
||||
} |
||||
|
||||
public function validateAttribute($model, $attribute) |
||||
{ |
||||
$value = $model->$attribute; |
||||
if (!Status::find()->where(['id' => $value])->exists()) { |
||||
$model->addError($attribute, $this->message); |
||||
} |
||||
} |
||||
|
||||
public function clientValidateAttribute($model, $attribute, $view) |
||||
{ |
||||
$statuses = json_encode(Status::find()->select('id')->asArray()->column()); |
||||
$message = json_encode($this->message, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); |
||||
return <<<JS |
||||
if ($.inArray(value, $statuses) === -1) { |
||||
messages.push($message); |
||||
} |
||||
JS; |
||||
} |
||||
} |
||||
``` |
||||
|
||||
> Tip: Powyższy kod został podany głównie do zademonstrowania jak wspierać walidację po stronie klienta. |
||||
> W praktyce można użyć podstawowego walidatora [in](tutorial-core-validators.md#in), aby osiągnąć ten sam cel. |
||||
> Możesz napisać taką zasadę walidacji następująco: |
||||
> |
||||
> ```php |
||||
> [ |
||||
> ['status', 'in', 'range' => Status::find()->select('id')->asArray()->column()], |
||||
> ] |
||||
> ``` |
||||
|
||||
### Kolejkowa walidacja <span id="deferred-validation"></span> |
||||
|
||||
Jeśli potrzebujesz przeprowadzić asynchroniczną walidację po stronie klienta, możesz utworzyć [obiekt kolejkujący](http://api.jquery.com/category/deferred-object/). |
||||
Dla przykładu, aby przeprowadzić niestandardową walidację AJAX, możesz użyć następującego kodu: |
||||
|
||||
```php |
||||
public function clientValidateAttribute($model, $attribute, $view) |
||||
{ |
||||
return <<<JS |
||||
deferred.push($.get("/check", {value: value}).done(function(data) { |
||||
if ('' !== data) { |
||||
messages.push(data); |
||||
} |
||||
})); |
||||
JS; |
||||
} |
||||
``` |
||||
|
||||
W powyższym kodzie, zmienna `deferred` jest dostarczona przez Yii, która jest tablicą zakolejkowanych obiektów. |
||||
Metoda jQuery `$.get()` tworzy obiekt kolejkowy, który jest dodawany do tablicy `deferred`. |
||||
|
||||
Możesz także utworzyć osobny obiekt kolejkowania i wywołać jego metodę `resolve()` po otrzymaniu asynchronicznej informacji zwrotnej. |
||||
Poniższy przykład pokazuje, jak zwalidować wymiary przesłanego obrazka po stronie klienta. |
||||
|
||||
```php |
||||
public function clientValidateAttribute($model, $attribute, $view) |
||||
{ |
||||
return <<<JS |
||||
var def = $.Deferred(); |
||||
var img = new Image(); |
||||
img.onload = function() { |
||||
if (this.width > 150) { |
||||
messages.push('Image too wide!!'); |
||||
} |
||||
def.resolve(); |
||||
} |
||||
var reader = new FileReader(); |
||||
reader.onloadend = function() { |
||||
img.src = reader.result; |
||||
} |
||||
reader.readAsDataURL(file); |
||||
|
||||
deferred.push(def); |
||||
JS; |
||||
} |
||||
``` |
||||
|
||||
> Note: Metoda `resolve()` musi być wywołana po zwalidowaniu atrybutu. W przeciwnym razie walidacja formularza nie zostanie ukończona. |
||||
|
||||
Dla uproszczenia, tablica `deferred` jest wyposażona w skrótową metodę `add()`, która automatycznie tworzy obiekt kolejkowy i dodaje go do tej tablicy. |
||||
Używając tej metody, możesz uprościć powyższy przykład: |
||||
|
||||
```php |
||||
public function clientValidateAttribute($model, $attribute, $view) |
||||
{ |
||||
return <<<JS |
||||
deferred.add(function(def) { |
||||
var img = new Image(); |
||||
img.onload = function() { |
||||
if (this.width > 150) { |
||||
messages.push('Image too wide!!'); |
||||
} |
||||
def.resolve(); |
||||
} |
||||
var reader = new FileReader(); |
||||
reader.onloadend = function() { |
||||
img.src = reader.result; |
||||
} |
||||
reader.readAsDataURL(file); |
||||
}); |
||||
JS; |
||||
} |
||||
``` |
||||
|
||||
|
||||
### Walidacja przy użyciu AJAX <span id="ajax-validation"></span> |
||||
|
||||
Niektóre walidacje mogą zostać wykonane tylko po stronie serwera, ponieważ tylko serwer posiada niezbędne informacje do ich przeprowadzenia. |
||||
Dla przykładu, aby sprawdzić, czy login został już zajęty, musimy sprawdzić tabelę użytkowników w bazie danych. |
||||
W tym właśnie przypadku możesz użyć walidacji AJAX. Wywoła ona żądanie AJAX w tle, aby spradzić to pole. |
||||
|
||||
Aby uaktywnić walidację AJAX dla pojedyńczego pola formularza, ustaw właściwość [[yii\widgets\ActiveField::enableAjaxValidation|enableAjaxValidation]] na `true` oraz określ unikalne ID |
||||
formularza: |
||||
|
||||
```php |
||||
use yii\widgets\ActiveForm; |
||||
|
||||
$form = ActiveForm::begin([ |
||||
'id' => 'registration-form', |
||||
]); |
||||
|
||||
echo $form->field($model, 'username', ['enableAjaxValidation' => true]); |
||||
|
||||
// ... |
||||
|
||||
ActiveForm::end(); |
||||
``` |
||||
|
||||
Aby uaktywnić walidację AJAX dla całego formularza, ustaw właściwość [[yii\widgets\ActiveForm::enableAjaxValidation|enableAjaxValidation]] na `true` na poziomie formularza: |
||||
|
||||
```php |
||||
$form = ActiveForm::begin([ |
||||
'id' => 'contact-form', |
||||
'enableAjaxValidation' => true, |
||||
]); |
||||
``` |
||||
|
||||
> Note: Jeśli właściwość [[yii\widgets\ActiveForm::enableAjaxValidation|enableAjaxValidation]] zostanie skonfigurowana na poziomie pola formularza i jednocześnie w samym formularzu, |
||||
pierwszeństwo będzie miała opcja określona w formularzu. |
||||
|
||||
|
||||
Musisz również przygotować serwer, aby mógł obsłużyć AJAXowe zapytanie o walidację. Możesz to osiągnąć przez następujący skrawek kodu w akcji kontrolera: |
||||
|
||||
```php |
||||
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) { |
||||
Yii::$app->response->format = Response::FORMAT_JSON; |
||||
return ActiveForm::validate($model); |
||||
} |
||||
``` |
||||
|
||||
Powyższy kod sprawdzi, czy zapytanie zostało wysłane przy użyciu AJAXa. Jeśli tak, w odpowiedzi zwróci wynik walidacji w formacie JSON. |
||||
|
||||
> Info: Możesz również użyć [walidacji kolejkowej](#deferred-validation) do wykonania walidacji AJAX, jednakże walidacja AJAXowa opisana w tej sekcji jest bardziej systematyczna i |
||||
wymaga mniej wysiłku przy kodowaniu. |
@ -0,0 +1,90 @@
|
||||
Praca ze skryptami |
||||
=========================== |
||||
|
||||
> Note: Ta sekcja nie została jeszcze ukończona. |
||||
|
||||
### Rejestrowanie skryptów |
||||
|
||||
Dzięki obiektowi [[yii\web\View|View]] możesz rejestrować skrypty w aplikacji. Przeznaczone są do tego dwie dedykowane metody: |
||||
[[yii\web\View::registerJs()|registerJs()]] dla skryptów wbudowanych oraz |
||||
[[yii\web\View::registerJsFile()|registerJsFile()]] dla skryptów zewnętrznych. |
||||
Skrypty wbudowane są przydatne przy konfiguracji oraz dynamicznym generowaniu kodu. |
||||
Możesz dodać je w następujący sposób: |
||||
|
||||
```php |
||||
$this->registerJs("var options = " . json_encode($options) . ";", View::POS_END, 'my-options'); |
||||
``` |
||||
|
||||
Pierwszy argument przekazywany do metody `registerJs` to kod JavaScript, który chcemy umieścić na stronie. Jako drugi argument wskazujemy miejsce, |
||||
w którym skrypt ma zostać umieszczony na stronie. Możliwe wartości to: |
||||
|
||||
- [[yii\web\View::POS_HEAD|View::POS_HEAD]] dla sekcji `head`. |
||||
- [[yii\web\View::POS_BEGIN|View::POS_BEGIN]] zaraz po otwarciu tagu `<body>`. |
||||
- [[yii\web\View::POS_END|View::POS_END]] zaraz przed zamknięciem tagu `</body>`. |
||||
- [[yii\web\View::POS_READY|View::POS_READY]] do wywołania kodu z użyciem zdarzenia `ready` na dokumencie. Ta opcja zarejestruje automatycznie [[yii\web\JqueryAsset|jQuery]] |
||||
- [[yii\web\View::POS_LOAD|View::POS_LOAD]] do wywołania kodu z użyciem zdarzenia `load` na dokumencie. Ta opcja zarejestruje automatycznie [[yii\web\JqueryAsset|jQuery]] |
||||
|
||||
Ostatnim argumentem jest unikalne ID skryptu, które jest używane do zidentyfikowania bloku kodu i zastąpienia go, jeśli taki został już zarejestrowany. |
||||
Jeśli ten argument nie zostanie podany, kod JavaScript zostanie użyty jako ID. |
||||
|
||||
Skrypt zewnętrzny może zostać dodany następująco: |
||||
|
||||
```php |
||||
$this->registerJsFile('http://example.com/js/main.js', ['depends' => [\yii\web\JqueryAsset::className()]]); |
||||
``` |
||||
|
||||
Argumenty dla metod [[yii\web\View::registerCssFile()|registerCssFile()]] są podobne do [[yii\web\View::registerJsFile()|registerJsFile()]]. |
||||
W powyższym przykładzie, zarejestrowaliśmy plik `main.js` z zależnością od `JqueryAsset`. Oznacza to, że plik `main.js` zostanie dodany PO pliku `jquery.js`. |
||||
Bez określenia tej zależności, względny porządek pomiędzy `main.js` a `jquery.js` nie zostałby zachowany. |
||||
|
||||
Tak jak i w przypadku [[yii\web\View::registerCssFile()|registerCssFile()]], mocno rekomendujemy, abyś użył [assetów](structure-assets.md) do zarejestrowania zewnętrznych plików JS |
||||
zamiast używania [[yii\web\View::registerJsFile()|registerJsFile()]]. |
||||
|
||||
|
||||
### Rejestracja assetów |
||||
|
||||
Jak zostało wspomniane wcześniej, korzystniejsze jest stosowanie assetów, zamiast kodu CSS i JS bezpośrednio (po informacje na ten temat sięgnij do sekcji |
||||
[menedżera assetów](structure-assets.md)). |
||||
Korzystanie z już zdefiniowanych pakietów jest bardzo proste: |
||||
|
||||
```php |
||||
\frontend\assets\AppAsset::register($this); |
||||
``` |
||||
|
||||
|
||||
### Rejestrowanie kodu CSS |
||||
|
||||
Możesz zarejestrować kod CSS przy użyciu metody [[yii\web\View::registerCss()|registerCss()]] lub [[yii\web\View::registerCssFile()|registerCssFile()]]. |
||||
Pierwsza z nich rejestruje blok kodu CSS, natomiast druga zewnętrzny plik `.css`. Dla przykładu: |
||||
|
||||
```php |
||||
$this->registerCss("body { background: #f00; }"); |
||||
``` |
||||
|
||||
Powyższy kod doda kod CSS do sekcji `head` strony: |
||||
|
||||
```html |
||||
<style> |
||||
body { background: #f00; } |
||||
</style> |
||||
``` |
||||
|
||||
Jeśli chcesz określić dodatkowe właściwości dla tagu `style`, przekaż tablicę `nazwa => wartość` jako drugi argument. |
||||
Jeśli chcesz się upewnić, że jest tylko jeden tag `style`, użyj trzeciego argumentu, tak jak zostało to opisane dla meta tagów. |
||||
|
||||
```php |
||||
$this->registerCssFile("http://example.com/css/themes/black-and-white.css", [ |
||||
'depends' => [BootstrapAsset::className()], |
||||
'media' => 'print', |
||||
], 'css-print-theme'); |
||||
``` |
||||
|
||||
Kod powyżej doda link w sekcji `head` strony do pliku CSS. |
||||
|
||||
* Pierwszy argument określa, który plik ma zostać zarejestrowany, |
||||
* Drugi argument określa atrybuty tagu `<link>`. Opcja `depends` jest obsługiwana w specjalny sposób, od niej zależy położenie pliku CSS. |
||||
W tym przypadku, plik link do pliku CSS zostanie umieszony ZA plikami CSS w [[yii\bootstrap\BootstrapAsset|BootstrapAsset]], |
||||
* Ostatni argument określa ID identyfikujące ten plik CSS. W przypadku jego braku, zostanie użyty do tego celu adres URL pliku CSS. |
||||
|
||||
Jest mocno wskazane używanie [assetów](structure-assets.md) do rejestrowania zewnętrznych plików CSS. Użycie ich pozwala Ci na łączenie i kompresowanie |
||||
wielu plików CSS, które jest wręcz niezbędne na stronach internetowych o dużym natężeniu ruchu. |
@ -0,0 +1,90 @@
|
||||
Obsługa błędów |
||||
============== |
||||
|
||||
Podczas obsługi żądania RESTfulowego API, w przypadku wystąpienia błędu w zapytaniu użytkownika lub gdy stanie się coś nieprzewidywanego |
||||
z serwerem, możesz po prostu rzucić wyjątkiem, aby powiadomić użytkownika, że coś poszło nieprawidłowo. |
||||
Jeśli możesz zidentyfikować przyczynę błędu (np. żądany zasób nie istnieje), powinieneś rozważyć |
||||
rzucenie wyjątkiem razem z odpowiednim kodem statusu HTTP (np. [[yii\web\NotFoundHttpException|NotFoundHttpException]] odpowiada statusowi o kodzie 404). |
||||
Yii wyśle odpowiedź razem z odpowiadającym jej kodem i treścią statusu HTTP. Yii dołączy również do samej odpowiedzi zserializowaną reprezentację |
||||
wyjątku. Przykładowo: |
||||
|
||||
``` |
||||
HTTP/1.1 404 Not Found |
||||
Date: Sun, 02 Mar 2014 05:31:43 GMT |
||||
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y |
||||
Transfer-Encoding: chunked |
||||
Content-Type: application/json; charset=UTF-8 |
||||
|
||||
{ |
||||
"name": "Not Found Exception", |
||||
"message": "The requested resource was not found.", |
||||
"code": 0, |
||||
"status": 404 |
||||
} |
||||
``` |
||||
|
||||
Poniższa lista zawiera kody statusów HTTP, które są używane przez Yii REST framework: |
||||
|
||||
* `200`: OK. Wszystko działa w porządku. |
||||
* `201`: Zasób został poprawnie stworzony w odpowiedzi na żądanie `POST`. Nagłówek `Location` zawiera URL kierujący do nowoutworzonego zasobu. |
||||
* `204`: Żądanie zostało poprawnie przetworzone, ale odpowiedź nie zawiera treści (jak w przypadku żądania `DELETE`). |
||||
* `304`: Zasób nie został zmodyfikowany. Można użyć wersji przetrzymywanej w pamięci podręcznej. |
||||
* `400`: Nieprawidłowe żądanie. Może być spowodowane przez wiele czynników po stronie użytkownika, takich jak przekazanie nieprawidłowych danych JSON, |
||||
nieprawidłowych parametrów akcji, itp. |
||||
* `401`: Nieudana autentykacja. |
||||
* `403`: Autoryzowany użytkownik nie ma uprawnień do danego punktu końcowego API. |
||||
* `404`: Żądany zasób nie istnieje. |
||||
* `405`: Niedozwolona metoda. Sprawdź nagłówek `Allow`, aby poznać dozwolone metody HTTP. |
||||
* `415`: Niewspierany typ mediów. Żądany typ zawartości lub numer wersji jest nieprawidłowy. |
||||
* `422`: Nieudana walidacja danych (dla przykładu w odpowiedzi na żądanie `POST`). Sprawdź treść odpowiedzi, aby poznać szczegóły błędu. |
||||
* `429`: Zbyt wiele żądań. Żądanie zostało odrzucone z powodu osiagnięcia limitu użycia. |
||||
* `500`: Wewnętrzny błąd serwera. To może być spowodowane wewnętrznymi błędami programu. |
||||
|
||||
|
||||
## Modyfikowanie błędnej odpowiedzi <span id="customizing-error-response"></span> |
||||
|
||||
Czasem wymagane może być dostosowanie domyślnego formatu błędnej odpowiedzi. Dla przykładu, zamiast używać różnych statusów HTTP dla oznaczenia różnych błędów, |
||||
można serwować zawsze status 200 i dodawać prawidłowy kod statusu HTTP jako część struktury JSON w odpowiedzi, jak pokazano to poniżej: |
||||
|
||||
``` |
||||
HTTP/1.1 200 OK |
||||
Date: Sun, 02 Mar 2014 05:31:43 GMT |
||||
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y |
||||
Transfer-Encoding: chunked |
||||
Content-Type: application/json; charset=UTF-8 |
||||
|
||||
{ |
||||
"success": false, |
||||
"data": { |
||||
"name": "Not Found Exception", |
||||
"message": "The requested resource was not found.", |
||||
"code": 0, |
||||
"status": 404 |
||||
} |
||||
} |
||||
``` |
||||
|
||||
Aby osiągnąć powyższy efekt, należy skonfigurować odpowiedź na event `beforeSend` dla komponentu `response` w aplikacji: |
||||
|
||||
```php |
||||
return [ |
||||
// ... |
||||
'components' => [ |
||||
'response' => [ |
||||
'class' => 'yii\web\Response', |
||||
'on beforeSend' => function ($event) { |
||||
$response = $event->sender; |
||||
if ($response->data !== null && Yii::$app->request->get('suppress_response_code')) { |
||||
$response->data = [ |
||||
'success' => $response->isSuccessful, |
||||
'data' => $response->data, |
||||
]; |
||||
$response->statusCode = 200; |
||||
} |
||||
}, |
||||
], |
||||
], |
||||
]; |
||||
``` |
||||
|
||||
Powyższy kod zreformatuje odpowiedź (zarówno typu sukces jak i błąd), kiedy `suppress_response_code` zostanie przekazane jako parametr `GET`. |
@ -0,0 +1,109 @@
|
||||
Skrypty wejściowe |
||||
================= |
||||
|
||||
Skrypty wejściowe są pierwszym krokiem procesu bootstrapowania aplikacji. Aplikacja (zarówno web |
||||
jak i konsolowa) posiada pojedynczy skrypt wejściowy. Użytkownicy końcowi wysyłają żądania do skryptów |
||||
wejściowych, które inicjują instancje aplikacji i przekazują do nich te żądania. |
||||
|
||||
Skrypty wejściowe dla aplikacji Web muszą znajdować się w folderach dostępnych dla Web, aby użytkownicy końcowi mogli je wywołać. |
||||
Zwykle nazywane są `index.php`, ale mogą mieć inne nazwy pod warunkiem, że serwery Web potrafią je zlokalizować. |
||||
|
||||
Skrypty wejściowe dla aplikacji konsolowych trzymane są zwykle w [ścieżce głównej](structure-applications.md) |
||||
aplikacji i nazywane `yii` (z sufiksem `.php`). Powinny być wykonywalne, aby użytkownicy |
||||
mogli uruchomić aplikacje konsolowe za pomocą komendy `./yii <ścieżka> [argumenty] [opcje]`. |
||||
|
||||
Skrypty wejściowe wykonują głównie następującą pracę: |
||||
|
||||
* Definiują globalne stałe, |
||||
* Rejestrują [autoloader Composera](https://getcomposer.org/doc/01-basic-usage.md#autoloading), |
||||
* Dołączają plik klasy [[Yii]], |
||||
* Ładują konfigurację aplikacji, |
||||
* Tworzą i konfigurują instancję [aplikacji](structure-applications.md), |
||||
* Wywołują [[yii\base\Application::run()|run()]], aby przetworzyć wysłane żądanie. |
||||
|
||||
|
||||
## Aplikacje Web <span id="web-applications"></span> |
||||
|
||||
Poniżej znajdziesz kod skryptu wejściowego dla [Podstawowego projektu szablonu Web](start-installation.md). |
||||
|
||||
```php |
||||
<?php |
||||
|
||||
defined('YII_DEBUG') or define('YII_DEBUG', true); |
||||
defined('YII_ENV') or define('YII_ENV', 'dev'); |
||||
|
||||
// register Composer autoloader |
||||
require(__DIR__ . '/../vendor/autoload.php'); |
||||
|
||||
// include Yii class file |
||||
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php'); |
||||
|
||||
// load application configuration |
||||
$config = require(__DIR__ . '/../config/web.php'); |
||||
|
||||
// create, configure and run application |
||||
(new yii\web\Application($config))->run(); |
||||
``` |
||||
|
||||
|
||||
## Aplikacje konsoli <span id="console-applications"></span> |
||||
|
||||
Podobnie, poniżej kod skryptu wejściowego dla aplikacji konsolowej: |
||||
|
||||
```php |
||||
#!/usr/bin/env php |
||||
<?php |
||||
/** |
||||
* Yii console bootstrap file. |
||||
* |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
defined('YII_DEBUG') or define('YII_DEBUG', true); |
||||
|
||||
// register Composer autoloader |
||||
require(__DIR__ . '/vendor/autoload.php'); |
||||
|
||||
// include Yii class file |
||||
require(__DIR__ . '/vendor/yiisoft/yii2/Yii.php'); |
||||
|
||||
// load application configuration |
||||
$config = require(__DIR__ . '/config/console.php'); |
||||
|
||||
$application = new yii\console\Application($config); |
||||
$exitCode = $application->run(); |
||||
exit($exitCode); |
||||
``` |
||||
|
||||
|
||||
## Definiowanie stałych <span id="defining-constants"></span> |
||||
|
||||
Skrypty wejściowe są najlepszym miejscem do definiowania globalnych stałych. Yii wspiera następujące trzy stałe: |
||||
|
||||
* `YII_DEBUG`: określa czy aplikacja działa w trybie debugowania. Podczas tego trybu aplikacja |
||||
przetrzymuje więcej informacji w logach i zdradza szczegóły stosu błędów, kiedy rzucony jest wyjątek. Z tego powodu |
||||
tryb debugowania powinien być używany głównie podczas fazy deweloperskiej. Domyślną wartością `YII_DEBUG` jest false. |
||||
* `YII_ENV`: określa środowisko, w którym aplikacja działa. Opisane jest to bardziej szczegółowo |
||||
w sekcji [Konfiguracje](concept-configurations.md#environment-constants). |
||||
Domyślną wartością `YII_ENV` jest `'prod'`, co oznacza, że aplikacja jest uruchomiona w środowisku produkcyjnym. |
||||
* `YII_ENABLE_ERROR_HANDLER`: określa czy uruchomić obsługę błędów przygotowaną przez Yii. Domyślną wartością tej stałej jest true. |
||||
|
||||
Podczas definiowania stałej często korzystamy z poniższego kodu: |
||||
|
||||
```php |
||||
defined('YII_DEBUG') or define('YII_DEBUG', true); |
||||
``` |
||||
|
||||
co odpowiada: |
||||
|
||||
```php |
||||
if (!defined('YII_DEBUG')) { |
||||
define('YII_DEBUG', true); |
||||
} |
||||
``` |
||||
|
||||
Jak widać pierwszy sposób jest bardziej zwięzły i łatwiejszy do zrozumienia. |
||||
|
||||
Definiowanie stałych powinno odbyć się na samym początku skryptu wejściowego, aby odniosło skutek podczas dołączania pozostałych plików PHP. |
@ -0,0 +1,74 @@
|
||||
Testowanie |
||||
========== |
||||
|
||||
Testowanie jest istotnym elementem produkcji każdego oprogramowania. Niezależnie, czy jesteśmy tego świadomi, czy też nie, testy przeprowadzamy nieustannie. |
||||
Dla przykładu, kiedy napiszemy klasę w PHP, możemy debugować ją krok po kroku lub po prostu użyć wyrażeń jak echo lub die, aby sprawdzić, czy implementacja |
||||
działa zgodnie z naszym początkowym planem. W przypadku aplikacji web wprowadzamy testowe dane w formularzach, aby upewnić się, że strona odpowiada tak, jak powinna. |
||||
|
||||
Proces testowania może zostać zautomatyzowany, dzięki czemu za każdym razem, kiedy musimy coś sprawdzić, wystarczy wywołać kod, który zrobi to za nas. |
||||
Kod, który weryfikuje zgodność wyniku z planowaną odpowiedzią, jest nazywany testem, a proces jego tworzenia i późniejszego wykonania jest nazywany testowaniem zautomatyzowanym, |
||||
co jest głównym tematem tych rozdziałów. |
||||
|
||||
|
||||
Tworzenie kodu z testami |
||||
------------------------ |
||||
|
||||
Tworzenie kodu opartego na testach (Test-Driven Development, TDD) i opartego na zachowaniach (Behavior-Driven Development, BDD) jest podejściem deweloperskim |
||||
opierającym się na opisywaniu zachowania fragmentu kodu lub też całej jego funkcjonalności jako zestawu scenariuszy lub testów przed napisaniem właściwego kodu |
||||
i dopiero potem stworzeniu implementacji, która pozwoli na poprawne przejście testów, spełniających zadane kryteria. |
||||
|
||||
Proces tworzenia funkcjonalności wygląda następująco: |
||||
|
||||
- Stwórz nowy test, opisujący funkcjonalność do zaimplementowania. |
||||
- Uruchom nowy test i upewnij się, że zakończy się błędem. To właściwe zachowanie, ponieważ nie ma jeszcze implementacji funkcjonalności. |
||||
- Napisz prosty kod, który przejdzie poprawnie nowy test. |
||||
- Uruchom wszystkie testy i upewnij się, że wszystkie zakończą się poprawnie. |
||||
- Ulepsz kod, sprawdzając czy testy wciąż są zdane. |
||||
|
||||
Po zakończeniu proces jest powtarzany dla kolejnej funkcjonalności lub ulepszenia. Jeśli istniejąca funkcjonalność ma być zmodyfikowana, |
||||
testy powinny być również zmienione. |
||||
|
||||
> **Wskazówka**: Jeśli czujesz, że tracisz czas, przeprowadzając dużo krótkich i prostych iteracji, spróbuj objąć testowym scenariuszem więcej działań, |
||||
> aby sprawdzić więcej kodu, przed ponownym uruchomieniem testów. Jeśli debugujesz zbyt dużo, spróbuj zrobić dokładnie na odwrót. |
||||
|
||||
Powodem tworzenia testów przed jakąkolwiek implementacją, jest możliwość skupienia się na tym, co chcemy osiągnąć, zanim przystąpimy do "w jaki sposób to zrobić". |
||||
Zwykle prowadzi to do stworzenia lepszej warstwy abstrakcji i łatwiejszej obsługi testów w przypadku poprawek funkcjonalności. |
||||
|
||||
Podsumowując, zalety takiego projektowania są następujące: |
||||
|
||||
- Pozwala na skupienie się na pojedynczej rzeczy na raz, dzięki czemu pozwala na lepsze planowanie i implementacje. |
||||
- Obejmuje testami więcej funkcjonalności w większym stopniu, co oznacza, że jeśli testy zakończyły się poprawnie jest spore prawdopodobieństwo, że wszystko działa poprawnie. |
||||
|
||||
Na dłuższą metę przynosi to zwykle efekt w postaci mnóstwa oszczędzonego czasu i problemów. |
||||
|
||||
> **Wskazówka**: Jeśli chcesz dowiedzieć się więcej na temat reguł ustalania wymagań dla oprogramowania i modelowania istoty tego rozdziału, |
||||
> warto zapoznać się z domenowym podejściem do tworzenia aplikacji [(Domain Driven Development, DDD)](https://pl.wikipedia.org/wiki/Domain-Driven_Design). |
||||
|
||||
Kiedy i jak testować |
||||
-------------------- |
||||
|
||||
Podejście typu "testy najpierw" opisane powyżej, ma sens w przypadku długofalowych i relatywnie skomplikowanych projektów i może być przesadne w przypadku prostszych. |
||||
Przesłanki, kiedy testy są odpowiednie są następujące: |
||||
|
||||
- Projekt jest już duży i skomplikowany. |
||||
- Wymagania projektowe zaczynają być skomplikowane. Projekt wciąż się powiększa. |
||||
- Projekt jest planowany jako długoterminowy. |
||||
- Koszty potencjalnych błędów są zbyt duże. |
||||
|
||||
Nie ma nic złego w tworzeniu testów obejmujących zachowania istniejących implementacji. |
||||
|
||||
- Projekt jest oparty starszym kodzie i stopniowo przepisywany. |
||||
- Projekt, nad którym masz pracować, nie ma w ogóle testów. |
||||
|
||||
W niektórych przypadkach jakakolwiek forma automatycznego testu może być nadmiarowa: |
||||
|
||||
- Projekt jest prosty i nie jest rozbudowywany. |
||||
- Projekt jest jednorazowym zadaniem, które nie będzie rozwijane. |
||||
|
||||
Pomimo tego, jeśli masz na to czas, automatyzacja testowania jest również dobrym pomysłem. |
||||
|
||||
|
||||
Biblioteka |
||||
------------- |
||||
|
||||
- Test Driven Development: By Example - Kent Beck. (ISBN: 0321146530) |
Loading…
Reference in new issue