よくあるご要望として、Magento上の顧客属性や顧客住所属性を増やしたい、というものがあります。
Community EditionのMagentoには顧客属性などを編集する機能が用意されていないので、このようなご要望はある意味当然だと思います。

今回は顧客・顧客住所属性を増やす方法について解説します。

Magentoのデータ構造について

Magentoの顧客データや、顧客住所データは、EAV(Entity - Attribute - Value)というデータ構造で管理されています。
Entityというのは顧客データや顧客住所データといったデータセットの定義です。他にも注文データや商品データ、カテゴリデータのエンティティが存在します。

Attributeは属性です。エンティティに紐付いているデータ項目を意味します。顧客エンティティであれば、氏名やメールアドレスが属性にあたります。
Valueは属性の値です。属性のデータ型によって分類された専用のテーブル上に記録されていきます。

EAVデータ構造では複数のテーブルにデータが分散して記録されるため、1件のデータを構成するすべてのデータを一度に確認することが難しくなります。
ですがその代わりに、データ項目を1つ増やす場合でもテーブル定義を増やす必要がありません。そのおかげでMagentoは柔軟なデータの拡張性を手に入れているのです。

顧客データと顧客住所データの関係性

Magento上の顧客データと、顧客住所データには1対多の関係があります。
1件の顧客データには複数の顧客住所データが作成でき、その中の1件または2件のデータに対し、「標準の請求先」「標準の配送先」を指定することができます。

誤解を招きやすいのは、1件しか住所データがない場合に、そのデータが「標準の請求先」と「標準の配送先」に指定されている場合です。
この場合、データが1件しかないにもかかわらず、2件あるように見えてしまいます。
データが1件しかないので請求先を編集すると配送先の内容も変わってしまうのですが、ついつい請求先しか変更したつもりではないのにどうしてだ、という声がでてきます。

よくよく考えると当然の動きなのですが、画面上はそうは見えにくい点に注意が必要です。

顧客データや顧客住所データに属性を追加するには

属性を追加したい場合、3つの方法があります。

  • 属性管理画面を提供するエクステンションの導入
  • 特定の属性だけを追加するエクステンションの導入
  • 必要な属性を追加する独自カスタマイズを行う

大きく分けると「エクステンションを導入する」か、「自分でカスタマイズする」かにわかれます。

このエントリでは「自分でカスタマイズする」方法について解説します。
Magentoに関するプログラムや設定ファイルを書かないといけないのですが、ディレクトリや設定ファイルの作成が実際はほとんどです。

自分でカスタマイズする際の方法

では、実際にカスタマイズしていきましょう。
今回はサンプルとしてフリガナを追加するコードを紹介します。
同じ要領で他のフィールドを増やすこともできます。

流れとしては、

  • エクステンションディレクトリの作成
  • Helper・Modelの作成
  • config.xmlの作成
  • セットアップスクリプトの作成
  • グローバル設定ファイルの作成
  • テストの実施と本番反映

という流れになります。 

エクステンションディレクトリの作成

まず最初にエクステンションのディレクトリを作ります。

app/code/local

にMyextensionというディレクトリを作り、その中にCustomerというディレクトリを作ります。
次にその中に、

  • Helper
  • Model
  • etc
  • sql

というディレクトリを作ります。
ここからMagentoのエクステンションコードを書いていきます。

Helperの作成

最初にHelperを作ります。

app/code/local/Myextension/Customer/Helper

に、Data.phpというファイルを作成し、以下のように記述します。

<?php
class Myextension_Customer_Helper_Data extends Mage_Core_Helper_Abstract
{

}

メソッドやプロパティはこの段階では何も書かなくても構いません。
必要に応じて作成していきます。

Modelの作成

次にModelを作成します。最初にEntityという名称のディレクトリをつくっておきます。
そして、Entityディレクトリの中に、Setup.phpを作り、以下のように記述します。

<?php
class Myextension_Customer_Model_Entity_Setup extends Mage_Sales_Model_Resource_Setup
{

}

ここでもメソッドやプロパティは定義しなくても構いません。

config.xmlの作成

続いてconfig.xmlを作成します。config.xmlはMagentoのモジュールに関する様々な定義を書くXMLファイルです。
etcディレクトリの中にconfig.xmlを作成し、以下のように記述します。

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <Myextension_Customer>
            <version>1.0.0</version>
        </Myextension_Customer>
    </modules>
    <global>
