Development

Documentation/id_ID/book/1.0/02-Exploring-Symfony-s-Code

You must first sign up to be able to contribute.

Version 2 (modified by tohenk, 9 years ago)
--

Bab 2 - Menjelajah Kode Symfony

Sekilas, kode di belakang aplikasi yang dibangun dengan symfony begitu membingungkan. Terdiri dari beberapa direktori dan skrip, dan file-file tersebut bercampur antara kelas-kelas PHP, HTML, dan bahkan percampuran antara keduanya. Anda juga akan melihat referensi ke kelas-kelas yang tidak akan ditemukan dalam folder aplikasi, dan kedalaman direktori aplikasi bahkan mencapai enam tingkatan. Tetapi sekali anda memahami alasan di belakang ke-kompleks-an tersebut, anda akan merasa hal tersebut begitu wajar sehingga anda tidak akan membandingkan struktur aplikasi symfony dengan yang lain. Bab ini mencoba menjelaskan untuk menghilangkan anggapan tersebut.

Pola MVC

Symfony didasarkan pada pola desain web klasik yang dikenal dengan arsitektur MVC, yang terdiri dari tiga tingkatan:

  • Model, mewakili informasi yang mana aplikasi beroperasi--logika bisnis.
  • View menggambarkan model ke dalam halaman web yang sesuai untuk interaksi dengan pemakai.
  • Controller merespon aksi pemakai dan mengaplikasikan perubahan pada model atau pada view.

Figur 2-1 mengilustrasikan pola MVC.

Arsitektur MVC memisahkan logika bisnis (model), dan presentasi (view), sehingga menghasilkan kemudahan pemeliharaan. Sebagai contoh, jika aplikasi anda seharusnya bisa berjalan pada browser web standar dan peralatan genggam, anda hanya memerlukan sebuah view baru; anda dapat membiarkan controller dan model sesuai aslinya. Controller membantu menyembunyikan detail dari protokol yang digunakan untuk request (HTTP, modus konsol, mail, dll) dari model dan view. Dan model mengabstraksi logika data, yang mana membuat view dan action menjadi independen, contohnya, tipe database yang dipakai oleh aplikasi.

Figur 2-1 - Pola MVC

The MVC pattern

Pelapisan MVC

Untuk membantu memahami keuntungan MVC, mari kita mengubah sebuah aplikasi PHP sederhana ke aplikasi berarsitektur MVC. Sebuah daftar postingan pada aplikasi weblog akan menjadi contoh yang sesuai.

Pemrograman Datar

Dalam sebuah file skrip PHP datar, untuk menampilkan daftar dari entri-entri database kemungkinan terlihat seperti skrip pada Listing 2-1.

Listing 2-1 - Sebuah Skrip Datar

[php]
<?php

// Koneksi, memilih database
$link = mysql_connect('localhost', 'myuser', 'mypassword');
mysql_select_db('blog_db', $link);

// Mengeksekusi query SQL
$result = mysql_query('SELECT date, title FROM post', $link);

?>

<html>
  <head>
    <title>List of Posts</title>
  </head>
  <body>
   <h1>List of Posts</h1>
   <table>
     <tr><th>Date</th><th>Title</th></tr>
<?php
// Menampilkan hasil sebagai HTML
while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
{
echo "\t<tr>\n";
printf("\t\t<td> %s </td>\n", $row['date']);
printf("\t\t<td> %s </td>\n", $row['title']);
echo "\t</tr>\n";
}
?>
    </table>
  </body>
</html>

<?php

// Menutup koneksi
mysql_close($link);

?>

Contoh tersebut sebentar untuk ditulis, cepat dieksekusi, dan sulit dipelihara. Berikut kelemahan terbesar dari kode tersebut:

  • Tidak ada pengecekan kesalahan (bagaimana jika koneksi ke database gagal?).
  • HTML dan kode PHP bercampur, bahkan campur aduk.
  • Kode hanya diperuntukkan untuk database MySQL.

Mengisolasi Presentasi

Perintah echo dan printf pada Listing 2-1 membuat kode sulit dipahami. Modifikasi kode HTML untuk memisahkan presentasi dengan sintaks yang ada akan membutuhkan sedikit usaha. Jadi kode tersebut dapat dipisahkan menjadi dua bagian. Pertama, kode PHP murni yang berisi logika bisnis berada pada skrip controller, seperti ditunjukkan pada Listing 2-2.

Listing 2-2 - Bagian Controller, pada index.php

[php]
<?php

 // Koneksi, memilih database
 $link = mysql_connect('localhost', 'myuser', 'mypassword');
 mysql_select_db('blog_db', $link);

 // Mengeksekusi query SQL
 $result = mysql_query('SELECT date, title FROM post', $link);

 // Mempersiapkan array untuk view
 $posts = array();
 while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
 {
    $posts[] = $row;
 }

 // Menutup koneksi
 mysql_close($link);

 // Menyertkan view
 require('view.php');

 ?>

Kode HTML, berisi sintaks PHP dengan model template, disimpan dalam skrip view, seperti ditunjukkan pada Listing 2-3.

Listing 2-3 - Bagian View, pada view.php

