Category: 小小草

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

  • 5 approaches to customise Magento product

    1. Configurable product. It is a built-in feature of Magento, and very easy to implement. No coding skills required. However, every sub product of the configurable must pre-exist as a simple product in Magento products. It is literally impossible to use it as made-to-order functionality, which aims at taking lots of parameters from customer’s input, calculating prices under millions scenarios.

    2. Product custom options. Again it is a built-in feature of Magento, and easy to implement. But it is labour intensive to set it up if you have thousands of products of same set of custom options. Alternatively, you can buy an extension called Custom Options Template for less than $100. But I do not like data redundancy. Also, custom options on its own can not build the prices on the fly.

    3. Made-to-order extension (MTO) developed by metrofindings.com. It does not require coding, either. I must admit it is a promising extension to some business. However, I think the majority of business pricing models are much more complicated than this MTO module can dealt with. It is not possible to describe pricing just based on xml or cvs, as far as my business is concerned.

    4. My favourite approach version 1.0. It is inspired by MTO module with two major differences.
    a) All raw data are stored in database rather than external files so a backend administrator can manage data changes without uploading xml or cvs files. I think it is a bad idea to mix daily maintenance with programming.
    b) All business logics (cost / profit calculation, supplier screening, etc) fully rely on programming. Because I am a programmer so it is easier for me to control the program to follow my business logics. But if you are not, you’d better find a programmer to do it rather than fiddling with xml. Your business logics are usually more complex than an xml can solve.

    5. My favourite approach version 2.0. When I developed version 1.0, I did not think carefully about how to store custom options. I added fields to quote_item and order_item, and created a session to store what customer’s inputs before they were written to database. Because it was not Magento native way to store options, when it came to reorder, I had to take extra care of those options. So, in version 2.0, I am going to (I have not implemented it) create ONE simple product that will be used for customisation across ALL made-to-order products. This product will be assigned a full range of custom options. If some custom options do not apply to certain made-to-order products, just leave them blank. And most importantly, this product will have a custom option to store sku telling us from which product the customisation is based on. I assume this approach does not break Magento reorder process. I only need to change some view templates to show this special product’s sku, image, description properly.

  • How Magento cache Blocks HTML output

    我曾错误地认为 Magento 安装后,只要启用 cache,Magento 就会缓存页面的大部分内容,比如,cms, product, category 的 content block。

    直到今天第 N 遍看 Magento wiki,才意识到 Magento 初始只启用了很小一部分 block cache。细想之下,Magento 默认不缓存 content block 有一定的道理:各用户对内容缓存的要求不一而足,所以 Magento 把这个问题留给用户自己去思考。

    Block cache 有三个参数,cache_lifetime 顾名思义,cache_tags 关系到 cache 何时更新,cache_key 关系到 cache 有多少个版本。

    在 Magento 目录下所有文件里搜索 cache_tags 这个词,我只发现它只出现在跟 Navigation (产品菜单),Footer (脚注),Adminhtml Menu (后台菜单) 相关的少数文件里。由此说明 Magento 根本没有缓存页面的最主要部分:content block。我联想到很久以前我在 Magento forum 上提问的一个问题:为什么 cache 只用掉了 0.5 MB 内存?当时我用的是memcached,结果热心人来问我 memcached 有没有安装正确啊,php-perl-memcache 有没有安装啊。就是没有人告诉我——一切正常,因为 Magento 尚未缓存页面主要内容

    了解了 Magento cache 机制,再根据自己的实际情况对 product page 缓存 content block 就简单了:只要在 extends Mage_Catalog_Block_Product_View 的基础上加入

        protected function _construct()
        {
            $this->addData(array(
                'cache_lifetime'    => 86400,  //seconds
                'cache_tags'        => array(Mage_Catalog_Model_Product::CACHE_TAG . "_" . $this->getProduct()->getId()),
                'cache_key'         => $this->getProduct()->getId(),
            ));
        }
    
    

    以此类推 cms page content block cache。Category page content block cache 稍微复杂一些,具体去看 Magento wiki。

    设置 content block cache 对速度优化效果显著,我的 product page requests per second 指标提高了约 70%。

    但我还是想让 Magento 跑得再快些,常说的那些 Magento 速度优化结果让我感觉不够畅快淋漓。我有个 page cache 想法,就是把整个页面缓存下来。Nginx 或其他的 web server 都有很好的机制去调度 html cache。据我测试,同一个静态内容的页面,保存为 html (Nginx 直接读取) 比保存为 php (经 php backend on socket or port 读取) 就快好几倍,这个结果让我对 page cache 充满了憧憬。

    如使用 page cache,必须对页面中的 dynamic block (如 sidebar cart,recent viewed/compared products, etc)进行改写,简言之就是 load pages in two stages by ajax。Magento Enterprise Edition 就有 page cache feature,但我不清楚它是不是跟我同个思路。

    与其买个 Magento Enterprise Edition,不过自己动手或请人实现 page cache。如果你恰好跟我有同样想法,请留言。

  • Solution to php fastcgi crashes

    One of my servers is running Fedora + Nginx + php-cgi (spawned). I noticed sometimes php-cgi crashes without a reason or warning (Nginx gives out 500 error), and I have to spawn it again.

    After some digging, I find exporting PHP_FCGI_MAX_REQUESTS to ENV cures the problem. As advised, I export PHP_FCGI_CHILDREN as well.

    To achieve that, in detail, just add the following to the top of spawn bash script.

    # Set these two env variables to reduce php-cgi crash
    PHP_FCGI_MAX_REQUESTS=1000
    export PHP_FCGI_MAX_REQUESTS
    PHP_FCGI_CHILDREN=5
    export PHP_FCGI_CHILDREN

  • Upgrade VirtualBox to 3.1.x

    刚从国内回来,电脑上积累了很多更新。其中 VirtualBox 有了 3.1.2 r56127,我从 3.0.x 直接升级失败,抛出一大堆的文件冲突信息。

    于是
    yum remove VirtualBox -y
    然后再
    yum localinstall -y --nogpgcheck VirtualBox-3.1-3.1.2_56127_fedora11-1.x86_64.rpm
    成功!

    此删除和重安装操作无须备份和恢复原有的 guest OS(but as a good practice, you should backup files before major changes)。

  • Expires affects Firefox

    我把 Magento 网店从 A 服务器迁移到 B 服务器后,发现一个问题:在 Firefox 下点 “Add to cart”,无论添加是否成功,系统没有提示(购物车有个选项是添加商品后留在当前页面),非得 F5 刷新后才能看到成功或错误信息。Safari 下正常,IE 下未实测。

    我原以为是 Magento cache 的问题,但禁用 Magento cache 后问题依旧。而且,只有 B 服务器才有这样的毛病。想来半天,觉得跟服务器参数有关。

    于是我查看了 Magento 在两台服务器的 http header,发现 B 服务器多了 cache 和 expiry 等 headers。这才特别关注了一下 nginx 的配置问题,发现 B 服务器的 server {} 里有一句 expires 1d; 不知这句是谁写到 nginx conf 文件里。这指名 Firefox 直接从本地读取,除非 F5。去掉 expires 这条目就好了。

  • Self-contained form

    Self-contained form
    Self-contained form

    视表单为一个对象

  • Knockout background using Photoshop action

    Knockout Background Using Photoshop Action
    Knockout Background Using Photoshop Action

    抠图是我最不想干的活。

  • My worry about Linksys wireless security

    前文提到 Linksys IP Camera 只能连入 Linksys wireless router,一开始就不喜欢厂家设置人为技术障碍的做法。细想之下,更觉得 Linksys wireless 安全机制堪忧。

    因为 Linksys WVC210 wireless IP camera 在设置无线联网时,只问一个 SSID,只要是 Linksys wireless router,不需密码就自动联入?如果是别人家的 Linksys wireless router 怎么办?虽然我凭着一个 Linksys WVC210 wireless IP camera 也控制不了别人家的网络设备,但如果我能对 Linksys WVC210 wireless IP camera 进行编程,是不是就相当于在别人家放置了颗隐形炸弹?Linksys wireless 或许有它独到之处,或许能隔离自动联网的设备,但我总觉得 wireless device isolation 不如直接用 password 来得更安全(至少心理上更舒服)。

  • Elements of same name in Zend_Form

    It is a rigid rule that Zend_Form can not have elements of same names. If I add a second element with the same name, the first one will be overwritten.

    When I started to use Zend_Form, I thought this rule makes life difficult. For example, if the form have “Next” and “Previous” buttons, I must give them different names. How can I tell which button is clicked? I must go through all names. I thought if these buttons could have same name but different value, it was easier to tell which button was clicked.

    It was before long I started to enjoy this rigid rule. Take the above example for example, it is NOT a good practice to judge which button was clicked by its value. Because for an internationalised program, the value may change and that is out of the programmers’ control.

    What if I want to add 5 text fields for people to fill in information like team members’ name? Two solutions. The first one looks stupid but I did not come across the second one at first.

    Solution 1:

    class MyNamespace_MyText extends Zend_Form_Element_Text {
    	protected $_name = "text";
    
    	public function init() {
    		static $sequence = 0;
    		$this->id = $this->_name . '_' . $sequence;
    		$this->_label = "Label " . ($sequence + 1);
    		$this->_name = $this->_name . '[' . $sequence . ']';
    		$sequence ++;
    	}
    }
    

    Solution 2:

    for ($sequence = 0; $sequence < 5; ++$sequence) {
    	$element = Mage::getModel('moduleName/modelName', "$sequence")
    				->setBelongsTo('text'); //my form is inside Magento
    }
    
  • Limitation of Mage::getModel method

    Magento getModel can not initialise an instance whose class requires more than 1 argument.

    I assume Magento native classes can explode options from the first argument to satisfy getModel. However, if I want to use 3rd party class like Zend_Form_Element inside Magento, there is no ways to use getModel to achieve the same result as

    $element = new Zend_Form_Text('name', $options);
    

    because

    $element = Mage::getModel('moduleName/modelName', 'name');
    

    takes 1 argument which is ‘name’ only. No way to pass $options on.