最近我写了一个小程序:Deal of the day for Magento。

它主要有以下功能:每天定时按预设权重随机抽取一个产品作为deal of the day;在产品名称前加上"Deal of the day"字样;设定它的is_deal_of_the_day为true;设定一个special price;归类到一个sales category下;同时把昨天的已过时的deal重置为原先状态。

Magento支持cron job我是知道的,但测试的第一个环节倒不是这个程序能否定时启动,而是程序能否完成独立完成这一系列的操作。为求简单,我把整个过程写在一个frontend controller的indexAction里,然后用访问url的方式去触发这个过程。我没有用backend controller,因为我考虑到Magento wiki上介绍的cron job万一不管用(之前我没有用过 Magento cron job),我还可以用 curl + linux crontab (这个我很熟)去触发这个过程。当然我会把这个url做得谁都猜不到,以策安全。

但是,在frontend controller里一运行到$product->save()或$productCollection->save(),就抛出以下错误:

// Warning: Invalid argument supplied for foreach() in /path/to/magento/app/code/core/Mage/Eav/Model/Entity/Abstract.php on line 995

初看这个错误,我总以为是product EAV某个attribute损坏了,因为我经常修改product attributes,一不小心,改坏了哪个不该改的attribute也不奇怪。可难就难在attributes那么多,我无法知道哪个坏了啊。我围绕着Abstract.php 995行左看右看,没有头绪整整一个下午,最后发现,如果把同样代码放在backend controller里,product就可以save了。

整整一个下午的时间只给我一个启示:product model在frontend是只读的,估计又属于Magento安全机制范畴。联想到以前碰到的一个问题:如果用户在Magento backend已登录,能否在frontend探知,以便针对backend用户访问frontend时显示不对外人开放的内容(就像wordpress那样会在每个post显示edit link)。但Magento把backend和frontend严格地分开,我研究好久,也没有让frontend访问到backend session。

我想,打破Magento苦心经营的安全机制去做一些事是不可取的。比如deal of the day定时切换的功能,就用magento鼓励的cron.php去启动,非常的方便,也非常的安全。只是我空下来还是想钻牛角尖: Magento是怎么把backend和frontend严格地分开的?只有知道了原理,如果、万一、假如、倘若我要frontend执行backend操作,也能做到了。