Skip to content

Magento: Loading the product from a template

When I wrangle with Magento Commerce and customize anything, every other bit is of course tied to a product's ID, or sometimes entity ID.

The challenging part is that whenever you're in a template in Magento, the scope is very different from the previous one. This is sometimes frustrating, but when you think of it — it makes sense. That is, in Magento! ;-)

Magento works in blocks and each block is basically a class file, of course $this is never the same. So for example the scope of a block that renders a product page is different from something like Mage_Sales_Block_Order_Item_Renderer_Default (used to display a row of an order).

Code

I recently had to customize the display of an item in an order in the customer's account.

To do so, I had a nifty helper which is tied to a product's ID. Unfortunately, I was only able to retrieve the SKU, quantity ordered and all sorts of other things right away — but the product's ID was not available.

So how do you load a product otherwise? Simple! Using the SKU!

// app/design/frontend/default/my-template/template/sales/order/items/renderer/default.phtml
$_sku     = $this->getItem()->getSku();
$_product = Mage::getModel('catalog/product')->loadByAttribute('sku', $_sku);
$_product->getEntityId(); // here is your ID

So yeah — Mage_Catalog_Model_Product = very helpful. And of course there are a bunch of other attributes to load products by. Well, just about any attribute. Just dig around the docs, or var_dump() a product object on a product page to see what else is available.

Fin

Quick and dirty — I just blogged this because it took me 25 minutes to find that model and the loadByAttribute() method.

And hopefully by blogging this, I'll never ever forget.

Find space hogs and prettify output using AWK

I really love awk.

You might disagree and call me crazy, but while awk might be a royal brainfuck at first, here's a very simple example of its power which should explain my endorsement.

Figuring out space hogs

Every once in a while I run out of diskspace on /home. Even though I am the only user on this laptop I'm always puzzled as of why and I start running du trying to figure out which install or program stole my diskspace.

Here's a example of how I start it off in $HOME: du -h --max-depth 1

If I run the above line in my $HOME directory, I get a pretty list of lies — and thanks to -h this list is including more or less useful SI units, e.g. G(B), M(B) and K(B).

However, since I have a gazillion folders in my $HOME directory, the list is too long to figure out the biggest offenders, so naturally, I pipe my du command to sort -n. This doesn't work for the following reason:

till@till-laptop:~$ du -h --max-depth 1|sort -n
(...)
2.5M    ./net_gearman
2.6M    ./logs
2.7M    ./.gconf
2.8M    ./.openoffice.org2
3.3G    ./.config
3.3M    ./ubuntu
(...)

The order of the files is a little screwed up. As you see .config ate 3.3 GB and listed before ubuntu, which is only 3.3 MB in size. The reason is that sort -n (-n is numeric sort) doesn't take the unit into account. It compares the string and all of the sudden it makes sense why 3.3G is listed before 3.3M.

This is what I tried to fix this: du --max-depth 1|sort -n

The above command omits the human readable SI units (-h), and the list is sorted. Yay. Case closed?

AWK to the rescue

In the end, I'm still human, and therefor I want to see those SI units to make sense of the output and I want to see them in the correct order:

du --max-depth 1|sort -n|awk '{ $1=$1/1024; printf "%.2f MB: %s\n",$1,$2 }'

In detail

Let me explain the awk command:

  • Whenever you pipe output to awk, it breaks the line into multiple variables. This is incredible useful as you can avoid grep'ing and parsing the hell out of simple strings. $0 is the entire line, then $1, $2, etc. — awk magically divided the string by _whitespace. As an example, "Hello World" piped to awk would be $0 equals "Hello World", $1 equals "Hello" and $2 equals "World".
till@till-laptop:~$ echo "Hello World" |awk '{ print $0 }'
Hello World
till@till-laptop:~$ echo "Hello World" |awk '{ print $1 }'
Hello
till@till-laptop:~$ echo "Hello World" |awk '{ print $2 }'
World
  • My awk command uses $1 (which contains the size in raw kilobytes) and devides it by 1024 to receive megabytes. No rocket science!
  • printf outputs the string and while outputting we round the number (to two decimals: %.2f) and display the name of the folder which is still in $2.

