All posts tagged cake

Upload file in CakePHP using Media Plugin

There are many solutions to handle file upload in PHP, one of the common solutions is to create a custom action that will check the type of the file, size, validate whether the file name already exists or not, and the last thing is moving the file using move_uploaded_file(). However, it doesn’t end when the files are in your server, after that you still need to write a function to delete the files, manipulate it if needed and so on.

I already tried several ways to handle upload file in CakePHP, from writing a private action in the app_controller and the last I write a component.

I can upload file, delete file, check the file type using my Upload Component, but I realize that there are many things missing in my component.

In searching for inspiration, I found CakePHP do have serveral plugins to handle File Upload and the features are beyond my component.

One of the plugin is Media Plugin by Davidpersson.

Using the plugin is quite easy, but the wiki and the CakeFest slide is not updated with the new configuration ( I am using v1.3alpha ), so you need to jumped in to the core and trying to understand the new configuration.

Basically the plugin consist of several behaviours :

  • Transfer
  • Polymorphic
  • Meta
  • Generator
  • Coupler

But in this post I will just cover the Transfer,Coupler and Meta behaviour because I only understand these behaviours. So lets go to the implementation part, here is my CakePHP and Media Plugin version :

  1. CakePHP 1.3.0
  2. Media Plugin 1.3 alpha

First you must create a table that has a ‘file’ field in it. Remember, the field must be named ‘file’ or the plugin won’t working. Here is the example with my application :

CREATE TABLE IF NOT EXISTS `photos` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `file` varchar(255) NOT NULL,
  `dirname` varchar(255) NOT NULL,
  `basename` varchar(255) NOT NULL,
  `checksum` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=13 ;

The field that will be used by the plugin are file, dirname, basename, and checksum. But the three last fields is optional, so you can have it in your table or not (if you are using Coupler, and Meta behaviour you MUST add the there fields ). Next, bake the application ( I was using ‘cake bake’ command ).

After that grab the Media Plugin from the github and put it in the plugins folder of your application. Next you will need to include the plugin to your application, open your bootstrap.php / core.php and add this line in it :

require APP . 'plugins/media/config/core.php';

Then create the folder that will be used for storing the files. Go to your application folder in terminal and type this command ( ex: /var/www/sample ) :

cake media init

The command will ask whether you want to create the directories or not, this is the print out of my terminal :

rudy@rudy-laptop:~/www/dummy$ cake media init
---------------------------------------------------------------
Media Shell
---------------------------------------------------------------
Do you want to create missing media directories now?
[n] > y
/dummy/webroot/media/                              [OK  ]
/dummy/webroot/media/static/                       [OK  ]
/dummy/webroot/media/static/aud                    [OK  ]
/dummy/webroot/media/static/css                    [OK  ]
/dummy/webroot/media/static/doc                    [OK  ]
/dummy/webroot/media/static/gen                    [OK  ]
/dummy/webroot/media/static/ico                    [OK  ]
/dummy/webroot/media/static/img                    [OK  ]
/dummy/webroot/media/static/js                     [OK  ]
/dummy/webroot/media/static/txt                    [OK  ]
/dummy/webroot/media/static/vid                    [OK  ]
/dummy/webroot/media/transfer/                     [OK  ]
/dummy/webroot/media/transfer/aud                  [OK  ]
/dummy/webroot/media/transfer/css                  [OK  ]
/dummy/webroot/media/transfer/doc                  [OK  ]
/dummy/webroot/media/transfer/gen                  [OK  ]
/dummy/webroot/media/transfer/ico                  [OK  ]
/dummy/webroot/media/transfer/img                  [OK  ]
/dummy/webroot/media/transfer/js                   [OK  ]
/dummy/webroot/media/transfer/txt                  [OK  ]
/dummy/webroot/media/transfer/vid                  [OK  ]
/dummy/webroot/media/filter/                       [OK  ]
 
/dummy/webroot/media/transfer/.htaccess is not in your webroot.
Remember to set the correct permissions on transfer and filter directory.

Change the permission of the folder so that the webserver can write in it :

chown -R www-data webroot/media

Configure the ‘Photo’ model like this :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Photo extends AppModel {
	var $name = 'Photo';
	var $displayField = 'title';
	var $actsAs = array('Media.Transfer','Media.Coupler','Media.Meta');
	var $validate = array(
		'file' => array(
			'mimeType' => array(
			'rule' => array('checkMimeType', false, array ( 'image/jpeg', 'image/png'))
		),
		'size' => array(
			'rule' => array('checkSize' , '5M')
		)
	));
}