[php]
<html>
  <head>
    <title>List of Posts</title>
  </head>
  <body>
    <h1>List of Posts</h1>
    <table>
      <tr><th>Date</th><th>Title</th></tr>
    <?php foreach ($posts as $post): ?>
      <tr>
        <td><?php echo $post['date'] ?></td>
        <td><?php echo $post['title'] ?></td>
      </tr>
    <?php endforeach; ?>
    </table>
  </body>
</html>

Sebuah aturan yang baik untuk menentukan apakah view sudah cukup bersih jika view tersebut hanya berisi sedikit kode PHP saja, agar mudah dimengerti oleh seorang desainer HTML tanpa perlu pengetahuan tentang PHP. Kebanyakan statemen umum yang dijumpai dalam view yaitu echo, if/endif, foreach/endforeach, dan hanya itu semua. Juga, seharusnya tidak ada kode PHP yang meng-echo-kan tag HTML.

Semua logika berapa pada skrip controller, dan hanya berisi kode PHP murni, tanpa ada HTML di dalamnya. Sebagai faktanya, anda dapat membayangkan bahwa controller tersebut dapat digunakan kembali untuk presentasi yang sama sekali berbeda, seperti untuk file PDF atau sebuah struktur XML.

Mengisolasi Manipulasi Data

Kebanyakan skrip pada controller digunakan untuk memanipulasi data. Tetapi bagaimana jika anda membutuhkan daftar postingan untuk controller yang lain, katakan untuk kontroller yang akan menghasilkan umpan RSS dari postingan weblog? Bagaimana jika anda ingin menempatkan semua query ke database dalam satu tempat, untuk menghindari pengulangan kode? Bagaimana jika anda memutuskan untuk mengubah model data sehingga tabel post berubah menjadi weblog_post? Bagaimana jika anda ingin berpindah ke PostgreSQL daripada MySQL? Agar semua itu terwujud, anda harus menghilangkan kode manipulasi data dari controller dan meletakkannya pada skrip lain, yang disebut model, seperti ditunjukkan pada Listing 2-4.

Listing 2-4 - Bagian Model, pada model.php

[php]
<?php

function getAllPosts()
{
  // Koneksi, memilih database
  $link = mysql_connect('localhost', 'myuser', 'mypassword');
  mysql_select_db('blog_db', $link);

  // Mengeksekusi query SQL
  $result = mysql_query('SELECT date, title FROM post', $link);

  // Mempersiapkan array
  $posts = array();
  while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
  {
     $posts[] = $row;
  }

  // Menutup koneksi
  mysql_close($link);

  return $posts;
}

?>

Controller yang sudah diperbarui seperti ditunjukkan pada Listing 2-5.

Listing 2-5 - Bagian Revisi Controller, pada index.php

[php]
<?php

// Menyertakan model
require_once('model.php');

// Mengambil semua daftar postingan
$posts = getAllPosts();

// Menyertakan view
require('view.php');

?>

Controller menjadi mudah dipahami. Tugas utamanya yaitu mengambil data dari model dan memberikannya pada view. Pada aplikasi yang lebih kompleks, controller juga berhubungan dengan request, sesi pemakai, otentikasi, dll. Penggunaan nama fungsi eksplisit pada model bahkan tidak membutuhkan komentar khusus pada controller.

Skrip model ditujukan untuk akses data dan dapat diorganisir menyesuaikannya. Semua parameter yang tidak tergantung pada lapisan data (seperti parameter request) harus diberikan oleh controller dan tidak diakses secara langsung oleh model. Fungsi-fungsi pada model dapat dengan mudah digunakan untuk controller yang lain.

Pemisahan Lapisan Di Luar MVC

Jadi prinsip arsitektur MVC adalah memisahkan kode ke dalam tiga lapisan, sesuai dengan fungsinya. Logika data ditempatkan pada model, kode presentasi pada view, dan logika aplikasi pada controller.

Dengan tambahan pola desain yang lain, pengalaman pengkodean bahkan menjadi lebih mudah. Model, view, dan controller dapat dibagi lebih jauh lagi.

Abstraksi Database

Lapisan model dapat dipisahkan menjadi lapisan akses data dan lapisan abstraksi database. Dengan cara tersebut, fungsi-fungsi akses data tidak akan menggunakan statemen query yang tergantung pada database tertentu, akan tetapi memanggil fungsi-fungsi lain yang berfungsi untuk melakukan query tersebut. Jika anda kemudian mengubah sistem database, hanya lapisan abstraksi database saja yang perlu diperbarui.

Sebuah contoh lapisan abstraksi database seperti ditunjukkan pada Listing 2-6, diikuti sebuah contoh lapisan akses data khusus untuk MySQL pada Listing 2-7.

Listing 2-6 - Bagian Abstraksi Database pada Model

[php]
<?php

function open_connection($host, $user, $password)
{
  return mysql_connect($host, $user, $password);
}

function close_connection($link)
{
  mysql_close($link);
}

function query_database($query, $database, $link)
{
  mysql_select_db($database, $link);

  return mysql_query($query, $link);
}

function fetch_results($result)
{
  return mysql_fetch_array($result, MYSQL_ASSOC);
}

Listing 2-7 - Bagian Akses Data pada Model

