propaganistas/laravel-phone

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

资助包维护!
Propaganistas

安装次数: 21,495,157

依赖者: 86

建议者: 1

安全: 0

星标: 2,685

关注者: 46

分支: 214

公开问题: 0

5.3.2 2024-04-24 09:18 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(varchar)= +3212456578

以输入时的方式呈现电话号码

如果您存储格式化电话号码,则原始用户输入将永久丢失。这可能对向您提供自己的输入电话号码的用户有益,例如在提高用户体验方面。

您需要

  • 两列来存储原始输入和相关国家

示例

  • 用户输入 = 012/34.56.78
  • 数据库列
    • phone(varchar)= 012/34.56.78
    • phone_country(varchar)= 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(varchar)= 12345678
    • phone_national(varchar)= 012345678
    • phone_e164(varchar)= +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) . '%')
    });