Yii Framework REST Web Service and Windows Phone 7 sebagai Client (POST Insert Data)

Setelah kemarin kita telah mengupas cara view data suatu aplikasi lewat aplikasi client lain, sekarang saya akan mencoba memaparkan cara input data menggunakan REST dengan aplikasi client yang tentu dalam hal ini saya contohkan dengan menggunakan windows phone 7. Project yang akan kita buat adalah meneruskan project sebelumnya dari postingan ini. Jadi fungsi-fungsi yang telah ada disana tidak akan saya tulis ulang pada postingan ini.

Pertama-tama pada aplikasi yii anda tetap di controller yang sama seperti postingan sebelumnya, buatlah sebuah action yang digunakan untuk menginput nilai lewat REST API.

// digunakan untuk proses input ke database
 public function actionCreate()
 {
   switch($_GET['model'])
   {
       case 'kab': // apabila yang di request adalah "kab", maka akan menginput data pada tabel kabupaten
         $model = new MKab; 
         break;
      default:
         $this->_sendResponse(501,sprintf('Mode <b>create</b> is not implemented for model <b>%s</b>',$_GET['model']) );
        // jika yang di request tidak ada, maka akan error
        Yii::app()->end();
   }
   foreach($_POST as $var=>$value) { // mengecek attribute satu per satu sesuai dengan inputan user
     if($model->hasAttribute($var))
        $model->$var = $value;
     else // jika ada inputan user yang salah, maka akan di tampilkan pesan error
        $this->_sendResponse(500, sprintf('Parameter <b>%s</b> is not allowed for model <b>%s</b>', $var,$_GET['model']) );
   }
   if($model->save()) // jika data berhasil disimpan, maka akan di tampilkan pesan berupa data hasil yang telah disimpan tadi
      $this->_sendResponse(200, CJSON::encode($model)); // mengirim pesan
   else { // jika data tidak berhasil disimpan, maka akan menampilkan pesan error
      $msg = "<h1>Error</h1>";
      $msg .= sprintf("Couldn't create model <b>%s</b>", $_GET['model']);
      $msg .= "<ul>";
      foreach($model->errors as $attribute=>$attr_errors) {
          $msg .= "<li>Attribute: $attribute</li>";
          $msg .= "<ul>";
          foreach($attr_errors as $attr_error)
              $msg .= "<li>$attr_error</li>";
          $msg .= "</ul>";
      }
      $msg .= "</ul>";
      $this->_sendResponse(500, $msg );
    }
 }

Penjelasan dari kode tersebut sudah saya selipkan di baris-baris code di atas.

Nah, setelah selesai membuat action untuk input data, sekarang kita akan membuat sebuah aplikasi client yang digunakan untuk menginput datanya. Bukalah visual studio anda lalu buatlah project windows phone baru. Kemudian buatlah form seperti berikut :

Kita memiliki 3 buah inputan disana yaitu inputan untuk kode daerah, nama daerah dan kode provinsi tersebut. Inputan tersebut sendiri sudah kita sesuaikan dengan model Kabupaten yang ada di dalam aplikasi yii kita. Kemudian karena inputan ini melibatkan 2 buah tabel yaitu tabel kabupaten yang akan diinput dan tabel provinsi yang mana akan berelasi dengan tabel kabupaten, maka kita perlu membuat 2 buah class baru pada aplikasi windows phone kita. Buatlah sebuah folder pada project anda dengan nama “ApiClass” dan buatlah 2 buah class baru yaitu class “Daerah” yang akan mengacu ke tabel provinsi, dan class “Kab” yang akan mengacu ke tabel kabupaten. Lalu pada class daerah masukkan code berikut :

namespace sirusa.ApiClass
{
  public class Daerah
  {
     public string kode_daerah { get; set; }
     public string nama_daerah { get; set; }
  }
}

dan class kab masukkan code berikut :

namespace sirusa
{
  public class Kab
  {
    public int kode_kab { get; set; }
    public string kode_daerah { get; set; }
    public string nama_kab { get; set; }
  }
}