[php]
function getAllPosts()
{
  // Koneksi ke database
  $link = open_connection('localhost', 'myuser', 'mypassword');

  // Eksekusi query SQL
  $result = query_database('SELECT date, title FROM post', 'blog_db', $link);

  // Mempersiapkan array
  $posts = array();
  while ($row = fetch_results($result))
  {
     $posts[] = $row;
  }

  // Menutup koneksi
  close_connection($link);

  return $posts;
}

?>

Anda dapat memeriksa bahwa tidak ada fungsi-fungsi yang bergantung database tertentu dapat ditemukan pada lapisan akses data, hal ini membuat data akses tidak tergantung database yang digunakan. Sebagai tambahan, fungsi-fungsi yang dibuat dalam lapisan abstraksi database dapat digunakan kembali oleh banyak fungsi-fungsi model yang lain ketika membutuhkan akses ke database tersebut.

CATATAN Contoh pada Listings 2-6 and 2-7 masih belum memuaskan, masih ada pekerjaan yang tersisa agar menjadi abstraksi database yang utuh (mengabstraksi kode SQL melalui sebuah query builder yang independen-database, memindah semua fungsi ke dalam kelas, dll). Tetapi tujuan dari buku ini bukan untuk menunjukkan cara membuat semua kode tersebut dengan tangan, dan anda akan melihat pada Bab 8 bahwa symfony secara alami mampu menangani abstraksi tersebut dengan baik.

Elemen-Elemen View

Lapisan view juga mendapatkan keuntungan dari pemisahan kode. Sebuah halaman web sering berisi elemen-elemen yang konsisten pada keseluruhan aplikasi: header halaman, tata letak grafis, footer, dan navigasi umum. Hanya bagian terdalam halaman yang berubah. Itulah sebabnya mengapa view dipisahkan menjadi layout dan template. Layout biasanya berlaku menyeluruh ke aplikasi, atau terhadap sebuah grup halaman. Template hanya menggambarkan variabel-variabel yang disediakan oleh controller. Beberapa logika dibutuhkan agar semua komponen tersebut bekerja bersama-sama, dan lapisan logika view akan disatukan dan dinamakan view. Menurut prinsip tersebut, bagian view pada Listing 2-3 dapat dipisahkan ke dalam tiga bagian, seperti ditunjukkan pada Listings 2-8, 2-9, dan 2-10.

Listing 2-8 - Bagian Template pada View, pada mytemplate.php

[php]
<h1>List of Posts</h1>
<table>
<tr><th>Date</th><th>Title</th></tr>
<?php foreach ($posts as $post): ?>
  <tr>
    <td><?php echo $post['date'] ?></td>
    <td><?php echo $post['title'] ?></td>
  </tr>
<?php endforeach; ?>
</table>

Listing 2-9 - Bagian Logika View pada View

[php]
<?php

$title = 'List of Posts';
$content = include('mytemplate.php');

?>

Listing 2-10 - Bagian Layout pada View

[php]
<html>
  <head>
    <title><?php echo $title ?></title>
  </head>
  <body>
    <?php echo $content ?>
  </body>
</html>

Action dan Front Controller

Controller tidak banyak melakukan tugasnya pada contoh sebelumnya, tetapi pada aplikasi web yang nyata, controller punya banyak pekerjaan. Bagian terpenting dari pekerjaan tersebut berlaku umum ke seluruh aplikasi. Tugas umum tersebut termasuk penanganan request, penanganan keamanan, memuat konfigurasi aplikasi, dan pekerjaan lain yang serupa. Itulah mengapa controller sering dipisahkan menjadi front controller, yang mana bersifat unik dalam keseluruhan aplikasi, dan action-action, yang berupa kode controller yang diperuntukkan hanya untuk satu halaman tertentu.

Salah satu keuntungan dari front controller yaitu menyediakan jalur masuk unik terhadap keseluruhan aplikasi. Jika anda merencanakan untuk menutup akses ke aplikasi, anda hanya perlu mengubah skrip yang ada pada front controller. Pada aplikasi tanpa front controller, masing-masing controller harus dimatikan satu per satu.

Orientasi Obyek

Semua contoh-contoh sebelumnya menggunakan pemrograman prosedural. Kemampuan OOP dari bahasa pemrograman modern bahkan membuat pemrograman menjadi lebih mudah, dikarenakan obyek-obyek dapat membungkus logika, pewarisan terhadap satu dengan yang lain, dan menyediakan konvensi penamaan yang bersih.

Penerapan arsitektur MVC pada bahasa yang tidak berorientasi obyek menimbulkan masalah namespace dan duplikasi kode, dan keseluruhan kode menjadi sulit dipahami.

Orientasi obyek memperbolehkan pengembang untuk memperlakukan obyek-obyek sebagai obyek view, obyek controller, dan kelas-kelas model, dan untuk mengubah semua fungsi-fungsi pada contoh sebelumnya menjadi metode-metode. Adalah seuatu keharusan pada arsitektur MVC.

TIP Jika anda ingin belajar lebih banyak mengenai pola desain untuk aplikasi web dengan konteks orientasi obyek, baca Patterns of Enterprise Application Architecture oleh Martin Fowler (Addison-Wesley, ISBN: 0-32112-742-0). Contoh kode dalam buku tersebut menggunakan Java atau C#, tetapi masih bisa dipahami oleh seorang pengembang PHP.

