Category: 小小草

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

  • 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
    }
    
    
  • 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.

  • xls is the best data import format for phpmyadmin

    尽管我挺不愿意看到这个结果,但事实是 xls () 是在 phpmyadmin 中导入大量数据的最佳选择。xls 优于 csv 和 ods (Open Document Spreadsheet) 格式,尤其是在行数据差异比较大时(比如有 empty cell)。

    尽管我用 Open Office Calc 生成原始数据,但保存为 Open Office 嫡出的 ods 格式再导入时,数据变得参差不齐。我正绝望时,试着保存为 xls 格式再导入,一切 OK。

    回想 microsoft 所出的各种应用程序,确实有它强大的地方,至少有一点无人能及——在各应用程序间流畅地拷贝、粘贴。

  • Manifest module for Magento

    Manifest module for Magento is developed for a Chinese takeaway restaurent to produce a manifest with order items’ product name in a language recognizable by chefs, no matter what languages store front are using.

    Manifest module utilises Magento valuable multiple-website-storegroup-store structure. It is easy to use as long as you have precedent knowledge of implementing multiple stores in Magento. Let’s go through it step by step.

    Firstly, you must have a store or stores selling products. (sure you have)

    Secondly, create a store in a language recognizable by chefs. If this language is one of those enabled for store front, you can skip the step. Otherwise, just create a store but you do not have to enable this store. The purpose of this store is storing the product name in a store specific language.

    Lastly, map store languages. In System >> Configuration >> Manifest >> Manifest Storeview, choose a store which has manifest information. If you have newly installed Manifest module, you must log out and log in again to access configuration section.

    That’s it. Sales Order now has a tab called Manifest.

    Known issue: manifest does not produce order item custom options or bundle-simple product selection information. Currently I have no intention of further development.

    Download Manifest module here Manifest.tar.gz

  • phpMyAdmin 2002 error

    最近把家里的测试服务器 Zend Server php 5.2 卸载了,重新安装了 5.3。phpMyAdmin 随着 5.2 卸载也被卸载了。我用

    yum install phpMyAdmin

    重新安装了 phpMyAdmin。在 config.inc.php 设置了必要的参数,但 phpMyAdmin prompted:

    #2002 – The server is not responding (or the local MySQL server’s socket is not correctly configured)

    phpMyAdmin 2002 error
    phpMyAdmin 2002 error

    我浪费了很多时间检查了所有可能的错误,却解决不了问题。最后在 phpmyadmin.net 下载了源码,使用同样的 config.inc.php,顺利登录!

  • Solve media type differencing after VirtualBox upgrade to 3.2.8

    Virtualbox Disks Inaccessible
    Virtualbox Disks Inaccessible

    我在 VirtualBox 升级到 3.2.8 以后发现其中的 Windows XP Guest OS 无法启动,其他 Guest OS 正常。Windows XP Guest OS 用到的两个 harddisk 文件也显示 inaccessible,而且也 release 不了它们,强行访问还给一个错误信息。

    Medium type of ‘/path/to/harddiskfile’ is differencing but it is not associated with any parent medium in the media registry (‘/path/to/.VirtualBox/VirtualBox.xml’).

    我也没怎么上心,觉得是 VirtualBox 升级版中的 bug,指望在后续版本中把它修复。可是好久没见 Oracle 出更新,只好 google 求帮助。

    我发现跟我有同样遭遇的人还不少,原因或许是 Host OS 使用了 ext4 文件系统导致不兼容。可为什么只影响 Windows Guest OS?管不了那么多,找解决办法要紧。

    解决方案众说纷纭。最后真正解决我的问题的是:

    Step 1: 去下载一个 fix 工具。我下载了 for linux VBoxFixHdd-Linux.tar.gz,其他的去 http://www.virtualbox.org/download/VBoxFixHdd/ 找。

    Step 2: 运行一下
    VBoxFixHdd --filename /path/to/image.vdi --zeroparentuuid

    其中 /path/to/image.vdi 就是 access 不了、release 不掉的问题文件,当然后缀不一定是 vdi,我的是 vmdk(不知道还有别的吗)。

  • CSS styling without images

    I am quite surprised with the styling effect achieved by pure CSS without the help of images. I can round corner and rotate html elements without creating any background images.

    See the result I get.

    Comprehensive styling using pure CSS
    Comprehensive styling using pure CSS

    And this is the ONLY product image in this CSS styling demo:

    Halloin 3D gift bags
    Halloin 3D gift bags

    Although the effect is comprehensive, but with the help of jQuery plugins, the syntax is very simple. Just a few lines of text.

  • SSL, Nginx and Magento

    SSL, Nginx and Magento 这三件东西对我都不陌生。但三件全排在一起,着实挑战了我一下,发生错误是 secure page redirect loop。

    Magento secure page redirect loop
    Magento secure page redirect loop

    原因是 $_SERVER[] 里缺少 HTTPS directive,需要在 fastcgi_params 里添加一行

    fastcgi_param HTTPS on;

    以 Magento 1.4.0.1 为例深究一下—— 在 $_SERVER[‘HTTPS’] 缺失时 app/code/core/Mage/Core/Model/Store.php 的 isCurrentlySecure() 返回值 false,所以 Magento 不停地重定向到 secure url 而不知道当前 url 已经是 secure 了。

    
    public function isCurrentlySecure()
    {
    if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
    return true;
    }
    
    if (Mage::isInstalled()) {
    $secureBaseUrl = Mage::getStoreConfig('web/secure/base_route_url');
    if (!$secureBaseUrl) {
    return false;
    }
    $uri = Zend_Uri::factory($secureBaseUrl);
    $isSecure = ($uri->getScheme() == 'https' )
    && isset($_SERVER['SERVER_PORT'])
    && ($uri->getPort() == $_SERVER['SERVER_PORT']);
    return $isSecure;
    } else {
    $isSecure = isset($_SERVER['SERVER_PORT']) && (443 == $_SERVER['SERVER_PORT']);
    return $isSecure;
    }
    }
    
    

    我一直觉得用 php 探测当前 protocol 是否为 https 的算法比较“土”,曾经以为会有更好的探测办法,目前看来是没有。不光是没有,而且不可能有。就如有个小秘负责拆信,然后把有用的信纸交给 CEO 阅读,所以 CEO 不可能知道某封信是拿什么信封装的。

  • Magento layout rendering mystery

    今天碰到个问题百思不得其解。起因是我在改进 Magento rcah module 时,想在 category/index/view 输出前修改 head block 里其中一个 item: link_rel。

    具体说来,我想调用 $headBlock->removeItem()->addLinkRel() 把修改过的 link_rel 添加到 head block 的 $_data[‘items’]。由于调用在 renderLayout() 之后,所以 head 在输出时仍然是修改前的 link_rel。这本不奇怪;奇怪的是,我观察到 $headBlock->getCssJsHtml() 在整个过程中只执行了一次,而且是在 $headBlock->removeItem()->addLinkRel() 之后,$headBlock->getCssJsHtml() 应该是跟 html 输出直接相关,为什么在 $headBlock->getCssJsHtml() 看来 link_rel 还是原值?

    Layout rendering 机制对我来说还比较神秘。我只能暂时这么解释:

    renderLayout() 时把所有 block 的状态记住了,所以此后再怎么修改 block 的状态都无济于事。到了输出 html 阶段,所有的输出都是以 renderLayout() 时的 block。

    BTW,在 rcah 模块中,我找到一个非常巧妙的办法来修改 link_rel (canonical link 的值),完全绕过了跟 head block 的纠缠。