Magento: Adding custom attributes to orders, Part II

In hindsight I probably should have tested the method I blogged about recently, just to make sure it works.

Because it doesn’t.

In hindsight I probably should have tested the method I blogged about recently, just to make sure it works.

Because it doesn’t.

Oh, the EAV attribute is created all right. But it’s useless, because as I learned since then, orders do not read from the EAV tables since Magento 1.4 (released end of 2010, maybe). They use a flat table ({sales_flat_order}) along with a bunch of other flat tables (order items, quotes, invoices…).

What to do? There are a couple of options. I could add a field to that flat table. Easy to do with an install script, something like:

$installer->run("ALTER TABLE ADD my_custom_field VARCHAR(500);");

Problem is, according to one poster on Stack Overflow, that’s probably not upgrade safe. Plan B would be to create a separate table, keyed on Order ID. Easy enough to do, and my first plan was to write the to the custom as the info is copied from the quote to the order, in Mage_Sales_Model_Convert_Quote::toOrder().

But that doesn’t look possible, because the Order ID isn’t set yet. Seems crazy, I know, but I tried to read

$order->getIncrementId() //I know that one's set
$order->getId() //Nope
$order->getOrderId() //Not that either
$order->getEntityId() //Because the order table's primary key field is entity_id

So I could use increment_id (not exactly sure what that field is good for, except for displaying to customers)… but then I decided to just key the custom table on quote_id. No need to worry about writing to the order, I just extend the order model like so:

class Npd_Myextension_Model_Sales_Order extends Mage_Sales_Model_Order
{
    public function getCustomField() {
    	$quote = Mage::getSingleton('sales/quote');
	$quote->load($this->getQuoteId());
   	return $quote->getCustomField();
    }
}

Which works, because orders always keep a reference to their source quote. Likewise, invoices keep a reference to their source order.

So there you go, and I’m making progress. Progress against a massive headwind, mind you. Again, I whine: why the hell is Magento making things so hard for developers?

PS: about the order ID, am I just kind of dim, or is it actually not set at that point? If it is, what getter function should my code be using? The fact that I’m even asking “what getter function should I be using?” shows either Magento or myself needs serious help…

I was wrong and it feels good

So I’m putting the finishing touches on an UberCart 2 module, and I’m thinking it’s as good as it’s going to get. Then I go ahead and test it—the most visible test would be the creation of a custom node type and product class—and… no go. The class is created, but the node type isn’t.

So I’m putting the finishing touches on an UberCart 2 module, and I’m thinking it’s as good as it’s going to get. Then I go ahead and test it—the most visible test would be the creation of a custom node type and product class—and… no go. The class is created, but the node type isn’t.

After a bit of googling, I realised I’d been doing it the wrong way. My code just had straight db_query‘s to insert the records in {node_type} and {uc_product_classes}. Well, the latter may have been okay, but the former totally wasn’t. db_query does execute correctly, but at some later point the node_type is deleted. Unfortunately I can’t find the particular page that told me this anymore.

Using node_type_save() won’t help, either, since that just calls INSERT or UPDATE commands.

I’ve got options, though. Implementing hook_node_info() and hook_form(), for one, as detailed here. This means I don’t have the option of leaving the node type in the system until the module is uninstalled; also, it still doesn’t answer the question of creating a corresponding product class. I tried adding code to my hook_node_type() implementation to insert the class, but that just had the effect of not creating the node type while creating the product class. Weird.

Still, I’m feeling very positive. This isn’t the first bump I’ve encountered on my Drupal learning curve. Won’t be the last, either, as just today I started porting this module to UberCart 3 / Drupal 7. About time, too, I’ve been itching to dig into D7!

Magento: Adding custom attributes to orders

I’m currently working on a little Magento side project. The learning curve is still steep, and still frustrating. A big part of it involves creating custom fields on orders.

I’m currently working on a little Magento side project. The learning curve is still steep, and still frustrating. A key part of it involves creating custom fields on orders.

Better Magento developers than me have already gone this route, so I didn’t need to reinvent the wheel. Alan Storm’s excellent post on setup resources was a huge help. I’ll just note a couple of things: first, the actual setup class name could in fact be anything, it doesn’t have to follow the Company_Module_Model_Mysql4_Setup pattern. All you need is to place it in the location in your directory that corresponds to the class name (as with all Magento classes).

Second, it bears repeating: the installer script will only run if the version stored in the core_resource table is different from the version being installed. To run the installer multiple times, simply delete the appropriate record from core_resource, then clear the cache (if it’s enabled) and refresh any page. Having only written one other extension with an installer script in my career, I’d forgotten that particular bit.

