Thursday, November 25, 2010

Referential Integrity - Good or Bad?

In relational database world such as MySQL, PostgreSQL, Derby / JavaDB, and HSQLDB RDBMS there is Referential Integrity.

It's very useful to avoid consistency mistakes with foreign keys during operation.

It's useful when we live in *relational* world. But during development of a modular application and agile, frequent upgrades.. Is referential integrity helping or hindering productivity?

Consider an application that has a Customer table that has a column an refers to a Country table. Each deployment would have its own Customer table data. However, Country table is pretty much "shared" globally. Country table is never meant to be modified from the admin's perspective.

When there is a new country or modification, new version of application will be released, containing an update to Country table.

In old-school style of upgrades, Country table should be replaceable similar to how we replace files during upgrade, i.e. overwriting a file called countries.xml.

However, due to referential integrity, it's not possible to simply drop the table, recreate it with the data. We have to issue proper DML SQL statements to update the data from the "current" version (yes, we must detect what is the current version) to the new version.

All in the name of not breaking foreign key checks aka referential integrity.

Isn't RDBMS making simple things complex?

Friday, November 5, 2010

Displaying PHP Errors on Ubuntu

Default configuration of PHP 5.3 / Apache 2.2 installation on Ubuntu 10.10 Maverick Meerkat does not display any syntax errors and simply throws an Internal Server Error (HTTP Error 500).

How to enable display/output of PHP 5 error messages :
  1. Edit /etc/php5/apache2/php.ini
  2. Set the following configuration values:

    display_errors = on
    display_startup_errors = on
    html_errors = on

  3. The default error_reporting threshold is :

    error_reporting = E_ALL & ~E_DEPRECATED

    which should be enough. But you can change it if you want.


Thursday, October 28, 2010

var_export bug Fatal error: Nesting level too deep - recursive dependency? [Workaround]

When doing var_export() on nested arrays/objects with recursive dependency, you'll get an error:

Fatal error: Nesting level too deep - recursive dependency? in /some/script.php on line 123

The workaround is:

ob_start();
var_dump($data);
$dataDump = ob_get_clean();

Bug report (but is incorrectly marked as Bogus): http://bugs.php.net/bug.php?id=30471

Dependency Injection in PHP vs Java

How to do Dependency Injection in PHP vs Java.

Plain PHP:

$helper_sales = new HelperSales();

Magento proprietary SPI:

// no type information!
$helper_sales = Mage::helper('sales');

Java / CDI :

@Inject
private HelperSales helperSales;

Java / get bean from Spring context :

HelperSales helperSales = appCtx.getBean(HelperSales.class);

The Java examples apply to Scala as well, of course.

Still envy PHP?

Sunday, October 24, 2010

Displaying AJAX Tables in PHP vs Java EE: ZFDataGrid and PrimeFaces DataTable

While developing with PHP + Zend Framework + Doctrine I missed an easy way to display/edit data using a grid/table.

A very useful component I found is ZFDataGrid.

