Form Oluşturma
Formların görünümü çok çeşitli olabilir. Uygulamada iki uç noktayla karşılaşabiliriz. Bir yandan, bir uygulamada
görsel olarak birbirine benzeyen bir dizi form oluşturma ihtiyacı vardır ve $form->render()
kullanarak şablon
olmadan kolay oluşturmayı takdir ederiz. Bu durum genellikle yönetim arayüzleri için geçerlidir.
Öte yandan, her birinin benzersiz olduğu çeşitli formlar vardır. Bunların görünümü en iyi şablonda HTML dili kullanılarak tanımlanır. Ve elbette, bahsedilen her iki aşırı uca ek olarak, arada bir yere düşen birçok formla karşılaşacağız.
Latte ile Rendering
Latte şablonlama sistemi, formların ve öğelerinin oluşturulmasını temel olarak kolaylaştırır. İlk olarak, kod üzerinde tam kontrol elde etmek için formların öğe öğe manuel olarak nasıl oluşturulacağını göstereceğiz. Daha sonra bu işlemin nasıl otomatikleştirileceğini göstereceğiz.
Nette\Forms\Blueprint::latte($form)
yöntemini kullanarak oluşturulan form için bir Latte
şablonu önerisine sahip olabilirsiniz, bu da tarayıcı sayfasına çıktı verecektir. Ardından, kodu bir tıklama ile
seçmeniz ve projenize kopyalamanız yeterlidir.
{control}
Bir formu oluşturmanın en kolay yolu bir şablon içine yazmaktır:
{control signInForm}
Oluşturulan formun görünümü, Renderer ve bireysel kontroller yapılandırılarak değiştirilebilir.
n:name
PHP kodundaki form tanımını HTML koduna bağlamak son derece kolaydır. Sadece n:name
niteliklerini ekleyin.
İşte bu kadar kolay!
protected function createComponentSignInForm(): Form
{
$form = new Form;
$form->addText('username')->setRequired();
$form->addPassword('password')->setRequired();
$form->addSubmit('send');
return $form;
}
<form n:name=signInForm class=form>
<div>
<label n:name=username>Username: <input n:name=username size=20 autofocus></label>
</div>
<div>
<label n:name=password>Password: <input n:name=password></label>
</div>
<div>
<input n:name=send class="btn btn-default">
</div>
</form>
Ortaya çıkan HTML kodunun görünümü tamamen sizin elinizdedir. n:name
özniteliğini şu şekilde
kullanırsanız <select>
, <button>
veya <textarea>
öğeleri varsa, iç
içerikleri otomatik olarak doldurulur. Buna ek olarak <form n:name>
etiketi, çizilen form nesnesi ve
kapanış ile $form
yerel değişkenini oluşturur. </form>
çizilmemiş tüm gizli öğeleri
çizer (aynı durum {form} ... {/form}
için de geçerlidir).
Ancak, olası hata mesajlarını oluşturmayı unutmamalıyız. Hem addError()
yöntemi (
{inputError}
kullanılarak) tarafından tek tek öğelere eklenenler hem de doğrudan forma eklenenler (
$form->getOwnErrors()
tarafından döndürülenler):
<form n:name=signInForm class=form>
<ul class="errors" n:ifcontent>
<li n:foreach="$form->getOwnErrors() as $error">{$error}</li>
</ul>
<div>
<label n:name=username>Username: <input n:name=username size=20 autofocus></label>
<span class=error n:ifcontent>{inputError username}</span>
</div>
<div>
<label n:name=password>Password: <input n:name=password></label>
<span class=error n:ifcontent>{inputError password}</span>
</div>
<div>
<input n:name=send class="btn btn-default">
</div>
</form>
RadioList veya CheckboxList gibi daha karmaşık form öğeleri öğe öğe işlenebilir:
{foreach $form[gender]->getItems() as $key => $label}
<label n:name="gender:$key"><input n:name="gender:$key"> {$label}</label>
{/foreach}
{label}
{input}
Her bir öğe için şablonda hangi HTML öğesini kullanacağınızı düşünmek istemez misiniz? <input>
,
<textarea>
vb. Çözüm evrensel {input}
etiketidir:
<form n:name=signInForm class=form>
<ul class="errors" n:ifcontent>
<li n:foreach="$form->getOwnErrors() as $error">{$error}</li>
</ul>
<div>
{label username}Username: {input username, size: 20, autofocus: true}{/label}
{inputError username}
</div>
<div>
{label password}Password: {input password}{/label}
{inputError password}
</div>
<div>
{input send, class: "btn btn-default"}
</div>
</form>
Form bir çevirmen kullanıyorsa, {label}
etiketlerinin içindeki metin çevrilecektir.
Yine, RadioList veya CheckboxList gibi daha karmaşık form öğeleri öğe öğe işlenebilir:
{foreach $form[gender]->items as $key => $label}
{label gender:$key}{input gender:$key} {$label}{/label}
{/foreach}
İşlemek için <input>
'nin kendisini Onay Kutusu öğesinde kullanmak için
{input myCheckbox:}
adresini kullanın. HTML nitelikleri virgülle ayrılmalıdır
{input myCheckbox:, class: required}
.
{inputError}
Form öğesi için, eğer varsa, bir hata mesajı yazdırır. Mesaj genellikle stil için bir HTML öğesine sarılır. Mesaj
yoksa boş bir öğe oluşturmaktan kaçınmak n:ifcontent
ile zarif bir şekilde yapılabilir:
<span class=error n:ifcontent>{inputError $input}</span>
hasErrors()
yöntemini kullanarak bir hatanın varlığını tespit edebilir ve üst öğenin sınıfını buna
göre ayarlayabiliriz:
<div n:class="$form[username]->hasErrors() ? 'error'">
{input username}
{inputError username}
</div>
{form}
Etiketler {form signInForm}...{/form}
bir alternatiftir
<form n:name="signInForm">...</form>
.
Otomatik Rendering
{input}
ve {label}
etiketleri ile herhangi bir form için kolayca genel bir şablon oluşturabiliriz.
Form şu etiketle sonlandırıldığında otomatik olarak işlenen gizli öğeler hariç, tüm öğelerini sırayla yineleyecek ve
işleyecektir </form>
etiketini kullanır. Oluşturulan formun adını $form
değişkeninde
bekleyecektir.
<form n:name=$form class=form>
<ul class="errors" n:ifcontent>
<li n:foreach="$form->getOwnErrors() as $error">{$error}</li>
</ul>
<div n:foreach="$form->getControls() as $input"
n:if="$input->getOption(type) !== hidden">
{label $input /}
{input $input}
{inputError $input}
</div>
</form>
Kullanılan kendi kendine kapanan çift etiketleri {label .../}
PHP kodundaki form tanımından gelen etiketleri
gösterir.
Bu genel şablonu basic-form.latte
dosyasına kaydedebilir ve formu oluşturmak için onu dahil edip form adını
(veya örneğini) $form
parametresine aktarabilirsiniz:
{include basic-form.latte, form: signInForm}
Belirli bir formun görünümünü etkilemek ve bir öğeyi farklı şekilde çizmek istiyorsanız, bunun en kolay yolu şablonda daha sonra üzerine yazılabilecek bloklar hazırlamaktır. Bloklar dinamik isimlere de sahip olabilir, böylece içine çizilecek öğenin adını ekleyebilirsiniz. Örneğin:
...
{label $input /}
{block "input-{$input->name}"}{input $input}{/block}
...
Örneğin username
öğesi için bu, {embed} etiketi kullanılarak kolayca geçersiz
kılınabilecek input-username
bloğunu oluşturur:
{embed basic-form.latte, form: signInForm}
{block input-username}
<span class=important>
{include parent}
</span>
{/block}
{/embed}
Alternatif olarak, basic-form.latte
şablonunun tüm içeriği $form
parametresi de dahil olmak
üzere bir blok olarak tanımlanabilir:
{define basic-form, $form}
<form n:name=$form class=form>
...
</form>
{/define}
Bu, kullanımı biraz daha kolaylaştıracaktır:
{embed basic-form, signInForm}
...
{/embed}
Bloğu yalnızca bir yerde, düzen şablonunun başında içe aktarmanız gerekir:
{import basic-form.latte}
Özel Durumlar
Formun yalnızca iç kısmını HTML etiketleri olmadan oluşturmanız gerekiyorsa <form>
örneğin snippet
gönderirken, n:tag-if
özniteliğini kullanarak bunları gizleyin:
<form n:name=signInForm n:tag-if=false>
<div>
<label n:name=username>Username: <input n:name=username></label>
{inputError username}
</div>
</form>
Etiket formContainer
bir form konteyneri içindeki girdilerin oluşturulmasına yardımcı olur.
<p>Which news you wish to receive:</p>
{formContainer emailNews}
<ul>
<li>{input sport} {label sport /}</li>
<li>{input science} {label science /}</li>
</ul>
{/formContainer}
Latte Olmadan Rendering
Bir formu oluşturmanın en kolay yolu çağırmaktır:
$form->render();
Oluşturulan formun görünümü, Renderer ve bireysel kontroller yapılandırılarak değiştirilebilir.
Manuel Rendering
Her form öğesi, form alanı ve etiket için HTML kodu üreten yöntemlere sahiptir. Bu kodlar bir dize ya da Nette\Utils\Html nesnesi olarak döndürülebilir:
getControl(): Html|string
öğenin HTML kodunu döndürürgetLabel($caption = null): Html|string|null
varsa etiketin HTML kodunu döndürür
Bu, formun öğe öğe işlenmesini sağlar:
<?php $form->render('begin') ?>
<?php $form->render('errors') ?>
<div>
<?= $form['name']->getLabel() ?>
<?= $form['name']->getControl() ?>
<span class=error><?= htmlspecialchars($form['name']->getError()) ?></span>
</div>
<div>
<?= $form['age']->getLabel() ?>
<?= $form['age']->getControl() ?>
<span class=error><?= htmlspecialchars($form['age']->getError()) ?></span>
</div>
// ...
<?php $form->render('end') ?>
Bazı öğeler için getControl()
tek bir HTML öğesi döndürürken (örn. <input>
,
<select>
vb.), diğerleri için bütün bir HTML kodu parçası döndürür (CheckboxList, RadioList). Bu
durumda, her öğe için ayrı ayrı girdiler ve etiketler oluşturan yöntemler kullanabilirsiniz:
getControlPart($key = null): ?Html
tek bir öğenin HTML kodunu döndürürgetLabelPart($key = null): ?Html
tek bir öğenin etiketi için HTML kodunu döndürür
Bu yöntemlerin önüne tarihsel nedenlerden dolayı get
eklenmiştir, ancak her çağrıda yeni bir
Html
öğesi oluşturup döndürdüğü için generate
daha iyi olacaktır.
Oluşturucu
Formun işlenmesini sağlayan bir nesnedir. $form->setRenderer
metodu tarafından ayarlanabilir.
$form->render()
metodu çağrıldığında kontrol aktarılır.
Eğer özel bir renderer ayarlamazsak, varsayılan renderer Nette\Forms\Rendering\DefaultFormRenderer kullanılacaktır. Bu, form öğelerini bir HTML tablosu olarak oluşturacaktır. Çıktı şu şekilde görünür:
<table>
<tr class="required">
<th><label class="required" for="frm-name">Name:</label></th>
<td><input type="text" class="text" name="name" id="frm-name" required value=""></td>
</tr>
<tr class="required">
<th><label class="required" for="frm-age">Age:</label></th>
<td><input type="text" class="text" name="age" id="frm-age" required value=""></td>
</tr>
<tr>
<th><label>Gender:</label></th>
...
Tablo kullanıp kullanmamak size bağlıdır ve birçok web tasarımcısı farklı işaretlemeleri tercih eder, örneğin bir
liste. DefaultFormRenderer
adresini hiç tabloya dönüştürmeyecek şekilde yapılandırabiliriz. Sadece uygun $wrappers ayarlamamız
gerekiyor. İlk indeks her zaman bir alanı, ikincisi ise bir elementi temsil eder. İlgili tüm alanlar resimde
gösterilmiştir:
Varsayılan olarak bir controls
grubu <table>
ve her pair
bir tablo satırıdır
<tr>
bir çift label
ve control
içeren (hücreler <th>
ve
<td>
). Tüm bu sarmalayıcı öğeleri değiştirelim. controls
adresini <dl>
pair adresini tek başına bırakın, label
adresini <dt>
ve control
adresini
<dd>
:
$renderer = $form->getRenderer();
$renderer->wrappers['controls']['container'] = 'dl';
$renderer->wrappers['pair']['container'] = null;
$renderer->wrappers['label']['container'] = 'dt';
$renderer->wrappers['control']['container'] = 'dd';
$form->render();
Sonuçlar aşağıdaki kod parçacığına dönüşür:
<dl>
<dt><label class="required" for="frm-name">Name:</label></dt>
<dd><input type="text" class="text" name="name" id="frm-name" required value=""></dd>
<dt><label class="required" for="frm-age">Age:</label></dt>
<dd><input type="text" class="text" name="age" id="frm-age" required value=""></dd>
<dt><label>Gender:</label></dt>
...
</dl>
Sarmalayıcılar birçok özelliği etkileyebilir. Örneğin:
- her form girişine özel CSS sınıfları ekleyin
- tek ve çift çizgiler arasında ayrım yapabilme
- gerekli ve isteğe bağlı çizimleri farklı yapın
- hata mesajlarının formun üstünde mi yoksa her bir öğenin yakınında mı gösterileceğini belirler
Seçenekler
Renderer'ın davranışı, tek tek form öğeleri üzerinde seçenekler ayarlanarak da kontrol edilebilir. Bu şekilde, giriş alanının yanında görüntülenen araç ipucunu ayarlayabilirsiniz:
$form->addText('phone', 'Number:')
->setOption('description', 'This number will remain hidden');
Eğer içine HTML içeriği yerleştirmek istiyorsak Html sınıfını kullanırız.
use Nette\Utils\Html;
$form->addText('phone', 'Phone:')
->setOption('description', Html::el('p')
->setHtml('<a href="...">Terms of service.</a>')
);
Etiket yerine Html öğesi de kullanılabilir: $form->addCheckbox('conditions', $label)
.
Gruplama Girişleri
Renderer, öğeleri görsel gruplar (alan kümeleri) halinde gruplandırmaya izin verir:
$form->addGroup('Personal data');
Yeni grup oluşturmak onu etkinleştirir – daha sonra eklenen tüm öğeler bu gruba eklenir. Bunun gibi bir form oluşturabilirsiniz:
$form = new Form;
$form->addGroup('Personal data');
$form->addText('name', 'Your name:');
$form->addInteger('age', 'Your age:');
$form->addEmail('email', 'Email:');
$form->addGroup('Shipping address');
$form->addCheckbox('send', 'Ship to address');
$form->addText('street', 'Street:');
$form->addText('city', 'City:');
$form->addSelect('country', 'Country:', $countries);
Oluşturucu önce grupları, ardından da herhangi bir gruba ait olmayan öğeleri çizer.
Bootstrap Desteği
Twitter Bootstrap 2, Bootstrap 3 ve Bootstrap 4 için Renderer yapılandırma örneklerini bulabilirsiniz
HTML Nitelikleri
Form öğeleri için rastgele HTML nitelikleri ayarlamak için setHtmlAttribute(string $name, $value = true)
yöntemini kullanın:
$form->addInteger('number', 'Number:')
->setHtmlAttribute('class', 'big-number');
$form->addSelect('rank', 'Order by:', ['price', 'name'])
->setHtmlAttribute('onchange', 'submit()'); // değişiklik üzerine JS fonksiyonu submit()'i çağırır
// <form> 'un kendi niteliklerini ayarlamak için
$form->setHtmlAttribute('id', 'myForm');
Eleman türünün belirtilmesi:
$form->addText('tel', 'Your telephone:')
->setHtmlType('tel')
->setHtmlAttribute('placeholder', 'Please, fill in your telephone');
Tür ve diğer niteliklerin ayarlanması yalnızca görsel amaçlara hizmet eder. Girdi doğruluğunun doğrulanması sunucuda gerçekleşmelidir; bunu uygun bir form denetimi seçerek ve doğrulama kuralları belirleyerek sağlayabilirsiniz.
Radyo veya onay kutusu listelerindeki ayrı öğeler için, her biri için farklı değerlere sahip bir HTML niteliği
ayarlayabiliriz. Değerin anahtara göre seçilmesini sağlayan style:
adresinden sonraki iki nokta üst üste
işaretine dikkat edin:
$colors = ['r' => 'red', 'g' => 'green', 'b' => 'blue'];
$styles = ['r' => 'background:red', 'g' => 'background:green'];
$form->addCheckboxList('colors', 'Colors:', $colors)
->setHtmlAttribute('style:', $styles);
Render:
<label><input type="checkbox" name="colors[]" style="background:red" value="r">red</label>
<label><input type="checkbox" name="colors[]" style="background:green" value="g">green</label>
<label><input type="checkbox" name="colors[]" value="b">blue</label>
readonly
gibi boolean nitelikleri ayarlamak için soru işaretli gösterimi kullanabiliriz:
$form->addCheckboxList('colors', 'Colors:', $colors)
->setHtmlAttribute('readonly?', 'r'); // birden fazla anahtar için dizi kullanın, örneğin ['r', 'g']
Render:
<label><input type="checkbox" name="colors[]" readonly value="r">red</label>
<label><input type="checkbox" name="colors[]" value="g">green</label>
<label><input type="checkbox" name="colors[]" value="b">blue</label>
Selectbox'lar için setHtmlAttribute()
yöntemi, selectbox'ın niteliklerini ayarlar. <select>
öğesi. Her bir eleman için öznitelikleri ayarlamak istersek <option>
yöntemini kullanacağız
setOptionAttribute()
. Ayrıca, yukarıda kullanılan iki nokta üst üste ve soru işareti de çalışır:
$form->addSelect('colors', 'Colors:', $colors)
->setOptionAttribute('style:', $styles);
Render:
<select name="colors">
<option value="r" style="background:red">red</option>
<option value="g" style="background:green">green</option>
<option value="b">blue</option>
</select>
Prototipler
HTML niteliklerini ayarlamanın alternatif bir yolu, HTML öğesinin oluşturulduğu şablonu değiştirmektir. Şablon bir
Html
nesnesidir ve getControlPrototype()
yöntemi tarafından döndürülür:
$input = $form->addInteger('number');
$html = $input->getControlPrototype(); // <input>
$html->class('big-number'); // <input class="big-number">
getLabelPrototype()
tarafından döndürülen etiket şablonu da bu şekilde değiştirilebilir:
$html = $input->getLabelPrototype(); // <label>
$html->class('distinctive'); // <label class="distinctive">
Checkbox, CheckboxList ve RadioList öğeleri için öğeyi saran öğe şablonunu etkileyebilirsiniz.
getContainerPrototype()
tarafından döndürülür. Varsayılan olarak „boş“ bir öğedir, bu nedenle hiçbir
şey işlenmez, ancak bir ad vererek işlenecektir:
$input = $form->addCheckbox('send');
$html = $input->getContainerPrototype();
$html->setName('div'); // <div>
$html->class('check'); // <div class="check">
echo $input->getControl();
// <div class="check"><label><input type="checkbox" name="send"></label></div>
CheckboxList ve RadioList söz konusu olduğunda, getSeparatorPrototype()
yöntemi tarafından döndürülen öğe
ayırıcı modelini etkilemek de mümkündür. Varsayılan olarak, bu bir öğedir <br>
. Bunu bir çift öğe
olarak değiştirirseniz, öğeleri ayırmak yerine tek tek saracaktır. Ayrıca, öğe etiketlerinin HTML öğesi şablonunu
etkilemek de mümkündür; bu şablon getItemLabelPrototype()
döndürür.
Çeviri
Çok dilli bir uygulama programlıyorsanız, muhtemelen formu farklı dillerde oluşturmanız gerekecektir. Nette Framework bu amaç için bir çeviri arayüzü tanımlar Nette\Localization\Translator. Nette'de varsayılan bir uygulama yoktur, Componette'de bulabileceğiniz birkaç hazır çözüm arasından ihtiyaçlarınıza göre seçim yapabilirsiniz. Belgeleri size çevirmeni nasıl yapılandıracağınızı anlatır.
Form, çevirmen aracılığıyla metin çıktısı almayı destekler. Bunu setTranslator()
yöntemini kullanarak
aktarıyoruz:
$form->setTranslator($translator);
Şu andan itibaren, sadece tüm etiketler değil, aynı zamanda tüm hata mesajları veya seçim kutusu girişleri de başka bir dile çevrilecektir.
Tek tek form öğeleri için farklı bir çevirmen ayarlamak veya null
ile çeviriyi tamamen devre dışı
bırakmak mümkündür:
$form->addSelect('carModel', 'Model:', $cars)
->setTranslator(null);
Doğrulama kuralları için, örneğin kural gibi belirli parametreler de çevirmene aktarılır:
$form->addPassword('password', 'Password:')
->addRule($form::MinLength, 'Password has to be at least %d characters long', 8)
çevirmen aşağıdaki parametrelerle çağrılır:
$translator->translate('Password has to be at least %d characters long', 8);
ve böylece characters
sözcüğü için doğru çoğul biçimini sayarak seçebilir.
Olay onRender
Form işlenmeden hemen önce kodumuzu çağırabiliriz. Bu, örneğin, düzgün görüntüleme için form öğelerine HTML
sınıfları ekleyebilir. Kodu onRender
dizisine ekliyoruz:
$form->onRender[] = function ($form) {
BootstrapCSS::initialize($form);
};