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.

Friday, July 23, 2010

sugarcrm logic hook problem

I created an after_save logic hook for Lead. My SugarCRM is version 5.5.2 and the function is quite simple:
function runMeAfterSave(SugarBean $bean, $event, $arguments)
{
if ($bean->first_name == 'someone') {
//do some tasks
}
}

The function works very well on my localhost. When i put it on another server, however, it doesn't work at all. So, i var_dump($bean->first_name), and it turns out to be NULL all the time, no matter what value i enter into first name field. I var_dump some other fields and get NULL as well. The server SugarCRM version is 5.5.3. I can't find any reason why it can't work.

Finally, i try var_dump($bean->id). This time i'm lucky! I can get its ID! So i add one line in my code: $bean->retrieve($bean->id) and everything works fine now.

Later I found a thread on SugarCRM forum regarding this issue http://panther.sugarcrm.com/forums/showthread.php?t=44872. It says "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"

Thursday, July 8, 2010

sugarcrm warning message

I created a new module. When i save a new entry, sugarcrm will show this message:
Warning: preg_match() expects parameter 2 to be string, array given in /var/www/crm/include/utils.php on line 1715

Call Stack
# Time Memory Function Location
1 0.0000 72612 {main}( ) ../index.php:0
2 0.0001 73516 require_once( '/var/www/crm/include/entryPoint.php' ) ../index.php:38
3 0.0019 214344 clean_incoming_data( ) ../entryPoint.php:124
4 0.0067 235068 clean_string( ) ../utils.php:1797
5 0.0068 235120 preg_match ( )
../utils.php:1715

So I traced the code back to line 1797 in utils.php, and found this code "if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']);".

Actually in this new module, i created a field called 'language' and it is MultiSelect type, which is an array. After i change the field name, this warning message disappeared.

Sunday, April 4, 2010

DON'T USE 'CREATE TABLE XXX SELECT * FROM YYY' TO BACKUP AN INNODB TABLE

The reason is simple: the backup table will lose all key/index attributes from the original innodb table.

Monday, March 22, 2010

Replace built-in PHP fatal errors with exceptions

We may want to use Exception instead of php4 style error handling systems to make error handling more consistent. We can build a bridge from old error handling to the new Exception handling.

class PhpErrorException extends Exception {}

function errorHandler($errno, $errstr, $errfile, $errline) {
throw new PhpErrorException ($errstr,$errno);
}

$handler= set_error_handler('errorHandler');

Now you can test it. For example: run echo 5/0; and you will see an exception is thrown instead that a PHP warning is given off.

Friday, March 19, 2010

memory usage in PHP

A very excellent blog about PHP memory usage: http://blog.preinheimer.com/index.php?/archives/354-Memory-usage-in-PHP.html

Unlike C/C++ developers, most PHP developers never think about memory management in PHP. It is true that PHP can free the memory after a request is processed. However, if you use PHP to process critical tasks with large amount of data, you'd better read this blog carefully, and test its memory-usage-example.php by yourself. You will see how different it is.

Monday, March 8, 2010

新版(浙版)西游记

张纪中拍的. 因为勾起了对儿时西游记的怀念, 就买了下来. 正如网上评价的, 不愧是2010年第一部雷人剧集.

白骨精是孙悟空的结拜兄妹, 最后为爱自尽.

最让我羡慕的是那个如来佛祖啊,座下美女菩萨如云: 观音, 文殊, 普贤, 全是美女. 看了真让人有恨不得早日成佛的感觉.

呵呵, 总的来说, 这部西游记作为无聊时的消遣也是可以的. 但是要和六小龄童演的西游记比起来, 考虑到时代和技术的进步, 实在是看不出新版的西游记有什么突破的地方.

哦, 对了, 剧中大牌明星云集: 唐国强是玉皇大帝, 陈冲是观音, 总而言之, 本剧可作消遣和笑料, 但成不了经典.

Tuesday, March 2, 2010

Interesting issue of Zend_Request Object

See the code below:
class TestController extends Zend_Controller_Action
{
public function testAction()
{
$params = $this->getRequest()->getParams();
}
}

It tries to get all parameters of a request. In most situations, it works fine. However, if the request contains a parameter like '?action=subscribe', and you try to get $action = $params['action']. Now, what do you think is the value of $action? If you say, it must be 'subscribe', then you are wrong.

How come this happen? The answer is, Zend_Request object set 3 default parameters: 'module', 'controller' and 'action', and they will overwrite the identified variables in the request. Back to the code above, if you var_dump($params), you probably will see the result like:
array(3) {
['module'] => string(7) "default"
['controller'] => string(5) "test"
['action'] => string(5) "test"
}

As you can see, the value of $action will be 'test'. What if we try to do $action = $this->getRequest()->getParam('action')? This doesn't help either, the value of $action is still 'test' instead of 'subscribe'. Same applies to $this->_getAllParams() and $this->_getParam().

So how do we get the correct value of action in the request? The answer is, for a POST request, we must exactly use $this->getRequest()->getPost('action'); for a GET request, we must use $this->getRequest()->getQuery('action')

Wednesday, February 24, 2010

GIT as version control system

I have been using GIT as version control system for a while. What impressed me most is GIT's branch management and merging.

You have a clean code base called master. Now you need to implement a new feature to your application. What you need to do is to create a new branch for this task, just like this: git branch new_feature_1. And then you can checkout this branch: git checkout new_feature_1. Now you have switch from master to new_feature_1, and you can start work on your feature on this branch.

If one day, while you are still in the middle of the new_feature_1, your manager comes and tells you 'hey, we have an urgent feature that must be done asap, and it has the highest priority'. You can simple save all your current work: git commit -a. This will commit all your work to the new_feature_1 branch. Then you can checkout master, the clean code base and create a new branch: urgent_feature.

Most people using CVS/SVN have painful experience with branch merging. GIT makes merging an incredibly simple and easy task. After you finish your work, you can simply merge it from master: git merge urgent_feature. Now, you can checkout new_feature_1 branch and continue your work. If you want to use some new functionalites in urgent_feature, you can simply merge the master branch or urgent_feature branch.

Monday, February 15, 2010

exec() vs system()

Besides all the descriptions from PHP manual, let us do a small test. Create a file called test.php:
echo 'hello';

Create another file called runexec.php:
exec('php test.php');

Create a runsystem.php:
system('php test.php');

All three files are located in the same directory. I found runexec.php cannot call test.php properly. I must use full path in the exec command. However, runsystem.php can work very well.