Modul Codeigniter Studi Kasus: Posting Seperti Facebook
#1 : Membuat Fitur Post #2 : Menambahkan Fitur Comment #3 : Menambahkan Fitur Like
http://toniharyanto.cs.upi.edu
[email protected] @yllumi
Pendahuluan Selamat datang di Modul Tutorial Codeigniter. Kali ini Topiknya adalah Studi Kasus membuat fitur posting semacam punyanya Facebook. Pembahasan topik ini akan dibagi menjadi tiga subtopik. Pertama membuat fitur utama yakni Posting, yang akan dilanjutkan dengan modul kedua tentang menambahkan fitur komentar untuk setiap posting, dan modul ketiga tentang menambahkan fitur like untuk setiap posting. Spesifikasi Modul Bahan yang diperlukan: Codeigniter versi 2, Jquery versi 1.5 atau yang terbaru; Level: Medium Prasyarat: Pemrograman PHP dan pengaturan awal Codeigniter, aturan dasar Jquery Tahapan Modul #1 1. Membuat tabel post pada database 2. Membuat controller, model, dan view untuk Post 3. Menambahkan fitur ajax dengan jquery
Membuat Tabel `post` Setelah menyiapkan codeigniter pada localhost dan membuat database, kita buat sebuah table dengan nama 'post'. CREATE TABLE `post` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `post` varchar(255) NOT NULL, `datetime` int(10) NOT NULL, `deleted` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
penjelasan: id untuk indentitas setiap baris data; user_id untuk menyimpan id user yang mengirimkan posting; post untuk menyimpan isi post, untuk membolehkan jumlah karakter yang lebih banyak, gunakan tipe data text; datetime untuk menyimpan waktu saat posting dikirim, nilai didapatkan dengan fungsi php time(); deleted untuk pengecekan apakah posting sudah pernah dihapus atau belum, default 0; Menyiapkan Controller, Model, dan View untuk Post Untuk membuat fitur post, kita perlu membuat beberapa file .php, diantaranya: controllers/ |– post.php models/ |– post_m.php views/ |– post/ |– index.php // untuk menampilkan halaman utama |– post.php // untuk menampilkan satu konten post |– form.php // untuk menampilkan form post |– confirm_delete.php // untuk menampilkan form konfirmasi penghapusan Pertama-tama, buat satu folder bernama assets/ di dalam folder program kita, sejajar dengan folder application/ dan system/. Kemudian simpan image untuk delete.png dengan ukuran 8 x 8 px dan contoh avatar dengan nama 0.png dengan ukuran 50 x 50 px.
delete.png 0.png
controllers/post.php load>helper(array('url', 'form')); // include model post_m, program masih akan error sampai Anda membuat model ini $this>load>model('post_m'); } /* POST FUNCTIONS ----------------------------------------------- */ /* fungsi ini untuk mengambil sejumlah data post * kemudian memuatnya ke dalam layout dari file view post/post.php * parameter : * $user_id untuk identifikasi konten milik user dengan user_id tersebut * $offset untuk pengacuan permulaan data yang akan diambil dari database * $limit untuk banyaknya data yang akan diambil setiap pemanggilan */ function post_loop($user_id, $offset = 0){ // ambil data post dari database $posts = $this>post_m>get_posts($user_id, $offset, $this>post_limit); // siapkan variabel untuk memuat sejumlah data yang nantinya akan dilayout $all_posts = ''; // layout semua data dari database ke view post/post.php foreach($posts as $post): // ganti dengan data asli 'nama' dari database $post['nama'] = 'Toni Haryanto'; // kirim $data ke view, lalu tambahkan hasilnya ke $all_posts $all_posts .= $this>load>view('post/post', $post, true); endforeach; return $all_posts; } /* Fungsi ini menampilkan halaman utama * parameter : * $page untuk menentukan halaman terkait pengambilan data, * satu halaman akan menampilkan sebanyak $post_limit data */
function index($page = 0) { // judul halaman $data['judul'] = "Post"; // muat view form.php untuk ditampilkan di halaman utama $data['form'] = $this>load>view('post/form', null, true); // set batas awal pengambilan data $offset = $page * $this>post_limit; // muat konten post menggunakan method $this->post_loop() // ganti parameter pertama dengan id user yang sedang aktif $data['posts'] = $posts = $this>post_loop(1, $offset);
// muat total data post // ganti parameter pertama dengan id user yang sedang aktif $data['total_post'] = $this>post_m>total_post(1); $data['page'] = $page; $data['limit'] = $this>post_limit; // tampilkan $data ke view post/index.php $this>load>view('post/index', $data); } /* Fungsi ini untuk menyimpan post ke database * data dikirim dari form di halaman utama via POST */ public function insert_post(){ //siapkan field data yang akan disimpan $data = array( // bersihkan terlebih dahulu konten post // keterangan fungsi yang digunakan silakan lihat manual php 'post' => nl2br(htmlentities(trim($this>input>post('status', true)))), //ganti nilai 1 dengan id user yang sedang aktif 'user_id' => 1, // keterangan fungsi yang digunakan silakan lihat manual php 'datetime' => time() ); //simpan ke database $res_id = $this>post_m>insert_post($data); //apabila input ke database sukses if($res_id){ // alihkan ke halaman utama redirect(getenv('HTTP_REFERER')); }
//apabila gagal menyimpan kembalikan nilai false else echo "Data gagal disimpan"; } // fungsi untuk konfirmasi penghapusan post // dibuat untuk mengakomodir penghapusan dari browser yang tidak support js function confirm_delete($post_id = null){ $data['post_id'] = $post_id; $this>load>view('post/confirm_delete', $data); } /* fungsi ini menghapus post dari database * parameter: * $post_id untuk identitas dari post yang dihapus */ public function delete_post($post_id = null){ // apabila data POST 'confirm' diterima dengan value 'y' if($this>input>post('confirm') == 'y'){ //hapus post $result = $this>post_m>delete_post($post_id); //apabila penghapusan berhasil if($result){ redirect('post/index'); //apabila gagal menghapus } else echo "Data gagal disimpan"; // apabila halaman diakses tanpa melalui POST } else redirect('post/index'); } }
models/post_m.php load>database(); } // fungsi untuk mengambil data post function get_posts($user_id, $offset = 0, $limit = 10){ $where = array('user_id'=>$user_id, 'deleted'=>0); return $this>db>where($where) >limit($limit, $offset) >order_by('datetime', 'desc') >get('post')>result_array(); }
// fungsi untuk mengambil total post function total_post($user_id){ return $this>db>where(array('user_id'=>$user_id, 'deleted'=>0)) >count_all_results('post'); } // fungsi untuk mengambil satu data post function get_detail($post_id){ return $this>db>where('id', $post_id)>get('post')>row_array(); } // fungsi untuk menyimpan data post function insert_post($data){ $this>db>insert('post', $data); return $this>db>insert_id(); } // fungsi untuk menghapus data post function delete_post($id){ $this>db>where('id', $id)>update('post', array('deleted'=>1)); return $this>db>affected_rows(); } }
views/post/index.php
<style type="text/css"> body { fontfamily:verdana,arial; fontsize:12px;} a { textdecoration:none; color:#669;} ul { margin:0;} li { liststyle:none;} div#form { width:405px; marginbottom:10px;} textarea#status { width:400px; height:50px; border:1px solid #aaa;} .loader { float:right; margin: 5px 5px 0 0;} ul#posts { width:405px; margin:0; padding:0;} li.post { padding:2px 0 4px 0; marginbottom:2px; borderbottom:1px solid #ddd;} div.post_avatar { display:inlineblock; verticalalign:top; width:55px;} div.post_content { display:inlineblock; verticalalign:top; width:335px;} div.post_delete { display:inlineblock; verticalalign:top; width:5px;} div.post_status { padding: 0 0 5px 0; color:#555; fontsize:14px;} div.post_meta { color:#aaa;} #pagination { width:395px; padding:5px; textalign:center; background:#eee;}
views/post/form.php 'post_form')); ?> 'status', 'id'=>'status', 'placeholder'=>'Apa yang Anda pikirkan?')); ?> 'submit', 'value'=>'true', 'type'=>'submit', 'content'=>'Kirim', 'class'=>'btnstatus')); ?>
views/post/post.php
assets/0.png" />
views/post/confirm_delete.php 'post_confirm')); ?> Yakin akan menghapus post ini?
'confirm', 'value'=>'y', 'type'=>'submit', 'content'=>'Hapus')); ?> 'confirm', 'value'=>'n', 'type'=>'submit', 'content'=>'Batal')); ?>
Menambahkan Fitur AJAX dengan JQuery Sejauh ini Fitur post yang kita buat masih sebatas standar CRUD. Fitur ini masih lebih mirip mobile facebook untuk handphone lama yang belum mendukung ajax. Akn tetapi hal ini juga memang sengaja kita buat untuk menjaga stabilitas program ketika javascript pada browser sengaja dimatikan. Sekarang kita akan menambahkan kemampuan ajax menggunakan Jquery untuk mengoptimalkan kemampuan pada browser terkini. Simpan file jquery.1.5.js atau terbaru di dalam folder assets/. Simpan juga file image ajaxload.gif (untuk loading ajax), Anda dapat mendownloadnya dari internet dengan style loading manapun yang Anda suka. Setelah itu tambahkan script ini di dalam tag pada file views/post/index.php. <script src="assets/jquery1.5.min.js" type="text/javascript">
Kemudian buat sebuah file dengan nama myapps.js di dalam folder yang sama. Di dalam file ini kita akan membuat script jquery untuk program kita. Jangan lupa tambahkan juga script untuk meng-embed file tersebut di dalam tag . <script type="text/javascript"> var site_url = ''; var base_url = ''; <script type="text/javascript" src="assets/myapps.js">
Sebelum embedding file myapps.js, kita menyiapkan dua buah variabel untuk dapat diakses oleh script jquery kita, yakni site_url dan base_url untuk url program kita. base_url digunakan untuk memanggil url file dan site_url digunakan untuk memangil halaman program. Kita akan membuat pengiriman post via ajax, sehingga data dikirimkan tanpa harus berpindah halaman. Kemudian setelah data tersimpan di database, data post baru tersebut langsung ditampilkan di halaman utama tanpa harus direfresh dahulu. Hal yang sama akan kita buat untuk penghapusan post. Sekarang isi file myapps.js dengan script jquery berikut. assets/myapps.js $(document).ready(function() { // ajax untuk submit form status // ketika .btnstatus dari form post diklik $('.btnstatus').click(function(){ // persiapkan elemen .tnstatus $elm = $(this);
// ambil url untuk mengirim post dari atribut action form var url = $elm.parent('form').attr('action'); // ambil data post yang akan dikirim dari textarea var status = jQuery.trim($('#status').val()); // apabila textarea kosong if(status != ''){ // pasang image loading di elemen berclass loader set_imgloader('.loader'); // nonaktifkan dulu textarea dan button submit disabled_element('.btnstatus, #status'); // mulai ajax $.ajax({ type: "POST", url: url, // set data yang akan dikirimkan untuk ditangkap oleh $_POST php data: 'ajax=true&status='+status, // setelah pengiriman ajax berhasil success: function(response){ // sisipkan data baru di awal ul $("ul#posts").prepend(response); // biar lebih smooth, tampilkan post baru dengan animasi slide $("ul#posts li:first").hide().slideDown(200); // sembunyikan image loading unset_imgloader('.loader'); // aktifkan kembali textarea dan button submit enabled_element('.btnstatus, #status'); // bersihkan textarea $elm.parent().find('#status').val(''); } }); } // return false supaya form tidak mengirimkan data dengan cara biasa return false; }); // ajax untuk menampilkan data post terdahulu // ketika link #next untuk next page diklik $('a#next').click(function(){ $elm = $(this); // ambil url dari atribut href elemen var url = $elm.attr('href');
// ambil data nomor halaman selanjutnya dari atribut rel elemen ini var nextpage = $elm.attr('rel'); // hapus atribut href supaya tidak bisa diklik // dan ganti teks link dengan gambar loading $elm.removeAttr('href') .html('
'); // mulai ajax $.ajax({ type: "POST", url: url, // siapkan data data: 'ajax=true&page='+nextpage, // setelah pengiriman data sukses success: function(response){ // apabila data post terdahulu diterima if(response){ // sisipkan postpost terdahulu di bagian akhir ul#posts $("ul#posts").append(response); // ganti nomor halaman selanjutnya nextpage++; $elm.attr('rel', nextpage); // kembalikan teks url dari image loading ke next page lagi $elm.attr('href', url).html('next page »'); // apabila data post terdahulu tidak diterima, berarti habis } else { $elm.html('end of posts ;)'); } } }); // tahan supaya link tidak berlaku seperti cara biasa/berpindah halaman return false; }); // ajax untuk menghapus data post // ketika link .delete_post untuk menghapus post diklik, // pakai function live() supaya bisa menangkap event elemen // dari post yang baru disisipkan via ajax $('.delete_post').live('click', function(){ var $elm = $(this); // ambil id post dari atribut id var id = $elm.attr('id'); // apabila konfirmasi penghapusan bernilai true if(confirm('yakin akan menghapus post ini?')){ // ini hanya efek fade sebelum penghapusan,
// tapi entah kenapa tanpa ini animasi penghapusan post // di bawah tidak berjalan sempurna $('#post'+id).fadeTo(200, .5); $.ajax({ type: "POST", url: site_url + '/post/delete_post', data: 'confirm=y&post_id=' + id, success: function(response){ // sembunyikan post yang dihapus $('#post'+id).hide(200); } }); } // tahan supaya link tidak berlaku seperti cara biasa/berpindah halaman return false; }); }); /* FUNGSIFUGSI UMUM */ // fungsi untuk menyisipkan image loading function set_imgloader(element){ $(element).html('
'); } // fungsi untuk menghapus sisipan image loading function unset_imgloader(element){ $(element).html(''); } // fungsi untuk menonaktifkan suatu elemen form function disabled_element(element){ $(element).css('opacity', .5).attr('disabled', 'disabled'); } // fungsi untuk mengaktifkan kembali suatu elemen form function enabled_element(element){ $(element).css('opacity', 1).removeAttr('disabled'); }
Kita akan membuat beberapa baris program tambahan pada file program yang sudah kita buat. Baris tambahan akan ditampilkan dengan cetak tebal. controllers/post.php
function __construct(){ parent::__construct(); $this>load>helper(array('url', 'form')); $this>load>model('post_m'); } /* POST FUNCTIONS ----------------------------------------------- */ /* fungsi ini untuk mengambil sejumlah data post * kemudian memuatnya ke dalam layout dari file view post/post.php * parameter : * $user_id untuk identifikasi konten milik user dengan user_id tersebut * $offset untuk pengacuan permulaan data yang akan diambil dari database * $limit untuk banyaknya data yang akan diambil setiap pemanggilan */ function post_loop($user_id, $offset = 0){ // ambil data post dari database $posts = $this>post_m>get_posts($user_id, $offset, $this>post_limit); // siapkan variabel untuk memuat sejumlah data yang nantinya akan dilayout $all_posts = ''; // layout semua data dari database ke view post/post.php foreach($posts as $post): // ganti dengan data asli 'nama' dari database $post['nama'] = 'Toni Haryanto'; // kirim $data ke view, lalu tambahkan hasilnya ke $all_posts $all_posts .= $this>load>view('post/post', $post, true); endforeach; return $all_posts; } /* Fungsi ini menampilkan halaman utama * parameter : * $page untuk menentukan halaman terkait pengambilan data, * satu halaman akan menampilkan sebanyak $post_limit data */ function index($page = 0) { // apabila fungsi dipanggil melalui ajax // ketika memanggil data terdahulu untuk ditampilkan if($this>input>post('ajax')){ // ambil data page yang dikirim melalui ajax $page = $this>input>post('page', true); // set batas awal pengambilan data $offset = $page * $this>post_limit; // cetak konten post menggunakan method $this->post_loop() // ganti parameter pertama dengan id user aktif // konten yang dicetak akan langsung ditangkap oleh jquery ajax
echo $posts = $this>post_loop(1, $offset); // apabila tidak melalui ajax, ketika javascript dimatikan // atau halaman diakses lewat browser yang belum support ajax } else { // judul halaman $data['judul'] = "Post"; // muat view form.php untuk ditampilkan di halaman utama $data['form'] = $this>load>view('post/form', null, true); // set batas awal pengambilan data $offset = $page * $this>post_limit; // muat konten post menggunakan method $this->post_loop() // ganti parameter pertama dengan id user yang sedang aktif $data['posts'] = $posts = $this>post_loop(1, $offset);
// muat total data post // ganti parameter pertama dengan id user yang sedang aktif $data['total_post'] = $this>post_m>total_post(1); $data['page'] = $page; $data['limit'] = $this>post_limit; // tampilkan $data ke view post/index.php $this>load>view('post/index', $data); } // tutup else } /* Fungsi ini untuk menyimpan post ke database * data dikirim dari form di halaman utama via POST */ public function insert_post(){ //siapkan field data yang akan disimpan $data = array( // bersihkan terlebih dahulu konten post // keterangan fungsi yang digunakan silakan lihat manual php 'post' => nl2br(htmlentities(trim($this>input>post('status', true)))), //ganti nilai 1 dengan id user yang sedang aktif 'user_id' => 1, // keterangan fungsi yang digunakan silakan lihat manual php 'datetime' => time() ); //simpan ke database $res_id = $this>post_m>insert_post($data); //apabila input ke database sukses if($res_id){
//apabila melalui ajax, return post yang baru tadi untuk disisipkan if($this>input>post('ajax')){ // tambahkan id post yang baru disimpan ke $data untuk ditampilkan $data['id'] = $res_id; //ganti dengan nama user dari database $data['nama'] = 'Toni Haryanto'; // cetak langsung data post yang baru $this>load>view('post/post', $data); //apabila tidak melalui ajak, kembali ke halaman sebelumnya } else { // alihkan ke halaman utama redirect(getenv('HTTP_REFERER')); } // tutup else } //apabila gagal menyimpan kembalikan nilai false echo "Data gagal disimpan"; } // fungsi untuk konfirmasi penghapusan post // dibuat untuk mengakomodir penghapusan dari browser yang tidak support js function confirm_delete($post_id = null){ $data['post_id'] = $post_id; $this>load>view('post/confirm_delete', $data); } /* fungsi ini menghapus post dari database * parameter: * $post_id untuk identitas dari post yang dihapus */ public function delete_post($post_id = null){ // prioritaskan post_id yang dikirim POST via ajax // post_id dari parameter digunakan bila javascript tidak berjalan $post_id = ($this>input>post('post_id')) ? $this>input>post('post_id') : $post_id; // apabila data POST 'confirm' diterima dengan value 'y' if($this>input>post('confirm') == 'y'){ //hapus post $result = $this>post_m>delete_post($post_id); //apabila penghapusan berhasil if($result){ redirect('post/index'); //apabila gagal menghapus } else echo "Data gagal disimpan"; // apabila halaman diakses tanpa melalui POST } else redirect('post/index');
} }
Pada file views/post/index.php, cari script berikut: $limit && $total_post/$limit >= $page+1): ?>
">next page »
dan tambahkan seperti script berikut: $limit && $total_post/$limit >= $page+1): ?>
" rel="" >next page »
atribut rel akan digunakan untuk menyimpan data nomor halaman selanjutnya yang nantinya akan diambil oleh fungsi pada jquery untuk mengambil data post terdahulu. Begitu juga dengan file views/post/post.php, tambahkan beberapa script yang dicetak tebal, sebagai identitas yang akan digunakan oleh jquery.
"> assets/0.png" />
. . .
Satu lagi file views/post/form.php, tambahkan satu elemen div untuk menampilkan image loading. 'post_form')); ?> 'status', 'id'=>'status', 'placeholder'=>'Apa yang Anda pikirkan?')); ?> 'submit', 'value'=>'true', 'type'=>'submit', 'content'=>'Kirim', 'class'=>'btnstatus')); ?>
Oke, sampai disini Modul Codeigniter Studi Kasus: Posting Seperti Facebook #1 : Membuat Fitur Post. Silakan coba hasil koding Anda, bila ada kendala, boleh kita diskusikan via email atau komentar di website saya. Alamatnya tertera di cover modul. Bersambung ke modul #2 tentang Menambahkan Fitur Komentar. ;D