Wednesday, February 18, 2009

Zend Framework - what a configuration

Hari ini mencoba sesuatu yang baru. Menggunakan 3 orang berpengalaman (including.. me:) )untuk menyelesaikan satu hal sepele.. yaitu mengkonfigurasi sebuah aplikasi PHP berbasis Zend Framework sehingga bisa ditaruh di folder selain webroot. Sebenarnya, tidak ada satupun yang pernah menggunakan Zend Framework (kami terbiasa dengan CakePHP dan CodeIgniter), jadi tentunya tetap ada tantangan.
CodeIgniter menggunakan file konfigurasi system/application/config/config.php untuk menset base_url, dan pada CodeIgniter yg kami pakai sudah ada algoritma deteksi otomatis yang berfungsi baik.
$config['base_url'] = "http://".$_SERVER['HTTP_HOST'];
$config['base_url'] .= preg_replace('@/+$@','',dirname($_SERVER['SCRIPT_NAME'])).'/';
Neverthless, untuk Zend tampaknya konfigurasi disimpan di file app.ini. Ternyata, agak sulit juga mencari dokumentasi tentang isi file ini. Setelah membrowsing-browsing cukup lama, kami menemukan dokumentasi fungsi setBaseUrl di FrontPageController. Pertanyaannya.. darimana ini harus disetup? Hipotesa bahwa baseUrl ini seharusnya diubah via app.ini ternyata salah, kami selanjutnya menemukan bahwa ada orang yang mengubah baseUrl di bootstrap.php.
Dan.. setelah mengikuti itu pun.. tetap saja aplikasi merefer ke CSS dan JS yang ditulis tanpa prefix baseUrl yang baru diset..
Penelusuran lebih lanjut, dengan lead dari seseorang dari kami yang menunjukkan bahwa kita baru menset baseUrl di controller, di mana ada kode pada view mengasumsikan keberadaan $this->baseUrl, yang mana.. ternyata bukan standar Zend Framework..
Mengutip seorang teman yang lebih senior, ternyata embe itu bukan kuda, memang Controller dengan View itu berbeda.. (lain dengan CodeIgniter ya, di mana $this di Controller ekivalen dengan $this di View)
Setelah browsing lebih lanjut, ketemu di blog entry ini dan juga ini, yang menjelaskan bahwa ini memang bukan standar Zend Framework, tapi kita dapat mensetnya di bootstrap.php (juga).
Intinya, cara yang standard dari Zend ialah membuat view dengan kode seperti :
<a href="<?php echo $this->url(array(
'controller' => 'user',
'action' => 'edit',
'id' => '123'
));?>">click me!</a>
untuk menggantikan
<a href="/my_app/user/edit/id/123/">click me!</a>

Tetapi ada cara yang lain (non-standard), yaitu
<a href="<?=$this->baseUrl ?>/user/edit/id/123/">click me!</a>
Sambil menambahkan di bootstrap.php sehingga (garis besarnya) ada fragmen seperti berikut:
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
//view renderer (from the helper broker)
if (is_null($viewRenderer->view)) {
$viewRenderer->init();
//force instantiation of the view
}

$frontController = Zend_Controller_Front::getInstance();
//frontcontroller

//... additional front controller setup goes here ...

$frontController->setBaseUrl('/my_app');
//set your base URL here

$viewRenderer->view->baseUrl = $frontController->getBaseUrl();
//set baseUrl for views, retrieved from the front controller