<helpers>
<mycustomer>
<class>Myextension_Customer_Helper</class>
</mycustomer>
</helpers>
<models>
<mycustomer>
<class>Myextension_Customer_Model</class>
</mycustomer>
</models>
        <resources>
            <mycustomer_setup>
                <setup>
                    <module>Myextension_Customer</module>
                    <class>Myextension_Customer_Model_Entity_Setup</class>
                </setup>
                <connection>
                    <use>core_setup</use>
                </connection>
            </mycustomer_setup>
        </resources>
        <fieldsets>
            <sales_copy_order_billing_address>
                <firstnamekana>
                    <to_order>*</to_order>
                </firstnamekana>
                <lastnamekana>
                    <to_order>*</to_order>
                </lastnamekana>
            </sales_copy_order_billing_address>
            <sales_copy_order_shipping_address>
                <firstnamekana>
                    <to_order>*</to_order>
                </firstnamekana>
                <lastnamekana>
                    <to_order>*</to_order>
                </lastnamekana>
            </sales_copy_order_shipping_address>
            <sales_convert_quote>
                <customer_firstnamekana>
                    <to_order>*</to_order>
                </customer_firstnamekana>
                <customer_lastnamekana>
                    <to_order>*</to_order>
                </customer_lastnamekana>
            </sales_convert_quote>
            <sales_convert_quote_address>
                <firstnamekana>
                    <to_order_address>*</to_order_address>
                    <to_customer_address>*</to_customer_address>
                </firstnamekana>
                <lastnamekana>
                    <to_order_address>*</to_order_address>
                    <to_customer_address>*</to_customer_address>
                </lastnamekana>
            </sales_convert_quote_address>
            <sales_convert_order_address>
                <firstnamekana>
                    <to_quote_address>*</to_quote_address>
                </firstnamekana>
                <lastnamekana>
                    <to_quote_address>*</to_quote_address>
                </lastnamekana>
            </sales_convert_order_address>
            <customer_account>
                <firstnamekana>
                    <to_quote>customer_firstnamekana</to_quote>
                    <create>1</create>
                    <update>1</update>
                    <name>1</name>
                </firstnamekana>
                <lastnamekana>
                    <to_quote>customer_lastnamekana</to_quote>
                    <create>1</create>
                    <update>1</update>
                    <name>1</name>
                </lastnamekana>
            </customer_account>
            <customer_address>
                <firstnamekana>
                    <to_quote_address>*</to_quote_address>
                </firstnamekana>
                <lastnamekana>
                    <to_quote_address>*</to_quote_address>
                </lastnamekana>
            </customer_address>
            <checkout_onepage_billing>
                <firstnamekana>
                    <to_customer>*</to_customer>
                </firstnamekana>
                <lastnamekana>
                    <to_customer>*</to_customer>
                </lastnamekana>
            </checkout_onepage_billing>
            <checkout_onepage_quote>
                <customer_firstnamekana>
                    <to_customer>firstnamekana</to_customer>
                </customer_firstnamekana>
                <customer_lastnamekana>
                    <to_customer>lastnamekana</to_customer>
                </customer_lastnamekana>
            </checkout_onepage_quote>
        </fieldsets>
    </global>
</config>

ここでの重要なポイントは、globalタグの下にあるfieldsetsタグの中身です。

fieldsetsタグの内容は、各データモデルにあるパラメータを別のデータモデルにコピーする設定を書いています。
これを書いておかないと、顧客データには登録したデータが入るのに、住所データには入らないといった現象が起きてしまいます。

セットアップスクリプトの作成

さて、実際に属性を追加するためのセットアップスクリプトを作ります。
セットアップスクリプトは、sqlディレクトリの下に作成するPHPスクリプトです。

mycustomer_setupというディレクトリを作成し、その中にinstall-1.0.0.phpというファイルを作ります。
そして、以下の内容を記述します。

