Category: 小小草

IT 技术领域学海无涯。其实任何领域都学海无涯,无非 IT 发展太快了,让我有更多嘘唏。希望我掌握的技术有如小小草,虽然渺小,却有旺盛的生命力。

  • Do not use is_null()

    测试一个变量是否为 NULL,我曾喜欢用 is_null() 函数,现在发现还比如直接用 === 比较来得快。

    php.net 上有人写了个测试,得出的结论是 === 比 is_null() 快30倍。

    
    $v = NULL;
    
    $s = microtime(TRUE);
    for($i=0; $i<1000; $i++) {
        is_null($v);
    }
    print microtime(TRUE)-$s;
    print "<br>";
    
    $s = microtime(TRUE);
    for($i=0; $i<1000; $i++) {
        $v===NULL;
    }
    print microtime(TRUE)-$s;
    
    

    这是2007年的事情了,我不清楚他的环境配置。如今在我 Intel(R) Celeron(R) CPU 2.80GHz PC 充当的测试服务器上,running zend server php 5.2.9,得出的结论是 === 比 is_null() 快1-2倍。看来 php is_null() 的效率进步了不少,但还是慢。以后我得改用 NULL === $v 的方式了。

  • Magento theme improvements from 1.3 to 1.4

    There are loads of improvements in the newest version of Magento themes. I just list some from my point of view. I observed these changes when I started using Magento 1.4 three days ago, but they may exist in the late version of 1.3.x.x already for long.

    Everyone knows we should separate presentation from content. Magento does it very well since its first public version. Magento 1.4 just makes separation even better. A theme is about presentation, usually made of two parts, app/design and skin. Compared with skin, app/design part is somehow closer to content. Magento 1.4 themes remove layouts and templates from app/design, which means they are fully rely on css to present different themes. Base/default theme is an exception, but it is a fall-back theme.

    In 2-column or 3-column page templates, main column code comes before left/right column. I think it hugely helps SEO. I first saw this kind layout in a Zen-Cart template. Maybe Magento was inspired by it. Under template/page, one-column.phtml was deleted, which saves confusion with 1column.phtml.

    The header logo is no longer displayed as a background image, which is a minor change but makes big improvement.

    I spent 3 days to re-write my theme to be compliant with Magento 1.4 but I love these changes.

  • How to call a Block multi times in Magento

    我觉得我对 Magento 的理解与日俱增(哈,这不是废话)。

    今天更新以前写的一段代码,有关在 block 里多次调用同一个 child block,但 child block 在每次调用时出现不同的内容,比如 product list block 去调用每个产品的 product block。Magento default theme 对此的处理方式跟我设想的不同,它把整个 product list block 就写成一个 block,没有 child block。在产品表现比较复杂的时候,特别是不同类的产品使用不同表现的时候,混写在一个 block 里代码就很乱,我想用 product list block 套用 product block 的方法去理清代码。

    这里涉及四个要点:

    1. 如果用 getChildHtml(‘product_block_name’),Magento 默认 block 只被调用一次,在 product list 循环里多次调用 getChildHtml(‘product_block_name’),结果所有产品显示的都是第一个产品。这是因为 Magento 缓存了 getChildHtml 返回值。如果要求每次都不用缓存值,必须使用 $useCache = false。$useCache 是 getChildHtml 的第二个可选参数,默认为 true,所以 getChildHtml(‘product_block_name’) 每次都得到了相同的结果;getChildHtml(‘product_block_name’, false) 就可以得到想要的不同结果。

    2. 既然说到缓存 $useCache,请分清这不是 block html cache。前者只是一个变量 cache,存储在 block class 的属性里;后者是 php code cache,存储在 files/apc/memcached, etc.

    3. Block 和 child block 之间怎么传递变量?亦即 product block 需要知道当前计算的哪个产品。很久以前我只会用 Mage::registry,于是每次在 product list block 里注册一个当前产品,然后调用 product block,在 product block 再取出注册值。我当时就不满意这种方案,我总觉得没有必要在全局注册一个变量来解决此类问题,但当时水平有限,想不到其他办法。现在有了:在 product list block 里使用

    getChild('product_block_name’)->setProduct($product)->toHtml();
    

    在 product block 写一个 setProduct() 方法:

    public function setProduct($product) {
    $this->_product = $product;
    return $this;
    }
    

    请注意 block 不同于 model,没有 magic method 可以用,所以必须老老实实写一个对应的setProduct() 方法。

    4. 如果用 getChild,就不用担心返回值被缓存,因为 getChild 不同于 getChildHtml,根本就不缓存返回值。

  • Editable Order extension for Magento is excellent

    Magento 要求太严,后台想修改 Order billing address or delivery address,必须 cancel the order and raise a new one。为了 traceability?我们觉得没有必要,怎么才能直接修改?

    找到两个 extension,一个 commercial,收 $89;一个 community,叫 Editable Order。

    当然先试试 Editable Order,一试很满意,虽然是德文,不影响使用。就用它了,有空再看看怎么把界面改成英文。

  • Cleanup after upgrade Magento to 1.4

    升级总有这样那样的问题,我不想节外生枝,也就不想在项目中途升级。我把一个正在开发中的 Magento 商店开始开发时版本是 1.3.2.4,但今天一不小心,敲入了

    ./pear install magento-core/Mage_All_Latest

    就把 Magento 升级到了 1.4。

    (要怪 Magento 升级太方便了?其实,今天的不小心是有原因的:我发现 Magento Connect 启动不了。尝试进入 Magento Connect 时通常要求再次输入管理员密码,但今天这个页面只有 Magento Connect logo,看上去页面意外中止。而我急着想试用一下某个 community extension,就用了 pear 命令。在敲键盘的过程中,脑筋没多想,竟然敲入 ./pear install magento-core/Mage_All_Latest,就坏事了。)

    升级以后发现后台 System/Configuration 保存时经常出错,错误提示:

    Error while saving this configuration: Invalid mode for clean() method

    CMS/Pages 也无法保存页面,错误提示:

    Error while saving Page. Please try again later

    Catalog/Products 也无法保存修改…

    我猜想所有这些错误都来自一个地方。错误多了反而好办——肯定他人也会碰到。果然,google 一下不怎么费力就找到答案:删除 app/code/core/Zend/Cache 目录就可以了。

    这证明了我的一个保证升级后不出错的土办法:先保持原有文件不动进行升级,然后把新老版本混合在一起的文件夹删除,然后再上传一份干净的新版本(被新版本抛弃的老文件就被删除了)。当然也可以用版本比较工具来找不同,但土办法更省事。

  • Dull_Addressfields Magento extension

    I could not edit customer order delivery address at backend using Magento 1.3.2.4. Checkbox “Same As Billing Address” is always ticked. When I untick it, it automatically tick itself. I was able to edit it some while ago. What happened since then?

    Half an hour later I found the problem was caused by installation of Dull_Addressfields 1.0. This extension was installed because I wanted to “Same As Billing Address” as a default choice at checkout. But even if I set “Default delivery address to billing address” to “No” without uninstall Dull_Addressfields. I upgrade Magento to 1.4. Problem remains.

    So I have to uninstall Dull_Addressfields. Actually, with the skills I acquired nowadays, I can make “Same As Billing Address” as a default choice without 3rd party extension. But my boss don’t want to make “Same As Billing Address” as a default choice. Situation changed since I installed Dull_Addressfields.

    Btw, Dull_Addressfields rewrites two classes: Mage_Customer_Model_Address and Mage_Sales_Model_Quote_Address. As Magento can’t safely handle two extensions rewrite a same class, I don’t want Mage_Customer_Model_Address and Mage_Sales_Model_Quote_Address to be rewritten by Dull_Addressfields (just to achieve a simple goal?). I’d like these important classes be untouched for future rewriting for important functionalities.

  • My third DNS server down for a month

    今年初,我退掉了 godaddy vps,把原来 godaddy vps 担当的辅助 DNS 角色转给了 1&1 server,却忘了开 1&1 server firewall port (硬件防火墙那道关)。

    今天才发现这台辅助 DNS 在过去的一个月根本无法执行 DNS 解析(因为我设置了三台 DNS,挂了一台没引起警觉)。难怪最近 webceo 给我的评分只有 5 分上下,google 的排名也有下降。

    赶紧打开防火墙,希望分数能上去。

  • Magento 1.4 is released

    说来也巧,当我想用 Magento 1.4 时,正好 1.4 stable 也刚发布。Magento 1.4 的测试版一直诱惑着我,就是太忙没去测试它,再说我也不太爱测试版,所以我一直抵制着诱惑等待正式版。

    今天在一台机子上搭建了一个全新的服务器环境,同时也有用到 Magento,既然是全新的,我就想装个 Magento 1.4 吧。在 Magento download 页面,找了半天,没发现 Magento 1.4 rc 版。好久才回过神,原来 1.4 在 full release 里,那就是说已经有正式版啦。我喜欢正式版不喜欢测试版,因为我不喜欢和一大堆的 bugs 打交道。既然 Magento 1.4 已经有了正式版,那还犹豫什么,赶紧装一个。

    Magento 1.4 stable is now available
    Magento 1.4 stable is now available

    安装碰到一点小问题,不清楚算不算 bug: 这次使用的是 zend server,默认 AllowOverride None,安装时却选择了使用 rewrite,安装完成后才设置 AllowOverride All,重启了 zend server,前台正常,却进不了后台,即使清空了 cache 和 session 仍无济于事。错误提示为:

    There has been an error processing your request

    我删了 Magento 数据库和 local.xml,重新安装一次,终于正常。

  • How to override a Magento controller

    Say I want to override Magento Catalog Product controller, say my namespace is Magex and my module name is Powercat.

    Firstly, add the following to Powercat/etc/config.xml. What it does is adding another route “prowercat” in addition to “catalog” to frontend. When http://mydomain/catalog/somecontroller/someaction/ is routered, powercat/somecontroller/someaction will be loaded before (see the attribute “before”?) catalog/somecontroller/someaction. If powercat/somecontroller/someaction is available, people get some page when visiting http://mydomain/catalog/somecontroller/someaction/ or http://mydomain/powercat/somecontroller/someaction/. I will not publish the latter url because the whole point of overriding a controller is reusing the Magento original url.

    <?xml version="1.0"?>
    <config>
    <frontend>
    <routers>
    <catalog>
    <args>
    <modules>
    <anyname before="Mage_Catalog">Magex_Powercat</anyname><!-- the tag name can be any name -->
    </modules>
    </args>
    </catalog>
    </frontend>
    </config>
    
    

    Secondly, create a subclass in the following format. “require_once” is essential because controllers are not auto-loaded.

    <?php
    require_once 'Mage/Catalog/controllers/SomeController.php';
    class Magex_Powercat_SomeController extends Mage_Catalog_SomeController
    {
    //function someAction here
    }
    ?>
    
    

    Last but not the least, put the overriding controllers into a dedicated module. Otherwise it is very easy to break Magento fallback mechanism. For example, suppose Magex_Powercat has two controllers.

    1. Magex_Powercat_IndexController does its own logic (not extending Mage_Catalog_IndexController, and
    2. Magex_Powercat_ProductController extends Mage_Catalog_ProductController

    The scenarios are:

    • When people visit http://mydomain/catalog/product/someaction/, powercat/somecontroller/someaction will be loaded – OK.
    • When people visit http://mydomain/catalog/category/someaction/, catalog/category/someaction will be loaded (because Powercat does not have CategoryController, Magento will fallback to Mage’s CategoryController) – OK.
    • When people visit http://mydomain/catalog/index/someaction/, if Powercat’s IndexController does not have someAction (only Mage’s IndexController has) – Error happens!
    • When people visit http://mydomain/catalog/index/someaction/, if Powercat’s IndexController does have someAction, page will load without error. However, remember Magex_Powercat_IndexController does its own logic? No router to the original logic!
  • Magent Events

    Magento wiki 上有篇文章列出了所有的 events dispatched by Magento。但 wiki as a CMS 自作主张地转化了某些字符,比如把

    ->转化成了→

    =>转化成了⇒

    这让我觉得有必要自己来格式化这篇文档。虽然曾想用 OpenOffice 来存储,但它竟然连一张简单的表格都格式得很费劲,最后只好用了 Ms Word。

    Download magento-events