Month: October 2010

  • Use collection model without creating resource model in Magento

    问题的起因是为 Magento CMS pages 增加一个 html sitemap。我新建了一个类 Qian_Cpfp_Model_Page extends Mage_Cms_Model_Page,但我不想在 config.xml 让 Qian_Cpfp_Model_Page rewrite Mage_Cms_Model_Page。在 Qian_Cpfp_Model_Page 里,有一个方法 getSubpagesCollection(),返回某种规则下的子页集。

    我想递归调用 Qian_Cpfp_Model_Page::getSubpagesCollection() 得到子页树。调试时发现,getSubpagesCollection() 返回的是 collection of Mage_Cms_Model_Page instead of collection of Qian_Cpfp_Model_Page,而 Mage_Cms_Model_Page 里没有 getSubpagesCollection(),所以递归嵌套一层就进行不下去了。

    于是我又建了第2个类 Qian_Cpfp_Model_Mysql4_Page_Collection extends Mage_Cms_Model_Mysql4_Page_Collection。我想让 Qian_Cpfp_Model_Page::getSubpagesCollection() 返回 Qian_Cpfp_Model_Mysql4_Page_Collection, which is a collection of Qian_Cpfp_Model_Page。通常一个 model 和它的 collection 是通过一个 resource model 来沟通的,这样需要再建第3个类 Qian_Cpfp_Model_Mysql4_Page extends Mage_Cms_Model_Mysql4_Collection。但我实在不想再多建一个文件,因为:

    • Qian_Cpfp_Model_Mysql4_Page 即使建了也没有提供额外的功能。
    • 为了让 Qian_Cpfp_Model_Mysql4_Page 正常运转,config.xml 还得多几行关于 <resourceModel> 的定义及其 <entities> 的定义,而相同的定义已经在 Mage_Cms module 里已经做过了。
    • 我实在不喜欢用拷贝代码的方式去解决问题。

    到底能不能跳过 resource model 让 model 和 collection 互访呢?准确地说,我的问题是,能不能不建子类的 resource model 而让子类的 model 和 collection 互访?

    答案是能!具体实施步骤是:

    1. 在 Qian_Cpfp_Model_Page 以特殊方式指定 collection

    
    public function getResourceCollection() {
    return Mage::getModel('cpfp/mysql4_page_collection');
    }
    
    

    2. 在 Qian_Cpfp_Model_Mysql4_Page_Collection 以特殊方式指定 model 和 resouce model (通常方式不明示 resource model,根据 model 自行寻找,一找不存在就出错了)

    
    public function _construct()
    {
    parent::_construct();
    $this->_init('cpfp/page', 'cms/page'); //the second param is vital here
    }
    
    
  • Less is more

    想把人民币换成英镑。

    我知道好多人有外汇留成,所以我从一开始就想跟他们兑换以节省汇兑损失。可是事有不凑巧,几个人问过来,他们要么出差、要么外汇用光、要么嫌眼下美元价位太低,总之一时没换成。我正想再询问几个人,无意中有朋友告诉我,找银行换嘛。

    是啊,我怎么这么傻,怎么就没想到找银行,而且还更实惠!以今天的汇率为例,RMB100 究竟可以换到多少英镑?

    • 如果跟熟人以美元现汇买入价结算,USD100 = RMB663.86,我仍需要把美元兑换成英镑,GBP100 = USD158.62,那么 RMB100 最终可以换成 GBP9.4965 (100/6.6386/1.5862)。
    • 如果跟熟人以美元中间价结算,USD100 = RMB667.54,那么 RMB100 最终可以换成 GBP9.4442 (100/6.6754/1.5862)。
    • 如果跟银行购汇,GBP100 = RMB1050.83,那么 RMB100 最终可以换成 GBP9.5163。

    所以我觉得很傻,忙乎了半天,结果却是这么简单!亏我数学还不错,怎么就没一开始动手算一算?!

  • Be careful: Magento layer filter label is not html escaped

    我发现 Magento 1.4.1.1 app/design/frontend/base/default/template/catalog/layer/filter.phtml 是这么写的:

    <ol>
    <?php foreach ($this->getItems() as $_item): ?>
    <li>
    <?php if ($_item->getCount() > 0): ?>
    <a href="<?php echo $this->urlEscape($_item->getUrl()) ?>"><?php echo $_item->getLabel() ?></a>
    <?php else: echo $_item->getLabel() ?>
    <?php endif; ?>
    (<?php echo $_item->getCount() ?>)
    </li>
    <?php endforeach ?>
    </ol>
    

    我觉得不太好,因为 staff 在设置 filter label 通常会忽视 html escape,所以最好是

    $this->htmlEscape($_item->getLabel());
    

    但这样一来把 price filter 正常的 html 输出给搞乱了。要兼顾普通 filter 和 price filter,我还没有一个比较 neat 的方案,只好要求 staff 做好 filter label 的 html escape。

    同样的问题在 app/design/frontend/base/default/template/catalog/layer/state.phtml 中也存在。

  • Limit table column width in IE6

    I have a 2×2 table coded like this:

    <table>
    <tr>
    <th id="r1c1">
    Short heading
    </th>
    <th id="r1c2">
    Short heading
    </th>
    </tr>
    <tr>
    <td id="r2c1">
    Very very long content blah blah blah
    </td>
    <td id="r2c2">
    Short content
    </td>
    </tr>
    </table>
    

    In the td cell r2c1, if the content does wrap, it takes more width than r1c1, say r1c1 requires 100px width, and r2c1 requires 300px.

    But I want r2c1 content words wrap and its width limits to 100px. I put width style in the first row, i.e.:

    <th id="r1c1" style="width:100px">
    

    It does not work in IE6.

    Then I put width attribute on col, i.e.:

    <table>
    <col width="100"/>
    <col width="100"/>
    ...
    

    It does not work in IE6, either.

    Then I put width attribute in r2c1, i.e.:

    <th id="r2c1" width="100">
    

    It does not work in IE6, either.

    At last, I put width style in r2c1, i.e.:

    <th id="r2c1" style="width:100px">
    

    Finally it works in IE6.

    I knew td’s width attribute is deprecated but I didn’t know deprecated IE6 does not read deprecated attribute.