Third, and this also bears repeating: damn, but Magento is not friendly to developers. Usual Magento bitching aside (convoluted config.xml, overcomplex extension class/directory structure), why is it making developers do extra work, like writing:

$installer = $this;
$installer->startSetup();
...
$installer->endSetup();

…in every installer script? It’s just a little thing, you say? Maybe, but it’s one of many unnecessary little things, one more little annoyance for experienced developers, one more thing novice devs need to remember, making the learning curve just a little bit steeper.

So that’s general instructions for the installer. Now, how do I specifically add this custom field? I got my answer from the first post on this page. The logic goes like this:

$setup = new Mage_Eav_Model_Entity_Setup('core_setup');
$setup->addAttribute('order', 'newfield', array(
    'position'             => 1,
    'type'              => 'text',
    'label'                => 'Your New Field',
    'global'            => 1,
    'visible'           => 1,
    'required'          => 0,
    'user_defined'      => 1,
    'searchable'        => 0,
    'filterable'        => 0,
    'comparable'        => 0,
    'visible_on_front'  => 1,
    'visible_in_advanced_search' => 0,
    'unique'            => 0,
    'is_configurable'   => 0,
    'position'          => 1,
));            

Pretty self-explanatory, right? Note, though, one thing that tripped me up before I found the above link: the first argument of addAttribute() is a string, not an integer. I’d expected to have to enter the entity_type_id corresponding to orders (5, in my system), but no, it looks like it needs the entity_type_code (‘order’). Weird, and against my common sense.

So there you go, now you know how add custom fields to orders.

PS: here’s some more Magento bitching. This whole EAV scheme, what exactly is it good for? Because frankly, so far it’s given me nothing but headaches. It makes the db bloated and slow, makes looking up data extremely time-consuming, and does not make my life as a developer easier. Like, at all. Other e-commerce platforms (*coughUbercartcough*) use simpler and saner systems that are just as flexible, if not more so.

PPS: While playing around with this extension, I discovered some weird / amusing behaviour related to installing & uninstalling extensions. Since this has nothing to do with custom attributes or installer scripts per se, I’m saving it for another post.

What I learned at Straight Camp

Ted Cox is an ex-Mormon missionary who found reason and now spends much of his time writing and talking about evangelical subcultures. In particular, he has gone undercover (posing as a gay man) to “ex-gay” retreats and workshops. His talk last night, sponsored by UBC Freethinkers, PrideUBC and the Secular Student Alliance, gave us a peek into the weird world of ex-gay ministries. Plus, it was his very first talk in Canada. Woo!

Ted Cox is an ex-Mormon missionary who found reason and now spends much of his time writing and talking about evangelical subcultures. In particular, he has gone undercover (posing as a gay man) to “ex-gay” retreats and workshops. His talk last night, sponsored by UBC Freethinkers, PrideUBC and the Secular Student Alliance, gave us a peek into the weird world of ex-gay ministries. Plus, it was his very first talk in Canada. Woo!

We started out with a brief history. The ex-gay Xian movement as we know it today has its roots in the “Jesus Freak” culture of the 60’s and 70’s, where basically a lot of hippies found religion. Apparently it’s in this culture that the notion of a personal saviour was invented, a Christ that loves you and wants to save you but that you have to personally accept before the magic can work. Interesting, that. I would have thought it was a lot older, dating back to the turn-of-the-century fundamentalists.

Add reactionary anti-feminist & anti-gay politics, a dash of outdated pseudo-scientific stereotypes (sexual deviancy is caused by overbearing mother / absent father / past sexual abuse) and there you have the anti-gay movement. From Love in Action (founded in 1973) to Exodus (founded in 1976, still going strong) to various Catholic, Mormon and Jewish groups that got in on the act, and you’ve got a weird, weird mix of subcultures that must be pure hell for any budding queer folks.

Predictably, no two groups can agree on the desired outcome. Catholic groups (who don’t believe in being born again) aim for lifelong celibacy. Evangelical groups might also limit themselves to celibacy, or they may claim to turn people straight, with opposite-sex marriage being the ultimate goal. They do seem to agree that, whatever Lady Gaga says, gays are not born this way; same-sex attraction is just a symptom of deeper emotional wounds (see: absent father, etc…), just like, e.g.: alcoholism. You need to address these wounds before you can conquer your same-sex attraction.

Mind you, that’s just for the groups that try to talk the scientific talk. All bets are off with the really loopy churches that will try to exorcise the demon of homosexuality from you. Cox showed us an incredibly disturbing clip of a group doing just that.