As you can see, I added 3 behaviors ( Transfer, Coupler and Meta ). The transfer behavior is used for uploading, moving and validating the file. The coupler is for deleting the file ( it will automatically delete the file if you delete a record associated with it and also will automatically add the value in dirname and basename ), the last thing that it will do is adding the meta description to the table ( checksum ).

Edit the add.ctp and adding the ‘type’ => ‘file’ in the $this->Form->create and the $this->Form->input(‘file’) so the form can handle file upload. In the controller you don’t need to change anything because the behavior automatically handle the validation, the path and moving the file. this is my controller :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?php
class PhotosController extends AppController {
 
	var $name = 'Photos';
 
	function index() {
		$this->Photo->recursive = 0;
		$this->set('photos', $this->paginate());
	}
 
	function view($id = null) {
		if (!$id) {
			$this->Session->setFlash(sprintf(__('Invalid %s', true), 'photo'));
			$this->redirect(array('action' => 'index'));
		}
		$this->set('photo', $this->Photo->read(null, $id));
	}
 
	function add() {
		if (!empty($this->data)) {
			$this->Photo->create();
			if ($this->Photo->saveAll($this->data)) {
				$this->Session->setFlash(sprintf(__('The %s has been saved', true), 'photo'));
				$this->redirect(array('action' => 'index'));
			} else {
				$this->Session->setFlash(sprintf(__('The %s could not be saved. Please, try again.', true), 'photo'));
			}
		}
	}
 
	function edit($id = null) {
		if (!$id && empty($this->data)) {
			$this->Session->setFlash(sprintf(__('Invalid %s', true), 'photo'));
			$this->redirect(array('action' => 'index'));
		}
		if (!empty($this->data)) {
			if ($this->Photo->save($this->data)) {
				$this->Session->setFlash(sprintf(__('The %s has been saved', true), 'photo'));
				$this->redirect(array('action' => 'index'));
			} else {
				$this->Session->setFlash(sprintf(__('The %s could not be saved. Please, try again.', true), 'photo'));
			}
		}
		if (empty($this->data)) {
			$this->data = $this->Photo->read(null, $id);
		}
	}
 
	function delete($id = null) {
		if (!$id) {
			$this->Session->setFlash(sprintf(__('Invalid id for %s', true), 'photo'));
			$this->redirect(array('action'=>'index'));
		}
		if ($this->Photo->delete($id)) {
			$this->Session->setFlash(sprintf(__('%s deleted', true), 'Photo'));
			$this->redirect(array('action'=>'index'));
		}
		$this->Session->setFlash(sprintf(__('%s was not deleted', true), 'Photo'));
		$this->redirect(array('action' => 'index'));
	}
}
?>

and this is my add view :

1
2
3
4
5
6
7
<?php echo $this->Form->create('Photo',array('type' => 'file'));?>
	<?php
		echo $this->Form->input('title');
		echo $this->Form->input('file',array('type' => 'file'));
	?>
<?php echo $this->Form->end(__('Submit', true));?>
</div>

Now you are ready to uploading files, deleting files, and validate them in the model ( for validation you can see the wiki in the github for complete validation ). That’s all :D

Lithium atau Li3 : PHP 5.3++ Framework

Setelah 3 hari dicekcoki dengan lagu Boyce Avenue yang diputar berulang-ulang di foobar akhirnya gwa jadi ada semangat buat update blog. Sebenarnya pengen nulis tentang Ruby on Rails dan e-TextEditor tapi keknya lebih pengen tulis tentang Lithium dulu deh.

Jadi apakah Lithium itu ? merk baterai ? merk baju ? merk mobil ? merk parfum ? atau merk deterjen ? jelas saja bukan. Lithium yang saya gwa maksud disini adalah salah satu framework PHP yang tersohor sekali seantero jagad raya, sampe presiden SBY aja kalo pidato dicoding dolo pake neh framework. Itu versi lebainya, sebenarnya Lithium atau Li3 ini adalah sebuah framework besutan bekas pentolan ex project manager dan lead developernya CakePHP.