Penerapaan MVC pada Symfony

Tunggu sebentar. Untuk sebuah halaman yang menampilkan daftar postingan sebuah weblog, berapa banyak komponen yang dibutuhkan? Seperti diilustrasikan pada Figur 2-2, kita memiliki bagian-bagian berikut:

  • Lapisan model
    • Abstraksi database
    • Akses data
  • Lapisan view
    • View
    • Template
    • Layout
  • Lapisan controller
    • Front controller
    • Action

Tujuh skrip--begitu banyak file-file harus dibuka dan dimodifikasi setiap akan membuat halaman baru! Akan tetapi, symfony membuat semuanya mudah. Sementara mengambil kebaikan dari arsitektur MVC, symfony menerapkan arsitektur tersebut sehingga membuat pengembangan aplikasi dapat dipercepat dan tidak menyusahkan.

Satu dari semuanya, front controller dan layout biasanya berlaku umum terhadap semua action-action dalam aplikasi. Anda boleh memiliki beberapa controller dan layout, tetapi yang diperlukan cukup satu. Front controller adalah komponen logika MVC murni, dan anda tidak akan perlu membuatnya sediri, karena symfony akan membuatnya untuk anda.

Berita baik lainnya bahwa kelas-kelas pada lapisan model juga diciptakan otomatis, berdasarkan struktur data yang anda buat. Tugas ini ditangani oleh librari Propel, yang menyediakan kerangka-kerangka kelas dan penciptaan kode. Jika Propel menemukan batasan foreign key atau field-field tanggal, dia akan menyediakan pengakses khusus dan metode-metode pemutasian yang akan membuat manipulasi data seperti sebuah potong kue. Dan abstraksi database secara keseluruhan tidak nampak bagi anda, karena dia ditangani oleh komponen lain, yang disebut Creole. Jadi jika suatu ketika anda memutuskan untuk mengubah database, anda tidak perlu menulis kode lagi. Anda hanya perlu mengubah parameter konfigurasi.

Dan yang terakhir adalah logika view dapat dengan mudah diterjemahkan menjadi file konfigurasi sederhana, tanpa perlu pengetahuan pemrograman.

Figur 2-2 - Alur symfony

Symfony workflow

Itu berarti bahwa daftar postingan seperti digambarkan pada contoh hanya membutuhkan tiga file agar bekerja di symfony, seperti ditunjukkan pada Listings 2-11, 2-12, dan 2-13.

Listing 2-11 - Action list, pada myproject/apps/myapp/modules/weblog/actions/actions.class.php

[php]
<?php
class weblogActions extends sfActions
{
  public function executeList()
  {
    $this->posts = PostPeer::doSelect(new Criteria());
  }
}

?>

Listing 2-12 - Template list, pada myproject/apps/myapp/modules/weblog/templates/listSuccess.php

[php]
<h1>List of Posts</h1>
<table>
<tr><th>Date</th><th>Title</th></tr>
<?php foreach ($posts as $post): ?>
  <tr>
    <td><?php echo $post->getDate() ?></td>
    <td><?php echo $post->getTitle() ?></td>
  </tr>
<?php endforeach; ?>
</table>

Listing 2-13 - View list, pada myproject/apps/myapp/modules/weblog/config/view.yml

listSuccess:
  metas: { title: List of Posts }

Sebagai tambahan, anda masih perlu menentukan sebuah layout, seperti ditunjukkan pada Listing 2-14, tetapi layout tersebut dapat dipakai berkali-kali.

Listing 2-14 - Layout, pada myproject/apps/myapp/templates/layout.php

[php]
<html>
  <head>
    <?php echo include_title() ?>
  </head>
  <body>
    <?php echo $sf_data->getRaw('sf_content') ?>
  </body>
</html>

Dan hanya itu yang dibutuhkan. Itulah persisnya kode yang dibutuhkan untuk menampilkan halaman yang sama persis seperti pada skrip datar sebelumnya pada Listing 2-1. Sisanya (membuat semua komponen berkerja bersama) ditangani oleh symfony. Jika anda menghitung jumlah baris, anda akan melihat bahwa membuat daftar postingan dengan arsitektur MVC menggunakan symfony tidak membutuhkan lebih banyak waktu atau coding dibandingkan dengan menulis file datar. Sebaliknya, anda akan memperoleh banyak keuntungan, khususnya pengorganisasian kode yang bersih, daya pakai ulang, kefleksibelan, dan banyak lagi kesenangan lain. Dan sebagai hadiah, anda memperoleh halaman yang berstandar XHTML, kemampuan debugging, kemudahan konfigurasi, abstraksi database, perutean URL pintar, banyak lingkungan pengembangan, dan banyak lagi peralatan pengembangan yang lain.

Kelas-Kelas Inti Symfony

