Sunday, February 20, 2011

php xdebug not formatting var_dump

I installed php 5.3 and xdebug on my ubuntu 10.10. However, the xdebug is not formatting php's var_dump().

The reason is in php.ini, by default html_errors = off. Simply change html_errors = on and you will see var_dump is formatted by xdebug.

Thursday, February 17, 2011

Magento Hierarchical Category Database Design

First of all, there are two ways to manage hierarchical data in MySql(or other relational database). One is Adjacency List Model and the other is The Nested Set Model. They both have pros and cons. Again, i recommend you read this article http://dev.mysql.com/tech-resources/articles/hierarchical-data.html first before you start to work on hierarchy related issue.

Magento uses Adjacency List Model for some reasons, which i don't know what they exactly are. The problem of Adjacency List Model is traversing hierarchy tree is very difficult and low efficient. Usually you have to recursively query database to find out the depth/level of a node.

To address the problem of Adjacency List Model, Magento's category table has three extra columns:level, path, children_count. As the names suggest, 'level' stores the level of a node, 'path' saves the path from the root node to this node and 'children_count' records the number of children the node has. If you are interested in what they really look like in Magento's database, you can simply download and install Magento.

As you can imagine, with the three extra columns, traversing hierarchy tree becomes extremely easy.

You may also find out that in this way, the difficult part goes to manipulating: adding/deleting/moving a node. For each of these operations, you have to update those three extra columns for the nodes involved in your operation.

However, there is no perfect solution to hierarchy data(even in Nested Set Model, manipulation is very hard) because relational database is not designed to handle hierarchical data, not like XML. It is a trade-off. We either sacrifice one side for the other side. And i think traversing hierarchy is obviously the most critical part.

Monday, February 14, 2011

Magento category management flaw (bug)

Category is a typical hierarchical data structure. Two options of Managing Hierarchical Data in relational database are Adjacency List Model and Nested Set Model. Here is a very excellent article about this topic: http://dev.mysql.com/tech-resources/articles/hierarchical-data.html

Theoretically, Magento allows a user to create unlimited level of categories. Magento uses Adjacency List Model to manage hierarchical data. To overcome the disadvantages of Adjacency List Model, Magento's catalog_category_entity table includes these columns: depth, level, children_count, path.

As far as i can see, the flaw is caused by the column 'path'. 'path' is a varchar(255), it stores the path from the top level category to itself. For example, the current category id is 5. It is a sub category of 4, a sub category of 3, a sub category of 1. The path data of id 5 will be like "1/3/4/5". Problem occurs when the length of the path string exceeds 255. The new category won't be able to displayed correctly.

I think this is a minor issue cause most of the time we don't need to create such huge and deep level of categories, or do we?

Mysqli VS PDO

The reason i prefer PDO is it supports both binding named parameters and binding positioned parameters. Mysqli, on the other hand, only supports binding positioned parameters.

1.Mysqli:
$sql = "select * from user where id > ? and id < ?";
$bind = array(1, 10);

As a developer, you must ensure your $bind array elements are in correct position. For the above example, if your $bind array is array(10, 1), the query will actually become "select * from user where id > 10 and id < 1)".

2.PDO(Mysql):
$sql = "select * from user where id > :start and id < :end";
$bind = array("end"=>10, "start"=>1);

My opinion is binding named parameters really improves the program's readability.

Tuesday, February 1, 2011

setup LAMP on ubuntu10.10

1. apache:
install apache
apt-get install apache2 apache2.2-common.

enable mod rewrite
sudo a2enmod rewrite

2. mysql
apt-get install mysql-server mysql-client

3. php
apt-get install php5 libapache2-mod-php5 php5-common php5-gd php5-mysql php5-imap php5-cli php5-cgi php-pear php-auth

4. pdo-mysql
Any one is not using pdo on his new projects?

sudo apt-get install php5-dev
sudo apt-get install php5-mysql

Restart your apache and it is done

Thursday, September 16, 2010

array index is null

Although this should never appear in your application, my colleague showed me this funny code: $a = array(null=>1); print_r($a);
the result is
Array
(
[]=>1
)
If we do echo $a[null], the output is 1. However, if we echo $a[''], we get the same output as well.
If we try xdebug_debug_zval('a'), we can find out that internally, PHP use '', not null as the array index.

Monday, August 30, 2010

SugarCRM design flaw (I believe it is)

i have a website. When a user submits a form, it will create a Lead in SugarCRM by calling its REST API.

It all works good until I create a logic hook for the Lead module. This is a after_save logic hook, which means it should only be executed after a Lead is saved.

The logic hook function is very simple, with only one line:
function RunMe(SugarBean $bean, $event, $arguments)
{
$bean->retrieve($bean->id);
}

Now, the problem comes out. The Leads created through REST service lost their Email information!

I try to create a Lead within SugarCRM, the Email information is saved properly.

This brings up two questions:
1. it seems $bean->retrieve($bean->id) cannot retrieve its email properly.
2. how can email get lost due to this after_save logic hook. Shouldn't the email get saved before this logic hook is fired? Further more, it only happens when we create Leads through REST. Leads created within SugarCRM Lead Module do not have this problem.

Solution:
I change my logic hook code like below
function RunMe(SugarBean $bean, $event, $arguments)
{
$emailAddress = clone $bean->emailAddress;
$bean->retrieve($bean->id);
$bean->emailAddress = $emailAddress;
}
Now, problem solved. Here is a thread on SugarCRM forum with similar problem. http://panther.sugarcrm.com/forums/showthread.php?t=44872

"The problem was that after_save, the bean discards all the new field info. So we needed to use $bean->retrieve($bean->id); to get it back. Then, it didn't retrieve the email addresses properly, so we needed to pull the email address out before we ran the retrieve".

In SugarCRM, Leads extends Person. When we save a Lead, SugarCRM will call Person::save() method. Within the Person's save method, it will call SugarBean's save() method first, and only after that, it calls $this->emailAddress->save() to save the email. But SugarBean's Save() method will fire after_save logic hook, and the logic hook code $bean->retrieve($bean->id) cannot retrieve its emailAddress properly, so, that explains why email is lost.

But the question becomes, why Leads created in Sugarcrm don't have this problem.