Seperti yang kita ketahui bersama bahwa Garrett J. Woodworth ( gwoo ) dan Nate Abele ( _nate_ ) memutuskan untuk hengkang dari CakePHP kira-kira 2-3 bulan lalu. Banyak desas-desus mengatakan kalau mereka terlibat konflik dengan foundernya CakePHP ( PhpNut ) dimana founder CakePHP ini tidak setuju dengan ide mereka tentang Cake 3.0.

Karena itulah akhirnya mereka minta cerai dan membuat framework sendiri yang basisnya dari Cake 3.0 dan diberi nama Lithium. Mungkin yang menjadi pertanyaan yang muncul di benak kita adalah apakah kehebatan framework baru ini ? kenapa kita harus belajar pake framework ini ? haruskah kita meninggalkan framework lama demi Li3 ? apa yang harus kita katakan kepada anak istri kita ? apakah orang tuaku akan setuju dengan keputusan ini ? aku ini anak siapa ? pacarku lagi dimana ? dan banyak pertanyaan-pertanyaan lainnya…

Beberapa fitur yang sempet gwa baca-baca dan sepertinya menarik adalah :

  • Li3 menggunakan namespace yang sebenarnya sampai sekarang gwa belum mengerti banyak sih. Tetapi setau gwa namespace adalah fitur baru dari PHP 5.3 yang katanya dapat mempercepat performa dari framework ini.
  • Li3 hanya untuk PHP 5.3++, berbeda dengan CakePHP yang mendukung PHP 4 & 5. Hal inilah yang katanya salah satu pemicu kenapa founder CakePHP tidak menyetujui Cake 3.0
  • Code Covention dimana disebutkan bahwa Lithium adalah framework pertama yang menggunakan Code Convention sehingga nanti kita dapat menggabungkan Lithium dengan framework seperti Symfony, dan Zend Framework
  • Lithium dibangun untuk menjadi framework yang RAD ( rapid application development ) dan Light Weight ( ringan )

Itulah beberapa fitur yang sempat gwa baca dan tentang Lithium. Untuk sekarang developmentnya baru menginjak versi 0.3, masih terlalu dini untuk membangun sebuah aplikasi dengan menggunakan framework ini tapi melihat dari visi yang ingin dicapai dan pengalaman dari developernya membuat framework ini salah satu framework yang menjanjikan nantinya.

Bayangkan jika nanti kita bekerja sama dengan orang yang menggunakan framework Symfony, karena adanya Code Convention kita dapat dengan mudah menggabungkan library-library dari framework yang berbeda. Berapa banyak waktu yang bisa kita hemat dan tentu saja seberapa bahagianya istri atau pacar kita nanti melihat kerjaan kita cepat kelar, apalagi anak di rumah semakin senang karena ayahnya punya waktu lebih banyak buat main sama dia.

Tapi untuk sekarang gwa sih lebih pengen belajar Ruby on Rails dulu, tar kalo Lithium dah stable baru jajal ini framework. :D

Group select box di CakePHP

Grouping di dalam select box adalah hal yang gampang ketika kita menggunakan codingan php biasa, tetapi kalau sudah masuk ke dalam codingan CakePHP kita harus banyak membaca documentation untuk teknik2nya, tickets jika ada yang pernah menanyakan hal yang sama dan tentu saja API agar kita tahu fungsi dari method yang akan kita pakai.

Jadi sekarang kita akan membuat sebuah grouping dalam select box seperti dalam gambar di bawah ini :

CakePHP Group Select

CakePHP Group Select

Di dalam contoh diatas gwa menggunakan 3 buah table di antaranya table majors ( jurusan ), table faculties ( fakultas ) dan table levels ( untuk pembagian apakah dia D3/S1 ). Hal pertama yang harus kita lakukan adalah men-query isi table dari majors ( dalam hal ini gwa menggunakan ClassRegistry karena table majors tidak ada relation dengan controller gwa ) :

1
2
3
4
$majors = ClassRegistry::init("Major")->find("all");
 
atau kalau punya relation / berada dalam controller sendiri
$majors = $this->Major->find("all");

Kemudian kita akan menggabungkan hasil query tersebut dan menyusunnya menjadi array yang jika kita masukkan ke dalam form helper maka akan secara otomatis menjadi select box yang tergroup. Kita akan menggunakan bantuan Set::combine untuk melakukan hal tersebut. Berikut contoh codingannya :

1
2
3
4
$majorsCombine = Set::combine($majors, "{n}.Major.id", array("%s - %s",
"{n}.Level.name", "{n}.Major.name"), "{n}.Faculty.name"); 
 