Pada saat pertama kali aplikasi wp7 ini dijalankan, pada inputan provinsi kita menginputnya dengan cara memilih provinsi yang sudah ada pada aplikasi server. Untuk itu, kita harus menyediakan sebuah API untuk mengambil list nama-nama provinsi dari aplikasi server. Untuk ini kita sudah pernah membahas bagaimana cara mengambil data dengan rest pada contoh postingan sebelumnya, silahkan terapkan fungsi tersebut untuk kasus ini..

Kemudian setelah kita telah membuat API untuk mengambil semua provinsi pada server, buatlah sebuah fungsi yang dimana setiap kita membuka aplikasi maka list provinsi yang ada di server langsung muncul di aplikasi wp7 kita. Pada mainpage.xaml.cs masukkan code berikut :

private List<Daerah> daftard = new List<Daerah>();//variabel untuk menyimpan data provinsi, digunakan agar
 // tidak melakukan load berulang kali ke server karena provinsi di anggap tidak terlalu banyak isinya
 // dan tidak sering mengalami perubahan, jadi disimpan di dalam satu variabel saja lebih dahulu
 private void GetDaerah()
 {
   string url = "http://localhost/sirusanew/index.php?r=webapi/list&model=daerah";// api yang di akses
   WebClient req = new WebClient(); 
   req.DownloadStringCompleted += (s, e) =>//jika proses download data selesai
   {
      if (e.Error == null) // jika kondisi tidak error
      {
         if (!string.IsNullOrEmpty(e.Result)) // jika data tidak kosong
            daftard = JsonConvert.DeserializeObject<List<Daerah>>(e.Result); // masukkan data ke dalam variabel daftard
         foreach (Daerah aa in daftard)
         {
            listBox1.Items.Add(aa.nama_daerah); // set data daftard ke dalam listbox
         }
      }
   };
   req.DownloadStringAsync(new Uri(url));
 }

Setelah itu pada constructor buat seperti berikut :

public MainPage()
 {
   InitializeComponent();
   GetDaerah(); // memanggil fungsi getdaerah()
 }

Setelah itu maka pertama kali membuat aplikasi akan muncul list provinsi seperti berikut :

Kemudian saatnya kita membuat fungsi untuk menginput data nya. Pada mainpage.xaml.cs masukkan code berikut :

 // event yang akan di jalankan ketika melakukan klik pada tombol button
 private void button1_Click(object sender, RoutedEventArgs e)
 {
    WebClient webClient = new WebClient();
    webClient.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
    var uri = new Uri("http://localhost/sirusanew/index.php?r=webapi/create&model=kab", UriKind.Absolute);// url yang dituju untuk input data
    StringBuilder postData = new StringBuilder();
    postData.AppendFormat("{0}={1}", "kode_kab", HttpUtility.UrlEncode(textBox2.Text)); // data-data yang akan dismipan dimasukkan ke dalam string
    postData.AppendFormat("&{0}={1}", "nama_kab", HttpUtility.UrlEncode(textBox1.Text));
    postData.AppendFormat("&{0}={1}", "kode_daerah", HttpUtility.UrlEncode(daftard.ElementAt(listBox1.SelectedIndex).kode_daerah));
    webClient.Headers[HttpRequestHeader.ContentLength] = postData.Length.ToString();
    webClient.UploadStringCompleted += new UploadStringCompletedEventHandler(webClient_UploadStringCompleted);
    // jika upload data selesai, maka akan menjalankan event webClient_uploadStringComplete
    webClient.UploadProgressChanged += webClient_UploadProgressChanged;
    // jika upload data dalam progress maka akan menjalankan even webClient_UploadPorgressChanged
    webClient.UploadStringAsync(uri, "POST", postData.ToString()); 
 }
 // event yang dijalankan pada saat upload data selesai
 void webClient_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
 {
    MessageBox.Show(e.Result);// menampilkan pesan sesuai yang diberikan dari serve
 }
// event yang dijalankan pada saat upload data dalam progress
 void webClient_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
 {
    MessageBox.Show(string.Format("Progress: {0} ", e.ProgressPercentage)); // menampilkan pesan progress
 }