Here's a sample code of how to use ZFDataGrid:

    function simpleAction()

    {         //Zend_Config         $config = new Zend_Config_Ini('./application/grids/grid.ini', 'production');                 //Grid Initialization         $grid = Bvb_Grid::factory('Bvb_Grid_Deploy_Table', $config, 'id');                 //Setting grid source         $grid->setSource(new Bvb_Grid_Source_Zend_Table(new Bugs()));                 //CRUD Configuration         $form = new Bvb_Grid_Form();         $form->setAdd(true)->setEdit(true)->setDelete(true);         $grid->setForm($form);                 //Pass it to the view         $this->view->pages = $grid;         $this->render('index');     }
It looks pretty good too.

Check the ZFDataGrid Live Demo here.

However, working with data grids using JSF 2.0 and PrimeFaces felt much more natural and easier.

Here's a sample code using PrimeFaces' DataTable :

<h:form>

    <p:dataTable var="car" value="#{tableBean.lazyModel}" paginator="true" rows="10" lazy="true"
                 paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
                 rowsPerPageTemplate="5,10,15"
                 selection="#{tableBean.selectedCar}" selectionMode="single"
                 onRowSelectComplete="carDialog.show()" onRowSelectUpdate="display">
        <f:facet name="header">
            Displaying 100,000,000 Cars
        </f:facet>
        <p:column headerText="Model">
            <h:outputText value="#{car.model}" />
        </p:column>
        <p:column headerText="Year">
            <h:outputText value="#{car.year}" />
        </p:column>
        <p:column headerText="Manufacturer">
            <h:outputText value="#{car.manufacturer}" />
        </p:column>
        <p:column headerText="Color">
            <h:outputText value="#{car.color}" />
        </p:column>
    </p:dataTable>

    <p:dialog header="Car Detail" widgetVar="carDialog" resizable="false"
              width="200" showEffect="explode" hideEffect="explode">
        <h:panelGrid id="display" columns="2" cellpadding="4">
            <f:facet name="header">
                <p:graphicImage value="/images/cars/#{tableBean.selectedCar.manufacturer}.jpg"/>
            </f:facet>
            <h:outputText value="Model:" />
            <h:outputText value="#{tableBean.selectedCar.model}"/>

            <h:outputText value="Year:" />
            <h:outputText value="#{tableBean.selectedCar.year}"/>

            <h:outputText value="Manufacturer:" />
            <h:outputText value="#{tableBean.selectedCar.manufacturer}"/>

            <h:outputText value="Color:" />
            <h:outputText value="#{tableBean.selectedCar.color}"/>
        </h:panelGrid>
    </p:dialog>

</h:form>

The above code may look verbose, but it packs a lot of functionality and it's very easy and intuitive to customize.
When you click a row it displays a nice dialog with a picture. Furthermore, it's actually lazy loading 100,000,000 rows!! (yes, ONE HUNDRED MILLION ROWS)

Here's how it looks:

You can see for real the PrimeFaces DataTable Lazy-loading Live Demo here.

It's very easy to add lazy-loading support to DataTable:

        lazyModel = new LazyDataModel<Car>() {

/**
* Dummy implementation of loading a certain segment of data.
* In a real application, this method should load data from a datasource
*/
@Override
public List<Car> load(int first, int pageSize, String sortField, boolean sortOrder, Map<String,String> filters) {
logger.log(Level.INFO, "Loading the lazy car data between {0} and {1}", new Object[]{first, (first+pageSize)});

                //Sorting and Filtering information are not used for demo purposes just random dummy data is returned

List<Car> lazyCars = new ArrayList<Car>();
populateLazyRandomCars(lazyCars, pageSize);

return lazyCars;
}
};

        /**
         * In a real application, this number should be resolved by a projection query
         */
        lazyModel.setRowCount(100000000);

Not to disrespect PHP or ZFDataGrid in anyway (I still need to use them for some of my work), but the experience with JSF 2.0 and PrimeFaces wins hands down. I think it's more because of PrimeFaces than JSF 2.0, but they're such a powerful combo (compared to if you use PrimeFaces with JSF 1.2).

I do hope that PrimeFaces provide a utility class that implements LazyDataModel for a Hibernate/HQL or JPA/JPQL query, but for now I can live with the above.

Fix CDATA Bug on WordPress 3.0.1's WXR Export

Today I migrated one of my client's website from WordPress 3.0.1 to Drupal CMS 6.19.

I used WordPress's export function to create a WXR backup/dump file and imported it to Drupal using WordPress Import module.

Unfortunately the WXR export file is unreadable/broken because it is non well-formed.

Some investigation reveals that WordPress export doesn't escape CDATA content properly, i.e. content containing "]]>" is left unescaped.

]]>