Penerapan MVC pada symfony menggunakan beberapa kelas yang akan sering anda jumpai dalam buku ini:

  • sfController adalah kelas controller. Tugasnya men-decode request dan melanjutkannya kepada action.
  • sfRequest menyimpan semua elemen-elemen request (parameter-parameter, cookie-cokie, header-header, dll).
  • sfResponse berisi header-header respon dan juga isi. Obyek ini sesungguhnya yang akan dikonversi sebagai respon HTML untuk dikirim kepada pengguna.
  • Konteks tunggal (diambil dengan sfContext::getInstance()) menyimpan referensi ke semua obyek-obyek inti dan juga konfigurasi sekarang; yang dapat diakses dari manapun.

Anda akan belajar banyak mengenai obyek-obyek ini pada Bab 6.

Seperti anda lihat, semua kelas-kelas symfony menggunakan awalan sf, seperti juga variabel-variabel inti symfony dalam template. Hal ini bertujuan menghindari bentrokan nama dengan nama kelas dan variabel anda, dan membuat kelas-kelas inti dari framework tersosialiasi dan mudah dikenali.

NOTE Di antara standarisasi kode yang digunakan oleh symfony, UpperCamelCase adalah standar yang digunakan untuk nama kelas dan nama variabel. Dua pengecualian: kelas-kelas inti symfony diawali sf, dalam bentuk huruf kecil, dan variabel-variabel yang ditemukan dalam template menggunakan sintaks dipisah garis bawah (underscore-separated).

Organisasi Kode

Sekarang anda mengetahui perbedaan komponen-komponen dari aplikasi symfony, anda mungkin kagum bagaimana kode tersebut diorganisir. Symfony mengorganisasi kode dalam sebuah struktur proyek dan meletakkan file-file proyek ke dalam struktur tree yang standar.

Struktur Proyek: Aplikasi, Modul, dan Action

Dalam symfony, sebuah proyek terdiri dari kumpulan servis-servis dan operasi-operasi yang tersedia di bawah satu nama domain, yang berbagi obyek model yang sama.

Di dalam sebuah proyek, operasi-operasi dikelompokkan secara logis ke dalam aplikasi. Sebuah aplikasi secara normal dapat berjalan independen dari aplikasi lain dalam satu proyek yang sama. Dalam kebanyakan kasus, sebuah proyek berisi dua aplikasi: satu untuk front-office dan satunya back-office, yang keduanya memakai database yang sama. Tetapi anda dapat memiliki sebuah proyek yang terdiri dari beberapa situs mini, dengan masing-masing situs sebagai aplikasi yang berbeda. Dengan catatan bahwa hyperlink antara aplikasi harus dalam bentuk absolut.

Masing-masing aplikasi terdiri dari satu atau serangkaian modul. Sebuah modul biasanya mewakili sebuah halaman atau sekelompok halaman dengan fungsi yang mirip. Sebagai contoh, anda bisa memiliki modul home, articles, help, shoppingCart, account, dll.

Modul menampung action-action, yang mewakili bermacam-macam action yang dapat dikerjakan dalam sebuah modul. Sebagai contoh, sebuah modul shoppingCart dapat memiliki action-action add, show, dan update. Umumnya, action-action dapat digambarkan sebagai kata. Bekerja dengan action hampir sama dengan mengerjakan halaman-halaman pada aplikasi web klasik, meskipun dua action dapat menghasilkan satu halaman yang sama (sebagai contoh, menambah sebuah komentar pada postingan weblog akan menampilkan ulang postingan tersebut dengan komentar yang baru dibuat).

TIP Jika terlalu banyak tingkatan dalam proyek permulaan, sangat mudah untuk mengelompokkan semua action-action dalam sebuah modul tunggal, sehingga struktur file dapat dibuat tetap sederhana. Ketika aplikasi bertambah kompleks, sekarang waktunya untuk mengorganisir action ke dalam modul terpisah. Seperti disebutkan pada Bab 1, menulis ulang kode untuk memperbaiki struktur atau kemudahan memahaminya (tetapi tetap menjaga tingkah lakunya) disebut refactoring, dan anda akan banyak melakukannya ketika menerapkan prinsip RAD.

Figur 2-3 menunjukkan sebuah contoh organisasi kode pada sebuah proyek weblog, dengan struktur project/application/module/action. Tetapi ingat struktur tree file sesungguhnya dari sebuah proyek akan berbeda dari contoh yang ditunjukkan pada gambar.

Figur 2-3 - Contoh organisasi kode

Example of code organization

Struktur Tree File

Semua proyek-proyek web umumnya berbagi pakai banyak tipe isi, seperti berikut:

  • Database, semisal MySQL atau PostgreSQL
  • File-file statis (HTML, gambar-gambar, file-file JavaScript, stylesheet, dll)
  • File-file yang diupload oleh pengguna dan administrator situs
  • Kelas-kelas dan librari-librari PHP
  • Librari-librari asing (skrip pihak ketiga)
  • File-file batch (skrip untuk dijalankan dari baris perintah atau melalui tabel cron)
  • File-file log (jejak yang dibuat oleh aplikasi dan/atau server)
  • File-file konfigurasi

Symfony menyediakan sebuah struktur tree file standar untuk mengorganisir semua isi-isi secara logis, yang konsisten dengan arsitektur yang digunakan (pola MVC dan pengelompokan project/application/module). Struktur tree file tersebut secara otomatis dibuat ketika menginisialiasi setiap proyek, aplikasi, atau modul. Tentunya, anda dapat mengkustomisasi sepenuhnya, untuk mengorganisasi ulang file-file dan direktori-direktori sesuai kebutuhan anda atau untuk menyesuaikan dengan persyaratan klien anda.

