Tags

, , , , ,

Lanjutan dari tulisan sebelumnya Yii2:Lebih Jauh Tentang Validation. Kali ini kita akan membahas lebih detil mengenai mass assignment. salah satu alasan diciptakannya framework atau library-library yang lain adalah untuk memanjakan programer pemalas sehinggah lebih sedikit code yang dia tulis untuk mendapatkan hasil yang sama. Jika setelah memakai framework jumlah baris yang ditulis masih sama panjangnya dengan memakai native. Patut dipertanyakan kemalasannya.
Misal kita punya model User dengan attributnya adalah id, nama, email, alamat dan no_telp. Untuk menset nilainya kita lakukan

$model = new User();
$post = Yii::$app->request->post('User',[]);
$model->nama = $post['nama'];
$model->email = $post['email'];
$model->alamat = $post['alamat'];
$model->no_telp = $post['no_telp'];
$model->save();

Bagi sebagian orang, kode di atas mungkin baik-baik saja. Tetapi sebagian yang lain akan bertanya, “Adakah cara lebih ringkas yang bisa kita lakukan?”. Kabar baiknya adalah, memang ada cara yang lebih ringkas.

$model = new User();
$model->load(Yii::$app->request->post());
$model->save();

Selain lebih ringkas, format di atas juga lebih independet terhadap model. Kita bisa copy paste kode tersebut ke tempat lain dengan sedikit perubahan. Dengan mengganti bagian new User(); dengan model yang lain kita sudah bisa menyimpan tabel yang berbeda. Itulah yang dinamakan mass assigment, mengisi nilai secara glondongan. Satu masalah selesai, programer bisa melanjutkan tidurnya sampai pagi.

Tunggu dulu. Masalah yang lain belum selesai. Mass assignment ternyata memiliki masalah serius terkait dengan skuritas. Sangat tidak lucu kalau validator yang diharapkan mengamankan integritas data justru berpeluang mengundang bahaya.

Kita kembali ke model User yang tadi. Di sana ada field id. Idealnya, field id adalah autoincrement dan nilainya tidak boleh dirubah. Jika ada user yang iseng memasukkan key id di $_POST tentu akan berakibat fatal. Karena itu model harus cukup cerdas untuk membedakan mana field yang aman untuk diisi glondongan dan mana yang tidak aman.
Di framework sebelah (sebut saja namanya bunga) untuk membedakan field yang aman(safe) atau tidak untuk diisi glondongan, kita harus mendefinisikannya di property $fillable.

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['nama', 'email', 'alamat', 'no_telp'];
}

Karena field id tidak ada di $fillable, maka ketika di $_POST ada value id tetep tidak akan diassign ke model. Kita tidak perlu lagi kuatir ada yang iseng memasukkan id lewat $_POST. Lalu bagaimana Yii melakukannya? Yii tidak melakukan seperti yang bunga lakukan. Karena di Yii, safe attribute terintegrasi dengan validasi.

class User extends ActiveRecord
{
    public function rules()
    {
        return [
            [['name', 'email'], 'required'],
            [['alamat', 'no_telp'], 'safe'],
        ];
    }
}

Semua field yang yang terdaftar di rules() otomatis akan menjadi safe attribute. Karena field id tidak ada di rules() maka dia termasuk yang unsafe attribute. Cukup cerdas bukan. Sekali lempar, dua mangga tetangga kita dapat.
“Apa artinya masalah kita sudah selesai?”
“Sayangnya belum.”
“Apa lagi yang kurang? Kita bisa menset banyak field sekaligus. Kita juga bisa memilah mana field yang boleh dan tidak boleh diset barengan”
safe validator adalah validator yang tidak melakukan apapun tetapi hanya membuat attribute tersebut aman untuk diset glondongan. Dengan validator ini, maka attribute tersebut menjadi safe walaupun tidak divalidasi. Kekurangan dari Yii2 adalah, tidak ada proses kebalikannya. Kita tidak bisa membuat suatu attribute tetap divalidasi dan pada saat yang sama tidak safe untuk mass assignment. Di Yii1 ada validator untuk ini yaitu unsafe validator. Entah karena alasan apa tidak dipakai lagi di Yii2.
Misal, di model ‘Userkita tambahkan lagi fieldstatus`. field ini tidak boleh null di database dengan nilai default adalah 0(inactive).

class User extends ActiveRecord
{
    public function rules()
    {
        return [
            [['status'], 'default', 'value' => 0],
            [['name', 'email'], 'required'],
            [['alamat', 'no_telp'], 'safe'],
        ];
    }
}

Pada saat yang sama kita tidak ingin field status ini bisa diinput dari end user. Setidaknya ada dua solusi untuk masalah ini dan keduanya bukanlah solusi yang menarik.

1.Menghapus dari rules()

Dengan menghapus status dari rules() otomatis field tersebut menjadi unsafe. Itu berarti kita juga kehilangan nilai default dari status tersebut. Kita harus menambahkan nilai default tersebut secara manual setiap kali create new user.

$model = new User();
$model->load(Yii::$app->request->post());
$model->status = 0;
$model->save();

Lalu bagaimana jika nilai defaultnya dari perhitungan yang kompleks seperti dalam tulisan sebelumnya. Apalagi jika model yang sama dipakai dalam beberapa form, tentu akan banyak redundansi.

2.Mengoverride method scenarios()

public function scenarios()
{
    return [
        'default' => ['name', 'email', 'alamat', 'no_telp', '!status'],
    ];
}

Field status diawali dengan karakter !. Ini menujukkan bahwa field tersebut akan tetap divalidasi tetapi tidak masuk dalam safe attribute. Cara ini juga tidak terlalu menarik. Jika lebih banyak scenario tentu akan lebih ribet lagi.
Masih berharap Yii2 akan memperkenalkan cara baru yang lebih efektif.

Disclaimer: Kadang ini bukan tentang berapa baris yang bisa kita hemat. Tetapi tentang berapa ego yang bisa kita tunjudkan 😀