Modest Mouse

March 5th, 2009

Got to see the show last night at Stubb’s. As I expected, it was heavy on Good News for People Who Love Bad News and We Were Dead Before the Ship Even Sank. Definitely not my choice Mouse, but they’re excellent performers and I was thrilled that I finally got to see one of my favorite bands. They did play Ohio and Doin’ the Cockroach, the latter of which turned into a solid 5 minutes of pure sticky jam goodness. Because of that, I left happy and that’s what counts.

/* Comment? */

Yer Bash shell got a purty mouth.

February 26th, 2009

Ubuntu Intrepid users are spoiled with a top-notch ~/.bashrc out of the box. Mac users have to attempt a poor substitute, here’s mine.

alias ls='ls -G'
alias ll='ls -lG'
alias la='ls -AG'
alias l='ls -CFG'
alias grep='grep --exclude=".svn" --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'

Try that in your ~/.bash_profile. Colored grep results are so much nicer.

/* Comment? */

Commis, throw this hat into the ring.

February 19th, 2009

It’s on. Sir Steve has expressed an interest in participating. My e-mailed response was as follows:

My test tubes and Bunsen burners are out and I have the ghost of Julia Child in a bottle ready to be unleashed on an unholy combination of science meets essence.

I’m pondering entering into the Kama Sutra category, not only because of the name, but because it allows the use of ingredients other than bread, cheese, and butter. Although, perhaps the relative homogeny in the Spoon group (only bread, cheese, and butter) would lend itself towards honing the recipe for delicousnesseses [sic]. Once cremini mushrooms get into a grilled cheese, you’re really off the deep end.

/* 1 Comment */

Magento SQL Query Inspection

February 19th, 2009

Magento can produce some rather complex queries, but you’d never know it just by coding modules for it. Leveraging their Model construct, it’s easy to avoid needing a knowledge of SQL. However, sometimes it’s really nice to know just what the hell the ORM is up to. All Magento resource collections are based on Varien’s base Varien_Data_Collection_Db class. It has a handy method, getSelect().

I was hacking on a batch emailer for new orders, a la drop shipping, and wound up with this rather hefty resource collection assignment.

$orders = Mage::getResourceModel('sales/order_collection')
    ->addAttributeToSelect('increment_id')
    ->addAttributeToSelect('created_at')
    ->addAttributeToSelect('grand_total')
    ->addAttributeToSelect('order_currency_code')
    ->addAttributeToSelect('store_id')
    ->joinAttribute('billing_firstname', 'order_address/firstname', 'billing_address_id', null, 'left')
    ->joinAttribute('billing_lastname', 'order_address/lastname', 'billing_address_id', null, 'left')
    ->joinAttribute('shipping_firstname', 'order_address/firstname', 'shipping_address_id', null, 'left')
    ->joinAttribute('shipping_lastname', 'order_address/lastname', 'shipping_address_id', null, 'left')
    ->addExpressionAttributeToSelect('billing_name',
        'CONCAT({{billing_firstname}}, " ", {{billing_lastname}})',
        array('billing_firstname', 'billing_lastname'))
    ->addExpressionAttributeToSelect('shipping_name',
        'CONCAT({{shipping_firstname}}, " ", {{shipping_lastname}})',
        array('shipping_firstname', 'shipping_lastname'))
    ->addAttributeToFilter('created_at', array('from' => $most_recent->getExecutedAt(), 'datetime' => true))
    ->addAttributeToSort('created_at', 'asc');

Anyway, I just wanted to know what Magento was actually selecting. ‘$orders->getSelect();‘ reveals all:

SELECT `e`.*,
    `_table_billing_address_id`.`value` AS `billing_address_id`,
    `_table_billing_firstname`.`value` AS `billing_firstname`,
    `_table_billing_lastname`.`value` AS `billing_lastname`,
    `_table_shipping_address_id`.`value` AS `shipping_address_id`,
    `_table_shipping_firstname`.`value` AS `shipping_firstname`,
    `_table_shipping_lastname`.`value` AS `shipping_lastname`,
    CONCAT(_table_billing_firstname.value, " ", _table_billing_lastname.value) AS `billing_name`,
    CONCAT(_table_shipping_firstname.value, " ", _table_shipping_lastname.value) AS `shipping_name`
FROM `magento_sales_order` AS `e`
LEFT JOIN `magento_sales_order_int` AS `_table_billing_address_id` ON
    (_table_billing_address_id.entity_id = e.entity_id) AND (_table_billing_address_id.attribute_id='112')
LEFT JOIN `magento_sales_order_entity_varchar` AS `_table_billing_firstname` ON
    (_table_billing_firstname.entity_id = _table_billing_address_id.value) AND (_table_billing_firstname.attribute_id='202')
LEFT JOIN `magento_sales_order_entity_varchar` AS `_table_billing_lastname` ON
    (_table_billing_lastname.entity_id = _table_billing_address_id.value) AND (_table_billing_lastname.attribute_id='204')
