From 30795649ead5b7212cad32f9d5a9ca6152beba27 Mon Sep 17 00:00:00 2001 From: kabayan <> Date: Wed, 29 Aug 2007 11:55:06 +0000 Subject: Indonesian Blog tutorial day 3,4, and 5 3rd tries --- .gitattributes | 27 +++ .../protected/pages/Day3/id/Auth.page | 102 ++++++++++ .../protected/pages/Day3/id/CreateAdminUser.page | 151 +++++++++++++++ .../protected/pages/Day3/id/CreateEditUser.page | 195 +++++++++++++++++++ .../protected/pages/Day3/id/CreateLoginUser.page | 162 ++++++++++++++++ .../protected/pages/Day3/id/CreateNewUser.page | 210 +++++++++++++++++++++ .../protected/pages/Day3/id/Overview.page | 26 +++ .../protected/pages/Day3/id/directories.gif | Bin 0 -> 10329 bytes .../protected/pages/Day3/id/output.gif | Bin 0 -> 10006 bytes .../protected/pages/Day3/id/output2.gif | Bin 0 -> 9222 bytes .../protected/pages/Day3/id/output3.gif | Bin 0 -> 9464 bytes .../protected/pages/Day4/id/CreateEditPost.page | 133 +++++++++++++ .../protected/pages/Day4/id/CreateListPost.page | 185 ++++++++++++++++++ .../protected/pages/Day4/id/CreateNewPost.page | 136 +++++++++++++ .../protected/pages/Day4/id/CreateReadPost.page | 135 +++++++++++++ .../protected/pages/Day4/id/Overview.page | 26 +++ .../protected/pages/Day4/id/directories.gif | Bin 0 -> 11129 bytes .../protected/pages/Day4/id/output.gif | Bin 0 -> 3406 bytes .../protected/pages/Day4/id/output2.gif | Bin 0 -> 6326 bytes .../protected/pages/Day4/id/output3.gif | Bin 0 -> 11874 bytes .../protected/pages/Day4/id/output4.gif | Bin 0 -> 11916 bytes .../protected/pages/Day5/id/ErrorLogging.page | 159 ++++++++++++++++ .../protected/pages/Day5/id/Performance.page | 67 +++++++ .../protected/pages/Day5/id/Summary.page | 36 ++++ .../protected/pages/Day5/id/UseTheme.page | 138 ++++++++++++++ .../protected/pages/Day5/id/output.gif | Bin 0 -> 4282 bytes .../protected/pages/Day5/id/output2.gif | Bin 0 -> 7798 bytes .../protected/pages/Day5/id/output3.gif | Bin 0 -> 5190 bytes 28 files changed, 1888 insertions(+) create mode 100644 demos/blog-tutorial/protected/pages/Day3/id/Auth.page create mode 100644 demos/blog-tutorial/protected/pages/Day3/id/CreateAdminUser.page create mode 100644 demos/blog-tutorial/protected/pages/Day3/id/CreateEditUser.page create mode 100644 demos/blog-tutorial/protected/pages/Day3/id/CreateLoginUser.page create mode 100644 demos/blog-tutorial/protected/pages/Day3/id/CreateNewUser.page create mode 100644 demos/blog-tutorial/protected/pages/Day3/id/Overview.page create mode 100644 demos/blog-tutorial/protected/pages/Day3/id/directories.gif create mode 100644 demos/blog-tutorial/protected/pages/Day3/id/output.gif create mode 100644 demos/blog-tutorial/protected/pages/Day3/id/output2.gif create mode 100644 demos/blog-tutorial/protected/pages/Day3/id/output3.gif create mode 100644 demos/blog-tutorial/protected/pages/Day4/id/CreateEditPost.page create mode 100644 demos/blog-tutorial/protected/pages/Day4/id/CreateListPost.page create mode 100644 demos/blog-tutorial/protected/pages/Day4/id/CreateNewPost.page create mode 100644 demos/blog-tutorial/protected/pages/Day4/id/CreateReadPost.page create mode 100644 demos/blog-tutorial/protected/pages/Day4/id/Overview.page create mode 100644 demos/blog-tutorial/protected/pages/Day4/id/directories.gif create mode 100644 demos/blog-tutorial/protected/pages/Day4/id/output.gif create mode 100644 demos/blog-tutorial/protected/pages/Day4/id/output2.gif create mode 100644 demos/blog-tutorial/protected/pages/Day4/id/output3.gif create mode 100644 demos/blog-tutorial/protected/pages/Day4/id/output4.gif create mode 100644 demos/blog-tutorial/protected/pages/Day5/id/ErrorLogging.page create mode 100644 demos/blog-tutorial/protected/pages/Day5/id/Performance.page create mode 100644 demos/blog-tutorial/protected/pages/Day5/id/Summary.page create mode 100644 demos/blog-tutorial/protected/pages/Day5/id/UseTheme.page create mode 100644 demos/blog-tutorial/protected/pages/Day5/id/output.gif create mode 100644 demos/blog-tutorial/protected/pages/Day5/id/output2.gif create mode 100644 demos/blog-tutorial/protected/pages/Day5/id/output3.gif diff --git a/.gitattributes b/.gitattributes index 5a783516..d605adf9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -718,6 +718,16 @@ demos/blog-tutorial/protected/pages/Day3/CreateLoginUser.page -text demos/blog-tutorial/protected/pages/Day3/CreateNewUser.page -text demos/blog-tutorial/protected/pages/Day3/Overview.page -text demos/blog-tutorial/protected/pages/Day3/directories.gif -text +demos/blog-tutorial/protected/pages/Day3/id/Auth.page -text +demos/blog-tutorial/protected/pages/Day3/id/CreateAdminUser.page -text +demos/blog-tutorial/protected/pages/Day3/id/CreateEditUser.page -text +demos/blog-tutorial/protected/pages/Day3/id/CreateLoginUser.page -text +demos/blog-tutorial/protected/pages/Day3/id/CreateNewUser.page -text +demos/blog-tutorial/protected/pages/Day3/id/Overview.page -text +demos/blog-tutorial/protected/pages/Day3/id/directories.gif -text +demos/blog-tutorial/protected/pages/Day3/id/output.gif -text +demos/blog-tutorial/protected/pages/Day3/id/output2.gif -text +demos/blog-tutorial/protected/pages/Day3/id/output3.gif -text demos/blog-tutorial/protected/pages/Day3/output.gif -text demos/blog-tutorial/protected/pages/Day3/output2.gif -text demos/blog-tutorial/protected/pages/Day3/output3.gif -text @@ -727,6 +737,16 @@ demos/blog-tutorial/protected/pages/Day4/CreateNewPost.page -text demos/blog-tutorial/protected/pages/Day4/CreateReadPost.page -text demos/blog-tutorial/protected/pages/Day4/Overview.page -text demos/blog-tutorial/protected/pages/Day4/directories.gif -text +demos/blog-tutorial/protected/pages/Day4/id/CreateEditPost.page -text +demos/blog-tutorial/protected/pages/Day4/id/CreateListPost.page -text +demos/blog-tutorial/protected/pages/Day4/id/CreateNewPost.page -text +demos/blog-tutorial/protected/pages/Day4/id/CreateReadPost.page -text +demos/blog-tutorial/protected/pages/Day4/id/Overview.page -text +demos/blog-tutorial/protected/pages/Day4/id/directories.gif -text +demos/blog-tutorial/protected/pages/Day4/id/output.gif -text +demos/blog-tutorial/protected/pages/Day4/id/output2.gif -text +demos/blog-tutorial/protected/pages/Day4/id/output3.gif -text +demos/blog-tutorial/protected/pages/Day4/id/output4.gif -text demos/blog-tutorial/protected/pages/Day4/output.gif -text demos/blog-tutorial/protected/pages/Day4/output2.gif -text demos/blog-tutorial/protected/pages/Day4/output3.gif -text @@ -735,6 +755,13 @@ demos/blog-tutorial/protected/pages/Day5/ErrorLogging.page -text demos/blog-tutorial/protected/pages/Day5/Performance.page -text demos/blog-tutorial/protected/pages/Day5/Summary.page -text demos/blog-tutorial/protected/pages/Day5/UseTheme.page -text +demos/blog-tutorial/protected/pages/Day5/id/ErrorLogging.page -text +demos/blog-tutorial/protected/pages/Day5/id/Performance.page -text +demos/blog-tutorial/protected/pages/Day5/id/Summary.page -text +demos/blog-tutorial/protected/pages/Day5/id/UseTheme.page -text +demos/blog-tutorial/protected/pages/Day5/id/output.gif -text +demos/blog-tutorial/protected/pages/Day5/id/output2.gif -text +demos/blog-tutorial/protected/pages/Day5/id/output3.gif -text demos/blog-tutorial/protected/pages/Day5/output.gif -text demos/blog-tutorial/protected/pages/Day5/output2.gif -text demos/blog-tutorial/protected/pages/Day5/output3.gif -text diff --git a/demos/blog-tutorial/protected/pages/Day3/id/Auth.page b/demos/blog-tutorial/protected/pages/Day3/id/Auth.page new file mode 100644 index 00000000..c4728cdf --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day3/id/Auth.page @@ -0,0 +1,102 @@ + + +

Otentikasi dan Otorisasi

+ +

+Sebelum kita siap mengimplementasikan halaman pengguna, kita perlu melakukan beberapa pekerjaan guna menghidupkan otentikasi dan otorisasi. +

+ +

+Kita menambah dua modul ke konfigurasi aplikasi seperti berikut: +

+ + + + ...TDataSourceConfig and TActiveRecordConfig modules... + + + + + + + +

+Modul TAuthManager mengatur seluruh alur kerja otentikasi dan otorisasi. Ia menggunakan modul users sebagai manajer penggunanya (lihat di bawah). Dengan menetapkan properti LoginPage, kita menginformasikan manajer otentikasi untuk mengalihkan browser pengguna ke halaman LoginUser saat otorisasi gagal. Kami akan menjelaskan bagaimana untuk membuat LoginUser dalam subbagian berikutnya. +

+ +

+Modul user adalah kelas TDbUserManager yang bertanggung jawab untuk memverifikasi keabsahan pengguna dan memelihara data dasar dalam sesi PHP. Properti UserClass diinisialisasi sebagai Application.BlogUser, yang menunjukan bahwa manajer pengguna akan melihar kelas BlogUser di bawah direktori protected (ingat alias Application merujuk ke direktori protected) dan menggunakannya untuk memelihara data sesi pengguna. +

