lasaas / address
租户级地址模块,基于 commerceguys/addressing,支持中国省市区三级联动与国外地址格式。
dev-main
2026-08-11 05:26 UTC
Requires
- php: ^8.3
- commerceguys/addressing: ^2.2
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-11 05:38:03 UTC
README
租户级地址模块,基于 commerceguys/addressing,支持中国省市区三级联动与国外地址格式。
- 包名:
lasaas/address(type: lasaas-module) - 命名空间:
Lasaas\Address\ - 适用区域:
central+tenant
功能
- 多态挂接:地址通过
addressables中间表挂接到任意业务实体(User、Order 等),业务模型零改动,无需引入 trait 或关系。 - 中国省市区三级级联:按行政区层级 Select 联动;直辖市(京津沪渝)自动跳过市级;国外地址同字段回退为自由文本输入。
- 本地化:国家与行政区名称跟随当前应用语言输出。
- 地址格式化:基于 commerceguys
DefaultFormatter,按国家格式输出完整地址,支持指定语言与 HTML 标记。 - 业务联系信息:
contact_name(收件人姓名)、phone(手机号)、phone_country_code(国际区号)存于主表,不进入 commerceguys 地理地址格式化;formattedWithContact()用于打印/物流面单。 - 主体私有属性:默认地址、标签、备注等存入
address_metas表(多态),不污染addresses主表。 - 地址用途类型:
billing/shipping/home/work/other,支持平台级与租户级定制。 - 前台个人后台:Livewire 页面管理当前用户地址(增删改、设默认),中央与租户侧边栏自动注入「地址」入口。
- Filament 管理资源:中央 admin 与租户 admin 面板均注册
AddressResource。 - 可复用表单组件:
AddressForm::schema()可在任意 Filament 业务资源中直接展开。
目录结构
packages/custom/lasaas/address/
├── composer.json
├── database/migrations/ # 中央迁移(安装时运行)
│ └── tenant/ # 租户迁移(安装到租户时运行)
├── resources/
│ ├── lang/ # 翻译(en / zh_CN)
│ └── views/pages/⚡addresses.blade.php # 前台地址管理页(Livewire SFC)
├── routes/
│ ├── web.php # 中央:GET /addresses → addresses.index
│ └── tenant.php # 租户:GET /addresses → tenant.addresses.index
├── src/
│ ├── AddressServiceProvider.php
│ ├── Database/Factories/AddressFactory.php
│ ├── Filament/
│ │ ├── Plugins/AdminAddressPlugin.php # 中央 admin 面板
│ │ ├── Plugins/TenantAddressPlugin.php # 租户 admin 面板
│ │ └── Resources/Addresses/ # 管理资源(列表/新建/编辑/查看)
│ ├── Forms/AddressForm.php # 可复用 Filament 表单字段
│ ├── Models/ # Address / AddressOwner / AddressMeta
│ ├── Repositories/AddressRepository.php
│ ├── Settings/ # 平台设置 + 租户设置
│ └── Support/ # SubdivisionService / AddressFormatter
└── tests/ # Pest 测试
数据表
| 表 | 说明 |
|---|---|
addresses | 地址主表,字段对齐 commerceguys addressing 模型(国家、行政区、街道、姓名、邮编、langcode 等),另含业务联系信息 contact_name/phone/phone_country_code |
addressables | 地址 ↔ 业务实体多态挂接表(addressable 多态 + type 用途) |
address_metas | 主体私有属性表(owner 多态 + meta_key/meta_value JSON),如 is_default |
使用:挂接/查询业务实体的地址
通过 AddressRepository 以多态方式操作,业务模型无需任何改动:
use Lasaas\Address\Repositories\AddressRepository;
$repo = app(AddressRepository::class);
// 查询某实体的全部地址(默认地址优先)
$addresses = $repo->for($order);
// 创建地址并挂接(type 须在设置声明的用途内)
$repo->createFor($order, $attributes, type: 'shipping');
// 复制已有地址到新业务实体(下单选地址簿条目时使用,双方编辑互不影响)
// 副本可覆盖字段;is_default 表示把副本同时设为目标实体的默认地址
$repo->copyFor($bookAddress, $order, type: 'shipping', [
'organization' => $company->name,
'is_default' => true,
]);
// 解绑(地址行仅属于该实体时随解绑清理)
$repo->detach($order, $address);
// 默认地址
$default = $repo->getDefault($order);
$repo->setDefault($order, $address);
$address->formatted() 按国家格式输出完整地址字符串(纯地理地址,不含联系信息)。
联系信息单独取值/输出,供打印、物流面单、导出:
$address->contact(); // 收件人姓名(contact_name 优先,回退 given_name + family_name)
$address->phoneNumber(); // 完整手机号(国际区号 + 号码,如 +86 13800138000)
$address->formattedWithContact(); // 收件人 + 手机号 + 纯地理地址(多行拼接)
// 与 commerceguys 值对象互转
$vo = $address->toBaseAddress(); // 模型 → 值对象
$addr = Address::fromBaseAddress($vo, ['phone' => '13800138000']); // 值对象 → 模型
注意:commerceguys 的
Address值对象不包含手机号/联系人(CLDR 只管地理地址),formatted()不会输出它们;扩展字段由 Eloquent 模型持有,与值对象解耦,升级 composer 包不受影响。
使用方冗余快照(推荐用法:选中即复制)
地址模块是「一行地址最多归属一个业务实体」的 copy-on-write 设计(Address::assertExclusiveOwner 保证)。业务实体(如订单)在下单/选地址时,应把选中的地址复制一份挂到自己名下,这样地址簿后续的修改/删除都不会影响历史订单的地址:
use Lasaas\Address\Models\Address;
use Lasaas\Address\Repositories\AddressRepository;
$repo = app(AddressRepository::class);
// 下单:把用户选中的地址簿条目冗余复制到订单(双方互不影响)
$snapshot = $repo->copyFor($selectedAddress, $order, type: 'shipping');
// 等价写法(模型便捷方法)
$snapshot = $selectedAddress->copyTo($order, type: 'shipping', [
'organization' => $company->name, // 覆盖副本字段,如订单抬头
'is_default' => true, // 同时把副本设为目标实体的默认地址
]);
// 订单展示/编辑自己的副本,永不串改用户地址簿
echo $repo->for($order)->first()->formatted();
要点:
- 副本是
addresses表里的一行独立地址,通过addressables独占挂接;地址簿条目被修改/删除时订单副本不受影响,反之亦然; - 主体私有属性(默认地址、标签、备注)不随副本迁移;
is_default仅影响副本,原地址的默认标记不动;copyFor忽略副本字段里的id/created_at/updated_at。
设置
- 平台设置
AddressPlatformSettings(中央后台「模块 → 设置」):default_country:表单默认国家(ISO-2)types:允许的地址用途 key => 显示名
- 租户设置
AddressTenantSettings(中央后台「租户 → 模块管理」):同名覆盖、其余回退到平台设置。
在业务资源中复用地址表单
use Lasaas\Address\Filament\Plugins\TenantAddressPlugin;
public static function schema(): array
{
return [
...TenantAddressPlugin::formSchema(),
// 业务字段……
];
}
测试
php artisan test --compact packages/custom/lasaas/address/tests
覆盖:地址表单互斥分支共享 statePath、前台页面增删改与默认地址、平台/租户设置、仓储挂接与校验、导航注入。