untuk penjelasan parameternya dapat dilihat di API CakePHP : <a href="http://api.cakephp.org/class/set#method-Setcombine">API CakePHP</a>

sedikit penjelasan tentang parameter yang gwa gunakan yaitu :

  • $majorsCombine Nama variable penampung.
  • Set::combine Nama method yang kita gunakan.
  • $majors Sumber data kita
  • {n}.Major.id Path pertama atau biasanya nilai dari select box kita
  • array(‘%s – %s’,'{n}.Level.name’, ‘{n}.Major.name’) Kalau ini path kedua yang berfungsi sebagai label dari isi select box kita, jika dilihat itu isinya ada level dan major jadi nanti keluarnya ( S1 – Teknik Informatika )
  • {n}.Faculty.name’ ini nama groupnya

Selanjutnya tinggal digunakan saja di viewnya seperti ini :

1
<?php echo $form->select("nama-form",$majorsCombine,null,null,"-- Pilih Jurusan Pertama --"); ?>

Penjelasannya kira-kira begini :

  • $form->select ini form helper yang kita gunakan
  • nama-form nama form helper yang kita gunakan
  • $majorsCombine sumber data
  • null,null,’– Pilih Jurusan Pertama — parameter tambahan lagi

Semoga membantu, silakan dicoba.. kalau ga jalan, dicoba lagi, kalau ga jalan juga ya sudah terima nasih aja :D

Review CakePHP

Setelah sekian lama ga update blog, akhirnya update blog lagi deh… Untuk kali ini ga bakalan cerita-cerita yang aneh-aneh ataupun yang lucu-lucu… soalnya emang lagi ga ada kejadian yang benar-benar “klik” yang bisa diceritakan ( beberapa hari ini semua terasa semu hix ).

Jadi kali ini gwa akan melakukan review terhadap framework PHP yang sudah gwa pelajari kurang lebih 5 bulan lamanya yaitu CakePHP. Selama 5 bulan ini gwa lewati dengan mempelajari CakePHP, dari baca ebook, nonton video tutorial sampai tanya-tanya sama orang-orang di channel #cakephp di irc.freenode.net.

Dalam waktu 5 bulan ini sudah banyak yang gwa pelajari dari CakePHP, tapi tetep masih lebih banyak lagi yang harus dipelajari dari CakePHP… Jadi intinya gwa bakal sharing apa yang sudah gwa dapatkan setelah lebih kurang 5 bulan mempelajari CakePHP ( FYI, gwa belom pernah pakai framework lain selain CakePHP ).

Salah satu hal yang gwa dapatkan dari mempelajari CakePHP adalah mengerti arsitektur MVC ( Model View Controller ). Untuk yang pengen tahu lebih banyak tentang MVC dapat dibaca di http://en.wikipedia.org/wiki/Model-view-controller.

Tapi gwa coba rangkum beberapa hal yang gwa mengerti tentang MVC, dalam pemprograman MVC seluruh program dibagi menjadi 3 bagian utama yaitu Model ( berhubungan dengan database ), Controller ( berhubungan dengan logic ), View ( berhubungan dengan tampilan program). Jadi jika pada pemprograman procedural atau pemprograman barbar kita bagi dalam function-function, maka pada MVC kita harus membaginya menjadi 3 bagian besar.

Jika kita ingin melakukan query,validasi, edit data kita masukkan ke dalam Model. Kalau kita ingin mengatur aliran data maka kita memasukkannya ke dalam Controller, dan yang terakhir kali jika kita ingin mengatur tampilan dari program kita ( designnya ) maka kita atur di View. 3 hal tersebut saling berhubungan dan mempunyai peran masing-masing.

Selain MVC tentu saja gwa banyak mempelajari penggunaan dari CakePHP itu sendiri. Penggunaan Helper-helper seperti AJAX, Session, Javascript, dan HTML. Jadi CakePHP secara default sudah menyediakan beberapa helper. Helper itu sendiri adalah sebuah class yang dapat digunakan untuk membantu kita dalam membuat aplikasi sesuai dengan helper yang kita gunakan. Jadi jika kita ingin membuat sebuah website yang menggunakan AJAX, kita dapat menggunakan AJAX helper yang dapat meringankan tugas kita dalam membuat aplikasi AJAX itu. Sama halnya jika kita ingin membuat session maka kita dapat menggunakan session helper untuk membantu kita mengatur session di CakePHP.

Selain helper dikenal juga istilah element di dalam CakePHP. Element disini bukan berarti elemen air, elemen api, elemen tanah. Element di dalam CakePHP itu lebih dapat diartikan sebagai view yang reuseable. Jadi misalnya kita mempunyai sebuah form dan kita ingin membuat form tersebut di 2 view yang berbeda maka kita dapat menggunakan element. Jadi kita tidak perlu membuat ulang kembali form tersebut di 2 view yang berbeda, cukup buat sebuah element dan panggil element tersebut di 2 view itu.

Paging dengan element

Paging dengan element

Dan satu hal lagi yang harus diperhatikan dalam merancang sebuah aplikasi dengan menggunakan konsep MVC adalah Model sebaiknya lebih memiliki banyak method dibandingkan controller. Hal itu dikarenakan konsep dari OOP itu sendiri yaitu ‘reuseable’.

Jadi gwa bisa menyimpulkan selama 5 bulan apa saja keuntungan yang didapatkan dari mempelajari CakePHP

  • Mengerti konsep MVC.
  • Waktu untuk mendevelop program menjadi lebih cepat.
  • Source code menjadi lebih terstruktur.
  • Kemampuan berbahasa inggris meningkat ( banyak baca cookbook + tanya2 pakai bahasa inggris wakaka.

Walaupun gwa tidak menampik adanya kerugian-kerugian yang didapatkan dari mempelajari CakePHP, ini beberapa kerugian tersebut :

  • Harus belajar kembali karena dengan menggunakan framework tentu saja kita harus mempelajari API yang sudah tersedia.
  • Aplikasi jadi lebih lemot.
  • Jadi makin malas karena sudah dimanjakan dengan fitur-fitur walaupun tidak semalas karena menggunakan CMS
  • Makin lupa syntax2 PHP yang dasar karena keseringan menggunakan syntax CakePHP

Tapi walaupun begitu semua kekurangan itu tertutupi oleh kelebihan-kelebihan yang didapatkan dari mempelajari CakePHP tersebut. Yah jelas, kalau banyak ruginya napaen gwa capek-capek belajar framework. Mungkin ada yang beranggapan kalau menggunakan framework itu sendiri dapat memperbodoh diri sendiri, dan gwa pun tidak menampik hal tersebut.

Tapi gwa menganalogikan mempelajari framework ini seperti sedang memasak mie goreng. Bedanya jika kita menggunakan framework maka kita menggunakan mie yang sudah dijual di pasaran tanpa kita tahu cara membuat mie tersebut. Sementara orang yang tidak menggunakan framework adalah orang yang membuat mienya sendiri.

Pertanyaannya adalah apakah mie goreng yang dibuat dengan mie jualan di pasar pasti lebih enak daripada mie yang dibuat sendiri ? bagaimana sebaliknya ? tentu saja jawabnya tergantung dari banyak faktor ( bisa kualitas mie, bisa kemampuan orang yang memasak ).

Sama halnya dalam menggunakan framework, seberapa bagusnya aplikasi kita bukan saja ditentukan dari framework apa yang kita gunakan, bukan juga ditentukan dari apakah kita menggunakan framework atau tidak. Tetapi juga ditentukan dari kemampuan orang tersebut, karena di mata client tetap saja yang dilihat itu adalah hasil jadinya, bukan codingannya ( kebanyakan client kan ga ngerti2 banget :P ). Jadi client mana mo tau itu mie hasil buat sendiri ato hasil beli di pasar, yang mereka tahu cuma “mie ini enak”, “mie ini ga enak”. Udah itu aja, simple sekali kan ?

Yah sebenarnya kalau mau didebatkan lagi sebenarnya banyak yang bisa didebatkan tapi intinya sekarang gwa malas nulis panjang-panjang dan juga tentu saja gwa mendukung semua orang untuk mempelajari framework. Kenapa ? karena sekarang persaingan sudah semakin ketat, kita sekarang membuat aplikasi semakin mudah dan semakin cepat. Ibarat kata pepatah “Siapa cepat dia dapat”. Sekarang itu ada di tangan anda, apakah anda ingin memakai mie yang dijual atau buat mie sendiri :P hohoho yang penting untuk sekarang 5 star buat CakePHP deh :)