+ +

+Seperti yang akan kita lihat dalam bagian nanti, dalam kontrol dan halaman, kita dapat menggunakan $this->User untuk memperoleh obyek BlogUser yang berisi informasi pengguna yang saat ini mengakses siistem. +

+ +

+Di bawah ini adalah rincian implementasi dari BlogUser. Perhatikan, Rekaman Aktif digunakan untuk melakukan query DB. Sebagai contoh, kita menggunakan UserRecord::finder()->findByPk($username) untuk mencari kunci primer yang ditetapkan oleh $username dalam tabel users. +

+ + +// Sertakan file TDbUserManager.php yang mendefinisikan TDbUser +Prado::using('System.Security.TDbUserManager'); + +/** + * BlogUser Class. + * BlogUser mewakili data pengguna yang perlu dijaga dalam sesi. + * Implementasi standar memelihara informasi aturan dan pengguna. + */ +class BlogUser extends TDbUser +{ + /** + * Membuat obyek BlogUser berdasarkan username yang ditetapkan. + * Metode ini diperlukan oleh TDbUser. Ia memeriksa database + * untuk melihat apakah username yang ditetapkan ada di sana. Jika ada, + * obyek BlogUser dibuat dan diinisialisasi. + * @param string username yang ditetapkan + * @return BlogUser obyek pengguna, null jika username tidak benar. + */ + public function createUser($username) + { + // gunakan Rekaman Aktif UserRecord untuk mencari username yang ditetapkan + $userRecord=UserRecord::finder()->findByPk($username); + if($userRecord instanceof UserRecord) // jika ditemukan + { + $user=new BlogUser($this->Manager); + $user->Name=$username; // setel nama pengguna + $user->Roles=($userRecord->role==1?'admin':'user'); // setel aturan + $user->IsGuest=false; // pengguna bukan seorang tamu + return $user; + } + else + return null; + } + + /** + * Memeriksa apakah (username, password) yang ditetapkan sudah benar. + * Metode ini diperlukan oleh TDbUser. + * @param string username + * @param string password + * @return boolean apakah username dan password sudah benar. + */ + public function validateUser($username,$password) + { + // pakai Rekaman Aktif UserRecord untuk mencari pasangan (username, password). + return UserRecord::finder()->findBy_username_AND_password($username,$password)!==null; + } + + /** + * @return boolean apakah pengguna ini adalah seorang administrator. + */ + public function getIsAdmin() + { + return $this->isInRole('admin'); + } +} + + +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day3/id/CreateAdminUser.page b/demos/blog-tutorial/protected/pages/Day3/id/CreateAdminUser.page new file mode 100644 index 00000000..c9ee7c5a --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day3/id/CreateAdminUser.page @@ -0,0 +1,151 @@ + + +

Membuat Halaman AdminUser

+ +

+Halaman AdminUser menampilkan semua akun pengguna dalam sebuah daftar agar administrator dapat melakukan beberapa pekerjaan administratif. Demi kemudahan, pekerjaan administratif sistem blog kita mendukung termasuk mengedit dan menghapus akun pengguna. +

+ +

+Kita akan menampilkan daftar pengguna dalam sebuah tabel. Setiap baris tabel mewakili satu akun pengguna, dan kolom berikut ditampilkan: +

+ + +

+Kita membuat dua file protected/pages/users/AdminUser.page dan protected/pages/users/AdminUser.php masing-masing untuk menyimpan template halaman dan kelas halaman. +

+ +

Membuat Template Halaman

+

+Kita menggunakan TDataGrid untuk menampilkan akun pengguna. Berdasarkan pada analisis di atas, kita mengkonfigurasi empat kolom berikut: +

+ + +

Template halaman lengkap ditampilkan seperti berikut:

+ + +<%@ Title="My Blog - Manage User Accounts" %> + +<com:TContent ID="Main"> + +

Manage User Accounts

+ +Create New User +
+ +<com:TDataGrid ID="UserGrid" + DataKeyField="username" + AutoGenerateColumns="false" + OnDeleteCommand="deleteButtonClicked"> + + <com:THyperLinkColumn + HeaderText="Username" + DataTextField="username" + DataNavigateUrlField="username"> + <prop:DataNavigateUrlFormatString># + $this->Service->constructUrl('users.EditUser',array('username'=>{0})) + </prop:DataNavigateUrlFormatString> + </com:THyperLinkColumn> + + <com:TBoundColumn + HeaderText="Email" + DataField="email" /> + + <com:TCheckBoxColumn + HeaderText="Administrator" + DataField="role" /> + + <com:TButtonColumn + HeaderText="Command" + Text="Delete" + ButtonType="PushButton" + CommandName="delete" /> + +</com:TDataGrid> + +</com:TContent> +
+ + +

Membuat Kelas Halaman

+ +

+Dalam template halaman di atas, event OnDeleteCommand datagrid dengan metode deleteButtonClicked() akan kita implementasikan dalam kelas halaman. Sebagai tambahan, datagrid perlu dipopulasi dengan data akun pengguna saat halaman diinisialisasi. Oleh karena itu, kita menulis kelas halaman seperti berikut: +