$response = $frontController->dispatch();
//do... something!
What a configuration. Sebetulnya kalo programmer aslinya (hiudah pakai url helper semua bakal beres. Dan ternyata, masih banyak URL yang ditulis bahkan tanpa referensi ke $this->baseUrl ataupun $this->url(...), yang harus ditulis ulang supaya aplikasi dapat hidup di dalam sebuah folder di bawah webroot.
The moral is.. know your framework well.. or else you'll be shot in

What? No delete event in Liferay Social Office?

A strange thing indeed, for some company to release a beta software which is not functionally complete. I always thought that a beta software is fully functional but without a production-grade stability. Of course, the software industry has its historical anti-example such as QuarkXpress (3.3 or 4, I forgot) which had an alpha release, beta release, and gamma release, before the true 'Release'.
Liferay Social Office is a simplification of Liferay Portal, configured for optimum social interaction, and in my opinion, knowledge sharing and management. What they really do is rewrite some GUI codes so the resulting UI is not too complicated to master. But here lies the catch. You could create a new Calendar Event, but there is no user interface from where you could delete the event.
Someone posted the question to Liferay's forums, and the question was answered with something like
.. er.. we would include the delete functionality in the next release ..
That is not an acceptable answer for me, because we were trying to use this Social Office for one of our client departments. So, for the meantime, I must be content with adding these lines :
<c:if test="<%= CalEventPermission.contains(permissionChecker, event, ActionKeys.DELETE) %>">
<portlet:actionURL windowState="<%= WindowState.MAXIMIZED.toString() %>" var="deleteURL">
<portlet:param name="struts_action" value="/calendar/edit_event" />
<portlet:param name="<%= Constants.CMD %>" value="<%= Constants.DELETE %>" />
<portlet:param name="redirect" value="<%= redirect %>" />
<portlet:param name="eventId" value="<%= String.valueOf(event.getEventId()) %>" />
</portlet:actionURL>
<liferay-ui:icon-delete url="<%= deleteURL %>" />
</c:if>

into the webapps/ROOT/html/portlet/calendar/view_event.jsp.

Wednesday, February 4, 2009

Javascript Confusion

Ketika saya dulu mencoba library/framework jQuery, muncul sebuah pertanyaan, kapan kita mulai menggunakan framework/javascript library ? Kapan benefitnya melebihi costnya, misalnya pada waktu eksekusi halaman, kurva pembelajaran.. Pada saat itu performansi jQuery kurang memuaskan untuk kebutuhan kami. Namun karena ga begitu ngerti javascript juga, akhirnya dibiarkan pake jQuery :).
Pada kesempatan berikutnya, saya dan teman saya membuat sebuah aplikasi sederhana dengan deadline yang lumayan ketat. Javascript dihindari karena belum begitu paham dan masalah cross-browser compatibility yang lumayan pelik. Tapi, pada suatu halaman, kita terpaksa menggunakan javascript untuk membuat dua buah radio group saling terkait satu sama lain, yaitu radio group kedua hanya boleh digunakan pada saat sebuah radio button tertentu di group pertama dipilih. Cuma sebuah script onclick, dan script yang dijalankan ketika halaman diload untuk mendisable radio group kedua pada awal halaman. Kenapa nggak di PHP? Takutnya kalau user mendisable javascript, dan kondisi awal halaman sudah di-disable, dia sama sekali tidak bisa memilih radio group kedua.. Biarlah aplikasi tetap berfungsi bagi user tanpa javascript, dengan degraded functionality.
Dengan kebutuhan se-simple itu, ternyata membutuhkan berjam-jam.. dan belum bisa juga menemukan versi yang berfungsi di Internet Explorer maupun Firefox. Akhirnya, aku taruh jquery.js di folder js, dan mulai menggunakannya. Sepuluh menit pertama, sudah bisa menemukan versi yang berjalan baik di IE maupun Firefox.. Meskipun belum sepenuhnya sesuai dengan yang diharapkan. Setelah tweaking lebih lanjut, dan mencoba-coba beberapa pilihan desain (mau didisable ato dihidden ya.. :) ), akhirnya selesai.. dengan empat baris perintah jQuery :) Ya, memang satu baris jQuery itu udah bisa macam-macam.. seperti :
$("#tanya_faskes").children().attr("disabled",true);
perintah satu baris ini mendisable semua children dari element dengan id 'tanya_faskes'.. Dan berfungsi untuk semua browser.
Now, kenapa kalau di IE tulisan di daerah radio groupnya ikut di disabled .. dan kalo di Firefox tidak...