Struktur Tree Dasar

Direktori berikut ditemukan pada dasar dari sebuah proyek symfony:

apps/
  frontend/
  backend/
batch/
cache/
config/
data/
  sql/
doc/
lib/
  model/
log/
plugins/
test/
  unit/
  functional/
web/
  css/
  images/
  js/
  uploads/

Tabel 2-1 menggambarkan isi dari direktori-direktori tersebut.

Tabel 2-1 - Direktori-Direktori Dasar

Direktori | Deskripsi ---------- | ------------ apps/ | Berisi sebuah direktori untuk setiap aplikasi dalam proyek (umumnya, frontend dan backend untuk front dan back office). batch/ | Berisi skrip-skrip PHP yang dipanggil dari baris perintah atau oleh sebuah skeduler, untuk menjalankan proses-proses batch. cache/ | Berisi versi caache dari konfigurasi, dan (jika anda mengaktifkannya) versi cache dari action-action dan template-template proyek. Mekanisme cache (detailnya ada pada Bab 12) menggunakan file-file tersebut untuk mempercepat respon pada request web. Setiap aplikasi akan memiliki sub direktori, yang berisi file PHP pra-proses dan file-file HTML. config/ | Menyimpan konfigurasi umum pada proyek. data/ | Di sini, anda dapat menyimpan file-file data proyek, seperti skema database, file-file SQL untuk membuat tabel-tabel, atau bahkan file database SQLite. doc/ | Menyimpan dokumentasi proyek, termasuk dokumentasi anda sendiri atau dokumentasi yang dibuat dengan PHPdoc. lib/ | Didedikasikan untuk kelas-kelas asing atau librai-librari. Di sini, anda dapat menambah kode yang dibutuhkan agar dapat digunakan bersama di antara aplikasi-aplikasi. Sub direktori model/ menyimpan obyek model dari proyek (dijelaskan pada Bab 8). log/ | Menyimpan file-file log yang dibuat langsung oleh symfony. Dapat juga berisi file-file log server web, file-file log database, atau file-file log dari bagian lain proyek. Symfony membuat sebuah file log per aplikasi dan per lingkungan (file-file log didiskusikan pada Bab 16). plugins/ | Menyimpan plug-ins yang terpasang dalam aplikasi (plug-ins didiskusikan pada Bab 17). test/ | Berisi pengujian unit dan fungsionalitas yang ditulis menggunakan PHP dan kompatibel dengan framework pengujian symfony (didiskusikan pada Bab 15). Sewaktu setup proyek, symfony otomatis menambahkan beberapa potongan-potongan pengujian dasar. web/ | Root server web. File yang hanya dapat diakses dari Internet diletakkan dalam direktori ini.

Struktur Tree Aplikasi

Struktur tree dari semua direktori aplikasi adalah sama:

apps/
  [application name]/
    config/
    i18n/
    lib/
    modules/
    templates/
      layout.php
      error.php
      error.txt

Tabel 2-2 menggambarkan sub direktori aplikasi.

Tabel 2-2 - Subdirektori Aplikasi

Direktori | Deskripsi ------------ | ----------- config/ | Menyimpan sejumlah file konfigurasi YAML. Kebanyakan adalah konfigurasi aplikasi, yang berbeda dari parameter default yang dapat ditemukan dalam framework. Perlu dicatat bahwa parameter default masih dapat diambil-alih jika diperlukan di sini. Anda akan belajar banyak tentang konfigurasi aplikasi pada Bab 5. i18n/ | Berisi file-file yang digunakan untuk internasionalisasi aplikasi--kebanyakan file-file translasi antar muka (Bab 13 berhubungan dengan internasionalisasi). And dapat melewati direktori ini jika anda memilih menggunakan database untuk internasionalisasi. lib/ | Berisi kelas-kelas dan librari-librari yang spesifik terhapad aplikasi. modules/ | Menyimpan semua modul-modul yang berisi fitur-fitur aplikasi. templates/ | Daftar template-template global aplikasi--yang dipakai bersama oleh semua modul-modul. Secara default, berisi sebuah file layout.php, yang merupakan layout utama dimana template dari modul nantinya akan disisipkan.

CATATAN Direktori i18n/, lib/, dan modules/ masih kosong pada sebuah aplikasi baru.

Kelas-kelas dari suatu aplikasi tidak dapat mengakses metode-metode atau atribut-atribut dari aplikasi lain dalam satu proyek yang sama. Juga perlu dicatat bahwa hyperlink antara aplikasi dalam satu proyek yang sama harus dalam bentuk absolut. Anda perlu mengingat batasan ini selama inisialisasi, ketika anda memutuskan untuk membagi proyek anda ke dalam aplikasi-aplikasi.

Struktur Tree Modul

Setiap aplikasi berisi satu atau beberapa modul. Setiap modul memiliki subdirektori sendiri pada direktori modules, dan nama direktori tersebut ditentukan ketika setup.

Berikut ini struktur tree umum pada sebuah modul:

