stormcode/laravel-phone

基于 Google 的 libphonenumber API 为 Laravel 添加电话号码功能。

支持包维护!
Propaganistas

dev-master 2024-08-27 08:33 UTC

This package is auto-updated.

Last update: 2024-09-27 08:43:19 UTC


README

Tests Latest Stable Version Total Downloads License

基于 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')

最常见类型是 mobilefixed_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` 和要设置的值不是某种国际格式的情况下,转换需要提示电话国家,以便正确地更改值。

这两个类以相同的方式接受转换参数

  1. 当存在同名的属性,但后缀为 _country(例如 phone_country)时,转换器将自动检测并使用它。
  2. 提供另一个属性名作为转换参数
  3. 提供一到多个国家代码作为转换参数
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) . '%')
    });