Okeh, selesai.. sekarang saatnya uji coba.. jika sudah benar ketika anda save data makan data yang anda masukkan akan masuk ke server langsung..

Selamat mencoba..

Semoga membantu… 😀

Yii Framework REST Web Service and Windows Phone 7 sebagai Client

Postingan saya terdahulu pernah membahas penerapan web service pada Yii Framework dengan menggunakan SOAP disini. Pada postingan tersebut juga saya memaparkan bagaimana suatu aplikasi client mengakses web service kita yang dimana saya contohkan client dengan menggunakan PHP dan C#. Postingan kali ini juga masih menyangkut web service hanya saja yang saya gunakan bukanlah SOAP tetapi REST. Untuk penjelasan lengkap perbedaan masing-masing metode dapat anda googling aja ya.. Menurut saya sendiri perbedaan umum dari kedua metode tsb adalah SOAP mengizinkan suatu aplikasi mengakses suatu API yang merupakan sebuah fungsi dari server yang menyediakan service, sementara REST lebih kepada mengakses URL dari suatu aplikasi yang menyediakan service.

Artikel yang cukup lengkap tentang penerapan REST pada Yii Framework bisa anda lihat disini (saya juga coba-coba dan nyontek dari sana). Sedangkan postingan kali ini saya hanya terapkan cara mengambil data (mungkin akan ada kelanjutannya pada postingan selanjutnya) dari suatu aplikasi server dengan menggunakan aplikasi lain yang kita sebut sebagai aplikasi client. Pertama misalnya saya ingin mengizinkan aplikasi lain dapat mengakses data master kabupaten dari aplikasi saya dengan menggunakan rest web service. Pertama buatlah sebuah controller baru misal saya beri nama webapiController. Kemudian buatlah sebuah action yang digunakan untuk mengambil data dari suatu model :

// action yang akan di panggil dari apliakasi lain
 public function actionList()
 {
   switch($_GET['model'])
   {
      case 'kab': // jika user request data "kab" maka akan di tampilkan data pada master kabupaten
        $models = Kabupaten::model()->findAll(array('select'=>array('nama_kab','kode_kab')));
        break;
     default: // jika yang di request user tidak ada, maka akan mengirimkan pesan error
        $this->_sendResponse(501, sprintf('Error: Mode <b>list</b> is not implemented for model <b>%s</b>',$_GET['model']) );
      Yii::app()->end();
   }

   if(empty($models)) { // jika tabel yang dituju ada tetapi isi data nya kosong, akan menampilkan pesan error
      $this->_sendResponse(200, 
      sprintf('No items where found for model <b>%s</b>', $_GET['model']) );
   } else {
      $rows = array();
      foreach ($models as $model)
      {
         $rows[] = $model->attributes;// memasukkan semua attribute suatu data ke dalam array
      }
      $this->_sendResponse(200, CJSON::encode($rows));
      // jika data yang diinginakan ada, maka data tersebut akan di convert dalam
      // format json kemudian akan mengirimkan data-data tersebut
    }
 }

Anda dapat melihat penjelasan masing-masing code dari komentar-komentar yang sudah disipkan di code tersebut. Nah, pada code di atas terdapat fungsi $this->_sendResponse yang artinya pada controller ini kita pasti punya sebuah fungsi bernama “_sendResponse”. Maka buatlah sebuah fungsi tersebut :