Even for the groups that pretend to scientific literacy, workshops and retreats are led by people with no formal training or certification. Books are written by quacks like Richard Cohen who were kicked out of their professional organisations for various reasons (in Cohen’s case, multiple ethics violations). The scientific consensus is that “ex-gay” therapies don’t work, can cause additional emotional damage, but these groups continue plugging merrily along, peddling their dogma.

You don’t even have to listen to scientists (who of course are all godless socialists, so what do they know?). Let’s ask John Paulk, or Ted Haggard, or George Rekers (he of the luggage-carrying rentboys.com escort). Pretty much all the success stories go gay again, publicly or on the sly.

Cox took us through a few Bible verses about homosexuality and women (Lev 18:19–22, the bit with Lot’s daughters in Sodom & Gomorrha) and concluded that, really, it’s not that God hates fags. It’s that God hates women. The problem homophobes have with gays is that they’re transgressing gender roles. Men are for fucking, women are for getting fucked, and when you mix that up, there’s no end to the anarchy that can result.

And just for fun, he took a few of us through “Healing Touch Therapy”, a “technique” he learned in one of the straight camps. It involved one guy (in this case, me) surrounded by 3 other guys and held in a warm but nonsexual way. The counselor (in this case, Cox) babbles a lot of nonsense about the walls inside myself, and how they kept me alive all this time, and he honours those walls, but now it’s time for the walls to come down. And then leads the audience in an inspirational singalong.

So yeah, it’s all in good fun, but I can see how it’d be a huge mind-fuck for vulnerable people. Guys steeped in a culture that frowned on any kind of male-male contact except chest bumps or brief manly hugs, who suddenly got permission to touch like that, even in a non-sexual way, would probably experience massive emotional releases. And indeed they do, but more often than not it just leads them away from the ex-gay scene. Apparently groups like that are a part of the coming-out process for many Evangelical Xians. And I am very, very glad I never had to go through that.

PS: The Healing Touch therapy didn’t work. Oh well, you get what you pay for.

George Takei’s happy dance and The Batman 1943 film serial

Behold the greatest thing ever:

Behold the greatest thing ever:

Man, George has got some sweet moves! I’d never heard of this project before now, but I wish them all the luck in the world.

The timing’s interesting, though, because I just finished watching The Batman, a 15-part 1943 movie serial. It features the Dynamic Duo going up against Doctor Tito Daka, an evil Japanese-American spymaster and mad scientist out to sabotage the US war effort and bring this beacon of democracy under the heel of Emperor Hirohito.

Also it serves as a great showcase of WWII anti-Japanese hatred and paranoia. Let’s see how the narrator introduces Gotham City’s Little Tokyo:

This was part of a foreign land, transplanted bodily to America, and known as Little Tokyo. Since a wise government rounded up the shifty-eyed Japs it has become virtually a ghost street where only one business survives, eking out a precarious existence on the dimes of curiosity-seekers.

Emphasis mine. Yes, they really said that. Oh, and the business in question, the front for Daka’s sinister lair? A “Japanese Chamber of Horrors” where visitors can see what horrible people the Japanese are: exhibits include some Japanese soldiers, more Japanese soldiers menacing a helpless lily-white American lady, and yet more Japanese soldiers pointing their bayonets at an American soldier in a cage. Just so viewers don’t forget, this chamber of horrors is shown over and over at least every other chapter. Oy.

Aside from that, though, the serial wasn’t half bad. Horribly low-budget, of course, but pretty decent entertainment. It’s an interesting look at a very, very early Batman, probably before much of the mythology was fully developed. The serial makes no mention of the heroes’ tragic origins, instead just portraying them as costumed crimefighters who spend most of their time breaking up gangs and such, but occasionally take orders directly from Washington to handle matters of national security.

What’s also interesting is how thin the line is between Batman and Bruce Wayne. True, in public he behaves as a useless rich playboy, but he doesn’t even try to change his voice or mannerisms when in costume, and when in private or in their car will casually remove his cowl. Batman is very human, just doing the punchy-punchy thing with bad guys, no special bat-gadgets. Which I guess makes sense if “Batman” is just a costume to Wayne and not an identity—and of course could just be due to the low budget—but I wonder how true this was to the comics of the time?

A couple of other thoughts:

  • Daka is actually smarter and more restrained than I expected for an old-school serial villain. He’s very pragmatic about using his zombifying machine to get slaves and extract information, and only takes a few seconds to gloat in Chapter 14 before sending Batman into the pit. Of course it had to have a silly death trap, but there you go, sometimes you can’t buck tradition. No unnecessarily slow-moving death trap, no cliffhanger, am I right?
  • Damn, Edna Mode was right. In the fight scenes, Batman and Robin kept getting all tangled in their capes. Batman’s cowl almost came off accidentally a couple of times, too.
  • According to TVTropes, this serial created several elements of the Bat-universe we now take for granted, like the Batcave and Alfred’s usual appearance of a skinny British guy.