+ + +class AdminUser extends TPage +{ + /** + * Mempopulai datagrid dengan daftar pengguna. + * Metode ini dipanggil oleh kerangka kerja saat inisialisasi halaman + * @param mixed event parameter + */ + public function onInit($param) + { + parent::onInit($param); + // ambil semua informasi data akun + $this->UserGrid->DataSource=UserRecord::finder()->findAll(); + // mengikat data ke komponen antarmua + $this->UserGrid->dataBind(); + } + + /** + * Menghapus rekaman pengguna yang ditetapkan. + * Metode ini merespon ke event OnDeleteCommand pada datagrid. + * @param TDataGrid pengirim event + * @param TDataGridCommandEventParameter parameter event + */ + public function deleteButtonClicked($sender,$param) + { + // dapatkan item datagrid yang berisi tombol hapus yang diklik + $item=$param->Item; + // dapatkan kunci primer terkait ke item datagrid + $username=$this->UserGrid->DataKeys[$item->ItemIndex]; + // menghapus rekaman pengguna dengan kunci primer nama pengguna + UserRecord::finder()->deleteByPk($username); + } +} + + +

+Dalam kode di atas, metode deleteButtonClicked() dipanggil kapan saja tombol "Delete" diklik. untuk menentukan baris mana pada tombol yang diklik, kita memeriksa properti Item.ItemIndex pada parameter event. Untuk selanjutnya mengidentifikasi akun pengguna mana yang akan dihapus, kita mengambil nilai kunci primer (username) melalui properti DataKeys pada DataGrid. +

+ + +Semua kontrol data-bound mempunyai pola penggunaan yang sama. Yaitu, Setel properti DataSource dengan data dan panggil metode dataBind() untuk mengikat data ke struktur internal kontrol. + + + +

Menambahkan Pemeriksaan Perijinan

+

+Karena AdminUser hanya bisa diakses oleh administrator, maka kita perlu menyesuaikan file konfigurasi halaman protected/pages/users/config.xml. +

+ + + + + + + + + + +

Pengujian

+

+Untuk menguji halaman AdminUser, kunjungi URL http://hostname/blog/index.php?page=users.AdminUser. Anda mungkin perlu masuk sebagai administrator lebih dahulu jika anda belum melakukannya. Kita akan melihat hasil seperti berikut. +

+ + + +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day3/id/CreateEditUser.page b/demos/blog-tutorial/protected/pages/Day3/id/CreateEditUser.page new file mode 100644 index 00000000..e15df047 --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day3/id/CreateEditUser.page @@ -0,0 +1,195 @@ + + +

Membuat Halaman EditUser

+ +

+Halaman EditUser sangat mirip dengan NewUser. Perbedaan utamanya adalah bahwa saat EditUser awalnya diminta, field input harus diinisialisasi dengan informasi pengguna yang sudah ada. Sedikit perbedaan lainnya adalah bahwa EditUser juga bisa diakses oleh pengguna normal. +

+ +

+Untuk menentukan akun pengguna mana yang diedit, kita menggunakan kebijakan berikut: +

+ + +

+Kita membuat dua file protected/pages/users/EditUser.page dan protected/pages/users/EditUser.php masing-masing untuk menyimpan template halaman dan kelas halaman. +

+ +

Membuat Template Halaman

+

+Seperti yang telah anda tebak, template halaman EditUser sebagian besar sama seperti pada NewUser. Selain perbedaan dalam judul halaman dan judul tombol submit, ada tiga perbedaan utama. +

+ +

+ + +<%@ Title="My Blog - Edit User" %> + +<com:TContent ID="Main"> + +

Edit User

+ +Username: +<com:TLabel ID="Username" /> + +
+Password: +
+<com:TTextBox ID="Password" TextMode="Password" /> + +
+Re-type Password: +<com:TCompareValidator + ControlToValidate="Password" + ControlToCompare="Password2" + ErrorMessage="Your password entries did not match." + Display="Dynamic" /> +
+<com:TTextBox ID="Password2" TextMode="Password" /> + +
+Email Address: +<com:TRequiredFieldValidator + ControlToValidate="Email" + ErrorMessage="Please provide your email address." + Display="Dynamic" /> +<com:TEmailAddressValidator + ControlToValidate="Email" + ErrorMessage="You entered an invalid email address." + Display="Dynamic" /> +
+<com:TTextBox ID="Email" /> + +<com:TControl Visible="<%= $this->User->IsAdmin %>"> +
+Role: +
+<com:TDropDownList ID="Role"> + <com:TListItem Text="Normal User" Value="0" /> + <com:TListItem Text="Administrator" Value="1" /> +</com:TDropDownList> +</com:TControl> + +
+First Name: +
+<com:TTextBox ID="FirstName" /> + +
+Last Name: +
+<com:TTextBox ID="LastName" /> + +
+<com:TButton Text="Save" OnClick="saveButtonClicked" /> + +</com:TContent> +
+ + +

Membuat Kelas Halaman

+ +

+Berdasarkan pada deskripsi di atas dan template, kita perlu menulis kelas halaman yang mengawali input dengan informasi pengguna yang sudah ada. Sebagai tambahan, kelas halaman juga perlu untuk mengimplementasikan metode saveButtonClicked() yang disertakan pada event tombol "save" OnClick. +

+ + +class EditUser extends TPage +{ + /** + * Menginisialisasi input dengan data pengguna yang sudah ada. + * Metode ini dipanggil oleh kerangka kerja saat halaman diinisialisasi. + * @param mixed event parameter + */ + public function onInit($param) + { + parent::onInit($param); + if(!$this->IsPostBack) // jika halaman awalnya diminta + { + // Ambil data pengguna yang sudah ada. Ini sama dengan: + // $userRecord=$this->getUserRecord(); + $userRecord=$this->UserRecord; + + // Populasikan kontrol input dengan data pengguna yang sudah ada + $this->Username->Text=$userRecord->username; + $this->Email->Text=$userRecord->email; + $this->Role->SelectedValue=$userRecord->role; + $this->FirstName->Text=$userRecord->first_name; + $this->LastName->Text=$userRecord->last_name; + } + } + + /** + * Menyimpan akun pengguna jika semua input sudah benar. + * Metode ini merespon event OnClick pada tombol "save". + * @param mixed event sender + * @param mixed event parameter + */ + public function saveButtonClicked($sender,$param) + { + if($this->IsValid) // saat semua validasi sukses + { + // Ambil data pengguna yang sudah ada. Ini sama dengan: + $userRecord=$this->UserRecord; + + // Ambil data input + $userRecord->username=$this->Username->Text; + // mutakhirkan kata sandi saat input tidak kosong + if(!empty($this->Password->Text)) + $userRecord->password=$this->Password->Text; + $userRecord->email=$this->Email->Text; + // mutakhirkan aturan jika pengguna saat ini adalah administrator + if($this->User->IsAdmin) + $userRecord->role=(int)$this->Role->SelectedValue; + $userRecord->first_name=$this->FirstName->Text; + $userRecord->last_name=$this->LastName->Text; + + // simpan ke database melalui mekanisme Rekaman Aktif + $userRecord->save(); + + // alihkan browser ke homepage + $this->Response->redirect($this->Service->DefaultPageUrl); + } + } + + /** + * Mengembalikan data pengguna yang diedit. + * @return UserRecord data pengguna yang diedit. + * @throws THttpException jika data pengguna tidak ditemukan. + */ + protected function getUserRecord() + { + // pengguna yang diedit adalah pengguna yang saat ini sudah masuk + $username=$this->User->Name; + // jika var GET 'username' tidak kosong dan pengguna saat ini adalah + // administrator, lebih baik kita menggunakan nilai var GET. + if($this->User->IsAdmin && $this->Request['username']!==null) + $username=$this->Request['username']; + + // gunakan Rekaman Aktif untuk melihat nama pengguna yang ditetapkan + $userRecord=UserRecord::finder()->findByPk($username); + if(!($userRecord instanceof UserRecord)) + throw new THttpException(500,'Username is invalid.'); + return $userRecord; + } +} + + + +Metode onInit() dipanggil oleh PRADO selama salah satu masa hidup halaman. Metode masa hidup umum lainnya ditimpa termasuk onPreInit(), onLoad() dan onPreRender(). + + +

Pengujian

+

+Untuk menguji halaman EditUser, kunjungi URL http://hostname/blog/index.php?page=users.EditUser&username=demo. Anda mungkin perlu masuk lebih dulu jika anda belum melakukannya. Coba masuk dengan akun berbeda (e.g. admin/demo, demo/demo) dan lihat bagaimana halaman ditampilkan secara berbeda. +

+ +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day3/id/CreateLoginUser.page b/demos/blog-tutorial/protected/pages/Day3/id/CreateLoginUser.page new file mode 100644 index 00000000..1debbec0 --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day3/id/CreateLoginUser.page @@ -0,0 +1,162 @@ + + +

Membuat Halaman LoginUser

+ +

+Halaman LoginUser menampilkan formulir masuk dan mengotentikasi pengguna yang mencoba untuk masuk. Seperti dijelaskan dalam otentikasi dan otorisasi, browser pengguna secara otomatis dialihkan ke halaman LoginUser ketika pengguna mencoba untuk mengakses halaman istimewa, seperti misalhnya halaman admin pengguna. +

+ +

+Alur kerja LoginUser sangat mirip dengan halaman Contact: +

+
    +
  1. Ketika pengguna mengakses halaman LoginUser, formulir masuk ditampilkan;
  2. +
  3. Pengguna mengisi nama pengguna dan kata sandi serta mengklik pada tombol "login";
  4. +
  5. LoginUser menerima event "login" dan memicu rangkaian otentikasi;
  6. +
  7. Jika pengguna memasukan nama pengguna dan kata sandi yang benar, sistem menempatkan identitas yang sah dan mengalihkan browser-nya ke halaman istimewa yang diinginkan; Jika tidak, pesan "password invalid" akan ditampilkan. +
+ +

+Kita membuat dua file protected/pages/users/LoginUser.page dan protected/pages/users/LoginUser.php masing-masing untuk menyimpan template halaman dan kelas halaman. +

+ +

Membuat Template Halaman

+ +

+Di bawah ini kita menampilkan template untuk LoginUser. Seperti kita lihat, halaman sebagian besar berisi kotak teks untuk mengumpulkan nama pengguna dan kotak teks untuk kata sandi. Input nama pengguna diperlukan, yang dipastikan oleh TRequiredFieldValidator. Kebenaran dari input kata sandi dipastikan oleh TCustomValidator yang memanggil metode validateUser() halaman ketika validasi dilakukan. Halaman juga mempunyai tombol "login" yang memanggil loginButtonClicked() halaman ketika itu diklik. +

+ + +<%@ Title="My Blog - Login" %> + +<com:TContent ID="Main"> + +

Login

+ +Username: +<com:TRequiredFieldValidator + ControlToValidate="Username" + ErrorMessage="Please provide your username." + Display="Dynamic" /> +
+<com:TTextBox ID="Username" /> + +
+Password: +<com:TCustomValidator + ControlToValidate="Password" + ErrorMessage="Your entered an invalid password." + Display="Dynamic" + OnServerValidate="validateUser" /> +
+<com:TTextBox ID="Password" TextMode="Password" /> + +
+<com:TButton Text="Login" OnClick="loginButtonClicked" /> + +</com:TContent> +
+ +

Membuat Kelas Halaman

+ +

+Seperti halaman Contact, halaman LoginUser juga memerlukan file kelas yang sebagian besar berisi implementasi pengendali event yang disertakan dalam template halaman. Di sini, kita perlu mengimplementasikan dua metode: validateUser() dan loginButtonClicked(). Dalam validateUser(), kita menggunakan manajer otentikasi untuk memverifikasi apakan nama pengguna serta kata sandinya sudah benar. Jika benar, manajer otentikasi akan secara otomatis membuat sesi pengguna dengan informasi identitas pengguna terkait. +

+ + +class LoginUser extends TPage +{ + /** + * Validates whether the username and password are correct. + * This method responds to the TCustomValidator's OnServerValidate event. + * @param mixed event sender + * @param mixed event parameter + */ + public function validateUser($sender,$param) + { + $authManager=$this->Application->getModule('auth'); + if(!$authManager->login($this->Username->Text,$this->Password->Text)) + $param->IsValid=false; // beritahu validator bawa validasi gagal + } + + /** + * Redirects the user's browser to appropriate URL if login succeeds. + * This method responds to the login button's OnClick event. + * @param mixed event sender + * @param mixed event parameter + */ + public function loginButtonClicked($sender,$param) + { + if($this->Page->IsValid) // semua validasi sukses + { + // Dapatkan URL pada halaman istimewa yang diinginkan pengguna yang akan dikunjungi + $url=$this->Application->getModule('auth')->ReturnUrl; + if(empty($url)) // pengguna mengakses halaman masuk secara langsung + $url=$this->Service->DefaultPageUrl; + $this->Response->redirect($url); + } + } +} + + + +

Pengujian

+ +

+Kita telah membuat halaman LoginUser. Kita dapat mengujinya dengan mengunjungi URL http://hostname/blog/index.php?page=users.LoginUser. Ingat dalam subbagian Membuat Database, kita sudah membuat dua akun pengguna (username/password): admin/demo dan demo/demo. Kita dapat menggunakannya untuk menguji halaman masuk kita. +

+ + + +

Menambahkan Link Login/Logout ke Master

+ +

+Guna melengkapi cara langsung bagi pengguna untuk masuk dan keluar, kita memodifikasi sedikit kontrol master MainLayout. Dalam keadaan tertentu, kita menambahkan hiperlink "login" yang mengaitkan halaman LoginUser. Kita juga menambahkan tombol link "logout" yang mengeluarkan pengguna saat ia diklik. +

+ +

+Kita memodifikasi bagian footer dari template MainLayout sebagai berikut. Penampakan "login" dan "logout" ditentukan berdasarkan status pengguna. Jika pengguna belum masuk, misalnya $this->User->IsGuest adalah true, link "login" terlihat sementara link "logout" tidak; dan begitu sebaliknya. +

+ + + + + +

+Karena tombol "logout" menempelkan event OnClick dengan metode yang dipanggil logoutButtonClicked(), kita juga perlu mengubah file kelas MainLayout. +

+ + +class MainLayout extends TTemplateControl +{ + /** + * Logs out a user. + * This method responds to the "logout" button's OnClick event. + * @param mixed event sender + * @param mixed event parameter + */ + public function logoutButtonClicked($sender,$param) + { + $this->Application->getModule('auth')->logout(); + $url=$this->Service->constructUrl($this->Service->DefaultPage); + $this->Response->redirect($url); + } +} + + +

+Sekarang jika kita mengunjungi setiap halaman pada sistem blog kita, kita akah melihat apakah ada link di bawah halaman. Link menampilkan "Login" jika kita belum masuk dan "Logout" jika telah masuk. Jika kita mengklik pada "Logout", browser akan mengalihkannya ke homepage dan "Login" ditampilkan yang berarti kita sudah dikeluarkan. +

+ +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day3/id/CreateNewUser.page b/demos/blog-tutorial/protected/pages/Day3/id/CreateNewUser.page new file mode 100644 index 00000000..905f7489 --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day3/id/CreateNewUser.page @@ -0,0 +1,210 @@ + + +

Membuat Halaman NewUser

+ +

+Halaman NewUser disediakan untuk pengguna administrator guna membuat akun pengguna baru. Ini perlu menampilkan sebuah formulir yang mengumpulkan informasi mengenai akun pengguna baru. Berdasarkan definisi database, kita akan perlu mengumpulkan informasi berikut: +

+ + + +

+Kita membuat dua file protected/pages/users/NewUser.page dan protected/pages/users/NewUser.php masing-masing untuk menyimpan template halaman dan kelas halaman. +

+ +

Membuat Template Halaman

+

+Berdasarkan pada analisis di atas, kita menulis template halaman seperti berikut: +

+ + +<%@ Title="My Blog - New User" %> + +<com:TContent ID="Main"> + +

Create New User

+ +Username: +<com:TRequiredFieldValidator + ControlToValidate="Username" + ErrorMessage="Please provide a username." + Display="Dynamic" /> +<com:TCustomValidator + ControlToValidate="Username" + ErrorMessage="Sorry, your username is taken by someone else. Please choose another username." + OnServerValidate="checkUsername" + Display="Dynamic" /> +
+<com:TTextBox ID="Username" /> + +
+Password: +<com:TRequiredFieldValidator + ControlToValidate="Password" + ErrorMessage="Please provide a password." + Display="Dynamic" /> +
+<com:TTextBox ID="Password" TextMode="Password" /> + +
+Re-type Password: +<com:TCompareValidator + ControlToValidate="Password" + ControlToCompare="Password2" + ErrorMessage="Your password entries did not match." + Display="Dynamic" /> +
+<com:TTextBox ID="Password2" TextMode="Password" /> + +
+Email Address: +<com:TRequiredFieldValidator + ControlToValidate="Email" + ErrorMessage="Please provide your email address." + Display="Dynamic" /> +<com:TEmailAddressValidator + ControlToValidate="Email" + ErrorMessage="You entered an invalid email address." + Display="Dynamic" /> +
+<com:TTextBox ID="Email" /> + +
+Role: +
+<com:TDropDownList ID="Role"> + <com:TListItem Text="Normal User" Value="0" /> + <com:TListItem Text="Administrator" Value="1" /> +</com:TDropDownList> + +
+First Name: +
+<com:TTextBox ID="FirstName" /> + +
+Last Name: +
+<com:TTextBox ID="LastName" /> + +
+<com:TButton Text="Create" OnClick="createButtonClicked" /> + +</com:TContent> +
+ +

+Template tidak jauh berbeda dari template Contact dan halaman LoginUser. Sebagian besar terdiri dari kotak teks dan validator. Beberapa kotak teks, seperti nama pengguna, dikaitkan dengan dua validator karena keterlibatan aturan multipel validasi. +

+ + +

Membuat Kelas Halaman

+ +

+Dari template halaman di atas, kita melihat bahwa kita perlu untuk menulis sebuah kelas halaman yang mengimplementasikan dua pengendali event: checkUsername() (disertakan ke event validator kustom OnServerValidate) dan createButtonClicked() (disertakan ke event tombol "create" OnClick). Oleh karena itu, kita menulis kelas halaman seperti berikut: +

+ + +class NewUser extends TPage +{ + /** + * Memeriksa apakah nama pengguna sudah ada dalam database. + * Metode ini merespon ke event OnServerValidate pada validator kustom nama pengguna. + * @param mixed event sender + * @param mixed event parameter + */ + public function checkUsername($sender,$param) + { + // benar jika nama pengguna tidak ditemukan dalam database + $param->IsValid=UserRecord::finder()->findByPk($this->Username->Text)===null; + } + + /** + * Membuat akun pengguna baru jika semua input benar. + * Metode ini merespon ke event OnClick pada tombol "create". + * @param mixed event sender + * @param mixed event parameter + */ + public function createButtonClicked($sender,$param) + { + if($this->IsValid) // ketika semua validasi sukses + { + // populasikan obyek UserRecord dengan input pengguna + $userRecord=new UserRecord; + $userRecord->username=$this->Username->Text; + $userRecord->password=$this->Password->Text; + $userRecord->email=$this->Email->Text; + $userRecord->role=(int)$this->Role->SelectedValue; + $userRecord->first_name=$this->FirstName->Text; + $userRecord->last_name=$this->LastName->Text; + + // simpan database melalui mekanisme Rekaman Aktif + $userRecord->save(); + + // alihkan browser ke homepage + $this->Response->redirect($this->Service->DefaultPageUrl); + } + } +} + + +

+Dalam kode di atas, memanggil save() akan menyisipkan baris baru dalam tabel users. Fitur intuitif ini dihidupkan oleh Rekaman Aktif. +

+ + +Untuk memudahkan, nama pengguna dalam sistem blg kita adalah tidak sensitif-huruf! Dalam banyak sistem praktis, nama pengguna mungkin perlu sensitif-huruf. Maka penanganan khusus perlu dibuat saat pembuatan akun pengguna baru dan juga melakukan otentikasi. Juga, ruang kosong dalam nama pengguna perlu dipotong ketika membuat akun baru dengan itu. + + + +

Pengujian

+

+Untuk menguji halaman NewUser, kunjungi URL http://hostname/blog/index.php?page=users.NewUser. Kita akan melihat output halaman berikut. Coba masukan informasi berbeda ke dalam formulir dan lihat bagaimana input divalidasi. Jika semua aturan validasi memuaskan, kita akan mengharapkan akun pengguna dibuat dan browser dialihkan ke homepage. +

+ + + + +

Menambahkan Pemeriksaan Perijinan

+

+Selama pengujian, anda mungkin bertanya: apakah halaman NewUser seharusnya hanya bisa diakses oleh pengguna administrator? Ya, ini disebut otorisasi. Sekarang kami menjelaskan bagaimana kita menambahkan pemeriksaan perijinan ini ke halaman NewUser. +

+ +

+Cara langsung pada pemeriksaan perijinan adalah dalam kelas halaman di mana kita memeriksa apakah $this->User->IsAdmin adalah true, dan jika tidak, kita mengalihkan browser ke halaman LoginUser. +

+ +

+PRADO menawarkan cara lebih sistematis terhadap pemeriksaan perijinan akses halaman. Untuk melakukannyaTo , kita perlu menggunakan konfigurasi halaman. Membuat sebuah file protected/pages/users/config.xml dengan konten seperti berikut: +

+ + + + + + + + + + + +

+Konfigurasi halaman berisi aturan otorisasi yang berlaku untuk halaman di bawah direktori protected/pages/users. Konfigurasi di atas terbaca bahwa NewUser bisa diakses oleh para pengguna dengan aturan admin (lihat BlogUser.createUser() untuk alasan kenapa kata "admin"), dan menolak akses anonim (users="?" berarti pengguna tamu) untuk seluruh halaman di bawah direktori. +

+ +

+Sekarang jika kita mengunjungi halaman NewUser sebagai seorang tamu, kita akan dialihkan ke halaman LoginUser terlebih dahulu. Jika kita masuk dengan sukses, kita akan mengalihkan kembali ke halamanNewUser. +

+ + +Konfigurasi halaman dapat berisi lebih dari satu aturan otorisasi. Sebagai contoh, ia dapat menyertakan modul seperti yang ktia lakukan dalam konfigurasi aplikasi. Untuk aplikasi PRADO, setiap direktori halaman dapat mempunyai konfigurasi halaman yang berlaku bagi halaman dalam direktori yang sama dan seluruh subdirektorinya. + + +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day3/id/Overview.page b/demos/blog-tutorial/protected/pages/Day3/id/Overview.page new file mode 100644 index 00000000..62c29438 --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day3/id/Overview.page @@ -0,0 +1,26 @@ + + +

Tinjauan Manajemen Pengguna

+ +

+Dalam bagian ini, kita membuat halaman yang terkait dengan manajemen pengguna. Dalam keadaan tertentu, kita mengimplementasikan fitur yang dibutuhkan ini: pengguna masuk/keluar, membuat akun pengguna baru dan memutakhirkan/menghapus akun pengguna. +

+ +

+Berdasarkan kebutuhan, kita perlu membuat halaman berikut. Guna mengatur lebih baik kode kita, halaman terkait-pengguna ini akan dibuat di bawah direktori baru protected/pages/users. +

+ + + +

+Setelah menyelesaikan bagian ini, kita mengharapkan bisa melihat direktori dan file berikut: +

+ + + +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day3/id/directories.gif b/demos/blog-tutorial/protected/pages/Day3/id/directories.gif new file mode 100644 index 00000000..f59fda58 Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day3/id/directories.gif differ diff --git a/demos/blog-tutorial/protected/pages/Day3/id/output.gif b/demos/blog-tutorial/protected/pages/Day3/id/output.gif new file mode 100644 index 00000000..0d812dd0 Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day3/id/output.gif differ diff --git a/demos/blog-tutorial/protected/pages/Day3/id/output2.gif b/demos/blog-tutorial/protected/pages/Day3/id/output2.gif new file mode 100644 index 00000000..749255d6 Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day3/id/output2.gif differ diff --git a/demos/blog-tutorial/protected/pages/Day3/id/output3.gif b/demos/blog-tutorial/protected/pages/Day3/id/output3.gif new file mode 100644 index 00000000..a11ee653 Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day3/id/output3.gif differ diff --git a/demos/blog-tutorial/protected/pages/Day4/id/CreateEditPost.page b/demos/blog-tutorial/protected/pages/Day4/id/CreateEditPost.page new file mode 100644 index 00000000..b7ded3b3 --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day4/id/CreateEditPost.page @@ -0,0 +1,133 @@ + + +

Membuat Halaman EditPost

+ +

+Halaman EditPost disediakan bagi para pembuat dan administrator untuk mengedit tulisan blog yang sudah ada. Seperti halaman NewPost , ia menampilkan sebuah formulir untuk mengumpulkan perubahan terhadap judul dan konten tulisan. +

+ +

+Kita membuat dua file protected/pages/posts/EditPost.page dan protected/pages/posts/EditPost.php masing-masing untuk menyimpan template halaman dan kelas halaman. +

+ +

Membuat Template Halaman

+

+Template halaman EditPost sangat mirip dengan template NewPost. Hanya judul halaman dan tombol yang berbeda. +

+ + +<%@ Title="My Blog - Edit Post" %> + +<com:TContent ID="Main"> + +

Edit Post

+ +Title: +<com:TRequiredFieldValidator + ControlToValidate="TitleEdit" + ErrorMessage="Please provide a title." + Display="Dynamic" /> +
+<com:TTextBox ID="TitleEdit" Columns="50" /> + +
+Content: +<com:TRequiredFieldValidator + ControlToValidate="ContentEdit" + ErrorMessage="Please provide content." + Display="Dynamic" /> +
+<com:THtmlArea ID="ContentEdit" /> + +
+<com:TButton Text="Save" OnClick="saveButtonClicked" /> + +</com:TContent> +
+ + +

Membuat Kelas Halaman

+ +

+Kelas halaman EditPage lebih kompleks dibanding NewPage karena ia perlu mengambil data tulisan yang ditetapkan terlebih dulu. Ia juga perlu melakukan pemeriksaan otorisasi tambahan. Ada kalanya ia perlu memastikan bahwa tulisan hanya bisa diedit oleh pembuat atau administrator. Pemeriksaan otorisasi sudah disediakan oleh PRADO. +

+ + +class EditPost extends TPage +{ + /** + * Menginisialisasi input dengan data tulisan yang sudah ada. + * Metode ini dipanggil oleh kerangka kerja saat halaman diinisialisasi. + * @param parameter event campuran + */ + public function onInit($param) + { + parent::onInit($param); + // Menambil data pengguna yang sudah ada. Ini sama dengan: + // $postRecord=$this->getPost(); + $postRecord=$this->Post; + // Pemeriksaan otorisasi: hanya pembuat atau administrator dapat mengedit tulisan + if($postRecord->author_id!==$this->User->Name && !$this->User->IsAdmin) + throw new THttpException(500,'You are not allowed to edit this post.'); + + if(!$this->IsPostBack) // jika halaman pertama kali diminta + { + // Mempopulasikan kontrol input dengan data tulisan yang sudah ada + $this->TitleEdit->Text=$postRecord->title; + $this->ContentEdit->Text=$postRecord->content; + } + } + + /** + * Menyimpan tulisan jika semua input sudah benar. + * Metode ini merespon event OnClick pada tombol "Save". + * @param pengirim event campuran + * @param parameter event campuran + */ + public function saveButtonClicked($sender,$param) + { + if($this->IsValid) // jika semua validasi sukses + { + // Mengambil data pengguna yang sudah ada. Ini sama dengan: + // $postRecord=$this->getPost(); + $postRecord=$this->Post; + + // Mengambil data input + $postRecord->title=$this->TitleEdit->SafeText; + $postRecord->content=$this->ContentEdit->SafeText; + + // menyimpan ke database via mekanisme Rekaman Aktif + $postRecord->save(); + + // mengalihkan browser ke halaman ReadPost + $url=$this->Service->constructUrl('posts.ReadPost',array('id'=>$postRecord->post_id)); + $this->Response->redirect($url); + } + } + + /** + * Mengembalikan data tulisan yang akan diedit. + * @return PostRecord data tulisan yang akan diedit. + * @throws THttpException jika data tulisan tidak ada. + */ + protected function getPost() + { + // ID tulisan yang diedit dikirimkan via parameter GET 'id' + $postID=(int)$this->Request['id']; + // gunakan Rekaman Aktif untuk mencari ID tulisan tertentu + $postRecord=PostRecord::finder()->findByPk($postID); + if($postRecord===null) + throw new THttpException(500,'Post is not found.'); + return $postRecord; + } +} + + +

Pengujian

+

+Untuk menguji halaman EditPost, masuk lebih dulu dan kemudian kunjungi URL berikut: http://hostname/blog/index.php?page=EditPost&id=1. URL ini juga bisa dijangkau dengan mengklik link Edit pada halaman rician tulisan. +

+ + + +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day4/id/CreateListPost.page b/demos/blog-tutorial/protected/pages/Day4/id/CreateListPost.page new file mode 100644 index 00000000..d682535e --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day4/id/CreateListPost.page @@ -0,0 +1,185 @@ + + +

Membuat Halaman ListPost

+ +

+Halaman ListPost menampilkan tulisan blog terakhir dalam sebuah daftar. Jika di sana terlalu banyak tulisan, maka akan ditampilkan dalam beberapa lembar halaman. +

+ +

+Sebelum kita berlanjut dengan implementasi, kita ingin mengarahkan homepage kita ke halaman ListPage mendatang, karena kita ingin para pengguna melihat tulisan terakhir saat mereka menyentuh website. Untuk melakukannya, kita mengubah konfigurasi aplikasi protected/application.xml sebagai berikut, +

+ + +...... + + + + + + + +

+Sekarang kita membuat file template dan kelas untuk halaman ListPost: protected/pages/posts/ListPost.page dan protected/pages/posts/ListPost.php. +

+ +

Membuat Template Halaman

+

+Berdasarkan pada kebutuhan fungsionalitas halaman ListPost, kita akan menggunakan dua kontrol dalam template halaman: +

+ + +

+Di bawah ini adalah konten dalam template halaman: +

+ + +<%@ Title="My Blog" %> + +<com:TContent ID="Main"> + +<com:TRepeater ID="Repeater" + ItemRenderer="Application.pages.posts.PostRenderer" + AllowPaging="true" + AllowCustomPaging="true" + PageSize="5" + /> + +<com:TPager ControlToPaginate="Repeater" OnPageIndexChanged="pageChanged" /> + +</com:TContent> + + +

+Dalam pengulang, kita menetapkan bahwa konten yang diulang ditampilkan menggunakan penyaji item PostRenderer yang akan kita buat nantinya. Agar PRADO bisa menemukan kelas ini, kita memberikan namespace Application.pages.posts.PostRenderer, berarti file kelasnya adalah protected/pages/posts/PostRenderer.php. +

+ +

+Kita juga menyetel beberapa properti lain pada pengulang untuk menghidupkan lembaran halaman. Dan kita menyetel properti ControlToPaginate pada lembaran agar ia mengetahui konten mana yang diulang harus dibuat lembaran. +

+ + +

Membuat Kelas Halaman

+ +

+Dari template halaman di atas, kita melihat bahwa kita perlu menulis kelas halaman yang mengimplementasikan pengendali event: pageChanged() (ditempelkan ke event lembaran OnPageIndexChanged). Kita juga perlu mempopulasikan data tulisan ke dalam pengulang berdasarkan pada setelan lembaran saat ini. Berikut ini adalah kode sumber lengkap kelas halaman: +

+ + +class ListPost extends TPage +{ + /** + * Menginisialisasi pengulang. + * Metode ini dipanggil oleh kerangka kerja saat menginisialisasi halaman + * @param mixed event parameter + */ + public function onInit($param) + { + parent::onInit($param); + if(!$this->IsPostBack) // jika halaman diminta pertama kali + { + // ambil jumlah total tulisan yang tersedia + $this->Repeater->VirtualItemCount=PostRecord::finder()->count(); + // populasikan data tulisan ke dalam pengulang + $this->populateData(); + } + } + + /** + * Pengendali event untuk event OnPageIndexChanged pada lembaran. + * Metode ini dipanggil saat pengguna mengklik tombol halaman + * dan kemudian mengubah halaman tulisan yang ditampilkan. + */ + public function pageChanged($sender,$param) + { + // ubah indeks halaman sekarang ke yang baru + $this->Repeater->CurrentPageIndex=$param->NewPageIndex; + // re-populasi data ke dalam pengulang + $this->populateData(); + } + + /** + * Menentukan halaman tulisan mana yang ditampilkan dan + * mempopulasi pengulang dengan data yang sudah diambil. + */ + protected function populateData() + { + $offset=$this->Repeater->CurrentPageIndex*$this->Repeater->PageSize; + $limit=$this->Repeater->PageSize; + if($offset+$limit>$this->Repeater->VirtualItemCount) + $limit=$this->Repeater->VirtualItemCount-$offset; + $this->Repeater->DataSource=$this->getPosts($offset,$limit); + $this->Repeater->dataBind(); + } + + /** + * Mengambil tulisan dari database dengan ofset dan limit. + */ + protected function getPosts($offset, $limit) + { + // Bentuk kriteria query + $criteria=new TActiveRecordCriteria; + $criteria->OrdersBy['create_time']='desc'; + $criteria->Limit=$limit; + $criteria->Offset=$offset; + // query untuk tulisan dengan kriteria di atas dan informasi pembuat + return PostRecord::finder()->withAuthor()->findAll($criteria); + } +} + + +

Membuat PostRenderer

+ +

+Kita masih perlu untuk membuat kelas penyaji item PostRenderer. Ia mendefinisikan bagaimana setiap tulisan harus ditampilkan dalam pengulang. Kita membuatnya sebagai kontrol template yang membolehkan kita untuk menetapkan penyajian tulisan menggunakan sintaks template fleksibel kita. Template dan file kelas masing-masing disimpan sebagai PostRenderer.tpl dan PostRenderer.php di bawah direktori protected/pages/posts. +

+ +

Membuat Template Penyaji

+

+Template penyaji menetapkan penyajian berbagai field dalam sebuah tulisan, termasuk judul, nama pembuat, waktu penulisan dan kontennya. Kita me-link judul tulisan ke ReadPost yang menampilkan lebih rinci atas tulisan yang dipilih. +

+

+Ekspresi $this->Data merujuk ke item data yang dikirimkan ke pengulang. Dalam kasus kita, ia adalah obyek PostRecord. Perhatikan bagaimana kita mengambil nama pembuat pada tulisan dengan $this->Data->author->username. +

+ + +
+

+<com:THyperLink Text="<%# $this->Data->title %>" + NavigateUrl="<%# $this->Service->constructUrl('posts.ReadPost',array('id'=>$this->Data->post_id)) %>" /> +

+ +

+Author: +<com:TLiteral Text="<%# $this->Data->author->username %>" />
+Time: +<com:TLiteral Text="<%# date('m/d/Y h:m:sa', $this->Data->create_time) %>" /> +

+ +

+<com:TLiteral Text="<%# $this->Data->content %>" /> +

+
+
+ +

Membuat Kelas Penyaji

+

+Kelas penyaji sangat sederhana. Ia diperluas dari TRepeaterItemRenderer dan tidak berisi kode apapun. +

+ +class PostRenderer extends TRepeaterItemRenderer +{ +} + + +

Pengujian

+

+Untuk menguji halaman ListPost, kunjungi URL http://hostname/blog/index.php (ingat kita telah menyetel ListPost sebagai homepage baru kita). Kita akan melihat hasil seperti berikut. Karena kita hanya mempunyai satu tulisan saat ini, lembaran tidak akan muncul. Nantinya ketika menyelesaikan NewPost, kita dapat menambah tulisan lebih banyak dan datang kembali untuk menguji lembaran halaman lagi. +

+ + + +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day4/id/CreateNewPost.page b/demos/blog-tutorial/protected/pages/Day4/id/CreateNewPost.page new file mode 100644 index 00000000..68dcde44 --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day4/id/CreateNewPost.page @@ -0,0 +1,136 @@ + + +

Membuat Halaman NewPost

+ +

+Halaman NewPost disediakan untuk mengotentikasi pengguna untuk pembuatan tulisan blog baru. Ia perlu untuk menampilkan formulir yang mengumpulkan informasi mengenai tulisan baru, termasuk judul tulisan dan konten badan tulisan. +

+ +

+Karena NewPost hanya bisa diakses oleh pengguna terotentikasi, kita menambahkan file konfigurasi config.xml di bawah direktori protected/pages/posts. Konfigurasi menetapkan bahwa para pengguna tidak bisa mengakses NewPost dan EditPost yang akan diperkenalkan dalam bagian berikutnya. +

+ + + + + + + + + + +

+Karena jumlah halaman kita berkembang, kita ingin memodifikasi MainLayout agar dalam footer pada halaman blog kita ada link ke berbagai halaman, termasuk homepage, halaman NewUser (hanya terlihat oleh administrator), dan halaman NewPost mendatang (hanya terlihat oleh pengguna terotentikasi). +

+ + + + + +

+Sekarang kita membuat dua file protected/pages/posts/NewPost.page dan protected/pages/posts/NewPost.php masing-masing untuk menyimpan template halaman dan kelas halaman. +

+ +

Membuat Template Halaman

+

+Template halaman NewPost berisi TTextBox untuk mengumpulkan judul tulisan dan THtmlArea untuk mengumpulkan konten tulisan. Yang terakhir adalah editor HTML WYSIWYG. Guna memastikan bahwa input pengguna sudah benar, kita mengaitkan validator dengan kontrol input ini. +

+ + +<%@ Title="My Blog - New Post" %> + +<com:TContent ID="Main"> + +

Create New Post

+ +Title: +<com:TRequiredFieldValidator + ControlToValidate="TitleEdit" + ErrorMessage="Please provide a title." + Display="Dynamic" /> +
+<com:TTextBox ID="TitleEdit" Columns="50" /> + +
+Content: +<com:TRequiredFieldValidator + ControlToValidate="ContentEdit" + ErrorMessage="Please provide content." + Display="Dynamic" /> +
+<com:THtmlArea ID="ContentEdit" /> + +
+<com:TButton Text="Create" OnClick="createButtonClicked" /> + +</com:TContent> +
+ + +

Membuat Kelas Halaman

+ +

+Dari template halaman di atas, kita melihat bahwa sebagian besar kita perlu menulis sebuah kelas halaman yang mengimplementasikan pengendali event: createButtonClicked() (ditempelkan ke tombo Create dalam event OnClick). +

+ + +class NewPost extends TPage +{ + /** + * Membuat tulisan baru jika semua input benar. + * Metode ini merespon event OnClick pada tombol "create". + * @param mixed event sender + * @param mixed event parameter + */ + public function createButtonClicked($sender,$param) + { + if($this->IsValid) // bila semua validasi sukses + { + // populasikan obyek PostRecord dengan input pengguna + $postRecord=new PostRecord; + // menggunakan SafeText datipada Text guna menghindari serangan Penaskahan Situs Silang + $postRecord->title=$this->TitleEdit->SafeText; + $postRecord->content=$this->ContentEdit->SafeText; + $postRecord->author_id=$this->User->Name; + $postRecord->create_time=time(); + $postRecord->status=0; + + // simpan ke database lewat mekanisme Rekaman Aktif + $postRecord->save(); + + // alihkan browser ke halaman tulisan yang baru dibuat + $url=$this->Service->constructUrl('posts.ReadPost',array('id'=>$postRecord->post_id)); + $this->Response->redirect($url); + } + } +} + + +

Pengujian

+

+Untuk menguji halaman NewPost, masuk lebih dulu dan klik pada link tombol New Post dalam footer pada homepage. Browser kita akan menampilkan hasil berikut dengan URL http://hostname/blog/index.php?page=NewPost. +

+ + +Ketika anda mengunjungi halaman NewPost untuk pertama kali, anda bisa melihat bahwa ia memerlukan beberapa detik sebelum halaman ditampilkan. Ini dikarenakan PRADO perlu mengurai dan mempublikasikan kode javascript dan gambar untuk kontrol THtmlArea yang dipakai dalam halaman. Ini dikerjakan sekali dan untuk semuanya. + + + +Untuk menguji fitur lembaran yang kita kembangkan untuk halaman ListPost, kita dapat membuat lima atau lebih tulisan dan melihat apa yang terjadi pada homepage. Lembar dalam ListPost menampilkan lima tulisan setiap halamannya. + + + + +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day4/id/CreateReadPost.page b/demos/blog-tutorial/protected/pages/Day4/id/CreateReadPost.page new file mode 100644 index 00000000..83c059e7 --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day4/id/CreateReadPost.page @@ -0,0 +1,135 @@ + + +

Membuat Halaman ReadPost

+ +

+Halaman ReadPost menampilkan rincian konten tulisan blog. Untuk para pengguna yang diotorisasi, akan ditampilkan tombol link yang membolehkan mereka untuk mengedit atau menghapus tulisan. +

+ +

+Kita membuat dua file protected/pages/posts/ReadPost.page dan protected/pages/posts/ReadPost.php masing-masing untuk menyimpan template halaman dan kelas halaman. +

+ +

Membuat Template Halaman

+

+Template halaman ReadPost sangat mirip dengan template PostRenderer, keduanya menyajikan konten tulisan. Perbedaannya adalah bahwa ReadPost perlu menampilkan dua tombol link ketika pengguna saat ini diotorisasi untuk mengedit atau menghapus tulisan. +

+ + +<com:TContent ID="Main"> + +

+<com:TLiteral Text="<%= $this->Post->title %>" /> +

+ +<com:TControl Visible="<%= $this->canEdit() %>"> + Edit | + <com:TLinkButton Text="Delete" + OnClick="deletePost" + Attributes.onclick="javascript:if(!confirm('Are you sure?')) return false;" /> +</com:TControl> + +

+Author: +<com:TLiteral Text="<%= $this->Post->author->username %>" />
+Time: +<com:TLiteral Text="<%= date('m/d/Y h:m:sa', $this->Post->create_time) %>" /> +

+ +

+<com:TLiteral Text="<%= $this->Post->content %>" /> +

+ +</com:TContent> +
+ +

+Banyak ekspresi PHP dipakai dalam template di atas. Ekspresi $this->Post merujuk ke properti yang didefinisikan dalam kelas halaman ReadPost. Ia mewakili obyek PostRecord yang terkait dengan tulisan yang saat ini sedang dilihat. +

+ + +Meskipun sebagian besar kita menggunakan ekspresi dalam template, we do not overuse them. A major guideline in determining whether we should use an expression in a template is that the expression should be a property or a simple presentational transformation of the property. By following this guideline, we ensure content and presentation are well separated without losing sufficient flexibility. + + +

+Kita juga mencatatan dalam template di atas bahwa dua link tombol dikurung di dalam TControl yang penampakannya ditentukan oleh ekspresi $this->canEdit(). Untuk link tombol Delete, kita menggunakan dialog konfirmasi javascript untuk memperoleh konfirmasi pengguna saat ia mengklik untuk menghapus tulisan. +

+ + +Seluruh kontrol PRADO mempunyai properti yang sangat berguna bernama Attributes yang dapat menerima pasangan nama-nilai bebas. Kebanyakan kontrol PRADO akan menyajikan pasangan nama-nilai dalam Attributes secara literal terkait tag HTML. Sebagai contoh, daam link tombol Delete di atas, kita mendefinisikan sebuah onclick yang disajikan sebagai atribut onclick yang menghasilkan tag <a>. + + + +

Membuat Kelas Halaman

+ +

+Dari template halaman di atas, kita melihat bahwa kita perlu menulis kelas halaman yang mengimplementasikan pengendali event: deletePost() (ditempelkan ke tombol Delete dalam event OnClick). Kita juga perlu untuk mengambil data tulisan yang ditetapkan oleh ID tulisan melalui parameter GET id.

+ + +Kita mengimplementasikan fitur penghapusan tulisan dalam halaman ReadPost karena ini sangat alami untuk melakukannya di sini. Ketika pengguna mengklik pada tombol Delete, dialog konfirmasi javascript akan muncul. Jika pengguna mengkonfirmasinya, penghapusan akan dibawa dalam respon terhadap event OnClick dari tombol Delete. + + + +class ReadPost extends TPage +{ + private $_post; + /** + * Mengambil data tulisan. + * Metode ini dipanggil oleh kerangka kerja saat inisialisasi halaman + * @param mixed event parameter + */ + public function onInit($param) + { + parent::onInit($param); + // id tulisan dikirimkan via parameter GET 'id' + $postID=(int)$this->Request['id']; + // mengambil PostRecord dengan informasi pembuat terisi dalam + $this->_post=PostRecord::finder()->withAuthor()->findByPk($postID); + if($this->_post===null) // jika id tulisan tidak benar + throw new THttpException(500,'Unable to find the specified post.'); + // setel judul halaman sebagai judul tulisan + $this->Title=$this->_post->title; + } + + /** + * @return PostRecord yang saat ini sedang dilihat + */ + public function getPost() + { + return $this->_post; + } + + /** + * Menghapus tulisan yang saat ini sedang dilihat + * Metode ini dipanggil saat pengguna mengklik tombol "Delete" + */ + public function deletePost($sender,$param) + { + // hanya pembuat atau administrator bisa menghapus tulisan + if(!$this->canEdit()) + throw new THttpException('You are not allowed to perform this action.'); + // hapus dari DB + $this->_post->delete(); + // alihkan browser ke homepage + $this->Response->redirect($this->Service->DefaultPageUrl); + } + + /** + * @return boolean apakah pengguna saat ini bisa mengedit/menghapus tulisan yg sedang dilihat + */ + public function canEdit() + { + // hanya pembuat atau administrator bisa mengedi/menghapus tulisan + return $this->User->Name===$this->Post->author_id || $this->User->IsAdmin; + } +} + + +

Pengujian

+

+Untuk menguji halaman ReadPost, kunjungi URL http://hostname/blog/index.php dan klik pada judul tulisan. Browser kita akan menampilkan hasil berikut dengan URL http://hostname/blog/index.php?page=ReadPost&id=1. Catatan, jika kita tidak masuk, dua tombol link tidak akan terlihat. +

+ + + +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day4/id/Overview.page b/demos/blog-tutorial/protected/pages/Day4/id/Overview.page new file mode 100644 index 00000000..3427e11f --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day4/id/Overview.page @@ -0,0 +1,26 @@ + + +

Tinjauan Manajemen Tulisan

+ +

+Pada bagian ini, kita membuat halaman yang terkait dengan manajemen tulisan. Dalam keadaan tertentu, kita mengimplementasikan operasi CRUD (Create-Retrieve-Update-Delete) dengan memperhatikan tulisan blog. +

+ +

+Berdasarkan pada kebutuhan, kita perlu membuat halaman berikut yang diatur di bawah direktori baru protected/pages/posts. +

+ + + +

+Setelah menyelesaikan bagian ini, kita akan mengharapkan untuk melihat direktori dan file berikut: +

+ + + +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day4/id/directories.gif b/demos/blog-tutorial/protected/pages/Day4/id/directories.gif new file mode 100644 index 00000000..5ba55184 Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day4/id/directories.gif differ diff --git a/demos/blog-tutorial/protected/pages/Day4/id/output.gif b/demos/blog-tutorial/protected/pages/Day4/id/output.gif new file mode 100644 index 00000000..8c1caea8 Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day4/id/output.gif differ diff --git a/demos/blog-tutorial/protected/pages/Day4/id/output2.gif b/demos/blog-tutorial/protected/pages/Day4/id/output2.gif new file mode 100644 index 00000000..7078e6c6 Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day4/id/output2.gif differ diff --git a/demos/blog-tutorial/protected/pages/Day4/id/output3.gif b/demos/blog-tutorial/protected/pages/Day4/id/output3.gif new file mode 100644 index 00000000..ff1834a4 Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day4/id/output3.gif differ diff --git a/demos/blog-tutorial/protected/pages/Day4/id/output4.gif b/demos/blog-tutorial/protected/pages/Day4/id/output4.gif new file mode 100644 index 00000000..b1208a0d Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day4/id/output4.gif differ diff --git a/demos/blog-tutorial/protected/pages/Day5/id/ErrorLogging.page b/demos/blog-tutorial/protected/pages/Day5/id/ErrorLogging.page new file mode 100644 index 00000000..9d69f1dd --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day5/id/ErrorLogging.page @@ -0,0 +1,159 @@ + + +

Penanganan Kesalahan dan Pencatatan

+ +

+Jika kita mencoba mengakses URL http://hostname/blog/index.php?page=EditPost&id=100, kita akan melihat halaman kesalahan berikut karena tulisan dengan ID 100 belum ada dalam sistem blog kita. Kita ingin mengkustomisasi halaman kesalahan ini agar ia terlihat lebih konsisten dengan tata letak halaman blog lain. Kita juga ingin mencatat jenis kesalahan ini untuk mempelajari kebiasaan pengguna. Dalam bagian ini, kita akan melaksanakan dua tugas ini. +

+ + + + +Tugas penting dalam aplikasi Web adalah penanganan kesalahan yang sering dikaitkan dengan pencatatan. Ada dua jenis kesalahan yang bisa terjadi dalam aplikasi PRADO: yang disebabkan oleh para pengembang dan yang disebabkan oleh pengguna-akhir. Pembentuk harus dipecahkan sebelum aplikasi dijadikan tahap produksi, sementara yang terakhir biasanya di dalam lingkup desain awal dan harus ditangani dengan baik (misalnya mencatat kesalahan dan menampilkan halaman khusus yang menginstruksikan pengguna-akhir apa yang harus dilakukan selanjutnya). PRADO mengimplementasikan kerangka kerja yang fleksibel serta bertenaga untuk menangani kesalahan dan pencatatan. + + + +

Mengkustomisasi Penanganan Kesalahan

+ +

+PRADO secara implisit mengambil modul TErrorHandler untuk menangani kesalahan. Kita ingin mengkustomisasi modul ini agar sistem blog kita dapat menampilkan halaman terkustomisasi untuk kesalahan yang disebabkan oleh pengguna-akhir. Selanjutnya memodifikasi konfigurasi aplikasi seperti berikut: +

+ + +...... + + ...... + + ...... + +...... + + +

+Kelas BlogErrorHandler seperti ditetapkan di atas adalah modul pengendali kesalahan baru as yang akan dibuat berikutnya. Ia memperluas dan mengganti modul standar TErrorHandler. +

+ +

+Kita membuat sebuah file bernama protected/BlogErrorHandler.php seperti berikut. Kelas BlogErrorHandler mengganti dua metode TErrorHandler: +

+ + +Prado::using('System.Exceptions.TErrorHandler'); +Prado::using('Application.BlogException'); + +class BlogErrorHandler extends TErrorHandler +{ + /** + * Mengambil template yang dipakai untuk menampilkan eksepsi eksternal. + * Metode ini mengganti implementasi leluhurnya. + */ + protected function getErrorTemplate($statusCode,$exception) + { + // gunakan template sendiri untuk BlogException + if($exception instanceof BlogException) + { + // ddapatkan path file template kesalahan: protected/error.html + $templateFile=Prado::getPathOfNamespace('Application.error','.html'); + return file_get_contents($templateFile); + } + else // sebaliknya gunakan template yang didefinisikan oleh PRADO + return parent::getErrorTemplate($statusCode,$exception); + } + + /** + * Menangani kesalahan eksternal yang disebabkan oleh pengguna-akhir. + * Metode ini mengganti implementasi leluhurnya. + * Ini dipanggil oleh PRADO saat eksepsi eksternal dikeluarkan. + */ + protected function handleExternalError($statusCode,$exception) + { + // catat kesalahan (hanya untuk BlogException) + if($exception instanceof BlogException) + Prado::log($exception->getErrorMessage(),TLogger::ERROR,'BlogApplication'); + // panggil implementasi leluhur untuk menampilkan kesalahan + parent::handleExternalError($statusCode,$exception); + } +} + + +

+Dalam kode di atas, kita menetapkan bahwa saat BlogException dikeluarkan, kita menggunakan template baru protected/error.html untuk menampilkan kesalahan. Oleh karena itu, kita perlu membuat kelas BlogException dan mengganti semua THttpException yang ada dalam kode kita (seperti misalnya EditUser dan halaman ReadPost). Kita juga perlu membuat template kesalahan protected/error.html. Kelas BlogException memperluas THttpException dan kosong. File kelas disimpan sebagai protected/BlogException.php. + +

+ + +class BlogException extends THttpException +{ +} + + +

+Di bawah ini konten dalam template kesalahan kita protected/error.html. Catatan, template bukan template PRADO karena ia hanya mengenal jumlah token yang sangat terbatas, seperti %%ErrorMessage%%, %%ServerAdmin%%. +

+ + + + +%%ErrorMessage%% + + +
+ +
+

%%ErrorMessage%%

+

+The above error happened when the server was processing your request. +

+

+If you think this is a server error, please contact the webmaster. +

+
+ + + + + +

Mencatat Kesalahan

+ +

+Dalam metode handleExternalError() pada BlogErrorHandler, kita memanggil Prado::log() untuk mencatat kesalahan jika tipenya adalah BlogException. Kesalahan dicatat dalam memori. Untuk menyimpan catatan ke dalam medium permanen seperti file atau database, kita perlu menghidupkan rute pencatatan kesalahan yang sesuai. Ini dikerjakan dalam konfigurasi aplikasi seperti berikut: +

+ + +...... + + ...... + + + + ...... + +...... + + +

+Dalam konfigurasi di atas, kita menambahkan rute log yang menyimpan catatan ke dalam sebuah file. Kita juga menetapkan filter kategori sebagai BlogApplication agar hanya mencatat pesan pada kategori yang dipilih yang disimpan. Ini membantu mengurangi ukuran file catatan dan juga meningkatkan pembacaannya. +

+ +

Pengujian

+

+Untuk melihat bagaimana sistem blog kita merespon permintaan tidak benar dari pengguna, kita menguji URL http://hostname/blog/index.php?page=posts.ReadPost&id=100. Kita akan melihat halaman kesalahan berikut yang berbeda dari apa yang telah kita lihat sebelumnya. +

+ + + +

+Jika kita mencari di bawah direktori protected/runtime, kita akan menemukan file bernama prado.log. Ini adalah file log yang baru dikonfigurasi untuk menyimpan pesan kesalahan. File dapat berisi konten seperti berikut, +

+ + +Jun 28 22:15:27 [Error] [BlogApplication] Unable to find the specified post. +Jun 29 08:42:57 [Error] [BlogApplication] Unable to find the specified post. + + + \ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day5/id/Performance.page b/demos/blog-tutorial/protected/pages/Day5/id/Performance.page new file mode 100644 index 00000000..62a195b3 --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day5/id/Performance.page @@ -0,0 +1,67 @@ + + +

Penyesuaian Performansi

+ +

+Sebelum kita menyebarkan sistem blog, kita ingin menyesuaikan performansi sistem. +

+ +

Mengubah Mode Aplikasi

+ +

+Aplikasi PRADO dapat dikonfigurasi untuk berjalan dalam mode berbeda. Standarnya, ia berjalan dalam mode debug yang membuat banyak catatan pesan dan seandainya ada kesalahan, menampilkan pangilan stack lengkap atas tempat kesalahan. Perilaku demikian lebih disukai selama pengembangan, tapi tidak jika sistem sudah dalam produksi. Untuk mengubah mode aplikasi dari Debug ke Normal (berarti mode produksi), kita memodifikasi konfigurasi aplikasi seperti berikut: +

+ + + + + ...... + + + +

Menghidupkan Cache

+ +

+Ada banyak pekerjaan penguraian terkait dalam sebuah aplikasi PRADO: konfigurasi XML, template, tema, skin, dll. Untuk setiap permintaan pengguna, PRADO perlu melakukan ulang penguraian. Untuk menghemat usaha ini, kita dapat menghidupkan cache. Untuk melakukannya, kita mengubah konfigurasi aplikasi seperti berikut, +

+ + +...... + + ...... + + ...... + +...... + + +

+Sekarang setelah mengakses setiap halaman dalam sistem blog kita, kita akan dapat menemukan file bernama sqlite3.cache. Ini adalah file database yang memelihara template halaman yang diuraikan, konfigurasi, dll. +

+ + +Modul cache yang baru kita hidupkan menggunakan database sebagai medium cache persisten. PRADO juga mempunyai modul cache lain yang menggunakan medium cache lebih cepat, seperti misalnya TMemCache, TAPCCache. Diperlukan instalasi dari ekstensi PHP terkait. + + + +

Menggunakan pradolite.php

+ +

+Menjalankan halaman PRADO melibatkan puluhan file PHP, yang dapat menghabiskan waktu. File-file ini juga membawa banyak komentar untuk membuat dokumentasi APU ramah-pengguna. Untuk mengurangi beban ini, kita memodifikasi index.php dan mengganti inklusi prado.php dengan pradolite.php. Yang kedua adalah file besar yang dibuat dengan menggabung file kode tertentu dan membuang komentar. Selanjutnya kita bisa mengubah index.php seperti berikut, +

+ +

Teknik Lain

+ +

+Ada teknik lain untuk meningkatkan performansi lebih lanjut terhadap aplikasi PRADO. Berdasarkan pengalaman kami, salah satu lubang botol dalam aplikasi Web adalah database tier. Query database seringkali membutuhkan waktu lama untuk menyelesaikannya, yang memperlambat waktu respon terhadap permintaan sebuah halaman. Cache adalah solusi utama untuk masalah ini. Modul cache yang dihidupkan dalam konfigurasi aplikasi kita juga bisa dipakai untuk keperluan ini. +

+ +

+Untuk halaman yang relatif stabil dan jarang diakses, output caching bisa dipertimbangkan. Output caching melakukan cache output HTML dari bagian yang dipilih pada sebuah halaman. Ini dapat meningkatkan performansi dari halaman yang di-cache secara signifikan. +

+ +

+Teknik cache server terbukti sangat efektif dalam meningkatkan performansi atas aplikasi PRADO. Sebagai contoh, kita telah mengamati bahwa dengan menggunakan Zend Optimizer, RPS (request per second) dari aplikasi PRADO bisa ditingkatkan lebih dari sepuluh kali lipat. Tentu saja, ini pada beban dari output lama, sementara teknik cache PRADO selalu memastikan kebenaran dari output. +

+ +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day5/id/Summary.page b/demos/blog-tutorial/protected/pages/Day5/id/Summary.page new file mode 100644 index 00000000..eff9c2a9 --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day5/id/Summary.page @@ -0,0 +1,36 @@ + + +

Ringkasan

+ +

+Akhirnya kita dapat menyebarkan sistem blog kita. Untuk melakukannya, kita hanya perlu meng-copy seluruh direktori blog directory ke direktori Web sasaran. Kita perlu untuk memodifikasi index.php agar ia dapat mencari path yang benar di mana kerangka kerja PRADO diinstalasi. +

+ +

+Dengan demikian kita telah menyelesaikan sistem blog kita. Proses terlihat tidak gampang karena ia memerlukan hampir lima hari untuk sampai di sini. Akan tetapi, karena kita memulainya dari awal, tujuan utama dari tutorial ini adalah untuk membantu para pengembang PRADO terbiasa dengan teknik yang umum digunakan dalam PRADO. Tutorial tidak berarti menyelesaikan sistem blog dalam waktu lima menit dan selanjutnya tidak mempelajari apapun. +

+ +

+Secara ringkas, mengembangkan aplikasi PRADO dengan kendali-DB melibatkan langkah-langkah berikut: +

+
    +
  1. Mendesain dan membuat database
  2. +
  3. Membuat tata letak aplikasi awal menggunakan prado-cli
  4. +
  5. Menyiapkan proses pengendalian kesalahan untuk menghadapi kesalahan pengguna-akhir
  6. +
  7. Membuat dan menyiapkan tema
  8. +
  9. Mendesain dan membuat kelas master untuk berbagi tata letak umum halaman
  10. +
  11. Membuat kelas database dan menyiapkan koneksi database
  12. +
  13. Mendesain dan membuat bermacam-macam halaman
  14. +
  15. Menguji dan menyesuaikan performansi
  16. +
  17. Menyebarkan aplikasi
  18. +
+ +

+Tidak seperti urutan dalam tutorial kita, pengendalian kesalahan dan pembuatan tema dikerjakan lebih awal dalam proses di atas. Ini dikarenakan seringkali diperlukan perubahan besar dalam kode kelas dan template. Sebagai contoh, kita perlu mengganti THttpException dengan BlogException dalam tutorial kita. Jika kita mendefinisikan kelas stylesheet lebih awal, kita dapat dengan mudah menggunakannya saat membuat template halaman. +

+ +

+Sebagai tips terakhir, coba untuk berpikir dalam cara terorientasi-obyek selama mendesain dan mengimplementasikan. Gunakan turunan kelas dan komposisi secara luas, dan anda akan menemukan seluruh proyek lebih mudah dikembangkan secara paralel oleh multipel pengembang. Kode juga lebih banya memiliki kesempatan dipakai ulang agar proyek mendatang dapat diselesaikan dalam waktu yang lebih cepat. +

+ +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day5/id/UseTheme.page b/demos/blog-tutorial/protected/pages/Day5/id/UseTheme.page new file mode 100644 index 00000000..6766d659 --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day5/id/UseTheme.page @@ -0,0 +1,138 @@ + + +

Menggunakan Tema dan Skin

+ +

+PRADO memiliki dukungan dasar untuk tema. Dengan menggunakan tema, kita dapat memisahkan logika dan penyajian secara lebih baik, dan kita juga bisa mengubah penampilan keseluruhan pada sistem blog kita jauh lebih mudah. +

+ +

Membuat Tema

+ +

+Pertama kita buat direktori baru bernama themes. Ini adalah direktori leluhur bagi semua tema terkait aplikasi PRADO tertentu. Setiap subdirektori di bawah direktori ini yang nama temanya adalah nama subdirektori. +

+ +

+Untuk membuat tema bernama Basic, kita membuat subdirektori theme/Basic. Di bawah direktori ini, kita dapat menempatkan file stylesheet dependen-tema, file Javascript, gambar, dan file skin. +

+ + +Direktori themes harus bisa diakses dari Web, seperti halnya direktori assets. Jangan menempatkan file data sensitif di bawah direktori ini. Anda bisa mengubah nama atau lokasi dari direktori ini dengan mengkonfigurasi modul TThemeManager dalam konfigurasi aplikasi. + + + +

Membuat File Stylesheet

+ +

+Di bawah direktori themes/Basic, kita membuat sebuah file CSS stylesheet bernama style.css. ketika sebuah halaman menggunakan tema ini, PRADO secara otomatis akan mengimpor stylesheet ini ke halaman. Hal yang sama terjadi untuk file Javascript. +

+ +

+File CSS ditampilkan seperti berikut. +

+ + +body { + font-family: verdana, 'trebuchet ms', sans-serif; + font-size: 10pt; + background: white; +} +#page { + margin: 0 auto 0 auto; + width: 600px; +} +#footer { + text-align: center; + margin-top: 10px; + padding: 10px; + border-top: 1px solid silver; +} +.post-box { + margin-bottom: 10px; + padding: 5px; +} +.post-box h3 { + padding: 5px; + font-size: 13pt; + background: lightgray; +} +.post-box a { + color: black; + text-decoration: none; +} +.post-box a:hover { + color: red; +} + + + +

Membuat File Skin

+ +

+Kita menggunakan skin untuk menginisialisasi properti kontrol PRADO. Skin disimpan sebagai file skin (nama berakhiran .skin) di bawah direktori tema. Setiap file skin bisa berisi multipel skin untuk satu atau beberapa tipe kontrol. +

+ +

+Sebagai pengujian, kita akan mencoba membuat sebuah skin yang mengubah warna latar belakang link tombol dalam footer halaman. Kita membuat sebuah file bernama button.skin di bawah direktori tema themes/Basic. +

+ + +<com:THyperLink SkinID="MainMenu" BackColor="lightgreen" /> + + +

+File skin button.skin hanya berisi satu skin untuk kontrol THyperLink yang properti SkinID-nya adalah MainMenu. Skin menyetel warna latar belakang kontrol ke hijau-terang. +

+ +

+Sejalan dengan itu, kita perlu memodifikasi protected/common/MainLayout.tpl agar link tombol dalam footer menggunakan MainMenu sebagai SkinID-nya. +

+ +...... + +...... + + + +Sintaks untuk file skin sangat mirip dengan template PRADO. Setiap tag <com:> mendefinisikan sebuah skin untuk tipe kontrol tertentu. PRADO secara otomatis mengumpulkan seluruh file skin dalam sebuah tema dan menerapkannya ketika halaman bertema sedang disajikan. + + + +

Menggunakan Tema

+ +

+Untuk menggunakan tema yang baru kita buat, kita memodifikasi konfigurasi aplikasi seperti berikut. Seperti kita lihat, properti Theme untuk semua halaman disetel sebagai Basic, nama tema yang baru saja kita buat. +

+ + +...... + + + + + +...... + + + +Dimungkinkan untuk menetapkan tema berbeda untuk halaman yang berbeda, dan ini dapat dikerjakan baik dalam konfigurasi aplikasi/halaman ataupun secara programatis (perhatikan Theme adalah properti halaman). Untuk yan gterakhir, ia harus dikerjakan dalam metode onPreInit() pada halaman karena PRADO menerapkan tema ke halaman sebelumnya dalam masa hidup halaman. + + + +

Pengujian

+

+Untuk melihat bagaimana halaman blog terlihat, kunjungi URL http://hostname/blog/index.php. Kita akan melihat font, tata letak, bingkai beruah dalam halaman. Juga, link tombol dalam footer mempunyai latar belakang hijau terang. +

+ + + +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day5/id/output.gif b/demos/blog-tutorial/protected/pages/Day5/id/output.gif new file mode 100644 index 00000000..67bd18a3 Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day5/id/output.gif differ diff --git a/demos/blog-tutorial/protected/pages/Day5/id/output2.gif b/demos/blog-tutorial/protected/pages/Day5/id/output2.gif new file mode 100644 index 00000000..16c81704 Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day5/id/output2.gif differ diff --git a/demos/blog-tutorial/protected/pages/Day5/id/output3.gif b/demos/blog-tutorial/protected/pages/Day5/id/output3.gif new file mode 100644 index 00000000..6879bbdf Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day5/id/output3.gif differ -- cgit v1.2.3