// digunakan untuk mengirimkan respon pada suatu request
 private function _sendResponse($status = 200, $body = '', $content_type = 'text/html')
 {
    $status_header = 'HTTP/1.1 ' . $status . ' ' . $this->_getStatusCodeMessage($status);
    header($status_header);
    header('Content-type: ' . $content_type);
    if($body != '') // jika data yang ingin dikirim tidak kosong, maka tampilkan data tersebut
    {
      echo $body;
    }
    else // jika data yang ingin dikirim kosong, maka kirim pesan sesuai statusnya.
    {
       $message = ''; // variabel yang digunakan untuk membuat pesan header pada pesan
       switch($status) // mengeset pesan sesuai dengan statusnya
       {
         case 401:
            $message = 'You must be authorized to view this page.';
            break;
        case 404:
            $message = 'The requested URL ' . $_SERVER['REQUEST_URI'] . ' was not found.';
            break;
        case 500:
            $message = 'The server encountered an error processing your request.';
            break;
        case 501:
            $message = 'The requested method is not implemented.';
            break;
       }
       $signature = ($_SERVER['SERVER_SIGNATURE'] == '') ? $_SERVER['SERVER_SOFTWARE'] . ' Server at ' . $_SERVER['SERVER_NAME'] . ' Port ' . $_SERVER['SERVER_PORT'] : $_SERVER['SERVER_SIGNATURE'];
       // signature, pesan-pesan mngenai informasi server

       // pesan yang akan di tampilkan kepada user
       $body = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
          <html>
             <head>
                <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
                <title>' . $status . ' ' . $this->_getStatusCodeMessage($status) . '</title>
             </head>
             <body>
                <h1>' . $this->_getStatusCodeMessage($status) . '</h1>
                <p>' . $message . '</p>
                <hr />
                <address>' . $signature . '</address>
             </body>
          </html>';
       echo $body;
     }
    Yii::app()->end();
 }

penjelasan code tersebut juga ada pada code di atas. Nah, pada code di atas juga ada sebuah fungsi  _getStatusCodeMessage, artinya kita juga harus membuat fungsi tersebut :

// mengembalikan pesan dari suatu request
 private function _getStatusCodeMessage($status)
 {
   $codes = Array(
     200 => 'OK',
     400 => 'Bad Request',
     401 => 'Unauthorized',
     402 => 'Payment Required',
     403 => 'Forbidden',
     404 => 'Not Found',
     500 => 'Internal Server Error',
     501 => 'Not Implemented',
   );
   return (isset($codes[$status])) ? $codes[$status] : '';
 }

Setelah membuat code tersebut, anda sudah selesai membuat rest api nya, dan untuk melihat hasilnya, cobalah mengakses URL berikut di browser anda :

http://localhost/namaaplikasianda/index.php?r=namacontroller/list&model=kab.

Parameter yang perlu anda masukkan adalah nama controllernya, nama action dalam hal ini “actionList”, nama variabel $_GET yang anda kirim beserta isi variabel $_GET nya. Setelah itu akan muncul tampilan seperti berikut :

Gambar di atas adalah hasil yang akan tampil dimana yang akan di tampilkan adalah kumpulan data yang kita ambil dari proses action list tadi. Kemudian bagaimana agar data tersebut data di akses dari aplikasi lain?

Okeh, saya akan memberikan contoh cara mengakses data tersebut dengan menggunakan Windows Phone 7. Anda dapat menggunakan platform apapun untuk mengakses data ini baik dengan PHP, java, iphone, dll asalkan anda menguasainya.. tapi dalam contoh ini saya akan tunjukkan menggunakan windows phone 7 karena kebetulan saya tertarik dengan platform satu ini..

Pertama-tama buatlah sebuah aplikasi baru pada windows phone 7. Karena kita mengolah data json, kita akan memnggunakan sebuah library untuk mempermudah kita mengolahnya dalam windows phone 7. Library tersebut dapat anda download disini, dan masukkan library tersebut ke dalam aplikasi anda dan jangan lupa definisikan ke dalam aplikasi anda dengan memasukkan code berikut pada mainpage.xaml.cs :

using Newtonsoft.Json;

Buatlah sebuah class baru dengan nama Kab.cs dan masukkan ke dalamnya code berikut :

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace sirusa
{
  public class Kab
  {
     public int kode_kab { get; set; }
     public string kode_daerah { get; set; }
     public string nama_kab { get; set; }
   }
}

Setelah itu pada mainpage.xaml.cs tambahkan sebuah fungsi berikut :

