stormcode / laravel-phone
基于 Google 的 libphonenumber API 为 Laravel 添加电话号码功能。
支持包维护!
Propaganistas
Requires
- php: ^8.1
- giggsey/libphonenumber-for-php-lite: ^8.13.35
- illuminate/contracts: ^10.0|^11.0
- illuminate/support: ^10.0|^11.0
- illuminate/validation: ^10.0|^11.0
Requires (Dev)
- larastan/larastan: ^2.9
- laravel/pint: ^1.14
- orchestra/testbench: *
- phpunit/phpunit: ^10.5
This package is auto-updated.
Last update: 2024-09-27 08:43:19 UTC
README
基于 PHP 端口 的 Google 的 libphonenumber 为 Laravel 添加电话号码功能。
目录
演示
查看此包在 演示 中的行为。
安装
运行以下命令安装最新版本的包
composer require propaganistas/laravel-phone
Laravel 会自动发现服务提供者。
在您的语言目录中,为每个 validation.php
语言文件添加额外的翻译
'phone' => 'The :attribute field must be a valid number.',
验证
在您的验证规则数组中使用 phone
关键字,或使用 Propaganistas\LaravelPhone\Rules\Phone
规则类以表达方式定义规则。
要限制允许的起始国家,可以显式指定允许的国家代码。
'phonefield' => 'phone:US,BE', // 'phonefield' => (new Phone)->country(['US', 'BE'])
或者为了更动态,您也可以匹配另一个包含国家代码的数据字段。例如,要求电话号码与提供的居住国相匹配。请确保国家字段与电话字段名称相同,但需要在后面附加 _country
以自动发现,或者将您自定义的国家字段名称作为参数传递给验证器
'phonefield' => 'phone', // 'phonefield' => (new Phone) 'phonefield_country' => 'required_with:phonefield',
'phonefield' => 'phone:custom_country_field', // 'phonefield' => (new Phone)->countryField('custom_country_field') 'custom_country_field' => 'required_with:phonefield',
注意:国家代码应符合 ISO 3166-1 alpha-2 标准。
要支持除白名单国家之外的所有有效国际格式电话号码,请使用 INTERNATIONAL
参数。这可以在您期望来自特定国家的本地格式号码时非常有用,同时也希望接受任何其他正确输入的外国号码
'phonefield' => 'phone:INTERNATIONAL,BE', // 'phonefield' => (new Phone)->international()->country('BE')
要指定对号码类型的约束,只需将允许的类型追加到参数的末尾,例如
'phonefield' => 'phone:mobile', // 'phonefield' => (new Phone)->type('mobile')
最常见类型是 mobile
和 fixed_line
,但您可以自由使用定义 在这里 的任何类型。
在类型前加一个感叹号以将其列入黑名单。请注意,您不能同时使用白名单和黑名单类型。
'phonefield' => 'phone:!mobile', // 'phonefield' => (new Phone)->notType('mobile')
您还可以通过使用 LENIENT
参数启用宽松验证。启用宽松验证后,只检查号码长度,而不是实际的网络运营商模式。
'phonefield' => 'phone:LENIENT', // 'phonefield' => (new Phone)->lenient()
属性转换
提供了两个转换类以自动转换 Eloquent 模型属性
use Illuminate\Database\Eloquent\Model; use Propaganistas\LaravelPhone\Casts\RawPhoneNumberCast; use Propaganistas\LaravelPhone\Casts\E164PhoneNumberCast; class User extends Model { public $casts = [ 'phone_1' => RawPhoneNumberCast::class.':BE', 'phone_2' => E164PhoneNumberCast::class.':BE', ]; }
这两个类都会自动将数据库值转换为 PhoneNumber 对象,以便在您的应用程序中进一步使用。
$user->phone // PhoneNumber object or null
设置值时,它们都接受字符串值或 PhoneNumber 对象。`RawPhoneNumberCast` 将数据库值更改为原始输入号码,而 `E164PhoneNumberCast` 将格式化的 E.164 电话号码写入数据库。
在 `RawPhoneNumberCast` 的情况下,转换需要提示电话国家,以便正确地将原始号码解析为电话对象。在 `E164PhoneNumberCast` 和要设置的值不是某种国际格式的情况下,转换需要提示电话国家,以便正确地更改值。
这两个类以相同的方式接受转换参数
- 当存在同名的属性,但后缀为
_country
(例如 phone_country)时,转换器将自动检测并使用它。 - 提供另一个属性名作为转换参数
- 提供一到多个国家代码作为转换参数
public $casts = [ 'phone_1' => RawPhoneNumberCast::class.':country_field', 'phone_2' => E164PhoneNumberCast::class.':BE', ];
重要提示:两个转换都期望 有效的 电话号码以便平滑地从/到 PhoneNumber 对象转换。请在设置模型上的电话号码之前验证电话号码。请参阅 验证文档 了解如何验证电话号码。
⚠️ 属性分配和 E164PhoneNumberCast
由于 E164PhoneNumberCast
的性质,如果号码不是以国际格式传入,则期望一个有效的国家属性。由于转换是按给定值的顺序应用的,因此在设置电话号码属性之前,务必设置国家属性。否则,E164PhoneNumberCast
将遇到空的国家值并抛出意外的异常。
// Wrong $model->fill([ 'phone' => '012 34 56 78', 'phone_country' => 'BE', ]); // Correct $model->fill([ 'phone_country' => 'BE', 'phone' => '012 34 56 78', ]); // Wrong $model->phone = '012 34 56 78'; $model->phone_country = 'BE'; // Correct $model->phone_country = 'BE'; $model->phone = '012 34 56 78';
实用 PhoneNumber 类
电话号码可以包裹在 Propaganistas\LaravelPhone\PhoneNumber
类中以增强其有用实用方法。在视图中直接引用这些对象或在保存到数据库时是安全的,因为它们将优雅地降级到 E.164 格式。
use Propaganistas\LaravelPhone\PhoneNumber; (string) new PhoneNumber('+3212/34.56.78'); // +3212345678 (string) new PhoneNumber('012 34 56 78', 'BE'); // +3212345678
格式化
PhoneNumber 可以以各种方式格式化
$phone = new PhoneNumber('012/34.56.78', 'BE'); $phone->format($format); // See libphonenumber\PhoneNumberFormat $phone->formatE164(); // +3212345678 $phone->formatInternational(); // +32 12 34 56 78 $phone->formatRFC3966(); // tel:+32-12-34-56-78 $phone->formatNational(); // 012 34 56 78 // Formats so the number can be called straight from the provided country. $phone->formatForCountry('BE'); // 012 34 56 78 $phone->formatForCountry('NL'); // 00 32 12 34 56 78 $phone->formatForCountry('US'); // 011 32 12 34 56 78 // Formats so the number can be clicked on and called straight from the provided country using a cellphone. $phone->formatForMobileDialingInCountry('BE'); // 012345678 $phone->formatForMobileDialingInCountry('NL'); // +3212345678 $phone->formatForMobileDialingInCountry('US'); // +3212345678
号码信息
获取有关电话号码的一些信息
$phone = new PhoneNumber('012 34 56 78', 'BE'); $phone->getType(); // 'fixed_line' $phone->isOfType('fixed_line'); // true $phone->getCountry(); // 'BE' $phone->isOfCountry('BE'); // true
相等比较
检查给定的电话号码是否(不是)等于另一个电话号码
$phone = new PhoneNumber('012 34 56 78', 'BE'); $phone->equals('012/34.56.76', 'BE') // true $phone->equals('+32 12 34 56 78') // true $phone->equals( $anotherPhoneObject ) // true/false $phone->notEquals('045 67 89 10', 'BE') // true $phone->notEquals('+32 45 67 89 10') // true $phone->notEquals( $anotherPhoneObject ) // true/false
辅助函数
该包公开了 phone()
辅助函数,该函数返回 Propaganistas\LaravelPhone\PhoneNumber
实例或如果提供了 $format
则返回格式化的字符串
phone($number, $country = [], $format = null)
数据库考虑
免责声明:电话号码的处理在每种应用程序中都有所不同。以下提到的主题因此被视为一组思考起点;将 不 提供支持。
在数据库中存储电话号码始终是一个猜测性的主题,而且根本不存在万能的解决方案。这完全取决于应用程序的需求。以下是一些注意事项以及一些实现建议。您的理想数据库设置可能是以下详细说明的一些指南的组合。
唯一性
E.164 格式在全球范围内唯一标识电话号码,并内在地暗示了特定的国家。它可以按原样提供给 phone()
辅助函数。
您需要
- 一个列来存储电话号码
- 在持久化之前将电话号码格式化为 E.164
示例
- 用户输入 =
012/45.65.78
- 数据库列
phone
(可变长文本)=+3212456578
以用户输入的方式呈现电话号码
如果您存储了格式化的电话号码,原始用户输入将无法检索。可能会将用户自己的输入电话号码呈现给用户,例如在改进用户体验方面。
您需要
- 两个列来存储原始输入和相关国家
示例
- 用户输入 =
012/34.56.78
- 数据库列
phone
(可变长文本)=012/34.56.78
phone_country
(可变长文本)=BE
支持搜索
通过电话号码进行搜索可能会很快变得荒谬复杂,并且始终需要深入了解应用程序的上下文和范围。这里是一个可能的方案,涵盖了相当多的“自然”用例。
您需要
- 三个额外的列来存储电话号码的可搜索变体
- 规范化输入(去除所有非字母字符的原始输入)
- 国家格式电话号码(去除所有非字母字符)
- E.164 格式电话号码
- 可能需要一个
saving()
观察器(或等效)在持久化之前预填充变体 - 使用可搜索变体的广泛搜索查询
示例
- 用户输入 =
12/34.56.78
- 观察器方法
public function saving(User $user) { if ($user->isDirty('phone') && $user->phone) { $user->phone_normalized = preg_replace('/[^0-9]/', '', $user->phone); $user->phone_national = preg_replace('/[^0-9]/', '', phone($user->phone, $user->phone_country)->formatNational()); $user->phone_e164 = phone($user->phone, $user->phone_country)->formatE164(); } }
- 数据库列
phone_normalized
(可变长文本)=12345678
phone_national
(可变长文本)=012345678
phone_e164
(变长字符串) =+3212345678
- 搜索查询
// $search holds the search term User::where(function($query) use ($search) { $query->where('phone_normalized', 'LIKE', preg_replace('/[^0-9]/', '', $search) . '%') ->orWhere('phone_national', 'LIKE', preg_replace('/[^0-9]/', '', $search) . '%') ->orWhere('phone_e164', 'LIKE', preg_replace('/[^+0-9]/', '', $search) . '%') });