All of the above is not just simple, but it should look somewhat familiar when you have a development background. Even shell allows you to divide a number and offers a printf function for formatting purposes.

Fin

Tada!

I hope awk is a little less confusing now. For further reading, I recommend the GNU AWK User Guide. (Or maybe just keep it open next time you think you can put awk to good use.)

Installing Varnish on Ubuntu Hardy

This is a quick and dirty rundown on how to install Varnish 2.1.x on Ubuntu Hardy (8.04 LTS).

Get sources setup

Add the repository to /etc/apt/sources.list:

deb http://repo.varnish-cache.org/ubuntu/ hardy Varnish-2.1 

Import the key for the new repository:

gpg --keyserver wwwkeys.eu.pgp.net --recv-keys 60E7C096C4DEFFEB
gpg --armor --export 60E7C096C4DEFFEB | apt-key add -

Installation

Update sources list and install varnish:

apt-get update
apt-get install varnish

Files of importance:

/etc/default/varnish
/etc/varnish/default.vcl
/etc/init.d/varnish

Double-check:

root@server:~# varnishd -V
varnishd (varnish-2.1.2 SVN )
Copyright (c) 2006-2009 Linpro AS / Verdens Gang AS

Further reading

I recommend a mix of the following websites/links:

Fin

That's all!

Selenium & Saucelenium: installation and dbus-xorg-woes

We're about to launch a new product, and this time it's pretty client-side-intense. The application is powered by a lot of JavaScript(-mvc) and jQuery, which do xhr calls to a ZF/CouchDB powered backend. While js-mvc has unit-testing sort of covetred, I was also looking for some integration testing, multiple browsers and all that.

Selenium vs. Saucelenium

I can't really say if you want one or the other. Revisiting Selenium in general, it's IMHO the only viable and suitable thing for a PHP shop. Primarily of course because all those nifty test cases will integrate into our existing suite of PHPUnit/phpt tests. And while I use Zend_Test already or find projects like SimpleTest's browser or even Perl's www::mechanize very appealing, neither of those executes JavaScript like a browser.

Selenium and Saucelenium have the same root — in fact Saucelenium is a Selenium fork. While the Selenium project seems to focus on 2.x currently, stable 1.x development seems to really happen at Saucelabs. That is if you call a commit from January 22nd of this year active development.

In the process of selecting one or the other, more people recommended that I'd use the Saucelabs distribution than the original one, and so I forked it on github.

Installation

Along with a script to start the damn thing, my fork also contains a README.md. Said README covers the installation part in detail, so I won't have to repeat myself here. All of this is pretty Ubuntu-centric and has been tested on Karmic Koala. I expect things to work just as well on Lucid, or on any other distribution if you get the installation right.

One thing that took me a while to figure out was the following error message:

till@testing:/usr/src/saucelenium$ sudo ./start.sh 
[...]
[config/dbus] couldn't take over org.x.config: org.freedesktop.DBus.Error.AccessDenied (Connection ":1.17" is not allowed to own the service "org.x.config.display0" due to security     policies in the configuration file)
(EE) config/hal: couldn't initialise context: unknown error (null)
13:17:23.166 INFO - Writing debug logs to /var/log/selenium.log
13:17:23.166 INFO - Java: Sun Microsystems Inc. 16.0-b13
13:17:23.166 INFO - OS: Linux 2.6.32.1-rscloud amd64
13:17:23.176 INFO - v1.0.1 [exported], with Core v@VERSION@ [@REVISION@]
13:17:23.296 INFO - Version Jetty/5.1.x
13:17:23.306 INFO - Started HttpContext[/selenium-server/driver,/selenium-server/driver]
13:17:23.306 INFO - Started HttpContext[/selenium-server,/selenium-server]
13:17:23.316 INFO - Started HttpContext[/,/]
13:17:23.326 INFO - Started SocketListener on 0.0.0.0:4444
13:17:23.326 INFO - Started org.mortbay.jetty.Server@7526e85f
^C13:18:09.796 INFO - Shutting down...

After Google'ing for a bit, I came to the conclusion that the above means that I didn't have the xserver installed.

The fix was rather simple: aptitude install xserver-xorg.

Example test