Next up: the 1949 Batman and Robin movie serial. Borrowed the DVD from a friend, this should be fun.

Adding custom fields to orders in Ubercart

Here’s a little something I figured out just recently. Let’s say you have Ubercart installed. Let’s say also that you want to add a custom field to the uc_orders table. There are a couple of ways to do this.

Here’s a little something I figured out just recently. Let’s say you have Ubercart installed. Let’s say also that you want to add a custom field to the uc_orders table. There are a couple of ways to do this.

One is to hack the uc_orders.install file’ and add the field to its schema definition. That seems untidy, and of course not upgrade-safe. Not to mention it won’t work if Ubercart is already installed. Wouldn’t you need to uninstall/disable uc_orders, drop the orders table, then reinstall it with the new scheme?

THere’s a better way, though. What I’ve done is write a separate module. Call it “mymodule,” just for originality. In mymodule.install, use db_add_field() like so:

mymodule_enable() {
  $ret = array();
  db_add_field($ret, 'uc_orders', 'newfield', array(
    'type'=>'varchar', 
    'length'=>50)
  );
}

Simple! So now I’ve added a field to the database. Calling uc_order_load() works fine: the new fields are part of the order object since it just reads from the orders table; however, calling uc_order_save() will not update the new field.

There’s one more thing I needed to do. uc_order_save() calls drupal_write_record(), which depends on the schema. So mymodule needs to add its new field to the schema, using hook_schema_alter():

So what you do is write the following in mymodule.module:

mymodule_schema_alter(&$schema) {
  $schema['uc_orders']['fields']['newfield'] = array(
    'type' => 'varchar',
    'length' => 50,
    'description' => 'custom field',
  );
}

And it works! I’m wondering if I could put this code in the .install file instead, in mymodule_schema(). Would that work? None of the documentation I’ve read says anything pro or con.

Mythbusters!

The Mythbusters were in town this Sunday! Jamie Hyneman and Adam Savage took over the Queen Elizabeth Theatre for a couple of hours of fun and science. Though I’m a huge fan I hadn’t actually planning to go, since I’ve got volleyball on Sunday nights, and I didn’t think a live show would really add much to the experience—unlike, say, Neil Gaiman and Amanda Palmer, who graced the Vogue Theatre back in November.

The Mythbusters were in town this Sunday! Jamie Hyneman and Adam Savage took over the Queen Elizabeth Theatre for a couple of hours of fun and science. Though I’m a huge fan I hadn’t actually planning to go, since I’ve got volleyball on Sunday nights, and I didn’t think a live show would really add much to the experience—unlike, say, Neil Gaiman and Amanda Palmer, who graced the Vogue Theatre back in November.

But no, this was totally worth it. Adam and Jamie brought lots of audience members, kids and adults, to participate in SCIENCE or play with cool tech like one of their high-speed cameras (ever see someone blowing a raspberry in slo-mo? Fucking hilarious). No explosions, because they couldn’t afford the insurance, but they did have a medley of their best blowing-shit-up moments on a big screen. (including the cement truck. That never gets old).

One thing that struck me was the number of kids, even on a school night. It’s great that their parents are raising them to love science and technology, to question and explore the world around them.

The men, the legends

Swami Adam testing his bed of nails

About to catch the arrow

Looking Back at 2011

Not a big list this time, I’ll just mention two memorable highlights of 2011: I started working with Drupal, and I turned 40.

Not a big list this time, I’ll just mention two memorable highlights of 2011: I started working with Drupal, and I turned 40.

Drupal

Since October 2010 I’ve been in a long-term contract as a developer with a small web shop, building e-commerce sites. After a few months working in Magento I started on a Drupal project (specifically Ubercart), and instantly fell in love. Most of the work I’ve done in 2011 has been in Drupal, mostly back-end coding around Ubercart, though there’s been some digging into core code, as well as front-end / theme development here and there.

In the last year or so I’ve gained tons of experience in Drupal—as well as WordPress in a few smaller projects, both paid and volunteer. Working with both systems has been extremely enjoyable, and I feel I’ve finally found my niche. I know it’ll open many doors for me.

The Big 4-0

I admit, I used to be antsy about turning 40, but when it actually happened, I felt just fine. 40 is just a number, right? Plus, what with volleyball, Taiji, cardio and weights, I’m in way better shape at 40 than at 30—or, hell, even at 39. Finally, everyone The other part is everybody telling me I look way younger than 40. The general consensus is early-thirtyish, though I did have one friend ask me if I was 26 when I mentioned my birthday. And I was all o_O. Just goes to show: 40 is the new 30.