[Yii Framework] Mengatasi Masalah Composite Primary Key
February 26, 2012 48 Comments
Menjawab sebuah pertanyaan di blog ini mengenai masalah pembangunan sebuah aplikasi yang memiliki composite primary key. Ada apa dengan composite key pada Yii? Generate code yang ada pada Yii tidak memungkinkan untuk menggenarate code yang tabel nya memiliki composite key. Lalu bagaimana cara mengatasinya? Ada 2 cara:
1. Anda rubah tabel anda hanya memiliki 1 buah Primary key dg field baru dan menjadikan 2 field composite sebelumnya menjadi Unique.
2. Anda tidak merubah tabel anda, tetapi membuat code CRUD pada Yii secara manual (tentunya anda harus memodifikasi bagian-bagian code anda)
Jika menggunakan opsi pertama, anda dapat menggenerate code nya seperti biasa dengan menggunakan Gii. Lalu bagaimana dengan opsi kedua? ya.. mari kita bahas..
Untuk menggenerate model pada Yii, anda tetap dapat mengenerate code anda. Tetapi untuk controller dan view, kita harus membuatnya manual. Tetapi kita akan mengikuti pola code hasil generate yii pada tabel yang tanpa composite key. Okeh, kita bahas dahulu untuk controller. Buatlah sebuah controller sesuai nama model anda pada folder Controllers pada aplikasi anda. Buat sama persis dengan code controller pada code controller lain hasil generate gii.. Lalu lihat pada fungsi loadModel yang tadinya seperti ini:
public function loadModel($id) { $model=NamaModel::model()->findByPk((int)$id); if($model===null) throw new CHttpException(404,'The requested page does not exist.'); return $model; }
rubah menjadi seperti ini:
public function loadModel($id,$id2) { $model=NamaModel::model()->findByAttributes(array('namaAttribute1'=>$id,'namaAttribute2'=>$id2)); if($model===null) throw new CHttpException(404,'The requested page does not exist.'); return $model; }
Penjelasan : karena kita memiliki composite key yang artinya terdapat 2 buah field atau lebih sebagai identitas unik suatu data, maka kita membuat parameternya juga sesuai dengan field tersebut. Saya asumsikan composite key kita terdiri dari 2 field, untuk itu kita membutuhkan 2 buah parameter pada code tersebut untuk itu kita menggunakan findByAttributes bukan findByPk lagi..
Lalu karena itu, tentu untuk action view, update, dan delete kita harus membuat 2 buah parameter untuk itu. Juga untuk setiap link yang mengarahkan kita ke tabel yang memiliki composite, kita harus sediakan 2 buah parameter disana. Silahkan rubah code actionView anda yang tadinya seperti berikut :
public function actionView($id) { $this->render('view',array( 'model'=>$this->loadModel($id), )); }
menjadi seperti berikut :
public function actionView($id,$id2) { $this->render('view',array( 'model'=>$this->loadModel($id,$id2), )); }
Code actionUpdate yang tadinya seperti ini :
public function actionUpdate($id) { $model=$this->loadModel($id); if(isset($_POST['NamaModel'])) { $model->attributes=$_POST['NamaModel']; if($model->save()) $this->redirect(array('view','id'=>$model->id)); } $this->render('update',array( 'model'=>$model, )); }
Menjadi seperti berikut :
public function actionUpdate($id,$id2) { $model=$this->loadModel($id,$id2); if(isset($_POST['NamaModel'])) { $model->attributes=$_POST['NamaModel']; if($model->save()) $this->redirect(array('view','id'=>$model->id,'id2'=>$model->id2)); } $this->render('update',array( 'model'=>$model, )); }
Dan actionDelete yang tadinya seperti berikut:
public function actionDelete($id) { if(Yii::app()->request->isPostRequest) { $this->loadModel($id)->delete(); if(!isset($_GET['ajax'])) $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin')); } else throw new CHttpException(400,'Invalid request. Please do not repeat this request again.'); }
menjadi seperti berikut :
public function actionDelete($id,$id2) { if(Yii::app()->request->isPostRequest) { $this->loadModel($id,$id2)->delete(); if(!isset($_GET['ajax'])) $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin')); } else throw new CHttpException(400,'Invalid request. Please do not repeat this request again.'); }
Selesai, setelah itu kita tinggal mengedit bagian view kita. Berikut contoh untuk mengarahkan pada halaman update dan view..
echo CHtml::link("Update",array('namaController/update','id1'=>$id1,'id2'=>$id2)); echo CHtml::link("View",array('namaController/view','id1'=>$id1,'id2'=>$id2));
Begitu juga dengan menu-menu yang ada pada tampilan anda.. semuanya harus anda modifikasi sesuai dengan action anda..
Selesai.. Selamat mencoba..
Semoga membantu.. 🙂
Kok di halaman admin masih ada yang error..saya bingung ni gan..salahnya dimana??
error ny apa gan?
Udah solve gan..seperti yang tak post digroup FB..
Bit, mau nanya dong.. Kalo hasilnya error 400, your request is invalid tuh apa yg kurang ya?
codingan gw kek gini :
model >>
public function primaryKey()
{
return array(‘kode_kabkot’, ‘kode_prov’);
}
view >>
array(‘class’=>’CButtonColumn’,’viewButtonUrl’=>’Yii::app()->controller->createUrl(“view”,$data->primaryKey)’,
‘updateButtonUrl’=>’Yii::app()->controller->createUrl(“update”,$data->primaryKey)’,
‘deleteButtonUrl’=>’Yii::app()->controller->createUrl(“delete”,$data->primaryKey)’,)
thanks before
kalo itu action pake actionPrimaryKey coba bor..
itu di model Bit.. kalo dr referensi si ga ada action
maksudnya,Bit?
itu nama fungsi mu ga ada “action” nya bor..
oh.. ku kirain action.. biasanya kalo error yg gitu berrti ga ada action yang namanya sesuai dengan yang di request bor..
btw, panggil “primaryKey” nya di view pake “()” bor di belakangnya..
masih ngerror Bit,, ttp sama errmsg nya tapi urlnya jd berubah..
before >>http://localhost/ibsv26/index.php?r=master_kab/view&kode_prop=32&kode_kab=01
after>> http://localhost/ibsv26/index.php?r=master_kab/view&0=kode_kab&1=kode_prop
coba ganti :
’Yii::app()->controller->createUrl(“view”,$data->primaryKey)
jadi :
’Yii::app()->controller->createUrl(“view”,array($data->primaryKey))
tetep ngerror yg sama Bit.. tp urlnya malah sama kyk yg pertama sblum gw tambahin primaryKey() td..
http://localhost/ibsv26/index.php?r=master_kab/view&0%5Bkode_prop%5D=32&0%5Bkode_kab%5D=01
hmmm.. kyak nya emang ga bisa bor definisiin URL kayak gitu..
make cara biasa aja bor definisiinya berrti..
ga usah pake fungsi yang PrimaryKey nya..
tapi tetep ngerror Bit,, udah gw comment tuh primaryKey() dan CButtonColumn nya dah gw bikin biasa.. gw bingung salah dmnnya..
kalo kau pake createUrl kayak gitu cara definisiinnya harusnya gini bor :
Yii::app()->controller->createUrl(“view”,array(‘kode_prov’=>1,’,’kode_kab’=>2))’
gitu bor..
oouh,, ga dinamis ya.. trus gw musti ganti kyk mana, Bit?
ya ntar dibuat dinamis bor.. kan bisa di tangkep variabel kode_prop dan kode_kab nya dari cgridview..
coba di cari aja bor cara nangkep nya..
okey, Bit.. thanks
wah kayaknya case-nya dbormamora sama kayak punyaku
aku juga lagi ngolah data yang berhubungan dengan data lokasi kdprop, kdkab, kdkec, kddesa. masalah muncul karena data yang tak olah gak ada PK. gak ada no_id-nya, sehingga harus akal-akalan
bang sabit. itu artinya kalo composite key-nya dari n field, maka perulangannya juga n ya? kalo dicontoh kan cuman 2. ato gmn ya enaknya…
strukturku kurang lebih kek gini nih tabelnya
kdprop
kdkab
kdkec
kddesa
namakk
alamat
flag
saran saya kalo udah sebanyak itu lebih baik dibuat PK nya aja gan.. tapi kalo emang nggak ya mau nggak mau di buat n-field yang mbak bilang itu…
gan klo di view nya gmn ??
itu udah saya contohin di atas gan..
kak, kalo tabel yang dipake tu ‘tabel view’ hasil denormalisasi dari banyak tabel gimana kak? masalahnya kalo tabel view itu ga ada primary key nya, gimana generate controllernya??
makasi kak 🙂
itu emang ga bisa di generate mbak.. harus di buat sendiri jadi nya mbak..
Kak, di halaman admin, pas mw klik icon (misalnya icon view), yg muncul “Error 400 Your request is invalid”. Knp yah kak?
itu harus mbak modifikasi lagi mbak button search halaman adminnya.. di set lagi URL nya..
klu button search nya ga masalah kak,, maksudku yg ga bs tuh icon view, update, n delete yg di dalam Cgridview nya..
mohon pencerahannya kak 😀
sory saya salah ketik mbak.. iya maksud nya button view, update, dan delete nya mbak.. itu harus di setting manual url link nya mbak..
coba liat contoh ini : http://www.yiiframework.com/wiki/106/using-cbuttoncolumn-to-customize-buttons-in-cgridview/
sipp kak, yg view sama update dah bisa. Tp yg delete url-nya gmn kak?
sama aja mbak, emang kenapa mbak?
code nya gini:
‘delete’ => array(
‘deleteConfirmation’=>”js:’Record with ID ‘+$(this).parent().parent().children(‘:first-child’).text()+’ will be deleted! Continue?'”,
),
tapi masih tetep error 400.
udah bisa kak, makasih ya 😀
mas mau tanya kalo misal saya mau buat pas create kalo kita isi sama primary key yg udah ada kan muncul pesan CDbCommand failed to execute the SQL statement: bla bla, kalo saya mau ganti pesan itu misalnya dengan tulisan ” Maaf data sudah ada”, ga harus bentuk message box, tulisannya di halaman web biasa gitu aja,itu gimana ya mas? terima kasih
itu bisa dibuat validasi sendiri aja gan lewat model nya..
coba cari aja di blog ini ada tutor untuk buat validasi yang kita custom sendiri..
Kayaknya lebih enak nggak usah pake composite key deh Gan.. Cmiiw
tapi gan klo many to many gimana gan klo gag pake composite pk??
tambahin aja sebuah field untuk primary key nya, trus yang composite key di jadiin unique..
tapi kalo field compositenya jadi unique jadi aneh om..
logika saya nangkepnya beda..
selagi bisa ga pake ga perlu gan.. tapi ini hanya cntoh kalo emang composite di perlukan..
Om sabit :
kan klo cara itu urlnya jadi..
/controller/action/id?id2
nah gimana biar urlnya dipercantik menjadi
/controller/action/id/id2 ??
mohon pencerahannya
di dokumentasi yii ada bahasan tentang Url management.. coba baca disana aja gan.. udah lumayan lengkap kok..
udah baca om..
belum nangkep intinya..
ntar tak baca lagi deh..
btw thanx om..
kalo many to many itu tidak ada aturan untuk pake composite gan.. yang jelas kalo many to many harus pake junction tabel.. coba di baca lagi aja gan konsep database many to many.. kalo udah bisa itu lebih enak nanti gan..
kak sabit, yang ini dimasukkin di bagian view yang mana yaaak?? masih bingung aku
echo CHtml::link(“Update”,array(‘namaController/update’,’id1’=>$id1,’id2’=>$id2));
echo CHtml::link(“View”,array(‘namaController/view’,’id1’=>$id1,’id2’=>$id2));
di view nya mbak..
Malam Kak sabit disini saya mau tanya yang source code yang ini diletakin dimana ya?
Nama File dan Foldernya apa? apakah di folder frotected?
echo CHtml::link(“Update”,array(‘namaController/update’,’id1’=>$id1,’id2’=>$id2));
echo CHtml::link(“View”,array(‘namaController/view’,’id1’=>$id1,’id2’=>$id2));
Mohon pencerahannya.
Terima kasih
di views nya gan. Kalo agan masih bingun views itu dimana, coba baca pahami kembali yii dari awal.
mohon bantuannya gan mau tanya kalo misal saya mau buat pas create kalo kita isi sama primary key yg udah ada kan muncul pesan CDbCommand failed to execute the SQL statement: bla bla, kalo saya mau ganti pesan itu misalnya dengan tulisan ” Maaf data sudah ada”, ga harus bentuk message box, tulisannya di halaman web biasa gitu aja,itu gimana ya mas? terima kasih