Author: 芳草苑主

  • How is customer_logged_in/out handle added to Magento layout?

    I was wondering how Magento merge or handle into handle in layout.

    I was expecting something like

    <default>
        <update handle="customer_logged_in" if="logged_in"/>
        <update handle="customer_logged_out" if="logged_out"/>
    </default>
    

    Obviously, there is not such codes in layouts.

    I searched within Magento folder for keyword “customer_logged_in”, but only occurrences I could find in layout/customer.xml.

    So, how is customer_logged_in/out handle added to Magento layout?

    At last, I found

    class Mage_Customer_Model_Observer
    {
        public function beforeLoadLayout($observer)
        {
            $loggedIn = Mage::getSingleton('customer/session')->isLoggedIn();
    
            $observer->getEvent()->getLayout()->getUpdate()
               ->addHandle('customer_logged_'.($loggedIn?'in':'out'));
        }
    }
    

    by tracing addHandle() in app/core/Mage/Core/Model/Layout/Update.php.

    I must say using observer adding layout handle makes very easy for other modules to detect customer login status.

  • Never use dotless domain for Magento installation

    Magento 说不要使用 localhost 安装,我也就不用,也没深究原因。

    我为了在本地调试一个网站,先拿了生产网站 euro-bags.eu 的一个子域名。后来该子域名被挪作他用,那时我想,如果换个子域名再被挪作他用,我干脆用一个用于域名保护而未建站的域名,于是开始用 euro-bags.com 来调试。

    没过很久,Euro Bags 要在生产网站上实施一条网站提速实践:静态文件使用单独的 cookieless domain。因为 euro-bags.eu 使用了顶级域名,顶级域名上使用了 cookie,那么子域名上无法实现 cookieless。Euro Bags 也不想依赖第三方服务 cookieless domain,于是启用 euro-bags.com 专门为生产网站提供静态文件。

    我的调试域名再次被挪作他用。为了防止此类不可预测的事情发生,我想到干脆用一个不可能用于生产网站的域名来完成调试,于是想到用 euro-bags。

    一开始没发现问题,用了几天后想登录 euro-bags admin area 发现登录不了,输入密码后总是弹回到登录页。

    百思后才得其解,原来在 Magento 里使用任何 dotless hostname 都犯了跟使用 localhost 同样的禁忌。Magento 基于安全考虑在 cookie 里打上 domain 烙印,而大部分浏览器用拒绝接受含 dotless hostname 的domain 烙印。虽然可以 comment out app/code/core/Mage/Core/Model/Session/Abstract/Varien.php 某些行让 Magento 在 cookie 里不打 domain 烙印,从而让浏览器接受它的 cookie,但我觉得这么做是南辕北辙:不含 domain 烙印的 cookie 固然通行,但 open to cookie hijacking。Magento 最值我称道的就是每个细节(我没见其它 ecommerce software 有如 Magento 的周到)。

    既然 Magento 要在 cookie 里打 domain 烙印,而大部分浏览器又不接受 cookie 里有 dotless hostname,那我就不要用 dotless hostname 来安装 Magento 不就得了。于是我最新启用euro-bags.net 来继续本地调试,因为未有迹象表明 Euro Bags 要把 euro-bags.net 纳入域名保护,也没有要用这个域名来提供服务的计划,所以我不用再频频更换调试域名了。

  • Non working day calculation is included in msdk module

    Although I am not ready to release msdk module for Magento, I finish a model called Qian_Msdk_Model_Nwd. It is to judge if a given date is a non working day by some pre-defined and user-defined rules. It can also work out what date of next n’th working day is.

    There are two types of rules, rule by date or rule by week. For Non Working Day (NWD) fixed by date, there is normally a make-up following working day as NWD if the original one is Saturday or Sunday. For NWD fixed by week, there is no make-up, usually.

    For the rule simplicity, I always assume make-up. When you are writing your own rules and do not want make-up to some rules, add “=” modifier to the beginning of each of them.

    How to read and write NWD rules?

    First thing to remember, as a general checking rule, I go through each line separated by “\n”, and verify if the supplied date (if omitted, assume today’s date) fall into the line of rule. There is no connection between lines, so do not expect a rule can make up another one.

    Second thing to remember, as PHP allows a date like “2010/13/33”, I allow you write rules like that too. However, avoid it if you can.

    Third thing to remember, PHP regards Sunday as 0 Saturday as 6, and I do the same.

    Fourth thing to remember, when ISO number weeks, it regards week starts Monday, and I do the same. If you do not know what I am talking about, read ISO-8601.

    Fifth thing to remember, I do not have a good algorithm to work out dates by lunar calendar. So that is no smart way to write a rule for Easter. Ditto many Chinese holidays. You have to use fixed date every year. I hope it won’t cost you long time write down all fixed dates of 10 years lunar NWD and just sit while this programme runs for 10 years. After 10 years, aha, you’ll find your way.

    OK, let’s get on to rule writing.

    1. Rule by date is something like “yyyy/mm/dd”, or “yyyy/mm/dd,dd,dd”. yyyy, mm or dd can take asterisk “*” as wild-card.

    For new year day, it is “*/01/01”. This is simplest scenario. For Christmas and Boxing day, it is “*/12/25,26”. Be careful here, do not write two rules “*/12/25” and “*/12/26”. They can not achieve the same result as “*/12/25,26”, because a rule can make up a following working day if the rule date is Saturday or Sunday, but it can not exclude days by other rules.

    You have to write in one rule if two or more NWDs are connected. However, the dates are not necessarily continuous. In theory, you can write a rule like “*/12/24,26”. In reality, I did not see any NWDs are scheduled like this.

    2. Rule by week is something like “yyyy/mm/dd/weekNumber/weekDay”, or “yyyy///weekNumber/weekDay”. yyyy, mm or dd can take asterisk “*” as wild-card. “yyyy///weekNumber/weekDay” use ISO-8601 to find the week and weekDay. I will cover it in section 3.

    “yyyy/mm/dd/weekNumber/weekDay” uses a reference year/month/day to find the n’th weekDay. N is specified by weekNumber.

    2.1 If both mm and dd are “*”, it uses a reference year. For example, “*/*/*/10/1” means 10th Monday of any year.

    2.2 If mm is a number, but dd is “*”, it uses a reference month. For example, “*/05/*/1/1” means 1st Monday in May. A lot of England bank holidays are specified this way.

    2.3 If dd is a number, it uses a reference day. For example, “*/06/06/0/1” means the Monday of the week where June 6 sits.

    In case of 2.1 and 2.2, weekNumber can take a negative number which means the last n’th weekDay. For example, “*/05/*/-1/1” means the last Monday in May. WeekNumber zero does not make sense here.

    In case of 2.3, weekNumber can take zero (means the same week), a positive number (n’th week forward), or a negative number (n’th week backward).

    3. “yyyy///weekNumber/weekDay” ISO-8601 style looks similar to case 2.1. But they are totally different.

    For example, “2011///1/6” means Saturday of week 1 of year 2011, which is 2011/01/08. But “2011/*/*/1/6” means the 1st Saturday of year 2011, which is 2011/01/01.

    Another example, “2010///52/6” means Saturday of week 52 of year 2010, which is 2011/01/01 (Yes, it goes into the following year). But “2010/*/*/52/6” means the 52th Saturday of year 2010, which is 2010/12/25.

    I think writing documentation helps programming. I have revised NWD documentation for 3 times or more, and every time I found a new way to structure the model.

    I also think any date calculation look simple but actual coding is very complex. This model took me half a year to finish although I am full time on it.

  • public static or static public

    在 php 中,public static 或 static public 怎么写都可以,所以我一直不知道哪种是正统的写法(象我这样追求正统的人,或许 python 更适合我?)。

    今天费点时间看看别人是怎么看待 public static or static public 这个问题的。我的结论是 public static 是正统的写法,于是我想把以前随意写成的 static public 都更新成 public static。所幸的是,以前一直用的都是 public static。倒是在 magento 的源码里找到一堆 static public,或许 magento developers 没被要求一定要怎么写,所以源码里混合了 public static 和 static public。

    我觉得 inconsistency 是最糟糕的,或许我在这个问题上吹毛求疵了。

  • My son and his classmates

    大宝在哪里呀,大宝在哪里(升调)

    1063975411967412742

    Image 1 of 63

  • Full page caching preparer module for Magento

    I am planning a project called Fpcp (Full Page Caching Preparer) to improve Magento performance. Yeah, it is called Fpcp and very similar to another module Cpfp (Cms Page Foot Print).

    I have a bit research on Magento Enterprise only features, and pick full page caching as my next interested project. I do not know how Magento Enterprise implements full page caching, but my idea is rewriting all blocks containing session related content with an ajax get method.

  • MB200 week calculation bug

    一个月前,我的 MB200 显示有系统更新可用,我就升级了一下。升级了以后很失望,firmware version 仍是 1.5,看来 motorola 不打算让 MB200 用上 android 1.6 以上版本了,有空了我还得自行升级。

    用了一个月,我发现了 MB200 现有的版本 (Blur version 1.3.39) 居然有个日期计算上的 bug。比如今天是星期天,它会认为是星期一。这样,我设定的闹钟,闹周一到周五,结果它闹的是周日到周四;10月的最后一个星期天的凌晨从夏令时切换到冬令时,结果它提前一天星期六就让我用上冬令时了,搞得我周六一早起来看时间后总觉得怪怪的。

    如果我来升级,我就上 android 2.2。

  • Double rainbow is nothing special

    Double Rainbow over Devon
    Double Rainbow over Devon

    This week I read a news on dailymail After seven years and 2,000 photographs… a double delight as rainbow lights up Devon

    By Daily Mail Reporter
    Last updated at 9:26 AM on 27th October 2010

    A photographer who has taken pictures of the view from his office window every day for seven years has finally struck gold by snapping this stunning double rainbow.

    Andy Kyle, 53, captured the weather phenomenon as it appeared to create a bridge over the river at Dartmouth in Devon.

    Andy, who runs a website called The View From The Dartmouth Office, has been posting pictures of the vista each day for the past seven years.

    He said he had taken more than 2,000 images of the view before he snapped the beautiful double rainbow.
    Howzat? Sometimes a dim secondary rainbow is seen outside the primary rainbow. Secondary rainbows are caused by a double reflection of sunlight inside the raindrops

    Howzat? The ‘bridge’ over the river at Dartmouth in Devon. Sometimes a dim secondary rainbow is seen outside the primary rainbow. They are caused by a double reflection of sunlight inside the raindrops

    Sometimes a fainter ‘secondary rainbow’ can be seen outside the main rainbow.

    Secondary rainbows are caused by a double reflection of sunlight inside the raindrops, and appear at an angle of 50–53°.

    If you look closely you can see the colours of the secondary rainbow are inverted, with blue on the outside and red on the inside.

    The secondary rainbow is fainter than the primary because more light escapes from two reflections than one and because the rainbow itself is spread over a greater area of the sky.

    The effect is quite ghostly, and makes for a stunning photograph, although it makes looking for the pot of gold slightly more tricky.

    I did not think about it too much. But today when I was taking my friend Erin to Heathrow Terminal 3, I saw double rainbow just above the airport. It was a pity I had no hands free to take a photo to compete because I was busy driving my car.

    When I am back home, I search for “double rainbow” photos, I find it is nothing special but reported many times in many places. If I head up a bit often, I may see double rainbow again very soon.

  • Magento promotional free shipping does not apply to tablerate

    Magento 自有的 shipping calculation 已足够强大,如果谁还说不够用,我就会说是经营上的问题。

    最近我被要求做这么一件事,在一个 storeview 下,对部分商品不论金额大小,一律 free shipping。一听之下我觉得可以用 cart salesrule free shipping action 来实现,实际尝试后却发现,cart salesrule free shipping 不能对 tablerate 起作用。而 tablerate 是 frontend 唯一一个 shipping method,被设置强制选择,顾客不会被问到 choose shipping method。在这个逻辑下,如果我启用 free shipping method,checkout 就多问一个问题,老板说这不好。而 flatrate 另有他用(backend 接单时对特殊地区额外征收运费),也无法拿它来实现部分商品 free shipping。

    这件事最后用一个普通 discount 抵消 shipping charge 的方式迂回解决,但解决得很别扭。我认为

    • shipping rates 是一种全局设置,就算能,也不应该为某些商品创建例外的;
    • 如果想为某些商品创建例外,那么再想一下为什么要创建例外,比如这些商品针对是一群特殊用户,如果 cross selling 对特殊用户不起作用,那就专门为他们建一个 store 或 website;
    • 新建 store 或 website 的成本与销售预期收益相比,是否值得?如果不值得,再反思一下是否值得为这些商品创建例外;
    • 自己写一个 shipping module 肯定可以实现任何稀奇古怪的 shipping rules,但写程序不是为了照顾 business 复杂化的需要。
  • Place Magento model, resource, collection class at your will

    Most Magento model, resource, collection are placed this way:

    • Model is located at Model folder
    • Resource is located at Model/Mysql4
    • Collection is located at Model/Mysql4/(ClassName)

    What if you want organise them in a different way? Say how place all of 3 classes under one folder?

    I enclose a complete a working sample.

    1. Model class

    
    class Qian_Msdk_Model_MediaGallery_Mg extends Mage_Core_Model_Abstract
    {
    public function _construct()
    {
    parent::_construct();
    $this->_init('msdk_mg/resource');
    }
    }
    
    

    2. Resource class

    
    class Qian_Msdk_Model_MediaGallery_Resource extends Mage_Core_Model_Mysql4_Abstract
    {
    public function _construct()
    {
    $this->_init('msdk_mg/product_attribute_media_gallery', 'value_id');
    }
    }
    
    

    3. Collection class

    
    class Qian_Msdk_Model_MediaGallery_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
    {
    public function _construct()
    {
    parent::_construct();
    $this->_init('msdk_mg/mg');
    }
    }
    
    

    4. config.xml

    
    <?xml version="1.0" encoding="UTF-8"?>
    <config>
    <global>
    <models>
    <msdk_mg>
    <class>Qian_Msdk_Model_MediaGallery</class>
    <resourceModel>msdk_mg_mysql4</resourceModel>
    </msdk_mg>
    <msdk_mg_mysql4>
    <class>Qian_Msdk_Model_MediaGallery</class>
    <entities>
    <product_attribute_media_gallery>
    <table>catalog_product_entity_media_gallery</table>
    </product_attribute_media_gallery>
    <product_attribute_media_gallery_value>
    <table>catalog_product_entity_media_gallery_value</table>
    </product_attribute_media_gallery_value>
    </entities>
    </msdk_mg_mysql4>
    </models>
    </global>
    </config>