should be escaped as

]]]]><![CDATA[>

I've reported this bug as Ticket #15203 on WordPress Trac.

I've also provided a patch as below:

diff --git a/wp-admin/includes/export.php b/wp-admin/includes/export.php
index a9e8f22..cd3a9d4 100644
--- a/wp-admin/includes/export.php
+++ b/wp-admin/includes/export.php
@@ -138,6 +138,7 @@ function export_wp( $args = array() ) {
                        $str = utf8_encode( $str );

                // $str = ent2ncr(esc_html($str));
+               $str = str_replace(']]>', ']]]]><![CDATA[>', $str);
                $str = "<![CDATA[$str" . ( ( substr( $str, -1 ) == ']' ) ? ' ' :

                return $str;


This fixed export functionality. However I think the import functionality is still affected, as it doesn't use a proper XML Parser (see WordPress Trac Ticket #7400).

With WordPress WXR fixed I can import WordPress contents to Drupal successfully.

P.S. WordPress Import module v6.x-2.1 for Drupal fails under PHP 5.3. Solution: Use the latest WordPress import module v6.x-2.x-dev.

Fix CDATA Bug on WordPress 3.0.1's WXR Export

Today I migrated one of my client's website from WordPress 3.0.1 to Drupal CMS 6.19.

I used WordPress's export function to create a WXR backup/dump file and imported it to Drupal using WordPress Import module.

Unfortunately the WXR file is unreadable because it is non well-formed.

Some investigation reveals that WordPress export doesn't escape CDATA content properly, i.e. content containing "]]>" is left unescaped.

        ]]>


should be escaped as

]]]]><![CDATA[>

I've reported this bug as Ticket #15203 on WordPress Trac.

I've also provided a patch as below:

diff --git a/wp-admin/includes/export.php b/wp-admin/includes/export.php
index a9e8f22..cd3a9d4 100644
--- a/wp-admin/includes/export.php
+++ b/wp-admin/includes/export.php
@@ -138,6 +138,7 @@ function export_wp( $args = array() ) {
                        $str = utf8_encode( $str );

                // $str = ent2ncr(esc_html($str));
+               $str = str_replace(']]>', ']]]]><![CDATA[>', $str);
                $str = "<![CDATA[$str" . ( ( substr( $str, -1 ) == ']' ) ? ' ' :

                return $str;

This fixed export functionality. However I think the import functionality is still affected, as it doesn't use a proper XML Parser (see WordPress Trac Ticket #7400).

With WordPress WXR fixed I can import WordPress contents to Drupal successfully.

P.S. WordPress Import module v6.x-2.1 for Drupal fails under PHP 5.3. Solution: Use the latest WordPress Import module v6.x-2.x-dev.

Sunday, October 10, 2010

Drupal 7.0 beta 1 Released [Announcement]

Our final Drupal 7 alpha version was released about three weeks ago. Today, we're proud to announce the first beta version of Drupal 7.x for your further testing and feedback!

The jump between alpha to beta means the following:

  • We think that we have resolved all critical data loss and security bugs in Drupal 7.
  • We think that our APIs are now frozen enough so that contributed module and theme authors can start (or pick up again) their #D7CX pledges.
  • We think that we have caught and fixed most of the problems with the upgrade path. We were able to successfully upgrade a copy of the Drupal.org database to Drupal 7.

That said, we definitely still have some bugs to shake out, and we need your help to find them! Especially new folks who haven't taken Drupal 7 for a spin yet. So please, do so, and let us know what bugs you find in the "Drupal core" issue queue (Please search incoming issues before filing).


What's new? Tons of stuff! A revamped user interface, a new admin and default core theme, image handling in core, fields (CCK!) in core, module and theme upgrades from within the browser, an automated testing framework with over 24,000 tests, improved security and scalability, revamped database, AJAX, and file systems, jQuery 1.4, jQuery UI 1.8, RDFa, and literally gazillions of other things! Please see CHANGELOG.txt for a comprehensive list of all improvements in Drupal 7.


Updating from previous versions The upgrade path from 6.x => 7.x is actually working reasonably well right now. We need people to test this like crazy! Most of the security issues in Drupal 7 have now been addressed, but the beta should still only be installed for testing and new development or working on migration from 6.x. If you are a module or theme developer, and you haven't started porting your modules and themes to 7.x yet, now is the time! Please report anything you find so that we can be sure to support your contributions.

Always make backups of your data and never do testing on your live site. This is to make sure you keep all of your information intact even if something goes wrong.


So when does 7.0 get released? The release version of Drupal 7.0 will be ready after (a) there are no more critical bugs and (b) we've had at least one release candidate (RC) without adding any more issues to the list.

When will that be? Well, it depends entirely on how many people chip in and help out! The more people help, the faster we can find and fix bugs, and the faster 7.0 gets released. The faster 7.0 gets released, the faster we can start adding new features to Drupal 8.0. So help out where you can, and let's make this the best and most solid release of Drupal yet! :)


How do I help test the beta? Start by either installing a new Drupal site or upgrading an existing one running on a previous version (see INSTALL.txt or UPGRADE.txt in the package). When setting up a new site, you can use the Development module to generate some test data (content, users, etc) to help you start testing quickly. As with everything still in development, we do not recommend running pre-releases on a live site. Also, always make sure to backup of your data before performing an upgrade or start testing.


New Drupal Users Are you completely (or relatively) new to Drupal? Or do you know just enough to be dangerous? Are you used to working with other content management systems and willing to lend your perspective in improving the way Drupal works? If so, you're a perfect candidate to help with usability testing and improving documentation! As you're going through Drupal 7, take notes on things you find difficult or confusing, and translate those notes into an issue which will show up in the issue tracker. Make sure to be as clear as possible about what the problem was and provide suggestions on how to improve it -- this makes it easier for developers to help!

You can also help by testing the D7 Install Guide and noting any mistakes on the issue for this.


Testers Do people often congratulate you on your ability to break things? Are you a creative individual who likes to experiment in unconventional ways to see what happens? Do you enjoy looking over other peoples' work and picking nits in order to make it as good as it possibly can be? If any of these apply to you, you could make a great tester! We need testers both to try out different aspects of Drupal itself, as well as take a look at the issue queue, checking bugs to see if they're valid and testing patches to verify they work properly. Read more about setting up a testing environment and applying patches.


Module and theme developers There is no better way to shake out any lingering bugs with the API and to ensure that your modules and themes will work with the new version of Drupal than to update your modules and update your themes! Make sure to file any bugs that you find! And try coding some upgrade routines to help make the process smoother for the next person!


Drupal Ninjas and Ninjas-in-training If you're adept at Drupal hacking, or are eager to learn, a great place to start is with the bug tracker or the patch queue. Even if you don't have a full solution for a problem, often even a step in the right direction can be enough for another developer to take it home! Read up on how to create patches.


Drupal interface translators The interface strings of Drupal 7.0 are mostly frozen. The days of major changes to the UI strings are over, but we still are changing texts to fix bugs or to lend clarity in the interface. Around release candidate 1, a formal "string freeze" will be declared at which point it should be safe to start translating.

Source: http://drupal.org/drupal-7.0-beta1

Friday, October 8, 2010

Relational DBMS vs Object-oriented DBMS vs Document-oriented databases issue is moot when you're already using multiple data stores!

The issue of:

1. Relational databases (RDBMS) e.g. MySQL, PostgreSQL, SQLite, JavaDB, HSQLDB... versus
2. Object-Oriented databases (OODBMS) e.g. db4o... versus
3. Document-oriented databases e.g. MongoDB, Apache CouchDB...

...is probably because many developers (including me! :) are not aware that the application is already using multiple data stores at once.

Note: Practically all data stores, except OODBMS, will require some form of roundtrip serialization, object-mapping and code generation to be conveniently usable inside an application, accessible not only via framework/library API but also via domain model objects and classes.

By the way even if you use an OODBMS, if you use features that require specific language support (e.g. Weaving traits and behaviors, like soft deletes, timestampable, nested sets) and the language (e.g. PHP, Java) doesn't support it, you'll still need to do either code generation, manual coding, or be content with dynamic proxying (say goodbye to IDE code hints!)

Why pick just one data store and debate?

A few I have in mind right now is:

1. Key-value stores.
The application INI configuration file.
Cache storage, be it file-backed, memcached-backed, or even RDBMS-backed! (you're just abstracting/implementing a key-value store on top of a relational schema).
Translation/localization data is sometimes also stored using this store.
Web application Session data also uses key-value (though it does automatic de/serialization).

2. Hierarchical data store / Object store.
XML file.
A hierarchy of folders, subfolders, and files.
In the case of Zend Frameworks's Zend_Config, also INI files.
JSON file.
YAML file.
CSS file (surprising, eh? Though it's only two levels deep.)
I think there's no such thing as an "object store". What exists is a data store that acts like an object repository, that does automatic de/serialization of objects, that stores its data in a hierarchical store or content/document store or hybrid.
How an object is serialized/its serialization representation (i.e. "should a GeoPoint instance be embedded or linked?") should be specifiable through some form of metadata/configuration/annotations.
The object graph, by itself, does not contain sufficient information to be managed as a data store.

3. Content/Document store.
A content store doesn't always restrict a type to a schema. It allows arbitrary properties to be attached to a content node.
Some content stores also allow nesting (hierarchical content stores).
The filesystem (fixed standard schema), but some filesystems support additional metadata.
The node API in Drupal (implemented on top of RDBMS).
The EAV tables in Magento (implemented on top of RDBMS).
Natively: the JCR (Java Content Repository) in Alfresco & Jackrabbit (Java), MongoDB, Apache CouchDB, Persevere.

4. Binary/BLOB store.
It's basically a key-value store with support for huge values and block/partial access.
The filesystem.
S3.

5. Structured markup.
HTML. Wiki format. Markdown. Textile.
All fits in one string.

6. Full text index store.
Apache Lucene.
Zend_Lucene.

7. Search store.
Apache Solr.
The search/faceted navigation index in Magento (built on top of RDBMS).

Did I miss something?

Thursday, October 7, 2010

Diem Content Management Framework: How does it compare to Drupal?

Replying to Aviblock's article : Diem, my new CMS of choice :

I’m also very impressed when I found Diem CMF.

I’m a bit torn here, I quite like Drupal, especially due to its popularity and choice of modules.

However looking at the description of Diem it really looks like it fits my “style” as you say it. I haven’t yet worked with Symfony, I only worked with Doctrine + Zend Framework but I already liked the way things work. (and I believe Symfony is much more convenient than Zend Framework)

Drupal’s architecture leaves a lot to be desired… but de facto it’s one of the most popular CMSes nowadays (along with Joomla and WordPress), with lots of PHP developers familiar with it.

Setelah debugging 3 jam ruwet, ternyata kesalahan terletak pada bug Zend_Loader_Autoload::getClassAutoloader() ! ah, Zend Framework kauuu membuatku...

Setelah debugging 3 jam ruwet, ternyata kesalahan terletak pada bug Zend_Loader_Autoload::getClassAutoloader() !

ah, Zend Framework kauuu membuatku...

Wednesday, October 6, 2010

For RIA in JavaScript, GWT is the most sane option

I just tried again coding a rich web UI with:

- Dojo (and DojoX and Dijit, including dojox.data)
- Ext JS by Sencha (including the data store)
- Prototype

The conclusion is: I missed Google GWT.

JavaScript OOP is such a complex beast that pretty much you have to do it by memory: IDE's won't help much (if at all) on this.

Since a GWT app is written in Java programming language, it comes with all the goodies a good Java IDE (Eclipse) can provide, and that is excellent code completion, refactoring, and error checking support.

Other JavaScript toolkits will require an additional "minification" phase. In GWT it's part of the build process: the app is guaranteed to be small & optimized.

Java does have its limits, such as its static-ness. Projects such as DWR can generate Java stubs. But when you play by Java's rules (including autogenerating stubs) you get back the nice IDE features and sometimes easier debugging. Oh joy. :)

For non-RIA type pages though, either jQuery, Dojo Core, or Prototype rocks. (though I am biased to jQuery due to ubiquity)

Monday, October 4, 2010

Assemble Route URL inside Zend_Form

If you want to assemble a route URL inside a Zend_Form (or any other object where you don't have access to the URL View Helper), get an instance of the router and call the assemble method like this:

class Abispulsa_Deposit_Claim extends Zend_Form {

  public function init() {
    $router = Zend_Controller_Front::getInstance()->getRouter();
    $url = $router->assemble(array('module' => 'deposit', 'controller' => 'index', 'action' => 'claim'));
    $this->setAction($url)->setMethod(self::METHOD_POST);
    ...

    Hope this is useful.

Sunday, October 3, 2010

Cannot write output to stream ... error on Zend_Log logger

I got a "Cannot write output to stream ..." when using Zend_Log and Zend_Log_Writer_Stream.

I have been frustrated by this problem for several long hours, and the cause is because I created a new logger instance in a local variable inside a method of a lot objects. If that sounds confusing, this is the example problem:

class Car {   public function drive() {     $logger = Zend_Log::factory(/*some config*/);     ...   } }
To solve the problem, I had to do this:

class Car {   protected static $_logger;            protected static function getLogger() {     if (!self::$_logger)       self::$_logger = Zend_Log::factory(/*some config*/);     return self::$_logger;   }   public function drive() {     $logger = self::getLogger();     ...   } }

Annoying, but that's the workaround that works. If I have the choice I definitely prefer SLF4J.

Thursday, September 30, 2010

I hate $this and array(...) ! [PHP rant]

$this->


I have no reason to hate the explicit reference to 'self' or 'this' object.

But it shouldn't be repeated everywhere all around the codebase, every single time!

Ruby:

@name = @first_name + ' ' + @last_name

Java:

name = firstName + " " + lastName

PHP:

$this->name = $this->first_name . ' ' . $this->last_name

Unnecessary typing, unnecessary duplication. I should create a shortcut just for typing "$this->"

array(...)


array(2, 3, 5) doesn't look so bad.

But when you're dealing with nested associative arrays (and it's quite common), it doesn't look very good.

$this->_voucher->setOptions(array(         'storeId' => 'voucherStore',         'storeType' => 'dojo.data.ItemFileReadStore',         'storeParams' => array(                 'url' => $router->assemble(array('controller' => 'index',                         'action' => 'vouchers-for-number', 'mobile_number_id' => 1)),                 'clearOnClose' => true),         'dijitParams' => array('searchAttr' => 'title') ));
Ruby and JavaScript nails the sweet spot here. As with Scala (on JVM).

Java (the language) is at least as guilty as PHP on this front and much worse hehehe.

Wednesday, September 29, 2010

Two code completion 'FAIL's with PHP

Note that _ denotes cursor.

#1


$user = Doctrine_Core::getTable('User')->find(1); $user->_
Code completion at this point should return all members of the "User" class, but we get nothing!

#2


$logger = Zend_Registry::get('Zend_Log'); $logger->_
It should provide a list of Zend_Log members, but... nothing!

So... it's not about dynamic typing vs static typing. It's more about type safety but maybe more accurately type awareness or simply type information.

The above probably also holds true with Ruby on Rails. (and it's probably the fault of Rails' super-flexible-dynamic design by nature)

Compare Cases with Type Information (or sometimes, Type Inference)


But very rarely heard in Java :

@Inject EntityManager em; ... em->_

You get full code completion above. And even at times when you get a dumb Object, you can always typecast to the type you know you want.

Rendering JSON Data for dojo.data.ItemFileReadStore - Zend Framework

Dojo library has dojo.data.ItemFileReadStore and dojo.data.ItemFileWriteStore which are convenient defaults for a simple data store.

However you still have to generate the JSON data from the server-side application.

Luckily Zend Framework has an utility to render JSON data to match dojo.data format called Zend_Dojo_Data class.

Here's an example usage:

    public function vouchersAction() {             $this->_helper->layout->disableLayout();             $this->_helper->viewRenderer->setNoRender(true);                          $vouchers = Doctrine_Core::getTable('Voucher')->findAll(Doctrine_Core::HYDRATE_ARRAY);             $data = new Zend_Dojo_Data('code', $vouchers, 'title');             header('Content-Type: application/json');             echo $data->toJson();     }

Disabling layout & view rendering for direct response output in Zend Framework

Sometimes you want to disable default layout & view rendering in Zend Framework, for example to output a JSON response.

The following bolded two lines do the job:

    public function vouchersForNumberAction() {             $this->_helper->layout->disableLayout();             $this->_helper->viewRenderer->setNoRender(true);             ...             $data = new Zend_Dojo_Data('code', $vouchers, 'title');             header('Content-Type: application/json');             echo $data->toJson();     }

Creating a module in a Zend Framework web application

Zend Framework MVC web application request dispatch mechanism is structured in modules (optional), then controllers, and finally actions.

You have to enable module support.

Then to create a module, use zf create module command line tool.

$ zf create module deposit Creating the following module and artifacts: /home/ceefour/zendapp/application/modules/deposit/controllers /home/ceefour/zendapp/application/modules/deposit/models /home/ceefour/zendapp/application/modules/deposit/views /home/ceefour/zendapp/application/modules/deposit/views/scripts /home/ceefour/zendapp/application/modules/deposit/views/helpers /home/ceefour/zendapp/application/modules/deposit/views/filters Updating project profile '/home/ceefour/zendapp/.zfproject.xml'

Then you can create controllers, actions, and view templates as usual.

Enable layout support in Zend Framework

Zend Framework application generated by Zend Tool doesn't support layouts by default.

Enabling Layout Support using zf Tool


Run on command line:

zf enable layout

Enabling Layout Support via application.ini


Edit application/configs/application.ini and add to the [production] environment :

resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"

Enable modules in Zend Framework

After installing zend framework quickstart, I was looking for a solution to enable modules. Finally I found the solution, add the below line to your application.ini file
in the production environment:

resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"

Source

Developing PHP Web Application with Zend Framework - First thoughts

I've been doing some PHP Development with Zend Framework using Aptana Studio IDE in the past few weeks.

During the past year or so, my work was primarily with Java EE / Spring Framework and Ruby on Rails.

So, there have been some differences in experience.

Good things

  • It will work on my hosting. Zend Framework requires PHP 5.2, which most hosting nowadays already support.
  • Quick setup... that's the PHP project. The framework, not so...
  • Pretty good manual. The Zend Framework manual is pretty helpful, and comprehensive. It's not extensive or too detailed, but it shows how to do basic tasks. The rest, you still need the Internet and some good luck.

Bad things

I think there are more bad things than good things.

  • PHP 5.3 won't be supported... yet. Most hosting has not yet installed PHP 5.3 due to a number of reasons (laziness probably one of them). So, forget Doctrine 2 and functional programming/lambdas/closures. For example, as of 25 Sep 2010 DreamHost still uses PHP 5.2.14.
  • Insufficient code completion. NetBeans, Eclipse, and IntelliJ IDE have excellent support for Java code completion. In PHP, not so. There is only limited support for code completion, and that's only for PHP and HTML. For INI files, XML, and proprietary data structures (hierarchical associative arrays)... you have to scour the manuals/Internet/tutorials/etc. Same can be said for Ruby on Rails, though.
  • Zend Framework has a very steep learning curve, and difficult to setup as a full-stack framework. This is more the "feature" of Zend Framework than PHP. Zend Framework is not a Ruby on Rails killer, and will probably never be due to different philosophy. It's fairer to compare Symfony to Ruby on Rails. It's probably fairer to compare Zend Framework to Spring Framework. Comparing Zend Framework to Symfony is like comparing Spring Framework or Java EE to JBoss Seam. However, I can see why Magento Commerce chooses Zend Framework... It's very flexible. I can imagine it's harder to tweak Symfony or Seam to fit your app, but Zend Framework and Spring Framework are built to be tweaked, mix-and-matched.
  • Doctrine ORM has to be integrated in manually. This is both a good thing (flexible) and a bad thing (cumbersome). But it's a bad thing for me because I think it should be easy to use Doctrine by default, and also easy to remove it when not needed. I still haven't set up Doctrine "correctly" in my ZF application, I'm too lazy, and that's ZF's fault. Symfony has done a better job at this.
  • Lack of important view/action helpers. By default, using the FlashMessenger is tedious, since I can only access it via controller and has to pass it to the view. Why not a flashMessenger() view helper by default?
I'll post more thoughts later on as I go...