private void GetData()
 {

  string url = "http://localhost/sirusanew/index.php?r=webapi/list&model=kab";
  // definisi url yang akan di akses 
  WebClient req = new WebClient();
  req.DownloadStringCompleted += (s, e) =>
  {
    if (e.Error == null)
    {
       string tt = ""; // nilai yang akan di tampilkan
       if (!string.IsNullOrEmpty(e.Result))
       {
          Kab[] deserializedJSON = JsonConvert.DeserializeObject<Kab[]>(e.Result);
          // konversi nilai json ke dalam class Kab dengan format array karena nilainya bisa lebih dari satu buah
          foreach (var k in deserializedJSON)
          {
             tt += k.nama_kab; // memasukkan nilai nama kabupaten untuk di tampilkan
          }
          MessageBox.Show(tt); // menampilkan nilai yang sudah disimpan tadi
       }
     }
   };
   req.DownloadStringAsync(new Uri(url));
 }

Setelah itu rubah contrstructornya menjadi seperti berikut :

// Constructor
 public MainPage()
 {
   InitializeComponent();
   GetData(); //memanggil fungsi getdata
 }

Jalankan aplikasi anda dan akan tampil seperti berikut :

 

 

Okeh.. selesai…

Selamat mencoba…

Semoga membantu… 😀

[Yii Framework] Select Data From Dialog

Control apa yang anda gunakan untuk memasukkan data yang berasa dari master? yah, lebih tepat nya hubungannya 1 to many lah.. Kadang orang-orang menggunakan radio button, tetapi kebanyakan orang menggunakan dropdownlist.. Lalu bagaimana jika data nya sangat banyak sehingga orang pusing kalo pake dropdownlist?? Ada autocomplete kok,, jadi sekalinya kita ngetik, data master akan di filter dengan sendiri nya… hmmm.. pilihan tepat…  Tapi bagaimana jika dalam suatu tabel master memiliki banyak filter untuk memudahkan user?

Misal nih.. kita ingin select wilayah hingga level kelurahan. Untuk memudahkan user, kita ingin agar dapat memilih suatu kelurahan dengan filter berdasarkan provinsi, kabupaten/kota, kecamatan, hingga kelurahan… Tentunya auto complete menjadi kurang cocok dalam kasus ini.. Karena itu solusi yang digunakan biasa nya adalah menggunakan dialog yang menampilkan tabel master, dan dari dialog tersebut kita dapat melakukan filter langsung sesuai field-field yang kita inginkan.. Kemudian setelah menemukan datanya.. kita tinggal memilih data yang ada di dialog dan done… data pun masuk ke dalam field..

Yah, kalo dari penjelasan di atas masih membingungkan.. anda bisa lihat gambaran apa yang ingin saya paparkan dari gambar berikut :

pada form kita menyediaakn fitur untuk user memilih wilayah.. Setelah user memilih “Pilih Wilayah”, maka akan muncul dialog seperti berikut :

User dapat mem-filter data di atas dengan menggunakan filter yang tersedia dan juga dapat melihat dengan pagination.. Jika data nya sudah di temukan, maka user tinggal memilih data tersebut dengan klik link “Pilih” yang ada pada masing-masing row. Kemudian data yang dipilih pun akan masuk ke dalam field :

Okeh, sekarang bagaimana cara membuatnya?

Perttama-tama pada form anda tambahkanlah control seperti berikut :

 <div class="row">
   <?php echo $form->labelEx($model,'wilayah'); ?>
   <?php 
      echo $form->hiddenField($model,'wilayah'); 
      echo CHtml::textField('wilayah_text','',array('size'=>60)); 
      echo Chtml::ajaxLink('Pilih Wilayah',Yii::app()->createUrl('namaController/namaAction'),
         array('update'=>'#wilayahfield'),array("id"=>'wilayah'));
   ?>
   <div id="wilayahfield" style="visibility: hidden;"></div>
   <?php echo $form->error($model,'wilayah'); ?>
 </div>