apps/
  [application name]/
    modules/
      [module name]/
          actions/
            actions.class.php
          config/
          lib/
          templates/
            indexSuccess.php
          validate/

Tabel 2-3 menggambarkan subdirektori pada modul.

Tabel 2-3 - Subdirektori-Subdirektori Modul

Direktori | Deskripsi ------------ | ------------ actions/ | Umumnya berisi kelas tunggal dengan nama actions.class.php, yang mana anda dapat menyimpan semua action-action dari modul tersebut. Anda juga dapat menulis action-action yang berbeda dari modul tersebut pada file-file yang terpisah. config/ | Dapat berisi file-file konfigurasi kustom yang berisi parameter-paramter modul lokal. lib/ | Menyimpan kelas-kelas dan librari-librari khusus untuk modul. templates/ | Berisi template-template yang berhubungan dengan action-action pada modul. Template default, dinamakan indexSuccess.php, dibuat ketika setup modul. validate/ | Didedikasikan untuk file-file konfigurasi yang digunakan pada waktu validasi form (didiskusikan pada Bab 10).

CATATAN Direktori config/, lib/, dan validate/ masih kosong pada sebuah modul yang baru.

Struktur Tree Web

Ada sedikit batasan untuk direktori web, yang mana direktori ini berisi file-file yang dapat diakses secara umum. Mengikuti sedikit konvensi penamaan dasar yang menyediakan tingkah laku default dan jalan pintas berguna pada template-template. Berikut sebuah contoh struktur direktori web:

web/
  css/
  images/
  js/
  uploads/

Secara konvensional, file-file statis didistribusikan pada direktori yang terdaftar pada Tabel 2-4.

Table 2-4 - Subdirektori Web Umum

Direktori | Deskripsi ---------- | ----------- css/ | Berisi stylesheet dengan ekstensi .css. images/ | Berisi gambar-gambar dengan format .jpg, .png, atau .gif. js/ | Menyimpan file-file JavaScript dengan exstensi .js. uploads/ | Berisi file-file yang diupload oleh pengguna. Meskipun direktori ini biasanya berisi gambar-gambar, namum berbeda dengan direktori images sehingga sinkronisasi antara server pengembangan dan produksi tidak mempengaruhi gambar-gambar yang diupload.

NOTE Meskipun sangat direkomendasikan untuk meggunakan struktur tree standar, sangat dimungkinkan mengubahnya sesuai kebutuhan spesifik, sehingga memungkinkan sebuah proyek dapat dijalankan pada server dengan aturan struktur tree dan konvensi pengkodean yang berbeda. Lihat Bab 19 untuk informasi lebih jauh tentang memodifikasi struktur tree file.

Instrumen-Instrumen Umum

Ada sedikit teknik yang digunakan berulang-ulang dalam symfony, dan anda akan cukup sering menemuinya dalam buku ini dan dalam proyek anda sendiri. Hal ini meliputi parameter holder, konstanta, dan autoloading kelas.

Parameter Holder

Banyak dari kelas-kelas symfony yang berisi parameter holder. Ini adalah cara yang meyakinkan untuk membungkus attribut-atribut dengan metode getter dan setter yang bersih. Sebagai contoh, kelas sfResponse menyimpan sebuah parameter holder yang mana anda dapat mengambilnya dengan memanggil metode getParameterHolder(). Setiap parameter holder menyimpan data dengan cara yang sama, seperti diilustrasikan pada Listing 2-15.

Listing 2-15 - Menggunakan Parameter Holder sfResponse

[php]
$response->getParameterHolder()->set('foo', 'bar');
echo $response->getParameterHolder()->get('foo');
 => 'bar'

Kebanyakan kelas-kelas yang menggunakan parameter holder menyediakan metode-metode perantara dengan tujuan memperpendek kode yang dibutuhkan pada operasi-operasi get/set. Hal ini juga berlaku pada obyek sfResponse, sehingga anda dapat melakukan hal yang sama dengan Listing 2-15 dengan kode pada Listing 2-16.

Listing 2-16 - Menggunakan Metode Perantara Parameter Holder sfResponse

[php]
$response->setParameter('foo', 'bar');
echo $response->getParameter('foo');
 => 'bar'

Getter parameter holder menerima nilai default sebagai argumen kedua. Hal ini menyediakan mekanisme fallback yang lebih ringkas dibandingkan menggunakan statemen kondisonal. Lihat Listing 2-17 sebagai contohnya.

Listing 2-17 - Menggunakan Nilai Default Getter Parameter Holder

[php]
// Parameter 'foobar' belum ditentukan, sehingga getter mengembalikan nilai kosong
echo $response->getParameter('foobar');
 => null

// Nilai default dapat dipakai dengan meletakkan getter dalam sebuah kondisi
if ($response->hasParameter('foobar'))
{
  echo $response->getParameter('foobar');
}
else
{
  echo 'default';
}
 => default

// Tetapi lebih cepat menggunakan argumen kedua getter untuk melakukannya daripada sebelumnya
echo $response->getParameter('foobar', 'default');
 => default

Parameter holder bahkan mendukung namespace. Jika anda menentukan argumen ketiga pada setter atau getter, argumen tersebut digunakan sebagai namespace, dan parameter hanya akan berlaku dalam namespace tersebut. Listing 2-18 menunjukkan contohnya.

