# Tworzenie formularzy ¶

## Formularze oparte na ActiveRecord: ActiveForm ¶

Podstawowym sposobem korzystania z formularzy w Yii jest użycie ActiveForm. Ten sposób powinien być używany, jeśli formularz jest bazowany na modelu. Dodatkowo, klasa Html zawiera sporo użytecznych metod, które zazwyczaj używane są do dodawania przycisków i tekstów pomocniczych do każdego formularza.

Formularz, który jest wyświetlany po stronie klienta, w większości przypadków, posiada odpowiedni model, który jest używany do walidacji danych wejściowych po stronie serwera (sprawdź sekcję Walidacja danych wejściowych aby uzyskać więcej szczegółów).
Podczas tworzenia formularza na podstawie modelu, pierwszym krokiem jest zdefiniowanie samego modelu. Model może być bazowany na klasie Active Record, reprezentując dane z bazy danych, lub może być też bazowany na klasie generycznej Model, aby przechwytywać dowolne dane wejściowe, np. formularz logowania.

> Wskazówka: Jeśli pola formularza są różne od kolumn tabeli w bazie danych lub też występuje tu formatowanie i logika specyficzna tylko dla tego formularza, zaleca się stworzenie oddzielnego modelu rozszerzającego yii\base\Model.

W poniższym przykładzie pokażemy, jak model generyczny może być użyty do stworzenia formularza logowania:

    <?php

    class LoginForm extends \yii\base\Model
    {
        public $username;
        public $password;

        public function rules()
        {
            return [
                // zasady walidacji
            ];
        }
    }

W kontrolerze przekażemy instancję tego modelu do widoku, gdzie widżet ActiveForm zostanie użyty do wyświetlenia formularza:

    <?php
    use yii\helpers\Html;
    use yii\widgets\ActiveForm;

    $form = ActiveForm::begin([
        'id' => 'login-form',
        'options' => ['class' => 'form-horizontal'],
    ]) ?>
        <?= $form->field($model, 'username') ?>
        <?= $form->field($model, 'password')->passwordInput() ?>

        <div class="form-group">
            <div class="col-lg-offset-1 col-lg-11">
                <?= Html::submitButton('Login', ['class' => 'btn btn-primary']) ?>
            </div>
        </div>
    <?php ActiveForm::end() ?>

### Otaczanie kodu przez `begin()` i `end()` ¶

W powyższym kodzie, begin() nie tylko tworzy instancję formularza, ale zaznacza też jego początek. Cała zawartość położona pomiędzy begin() i end() zostanie otoczona tagiem HTML'owym `<form>`. Jak w przypadku każdego widżetu, możesz określić kilka opcji z jakimi widżet powinien być skonfigurowany przez przekazanie tablicy do metody `begin`. W tym przypadku dodatkowa klasa CSS i identyfikator ID zostały przekazane do otwierającego tagu `<form>`. Aby zobaczyć wszystkie dostępne opcje, zajrzyj do dokumentacji API ActiveForm.

Do utworzenia formularza, wraz z elementami etykiet oraz wszelkimi walidacjami JavaScript, wywoływana jest metoda field(), która zwraca instancję obiektu ActiveField. Kiedy rezultat tej metody jest bezpośrednio wyświetlany, tworzone jest regularne pole tekstowe. Aby dostosować pola, możesz używać dodatkowych metod łączonych ActiveField:

    // pole hasła
    <?= $form->field($model, 'password')->passwordInput() ?>
    // dodanie podpowiedzi oraz zmiana etykiety
    <?= $form->field($model, 'username')->textInput()->hint('Please enter your name')->label('Name') ?>
    // utworzenie pola email w formacie HTML5
    <?= $form->field($model, 'email')->input('email') ?>

Powyższy kod utworzy tagi `<label>`, `<input>` oraz wszystkie inne, według pól formularza zdefiniowanych w template. Nazwa pola określana jest automatycznie z modelu formName() i nazwy atrybutu. Dla przykładu, nazwą pola dla atrybutu `username` w powyższym przykładzie będzie `LoginForm[username]`. Ta zasada nazewnictwa spowoduje, że tablica wszystkich atrybutów z formularza logowania będzie dostępna w zmiennej `$_POST['LoginForm']` po stronie serwera.

Określanie atrybutów modelu może być wykonane w bardziej wyrafinowany sposób. Dla przykładu, kiedy atrybut będzie potrzebował pobierać tablicę wartości, podczas przesyłania wielu plików lub wybrania wielu pozycji, możesz określić go jako tablicę dodając `[]` do nazwy atrybutu:

    // pozwól na przesłanie wielu plików
    echo $form->field($model, 'uploadFile[]')->fileInput(['multiple'=>'multiple']);

    // pozwól na zaznaczenie wielu pozycji
    echo $form->field($model, 'items[]')->checkboxList(['a' => 'Item A', 'b' => 'Item B', 'c' => 'Item C']);

Bądź ostrożny podczas nazywania elementów formularza takich jak przyciski wysyłania. Odnosząc się do dokumentacji jQuery, istnieje kilka zarezerwowanych nazw, które mogą powodować konflikty.

