customer_addresses テーブル定義
テーブル概要
会員が事前に登録した配送先住所を管理するテーブルです。ECCUBEのdtb_customer_addressテーブル構造を参考にしています。
テーブル名: customer_addresses
説明: 会員配送先住所
用途: 会員が事前に登録した配送先リストを管理。注文時に選択してaddressesテーブルにコピーされる。
カラム定義
| カラム名 | 型 | NULL | デフォルト | キー | 説明 |
|---|---|---|---|---|---|
| id | BIGINT UNSIGNED | NOT NULL | AUTO_INCREMENT | PK | 主キー |
| user_id | BIGINT UNSIGNED | NOT NULL | - | FK, INDEX | 会員ID(users.id) |
| address_name | VARCHAR(255) | NOT NULL | - | INDEX | 住所名("自宅", "実家", "会社"等) |
| last_name | VARCHAR(255) | NOT NULL | - | - | 姓 |
| first_name | VARCHAR(255) | NOT NULL | - | - | 名 |
| last_name_kana | VARCHAR(255) | NULL | NULL | - | 姓カナ |
| first_name_kana | VARCHAR(255) | NULL | NULL | - | 名カナ |
| company_name | VARCHAR(255) | NULL | NULL | - | 会社名 |
| phone_number | VARCHAR(14) | NOT NULL | - | INDEX | 電話番号 |
| country_id | BIGINT UNSIGNED | NOT NULL | - | FK | 国ID(countries.id) |
| postal_code | VARCHAR(8) | NOT NULL | - | INDEX | 郵便番号/ZIP |
| state_province | VARCHAR(255) | NOT NULL | - | INDEX | 州/省/都道府県 |
| address_line1 | VARCHAR(255) | NOT NULL | - | - | 住所1(市区町村・番地) |
| address_line2 | VARCHAR(255) | NULL | NULL | - | 住所2(建物名等) |
| address_line3 | VARCHAR(255) | NULL | NULL | - | 住所3(追加情報) |
| is_default | BOOLEAN | NOT NULL | FALSE | INDEX | デフォルト配送先フラグ |
| created_at | TIMESTAMP | NULL | NULL | - | 作成日時 |
| updated_at | TIMESTAMP | NULL | NULL | - | 更新日時 |
インデックス
| 種別 | 名称 | 対象カラム | 説明 |
|---|---|---|---|
| PRIMARY KEY | pk_customer_addresses | id | 主キー |
| INDEX | idx_customer_addresses_user | user_id | 会員別検索 |
| INDEX | idx_customer_addresses_name | address_name | 住所名検索 |
| INDEX | idx_customer_addresses_phone | phone_number | 電話番号検索 |
| INDEX | idx_customer_addresses_postal | postal_code | 郵便番号検索 |
| INDEX | idx_customer_addresses_state | state_province | 都道府県/州検索 |
| INDEX | idx_customer_addresses_default | is_default | デフォルト配送先検索 |
外部キー制約
| 名称 | 対象カラム | 参照先 | ON DELETE | ON UPDATE | 説明 |
|---|---|---|---|---|---|
| fk_customer_addresses_user | user_id | users(id) | CASCADE | RESTRICT | 会員削除時に配送先も削除 |
| fk_customer_addresses_country | country_id | countries(id) | RESTRICT | RESTRICT | 国削除時はエラー |
リレーション
| 関連先テーブル | 関連タイプ | 外部キー | 参照先 | ON DELETE | ON UPDATE | 説明 |
|---|---|---|---|---|---|---|
| users | N:1 | user_id | id | CASCADE | RESTRICT | 配送先は1つの会員に属する |
| countries | N:1 | country_id | id | RESTRICT | RESTRICT | 配送先は1つの国に属する |
データ例
| id | user_id | address_name | last_name | first_name | phone_number | postal_code | state_province | address_line1 | is_default |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 自宅 | 山田 | 太郎 | 090-1234-5678 | 554-0001 | 大阪府 | 大阪市此花区高見1-2-3 | TRUE |
| 2 | 1 | 会社 | 山田 | 太郎 | 06-1234-5678 | 530-0001 | 大阪府 | 大阪市北区梅田1-1-1 | FALSE |
| 3 | 2 | 実家 | 佐藤 | 花子 | 080-9876-5432 | 100-0001 | 東京都 | 千代田区千代田1-1 | TRUE |
備考・注意事項
住所設計
世界共通フォーマット
- 5つのフィールド(country_id, postal_code, state_province, address_line1-3)で全世界対応
- JSON不要でシンプル
- 検索・ソートが高速
日本の例
- country_id: 日本
- postal_code: 554-0001
- state_province: 大阪府
- address_line1: 大阪市此花区高見1-2-3
- address_line2: ○○マンション101号
アメリカの例
- country_id: USA
- postal_code: 10001
- state_province: NY
- address_line1: 123 Main Street
- address_line2: Apt 4B
- address_line3: New York
デフォルト配送先管理
is_defaultフラグ
- 1つの会員につき、1つのデフォルト配送先のみ設定可能
- 新しい配送先をデフォルトに設定する際は、既存のデフォルトを解除する必要がある
- アプリケーション層で制御(データベース制約は設定しない)
推奨実装
// デフォルト配送先を設定
public function setDefaultAddress(CustomerAddress $address): void
{
// 既存のデフォルトを解除
$this->customerAddresses()
->where('is_default', true)
->update(['is_default' => false]);
// 新しいデフォルトを設定
$address->update(['is_default' => true]);
}
addressesテーブルとの関係
役割の違い
customer_addresses: 会員の登録配送先リスト(事前登録)addresses: 注文時のスナップショット住所(注文時点での情報を記録)
データフロー
- 会員が
customer_addressesに配送先を事前登録 - 注文時に
customer_addressesから選択 - 選択した配送先情報を
addressesテーブルにコピー - 会員が後から
customer_addressesを変更しても、addressesの情報は変わらない
Eloquentモデル例
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class CustomerAddress extends Model
{
protected $fillable = [
'user_id',
'address_name',
'last_name',
'first_name',
'last_name_kana',
'first_name_kana',
'company_name',
'phone_number',
'country_id',
'postal_code',
'state_province',
'address_line1',
'address_line2',
'address_line3',
'is_default',
];
protected function casts(): array
{
return [
'is_default' => 'boolean',
];
}
// リレーション
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function country(): BelongsTo
{
return $this->belongsTo(Country::class);
}
// アクセサ
public function getFullNameAttribute(): string
{
return trim($this->last_name . ' ' . $this->first_name);
}
public function getFullNameKanaAttribute(): string
{
return trim(($this->last_name_kana ?? '') . ' ' . ($this->first_name_kana ?? ''));
}
// スコープ
public function scopeDefault($query)
{
return $query->where('is_default', true);
}
// デフォルト配送先を設定
public function setAsDefault(): void
{
// 既存のデフォルトを解除
$this->user->customerAddresses()
->where('is_default', true)
->where('id', '!=', $this->id)
->update(['is_default' => false]);
// この配送先をデフォルトに設定
$this->update(['is_default' => true]);
}
}