Listing 2-18 - Menggunakan Namespace Parameter Holder sfResponse

[php]
$response->setParameter('foo', 'bar1');
$response->setParameter('foo', 'bar2', 'my/name/space');
echo $response->getParameter('foo');
 => 'bar1'
echo $response->getParameter('foo', null, 'my/name/space');
 => 'bar2'

Dan tentunya, anda dapat menambahkan sebuah parameter holder pada kelas-kelas anda sendiri untuk mendapatkan keuntungan dari fasilitias sintaksnya. Listing 2-19 menunjukkan bagaimana membuat sebuah kelas dengan parameter holder.

Listing 2-19 - Menambahkan Parameter Holder ke Suatu Kelas

[php]
class MyClass
{
  protected $parameter_holder = null;

  public function initialize ($parameters = array())
  {
    $this->parameter_holder = new sfParameterHolder();
    $this->parameter_holder->add($parameters);
  }

  public function getParameterHolder()
  {
    return $this->parameter_holder;
  }
}

Konstanta

Anehnya, anda hanya akan menjumpai sedikit konstanta dalam symfony. Hal ini dikarenakan konstanta memiliki kekurangan besar dalam PHP: anda tidak dapat mengubah nilainya sekali anda mendefinisikannya. Sehingga symfony menggunakan obyek konfigurasinya sendiri, yang dinamakan sfConfig, yang berfungsi menggantikan konstanta. Kelas ini menyediakan metode statis yang dapat digunakan untuk mengakses parameter dari manapun. Listing 2-20 mendemonstrasikan penggunaan metode-metode kelas sfConfig.

Listing 2-20 - Menggunakan Metode Kelas sfConfig daripada Konstanta

[php]
// Daripada menggunakan konstanta PHP,
define('SF_FOO', 'bar');
echo SF_FOO;
// Symfony mennggunakan obyek sfConfig
sfConfig::set('sf_foo', 'bar');
echo sfConfig::get('sf_foo');

Metode-metode sfConfig mendukung nilai-nilai default, dan anda dapat memanggil metode sfConfig::set() lebih dari sekali pada parameter yang untuk mengubah nilainya. Bab 5 mendiskusikan metode sfConfig dengan lebih detail.

Autoloading Kelas

Secara klasik, ketika anda menggunakan metode dari sebuah kelas atau ketika membuat obyek dalam PHP, anda perlu menyertakan pendefinisian kelas sebelumnya.

[php]
include 'classes/MyClass.php';
$myObject = new MyClass();

Tetapi pada proyek yang besar dengan banyak kelas-kelas dengan struktur direktori yang dalam, mengingat semua file-file kelas dan menyertakan path file kelas tersebut akan banyak membutuhkan waktu. Dengan menyediakan sebuah fungsi __autoload() (atau sebuah fungsi spl_autoload_register()), symfony membuat statemen include tidak dibutuhkan lagi, dan anda dapat menulis langsung:

[php]
$myObject = new MyClass();

Symfony kemudian akan mencari definisi MyClass pada semua file dengan akhiran php pada salah satu direktori lib/ proyek. Jika definisi kelas ditemukan, symfony kemudian otomatis menyertakannya.

Jadi jika anda menyimpan semua kelas-kelas pada direktori lib/, anda tidak perlu lagi menyertakan kelas. Itulah mengapa proyek-proyek symfony umumnya tidak mengandung statemen-statemen include atau require.

CATATAN Untuk performa yang lebih baik, autoloading symfony memeriksa sebuah daftar direktori (didefinisikan pada file konfigurasi internal) sewaktu request yang pertama. Kemudian semua kelas-kelas pada direktori tersebut didaftarkan dan disimpan pada file PHP sebagai array assosatif. Dengan cara tersebut, request selanjutnya tidak membutuhkan pemeriksaan direktori lagi. Inilah mengapa anda perlu membersihkan cache setiap kali anda menambah atau memindahkan sebuah file kelas dalam proyek dengan memanggil perintah symfony clear-cache. Anda akan banyak belajar lebih banyak tentang cache pada Bab 12, dan tentang konfigurasi autoloading pada Bab 19.

Kesimpulan

Menggunakan framework MVC memaksa anda untuk membagi dan mengorganisasi kode menurut konvensi framework tersebut. Kode presentasi berada pada view, kode manipulasi data berada pada model, dan logika manipulasi request berada pada controller. Hal ini membuat aplikasi dengan kedua pola MVC tersebut sangat membantu dan juga membatasi.

Symfony adalah sebuah framework MVC yang ditulis menggunakan PHP 5. Strukturnya didesain untuk mendapatkan yang terbaik dari pola MVC, tetapi dengan kemudahan penggunaannya. Dengan dukungan kepandaian yang bermacam-macam dan dapat dikonfigurasi, symfony cocok digunakan untuk semua proyek-proyek aplikasi web.

Sekarang anda mengerti teori yang mendasari di belakang symfoni, anda hampir siap untuk membangun aplikasi yang pertama. Tetapi sebelumnya, anda perlu memasang dan menjalankan symfony pada server pengembangan anda.