The following is an example test case. It'll open http://www.php.net/ and make sure it finds "What is PHP?" somewhere on that page.

Then it will continue to /downloads.php (by clicking on that link) and will make sure it finds "Binaries for other systems" on that page.

To run this test, execute: phpunit ExampleTestCase.php.

class ExampleTestCase extends PHPUnit_Extensions_SeleniumTestCase
{
    protected function setUp()
    {
        $this->setHost('localhost');
        $this->setPort(4444);
        $this->setBrowser("*chrome");
        $this->setBrowserUrl("http://www.php.net/");
    }

    public function testPHP()
    {
        $this->open('/');
        $this->waitForPageToLoad('30000');
        $this->assertTextPresent('What is PHP?');
        
        $this->click('//a[@href="/downloads.php"]');
        $this->waitForPageToLoad('30000');
        $this->assertTextPresent('Binaries for other systems');

        // check this out, especially useful for debugging:
        $this->assertEquals('http://www.php.net/downloads.php', $this->drivers[0]->getLocation());
    }
}

That's all.

Thanks for reading, and until next time.

Tumblr: Display a list of entries in the sidebar

Update 2010-09-06: I turned my JavaScript code into a handy plugin for jQuery — let me introduce: jquery-simplerss.

So for whatever reason, on a lot of blogs (but not mine ;-)), the sidebar also contains the list of latest entries on said blog.

I recently edited a template for a client and he requested the same feature — which put me through three hours of nightmare.

Tumblr

Tumblr is a hosted blog service. It doesn't have as many (confusing) features as for example Wordpress or Serendipity, but it's doing really well at people usually do with blogs: posting stuff. Stuff includes text, excerpts from chats, photos, quotes, music, videos and maybe more.

The advantages of Tumblr versus any local blog install are:

  • it's (completely ad-)free (a local blog requires a webhost or server of some kind)
  • no installation
  • no security updates

Tumblr also comes with a domain and custom theme feature where you can basically CNAME a domain name to their server and it looks like it's part of your domain — take my activity stream for an example.

While I realize that Tumblr is not free for forever, all of the above are plenty of good reasons why I'd rather recommend my clients to get a Tumblr account instead of installing Wordpress on their server, and getting hacked a week or so later.

Customized themes

For those of us with slightly less design skills, there are commercial themes available, for the rest, they may use customize any theme available.

Customized themes are simple and to be kept simple for the most part. So for example a sidebar with the latest posts is not something the theme allows you to do and while I value that my suggestion was taken to the development team (like others before), I couldn't really wait until someone gets around to making it happen.

JavaScriptjQuery to the rescue!

So I decided to use jQuery to parse the blogs RSS feed and display the three latest items. While I realize that there are plugins available, I thought I'd do it myself — quick and dirty — because jQuery offers with $.ajax() and .find() pretty much all you need to download the RSS feed and parse the bits from it. Since my blog runs on http://blog.example.org/ and the RSS feed is at http://blog.example.org/rss not even the cross-domain obstacles apply!

Here's how I did it!

Let's walk through the code, shall we?

  • $.ajax() is used to GET the feed
  • for Tumblr: dataType: 'xml'
  • .find() is used to select the items (rss > channel > item)
  • inside the loop:
    • find title, description and guid
    • create html (which is basically my template)
    • exit from the loop after we ran through the 3 latest items
  • after the loop: append to a selector

For the above to work you'll need (to include jQuery and the following HTML):

<ul id="blogposts"></ul>

Gotchas

So even though Tumblr's feed is a valid RSS feed per feed-validator.org, there were a few things that didn't work right away.

At first I used dataType: feed in $.ajax() — which made sense at the time. But the problem is that Tumblr sends Content-Type: text/xml for their RSS feed. I haven't checked the internals of the dataType but apparently Google Chrome applies stricter rules to what it thinks are feeds.

This issues implies that for example the entities in <title> make Google Chrome drop the <title> all together when the XML feed is imported. There is an interesting thread on Stackoverflow about the issue. The quickfix is to use dataType: xml instead.

The second problem is that <link> is dropped/ignored because the link is wrapped in doublequotes. So I used <guid> instead.

Fin

I certainly hope that this example is complete and saves someone else some time.