> Formularz i jego elementy podrzędne powinny nie używać nazw pól lub nazw identyfikatorów które tworzą konflikt z właściwościami formularza, takich jak `submit`, `length` lub `method`. Konflikty nazw mogą powodować mylące błędy. Kompletna lista zasad oraz walidator znaczników dla tych problemów znajduje się na stronie DOMLint.

Dodatkowe tagi HTML mogą zostać dodane do formularza używając czystego HTML'a lub używając metody z klasy pomocniczej - Html, tak jak było to zrobione w przykładzie wyżej z submitButton().

> Wskazówka: Jeśli używasz Twitter Bootstrap CSS w Twojej aplikacji, możesz użyć yii\bootstrap\ActiveForm zamiast yii\widgets\ActiveForm. Rozszerza on ActiveForm i podczas generowania pól formularza używa stylu specyficznego dla Bootstrap.

> Wskazówka: Jeśli chcesz oznaczyć wymagane pola gwiazdką, możesz uzyć poniższego kodu CSS:

>     div.required label:after {
>         content: " *";
>         color: red;
>     }

## Tworzenie list ¶

Wyróżniamy trzy typy list:

- Listy rozwijane
- Listy opcji typu radio
- Listy opcji typu checkbox

Aby stworzyć listę, musisz najpierw przygotować jej elementy. Można to zrobić ręcznie:

    $items = [
        1 => 'item 1',
        2 => 'item 2'
    ]

lub też pobierając elementy z bazy danych:

    $items = Category::find()
            ->select(['label'])
            ->indexBy('id')
            ->column();

Elementy `$items` muszą być następnie przetworzone przez odpowiednie widżety list. Wartość pola formularza (i aktualnie aktywny element) będzie automatycznie ustawiony przez aktualną wartość atrybutu `$model`.

#### Tworzenie listy rozwijanej ¶

Możemy użyć metody klasy ActiveForm yii\widgets\ActiveForm::dropDownList() do utworzenia rozwijanej listy:

    /* @var $form yii\widgets\ActiveForm */

    echo $form->field($model, 'category')->dropdownList([
            1 => 'item 1',
            2 => 'item 2'
        ],
        ['prompt'=>'Wybierz kategorię']
    );

#### Tworzenie radio listy ¶

Do stworzenia takiej listy możemy użyć metody ActiveField yii\widgets\ActiveField::radioList():

    /* @var $form yii\widgets\ActiveForm */

    echo $form->field($model, 'category')->radioList([
        1 => 'radio 1',
        2 => 'radio 2'
    ]);

#### Tworzenie checkbox listy ¶

Do stworzenia takiej listy możemy użyć metody ActiveField yii\widgets\ActiveField::checkboxList():

    /* @var $form yii\widgets\ActiveForm */

    echo $form->field($model, 'category')->checkboxList([
        1 => 'checkbox 1',
        2 => 'checkbox 2'
    ]);

## Praca z Pjaxem ¶

Widżet Pjax pozwala na aktualizację określonej sekcji strony, zamiast przeładowywania jej całkowicie. Możesz użyć go do odświeżenia formularza i podmienić jego zawartość po wysłaniu danych.

Możesz skonfigurować $formSelector, aby wskazać, które formularze powinny wyzwalać użycie pjaxa. Jeśli nie zostanie to ustawione inaczej, wszystkie formularze z atrybutem `data-pjax` objęte widżetem Pjax będą wyzwalały jego użycie.

    use yii\widgets\Pjax;
    use yii\widgets\ActiveForm;

    Pjax::begin([
        // opcje Pjaxa
    ]);
        $form = ActiveForm::begin([
            'options' => ['data' => ['pjax' => true]],
            // więcej opcji ActiveForm
        ]);

            // zawartość ActiveForm

        ActiveForm::end();
    Pjax::end();

> Wskazówka: Należy być ostrożnym z użyciem linków wewnątrz widżetu Pjax, ponieważ ich cel również zostanie wyrenderowany wewnątrz widżetu. Aby temu zapobiec, należy użyć atrybutu HTML `data-pjax="0"`.

#### Wartości w przyciskach submit i przesyłanie plików ¶

Znane są problemy z użyciem `jQuery.serializeArray()` podczas obsługi [[https://github.com/jquery/jquery/issues/2321|plików]] i [[https://github.com/jquery/jquery/issues/2321|wartości przycisku submit]], które nie będą jednak rozwiązane i zamiast tego zostały porzucone na rzecz klasy `FormData` wprowadzonej w HTML5.

Oznacza to, że oficjalne wsparcie dla plików i wartości przycisku submit używanych w połączeniu z ajaxem lub widżetem Pjax zależy od [[https://developer.mozilla.org/en-US/docs/Web/API/FormData#browser_compatibility|wsparcia przeglądarki]] dla klasy `FormData`.

## Dalsza lektura ¶

Następna sekcja Walidacja danych wejściowych dotyczy walidacji przesłanych przed formularz danych po stronie serwera, przy użyciu ajax oraz walidacji po stronie klienta.

Aby przeczytać o bardziej złożonych użyciach formularzy możesz zajrzeć do poniższych sekcji:

- Odczytywanie tablicowych danych wejściowych - do pobierania danych dla wielu modeli tego samego rodzaju.
- Pobieranie danych dla wielu modeli - do obsługi wielu różnych modeli w tym samym formularzu.
- Wysyłanie plików - jak używać formularzy do przesyłania plików.