<?php
$installer = $this;
$installer->addAttribute(
    'customer',
    'firstnamekana',
    array(
        'label' => 'First Name Kana',
        'is_required' => '0'
    )
);
$installer->addAttribute(
    'customer',
    'lastnamekana',
    array(
        'label'         => 'Last Name Kana',
        'is_required' => '0'
    )
);
$installer->addAttribute(
    'customer_address',
    'firstnamekana',
    array(
        'label' => 'First Name Kana',
        'is_required' => '0'
    )
);
$installer->addAttribute(
    'customer_address',
    'lastnamekana',
    array(
        'label' => 'Last Name Kana',
        'is_required' => '0'
    )
);
$installer->addAttribute(
    'quote',
    'customer_firstnamekana',
    array(
        'visible'=> false
    )
);
$installer->addAttribute(
    'quote',
    'customer_lastnamekana',
    array(
        'visible'=> false
    )
);
$installer->addAttribute(
    'quote_address',
    'firstnamekana',
    array()
);
$installer->addAttribute(
    'quote_address',
    'lastnamekana',
    array()
);
$installer->addAttribute(
    'order',
    'customer_firstnamekana',
    array(
        'visible'=> false
    )
);
$installer->addAttribute(
    'order',
    'customer_lastnamekana',
    array(
        'visible'=> false
    )
);
$installer->addAttribute(
    'order_address',
    'firstnamekana',
    array()
);
$installer->addAttribute(
    'order_address',
    'lastnamekana',
    array()
);

$eavConfig = Mage::getSingleton('eav/config');
Mage::app()->reinitStores();
$websites  = Mage::app()->getWebsites(false);

$scopes = array('customer', 'customer_address');
$attributes = array('firstnamekana', 'lastnamekana');
$form_code = array(
                                'checkout_register',
                                'customer_account_edit',
                                'customer_account_create',
                                'adminhtml_customer',
                                'customer_address_edit'
                                );
$form_code_address = array('adminhtml_customer_address','customer_register_address',);

foreach ($websites as $website) {
    $store = $website->getDefaultStore();
    if (!$store) {
        continue;
    }
    foreach($scopes as $scope) {
        foreach($attributes as $attribute) {
                $_attribute = $eavConfig->getAttribute($scope, $attribute);
               
                if ($scope == 'customer_address') {
                    $_attribute->setData('used_in_forms', array_merge($form_code, $form_code_address));
                } else {
                    $_attribute->setData('used_in_forms', $form_code);
                }
                $_attribute->setWebsite($website);
                $_attribute->save();
         }
    }
   


$installer->endSetup();

セットアップスクリプトは、install-x.x.x.phpと、update-x.x.x-y.y.y.phpの2種類があります。

install-x.x.x.phpは初回インストール用。update-x.x.x-y.y.y.phpはアップデート用です。エクステンションがバージョンアップして、データモデルに修正を加えたい際に使用します。
x.x.xとy.y.yにはエクステンションのバージョン番号が入ります。アップデートさせる際はxよりyのほうが新しいバージョン番号であることが必須です
この値とconfig.xmlに記述したバージョン番号が一致していないと正しく動きません。

グローバル設定ファイルの作成

最後にグローバル設定ファイルを作成します。
このファイルは

app/etc/modules

ディレクトリに作成します。Myextension_Customer.xmlという名前でファイルを作成し、以下のように記述します。

<?xml version="1.0"?>
<config>
   <modules>
       <Myextension_Customer>
           <active>true</active>
           <codePool>local</codePool>
       </Myextension_Customer>
   </modules>
</config>

このファイルがないと、エクステンションのコードをいくら記述しても全く動きません。
そのため、本番環境にファイルをアップする場合はこのグローバル設定ファイルを最後にするほうが無難です。
このファイルさえなければエクステンションが動作しないので、エクステンションのインストール処理が実行されるタイミングを制御できるわけです。

テストの実施と本番反映

出来上がったエクステンションをテスト用の環境で正しく動くか試します。
ここでうまくいかない場合は、うまくいくまで調整を繰り返します。

全てうまくいくようになったら、本番環境に反映します。

顧客属性・住所属性を追加する際のポイント

注文データに使うのか使わないのか

その属性が注文データにも必要か否か、と言うのは追加前にチェックする必要があります。
というのもconfig.xmでのfieldset定義に影響するわけで、書かなければデータは反映されません。

customer_form_attributeテーブルへの登録

セットアップスクリプトの中で記述したforeach文では、formというデータ定義を行っています。
Magentoの顧客データや住所データなどのEAVをデータモデルに使用する画面では、customer_form_attributeテーブルの定義を用いて、定義されているデータ項目だけを使用するようになっています。
ですから定義していないフィールドを勝手に作ったとしても、そのデータはデータベースに格納されることはありません。