Files
yii/docs/guide/id/form.model.txt
2010-11-14 14:17:44 +00:00

430 lines
15 KiB
Plaintext

Membuat Model
=============
Sebelum menulis kode HTML yang diperlukan oleh sebuah form, kita harus menetapkan jenis
data apa yang diharapkan dari pengguna akhir dan aturan apa pada data ini harus
diterapkan. Kelas model dapat dipakai guna menyimpan informasi ini. Model,
seperti yang didefinisikan dalam subseksi [Model](/doc/guide/basics.model), adalah
tempat utama untuk menyimpan input pengguna dan memvalidasinya.
Tergantung pada bagaimana kita menggunakan input pengguna, kita bisa membuat dua jenis
model. Jika input pengguna dikumpulkan, dipakai dan kemudian diabaikan, kita bisa
membuat [model formulir](/doc/guide/basics.model); jika input pengguna
dikumpulkan dan disimpan ke dalam database, sebaliknya kita dapat menggunakan [active
record](/doc/guide/database.ar). Kedua jenis model berbagi basis kelas
[CModel] yang sama yang mendefinisikan antar muka umum yang diperlukan oleh form.
> Note|Catatan: Kita menggunakan model form terutama dalam contoh pada bagian ini.
Akan tetapi, hal yang sama bisa juga diterapkan pada model [active
record](/doc/guide/database.ar).
Mendefinisikan Kelas Model
--------------------------
Di bawah ini kita membuat kelas model `LoginForm` yang dipakai untuk mengumpulkan input pengguna pada
halaman login. Karena informasi login hanya dipakai untuk mengotentikasi pengguna
dan tidak perlu menyimpan, kita membuat `LoginForm` sebagai sebuah model formulir.
~~~
[php]
class LoginForm extends CFormModel
{
public $username;
public $password;
public $rememberMe=false;
}
~~~
Tiga atribut dideklarasikan dalam `LoginForm`: `$username`, `$password` dan
`$rememberMe`. Ini dipakai untuk memelihara nama pengguna dan kata sandi
yang dimasukkan, dan opsi apakah pengguna menginginkan untuk mengingat login-nya.
Karena `$rememberMe` memiliki nilai standar `false`, opsi terkait
saat awal ditampilkan dalam formulir login tidak akan dicentang.
> Info: Alih-alih memanggil properi variabel anggota ini, kita menggunakan
nama *attributes* untuk membedakannya dari properti normal. Atribut
adalah properti yang terutama dipakai untuk menyimpan data yang berasal dari
input pengguna atau database.
Mendeklarasikan Aturan Validasi
-------------------------------
Setelah pengguna mengirimkan inputnya dan model sudah dipopulasi, kita perlu
memastikan bahwa input benar sebelum menggunakannya. Ini dikerjakan dengan
melakukan validasi input terhadap satu set aturan. Kita menetapkan aturan
validasi dalam metode `rules()` yang harus mengembalikan array konfigurasi
aturan.
~~~
[php]
class LoginForm extends CFormModel
{
public $username;
public $password;
public $rememberMe=false;
private $_identity;
public function rules()
{
return array(
array('username, password', 'required'),
array('rememberMe', 'boolean'),
array('password', 'authenticate'),
);
}
public function authenticate($attribute,$params)
{
$this->_identity=new UserIdentity($this->username,$this->password);
if(!$this->_identity->authenticate())
$this->addError('password','Incorrect username or password.');
}
}
~~~
Contoh kode di atas menetapkan bahwa `username` dan `password` keduanya diperlukan,
`password` harus diotentikasi.
Setiap aturan yang dikembalikan oleh `rules()` harus dalam format berikut:
~~~
[php]
array('AttributeList', 'Validator', 'on'=>'ScenarioList', ...opsi tambahan)
~~~
di mana `AttributeList` adalah string nama atribut yang dipisahkan dengan koma
yang perlu divalidasi sesuai dengan aturan; `Validator` menetapan jenis validasi
apa yang harus dilakukan; parameter `on` adalah opsional yang menetapkan daftar
skenario di mana aturan harus diterapkan; dan opsi tambahan adalah pasangan
nama-nilai yang dipakai untuk menginisialisasi nilai properti validator
terkait.
Ada tiga cara untuk menetapkan `Validator` dalam aturan validasi. Pertama,
`Validator` dapat berupa nama metode dalam kelas model, seperti
`authenticate` dalam contoh di atas. Metode validator harus berupa tanda tangan
berikut:
~~~
[php]
/**
* @param string nama atribut yang akan divalidasi
* @param array opsi yang ditetapkan dalam aturan validasi
*/
public function ValidatorName($attribute,$params) { ... }
~~~
Kedua, `Validator` dapat berupa nama kelas validator. Saat aturan diterapkan,
instance kelas validator akan dibuat untuk melakukan validasi sebenarnya.
Opsi tambahan dalam aturan dipakai untuk menginisialisasi nilai atribut
instancenya. Kelas validator harus diperluas
dari [CValidator].
Ketiga, `Validator` dapat berupa alias pradefinisi untuk kelas validator. Dalam
contoh di atas, nama `required` adalah alias untuk [CRequiredValidator]
yang memastikan nilai atribut yang divalidasi tidak kosong. Di bawah ini
adalah daftar lengkap alias pradefinisi validator aliases:
- `boolean`: alias [CBooleanValidator], memastikan atribut memiliki
nilai baik berupa [CBooleanValidator::trueValue] ataupun
[CBooleanValidator::falseValue].
- `captcha`: alias [CCaptchaValidator], memastikan atribut sama dengan
kode verifikasi yang ditampilkan dalam
[CAPTCHA](http://en.wikipedia.org/wiki/Captcha).
- `compare`: alias [CCompareValidator], memastikan atribut sama dengan
atribut atau konstan lain.
- `email`: alias [CEmailValidator], memastikan atribut berupa alamat
email yang benar.
- `default`: alias [CDefaultValueValidator], menempatkan nilai standar
ke atribut yang ditetapkan.
- `exist`: alias [CExistValidator], memastikan nilai atribut dapat
ditemukan dalam kolom tabel.
- `file`: alias [CFileValidator], memastikan atribu berisi nama file
yang di-upload.
- `filter`: alias [CFilterValidator], mengubah atribut dengan
filter.
- `in`: alias [CRangeValidator], memastikan data ada diantara
daftar nilai yang sudah ditetapkan.
- `length`: alias [CStringValidator], memastikan panjang data
di dalam jangkauan tertentu.
- `match`: alias [CRegularExpressionValidator], memastikan data
sesuai dengan ekspresi reguler.
- `numerical`: alias [CNumberValidator], memastikan data adalah
angka yang benar.
- `required`: alias [CRequiredValidator], memastikan atribut
tidak kosong.
- `type`: alias [CTypeValidator], memastikan atribut adalah
jenis data tertentu.
- `unique`: alias [CUniqueValidator], memastikan data adalah unik dalam
kolom tabel database.
- `url`: alias [CUrlValidator], memastikan data berupa URL yang benar.
Di bawah ini daftar beberapa contoh pemakaian validator pradefinisi:
~~~
[php]
// username diperlukan
array('username', 'required'),
// username harus antara 3 dan 12 karakter
array('username', 'length', 'min'=>3, 'max'=>12),
// saat dalam skenario registrasi, password harus sama dengan password2
array('password', 'compare', 'compareAttribute'=>'password2', 'on'=>'register'),
// saat dalam skenario login, password harus diotentikasi
array('password', 'authenticate', 'on'=>'login'),
~~~
Mengamankan Penempatan Atribut
------------------------------
Setelah instance model dibuat, seringkali kita perlu mempopulasikan atributnya
dengan data yang dikirimkan oleh pengguna-akhir. Ini bisa dikerjakan
dengan nyaman menggunakan penempatan masal berikut:
~~~
[php]
$model=new LoginForm;
if(isset($_POST['LoginForm']))
$model->attributes=$_POST['LoginForm'];
~~~
Pernyataan terakhir adalah *penempatan masal (massive assignment)* yang menempatkan setiap entri
dalam `$_POST['LoginForm']` ke atribut model terkait dalam skenario
`login`. Ini sama dengan penempatan berikut:
~~~
[php]
foreach($_POST['LoginForm'] as $name=>$value)
{
if($name is a safe attribute)
$model->$name=$value;
}
~~~
Sangat krusial untuk menentukan apakah atribut safe (aman) atau tidak. Misalnya,
mengekspos primary key suatu tabel menjadi safe, maka penyerang
memiliki kesempatan mengubah primary key dari record yang diberikan dan sehingga
memalsukan data yang seharusnya dia tidak memiliki hak untuk itu.
Aturan untuk menentukan apakah sebuah atribut itu safe atau tidak berbeda antara versi 1.0
dan 1.1. Berikut, kita akan menjelaskan mereka secara terpisah.
###Atribut Safe dalam 1.1
Pada versi 1.1, sebuah atribut dianggap aman jika muncul dalam rule validasi
yang dapat diaplikasikan pada skenario yang diberikan. Misalnya,
~~~
[php]
array('username, password', 'required', 'on'=>'login, register'),
array('email', 'required', 'on'=>'register'),
~~~
Dalam contoh di atas, atribut `username` dan `password` diperlukan dalam skenario `login`
sedangkan atribut `username`, `password` dan `email` diperlukan dalam skenario `register`.
Sebagai hasilnya, jika kita melakukan penempatan massal (massive assign) di dalam skenario
`login`, hanya `username` dan `password` yang akan ditempatkan secara massal karena
hanya mereka yang muncul dalam aturan validasi untuk `login`. Di lain sisi, jika skenarionya adalah
`register`, maka ketiga atribut dapat
ditempatkan secara massal semuanya.
~~~
[php]
// in login scenario
$model=new User('login');
if(isset($_POST['User']))
$model->attributes=$_POST['User'];
// in register scenario
$model=new User('register');
if(isset($_POST['User']))
$model->attributes=$_POST['User'];
~~~
Jadi mengapa kita menggunakan kebijakan demikian untuk menentukan apakah sebuah atribut aman atau tidak?
Logika dibelakangnya adalah jika sebuah atribut sudah memiliki satu atau beberapa aturan validasi
untuk mengecek validasinya, apa yang harus kita khawatirkan lagi?
Sangat penting untuk diingat bahwa aturan validasi digunakan untuk mengecek data inputan user
alih-alih data yang dihasilkan kita di dalam kode (misalnya tanggal waktu, primary key yang di-generate otomatis).
Oleh karenanya, JANGAN menambah aturan validasi untuk atribut yang tidak pernah diharapkan untuk diinput
dari end-user.
Kadangkala, kita ingin mendeklarasi sebuah atribut safe, walaupun kita tidak memiliki aturan
spesifik padanya. Misalnya sebuah konten artikel yang bisa menerima inputan apapun dari user.
Kita dapat menggunakan aturan `safe` khusus untuk mendapatkan tujuan ini :
~~~
[php]
array('content', 'safe')
~~~
Untuk lebih lengkap, terdapat aturan `unsafe` juga yang digunakan secara eksplisit
untuk mendeklarasi sebuah atribut tidak aman.
~~~
[php]
array('permission', 'unsafe')
~~~
Peraturan `unsafe` jarang digunakan, dan merupakan perkecualian untuk definisi atribut
safe sebelumnya.
###Safe Attributes in 1.0
Dalam versi 1.0, tugas menentukan apakah sebuah entri data aman atau tidak
tergantung pada nilai return dari sebuah metode bernama `safeAttributes` dan skenario
yang dispesifikasi. Secara default, metode mengembalikan semua nilai variabel member publik
sebagai atribut aman untuk [CFormModel], sedangkan pada [CActiveRecord] dia mengembalikan
semua kolom pada tabel sebagai aman kecuali primary key. Kita bisa
meng-override metode ini untuk membatasi atribut safe sesuai skenario.
Misalnya, sebuah model user mungkin mengandung banyak atribut, tetapi dalam skenario
`login` kita hanya memerlukan atribut `username` dan `password`.
Kita dapat mespesifikasi batasan sebagai berikut :
~~~
[php]
public function safeAttributes()
{
return array(
parent::safeAttributes(),
'login' => 'username, password',
);
}
~~~
Lebih tepatnya, nilai balik metode `safeAttributes` seharusnya dalam struktur
sebagai berikut:
~~~
[php]
array(
// atribut ini dapat ditempatkan secara masalah dalam setiap skenario
// yang tidak ditetapkan secara eksplisit di bawah ini
'attr1, attr2, ...',
*
// atribut ini dapat ditempatkan secara masal hana dalam skenario 1
'scenario1' => 'attr2, attr3, ...',
*
// atribut ini dapat ditempatkan secara masal hana dalam skenario 2
'scenario2' => 'attr1, attr3, ...',
)
~~~
Jika model bukan sensitif-skenario (misalnya, ia hanya dipakai dalam
satu skenario, atau semua skenario berbagi set atribut aman yang sama),
nilai balik dapat disederhanakan sebagai string tunggal:
~~~
[php]
'attr1, attr2, ...'
~~~
Untuk entri data yang tidak aman, kita perlu menempatkannya ke atribut
terkait menggunakan pernyataan penempatan individual, seperti berikut:
~~~
[php]
$model->permission='admin';
$model->id=1;
~~~
Memicu Validasi
---------------
Setelah model dipopulasi dengan data yang dikirimkan pengguna, kita memanggil [CModel::validate()]
untuk memicu proses validasi data. Metode mengembalikan nilai yang menunjukan
apakah validasi sukses atau tidak. Untuk model [CActiveRecord],
validasi juga dapat dipicu secara otomatis saat kita memanggil metode
[CActiveRecord::save()].
Kita dapat mengeset skenario dengan properti [scenario|CModel::scenario] dan
dari situ mengindikasikan aturan validasi yang mana yang harus diaplikasikan.
Validasi dilakukan berdasarkan skenario. Properti [scenario|CModel::scenario]
mentukan skenario model mana yang digunakan dan aturan validasi mana yang
Misalnya, untuk skenario `login`, kita hanya ingin
memvalidasi input `username` dan `password` pada user model; sedangkan pada skenario
`register`, kita peru memvalidasi inputan yang lebih banyak seperti `email`,`address` dan lain-lain.
Contoh berikut menunjukkan bagaimana melakukan validasi pada skenario `register`:
~~~
[php]
// creates a User model in register scenario. It is equivalent to:
// $model=new User;
// $model->scenario='register';
$model=new User('register');
// populates the input values into the model
$model->attributes=$_POST['User'];
// performs the validation
if($model->validate()) // if the inputs are valid
...
else
...
~~~
Skenario yang dapat diaplikasikan pada aturan yang terkait dapat dispesifikasikan
dengan opsi `on` pada aturan. Jika opsi `on` tidak diset, artinya aturan bersangkutan
akan digunakan di seluturh skenario. Contohnya,
~~~
[php]
public function rules()
{
return array(
array('username, password', 'required'),
array('password_repeat', 'required', 'on'=>'register'),
array('password', 'compare', 'on'=>'register'),
);
}
~~~
Aturan pertama akan diaplikasikan pada semua skenario,
sedangkan dua aturan berikutnya diaplikasikan pada skenario `register`.
Mengambil Kesalahan Validasi
----------------------------
Begitu validasi dilakukan, apabila terdapat kesalahan (error) akan disimpan
dalam objek model. Kita bisa mengambil pesan error dengan memanggil fungsi [CModel::getErrors()]
dan [CModel::getError()]. Perbedaan antara kedua metode ini adalah yang pertama
akan mengembalikan *semua* error untuk atribut model bersangkutan
sedangkan yang metode yang kedua akan mengembalikan error *pertama*.
Label Atribut
-------------
Ketika medesain sebuah form, seringkali kita perlu menampilkan label untuk setiap field
input. Label memberitahu pengguna jenis informasi apa yang harus dimasukkan
ke dalam field. Meskipun kita dapat memberi label secara langsung dalam sebuah tampilan,
akan lebih fleksibel dan nyaman jika kita menetapkannya dalam
model terkait.
Secara default, [CModel] akan mengembalikan nama atribut sebagai labelnya.
Ini dapat dikustomisasi dengan meng-override metode
[attributeLabels()|CModel::attributeLabels]. Seperti yang akan kita lihat dalam
subbagian berikutnya, menetapkan label dalam model memungkinkan kita untuk membuat
form lebih cepat dan powerful.
<div class="revision">$Id: form.model.txt 2285 2010-07-28 20:40:00Z qiang.xue $</div>