LEFT JOIN `magento_sales_order_int` AS `_table_shipping_address_id` ON
    (_table_shipping_address_id.entity_id = e.entity_id) AND (_table_shipping_address_id.attribute_id='113')
LEFT JOIN `magento_sales_order_entity_varchar` AS `_table_shipping_firstname` ON
    (_table_shipping_firstname.entity_id = _table_shipping_address_id.value) AND (_table_shipping_firstname.attribute_id='202')
LEFT JOIN `magento_sales_order_entity_varchar` AS `_table_shipping_lastname` ON
    (_table_shipping_lastname.entity_id = _table_shipping_address_id.value) AND (_table_shipping_lastname.attribute_id='204')
WHERE (e.entity_type_id = '11') AND (e.created_at >= '2009-02-19 06:03:57')
ORDER BY `e`.`created_at` ASC

Pretty handy if you want to replicate a result set in a query browser or with the MySQL command line tool.

/* Comment? */

Custom EAV Gallery Attributes in Magento

February 5th, 2009

The default Magento install has several media gallery attributes allowing you to choose a thumbnail, small, and base image for a product’s image gallery. I’ve often had the need to use additional image types. For instance, my latest project required the addition of a header banner for product detail pages.

It is possible to simply insert two rows into the eav_attribute and eav_attribute_group tables to accomplish this, but it will be lost if your database ever is. Here’s how to implement such a feature properly.

First, we’ll create a standard Magento module directory structure inside app/code/local. Here’s a screenshot, just create blank files as placeholders for everything you see, we’ll edit them later. Change the name of the company (Company) and module (Customized) as you desire.

Alright Dudley, make yours like mine.

Alright Dudley, make yours like mine.

This is a pretty sparse module. The only thing it does is install some attributes for us. First, let’s look at the configuration file, config.xml.

<config>
  <modules>
    <company_customized>
      <version>0.1.0</version>
    </company_customized>
  </modules>  
  <global>    
    <models>      
      <customized>
        <class>Company_Customized_Model</class>
        <resourcemodel>customized_resource_eav_mysql4</resourcemodel>
      </customized>
      <customized_resource_eav_mysql4>
        <class>Company_Customized_Model_Resource_Eav_Mysql4</class>
      </customized_resource_eav_mysql4>
    </models>      
    <resources>
      <customized_setup>
        <setup>
          <module>Company_Customized</module>
          <class>Company_Customized_Model_Resource_Eav_Mysql4_Setup</class>
        </setup>
        <connection>
          <use>core_setup</use>
        </connection>
      </customized_setup>
    </resources>
  </global>
</config>

Here, we’re essentially setting up a skeletal EAV resource for Magento, there’s no model, just the setup file that will be instantiated when the install file in sql/customized_setup is run by Magento. In Setup.php, we define our entities. In our case, we’re adding an entity to the product model under the Images group. For clarity, here’s Setup.php.

class Company_Customized_Model_Resource_Eav_Mysql4_Setup extends Mage_Eav_Model_Entity_Setup
{

  public function getDefaultEntities()
  {
    return array(
      'catalog_product' => array(
        'entity_model'      => 'catalog/product',
        'attribute_model'   => 'catalog/resource_eav_attribute',
        'table'             => 'catalog/product',
      'attributes'        => array(
        'banner_image' => array(
          'group'             => 'Images',
          'type'              => 'varchar',
          'frontend'          => 'catalog/product_attribute_frontend_image',
          'label'             => 'Banner Image',
          'input'             => 'media_image',
          'class'             => '',
          'source'            => '',
          'global'            => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE,
          'visible'           => true,
          'required'          => false,
          'user_defined'      => false,
          'default'           => '',
          'searchable'        => false,
          'filterable'        => false,
          'comparable'        => false,
          'visible_on_front'  => false,
          'unique'            => false,
          )
        )
      )
    );
  }
}

All this file does is define a function (getDefaultEntities()) that returns an array of entities. This function is called by installEntities() within the install file, which we’ll look at last. mysql4-install-0.1.0.php is only two lines. Notice how the version number from config.xml corresponds to the file name.

$installer = $this;
$installer->installEntities();

To get the ball rolling, you need to add a module configuration file in app/etc/modules. In my case, it’s named Company_All.xml. Here’s the contents.

<config>
  <modules>
    <company_customized>
      <active>true</active>
      <codepool>local</codepool>
    </company_customized>
  </modules>
</config>

Once you’re all set, disable or refresh Magento’s EAV types and attributes cache in the administration interface under System -> Cache Management. After you refresh the page, you should see something like this when you edit a product’s images.

Look Ma, a banner image radio!

Look Ma, a banner image radio!

Here is a zip file containing everything discussed. This code was used with Magento 1.2.0.3.

/* 1 Comment */

I’m back.

December 8th, 2008

Hi Internet,

It’s been a while, but I’m back. It’s nice to see you and I hope you’ve been well.

/* Comment? */