Pada tampilan di atas, kita membuat membuat sebuah tipe inputan “hidden” untuk nilai “wilayah” dan satu buah textfield dengan nama “wilayah_text”. Kenapa hidden? ini sama seperti kasus auto increment. Kita sebenarnya menginput kode dari suatu tabel master ke dalam database kita, tetapi kita ingin menampilkan pada user bukan kode nya, tapi isi dari tabel tersebut. Untuk itu kita menyediakan sebuah textfield yang tidak akan disimpan guna menampilkan data dari tabel master, dan field wilayah kita buat tipe hidden yang menyimpan kode dari tabel master, dibuat hidden karena user tidak perlu tahu dan agar tak membingungkan user.

Selain itu kita juga menyediakan sebuah ajaxlink yang isinya akan memanggil sebuah action dan dimana ketika sukses hasil dari ajaxlink tersebut akan mengupdate tag html yang memiliki id = “wilayahfield”.

Kemudian setelah membuat itu pada form, kita kemudian membuat action pada suatu controller yang akan berjalan ketika di request setelah memilih tombol ajaxlink di atas.. Jadi pada controller anda masukkan code berikut :

public function actionNamaaction()
{
  $model=new Demography('search');
  $model->unsetAttributes(); // clear any default values
  if(isset($_GET['Demography']))
     $model->attributes=$_GET['Demography'];
   $this->renderPartial('getwilayah',array(
      'model'=>$model,
   ),false,true);

   Yii::app()->end();
 }

Kemudian pada view, buat sebuah file getwilayah.php lalu buat code berikut

<?php
 $this->beginWidget('zii.widgets.jui.CJuiDialog', array(
   'id' => 'bandsdialog3',
   'options' => array(
   'autoOpen' => true,
   'title' => 'Pilih Wilayah',
   'modal' => false,
   'width' => '600',
   ))
 );
 $this->widget('zii.widgets.grid.CGridView', array(
   'id'=>'user-grid',
   'dataProvider'=>$model->search(),
   'filter'=>$model,
   'columns'=>array(
       'propinsi',
       'kota',
       'kecamatan',
       'kelurahan',
       'kodepos',
        array(
           'header'=>'Pilih',
           'type'=>'raw',
           'value'=>'CHtml::link("Pilih","",array(
               "onClick"=>CHtml::ajax(array(
               "url"=>Yii::app()->createUrl("namaController/selectwilayah",array("id"=>$data->primaryKey)),
               "dataType"=>"json",
               "success"=>"function(data){
                     $(\"#Namamodel_wilayah\").val(data.satu);
                     $(\"#wilayah_text\").val(data.dua);
                     $(\"#bandsdialog3\").remove();
                }")
            ),"id"=>"child".$data->primaryKey,"style"=>"cursor:pointer;"))',
         ),
       ),
  ));
  $this->endWidget('zii.widgets.jui.CJuiDialog');
 ?>

Okeh, kode di atas akan menampilkan cgridview dimana dapat kita lakukan filter, pagination, juga dapat kita pilih nilainya.. Cara memilih nilainya sendiri juga menggunakan AJAX.. disana kita memanggil sebuah action dari sebuah controller dimana memiliki sebuah parameter dengan primary key data yang telah terpilih.. kemudian setelah sukses dijalankan, AJAX terssebut akan mengupdata field dengan id “Namamodel_wilayah”, “wilayah_text” dan menghapus “bandsdialog3”.

Nah, sekarang kita tinggal membuat action yang di request oleh ajax di atas… Untuk itu pada controller buatlah sebuah action seperti berikut :

public function actionSelectdemografi($id)
 {
   $satu='';
   $dua='';

    $model=Namamodel::model()->findByPk($id);
    $satu=$model->primaryKey;
    $dua=$model->propinsi.' - '.$model->kota.' - '.$model->kecamatan.' - '.$model->kelurahan;
    echo CJSON::encode(array
    (
       'satu'=>$satu,
       'dua'=>$dua,
    ));
    Yii::app()->end();
 }

Kode di atas akan mengembalikan 2 buah nilai, yang pertama nilai isi dari tabel wilayah dan yang kedua mengembalikan primary key…

 

Selesai…

Selamat mencoba… Semoga membantu… 😀

%d bloggers like this: