moonlydays/laravel-mno 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

moonlydays/laravel-mno

Composer 安装命令:

composer require moonlydays/laravel-mno

包简介

Utilities for configuring interactions with operator phone numbers and subscribers.

README 文档

README

Tests Latest Version Total Downloads PHP Version Laravel License

Laravel package for validating, normalizing, and working with MSISDN phone numbers tied to a single Mobile Network Operator. A wrapper around giggsey/libphonenumber-for-php with integration into Laravel's validation system, Eloquent casts, Faker, schema builder, and facades.

Released under the MIT License.

Requirements

  • PHP 8.2+
  • Laravel 11, 12, or 13

Installation

composer require moonlydays/laravel-mno

Publish the configuration file:

php artisan vendor:publish --tag="mno-config"

Configuration

Set up the environment variables:

MNO_NAME=MTS
MNO_COUNTRY=RU
MNO_NETWORK_CODES=910,911,912
MNO_MIN_LENGTH=10
MNO_MAX_LENGTH=10
Variable Description
MNO_NAME Name of the mobile network operator
MNO_COUNTRY ISO 3166-1 alpha-2 country code (e.g., RU, TZ)
MNO_NETWORK_CODES Comma-separated National Destination Code (NDC) prefixes for the operator
MNO_MIN_LENGTH Minimum national number length (optional — inferred from libphonenumber metadata)
MNO_MAX_LENGTH Maximum national number length (optional — inferred from libphonenumber metadata)

When MNO_MIN_LENGTH / MNO_MAX_LENGTH are unset, the package infers the length from libphonenumber metadata for the configured country, walking the number_types priority list in config/mno.php (defaults to Mobile, then General).

Usage

Creating a Msisdn

use MoonlyDays\MNO\Values\Msisdn;

// Parse, throwing InvalidMsisdnException on failure
$phone = Msisdn::from('+79101234567');
$phone = Msisdn::from('9101234567', 'RU');
$phone = Msisdn::from(79101234567, 'RU'); // integers are accepted

// Safe parse, returning null on failure
$phone = Msisdn::tryFrom('invalid'); // null

// Global helper
$phone = msisdn('+79101234567');

Msisdn is a lightweight value object wrapping libphonenumber's native PhoneNumber. It implements Stringable (casting to string produces the E.164 form), JsonSerializable (serializes as E.164), and Castable (can be used directly as an Eloquent cast). It also uses Laravel's Macroable and Tappable traits.

Formatting

$phone = Msisdn::from('+79101234567');

$phone->e164();          // "+79101234567"
$phone->national();      // "8 (910) 123-45-67"
$phone->international(); // "+7 910 123-45-67"
$phone->toInteger();     // 79101234567  (E.164 digits without the leading plus)
(string) $phone;         // "+79101234567"

Retrieving number components

$phone = Msisdn::from('+79101234567');

$phone->countryCode();      // 7
$phone->countryIso();       // "RU"
$phone->nationalNumber();   // "9101234567"
$phone->networkCode();      // "910"
$phone->subscriberNumber(); // "1234567"
$phone->toPhoneNumber();    // underlying libphonenumber\PhoneNumber

Two Msisdn instances can be compared via $a->equals($b) (equality is based on the E.164 form).

Timezones

$phone = Msisdn::from('+79101234567');

$phone->timezone();  // "Europe/Moscow" — primary IANA identifier, or null if unknown
$phone->timezones(); // ["Europe/Moscow", ...] — all IANA identifiers for the number

Validation

use Illuminate\Validation\Rule;

// Use the Rule::msisdn() macro — picks up defaults from config
$request->validate([
    'phone' => ['required', Rule::msisdn()],
]);
use MoonlyDays\MNO\Rules\MsisdnRule;

// Customize the rule fluently
$request->validate([
    'phone' => [
        'required',
        (new MsisdnRule())
            ->country('RU', 'BY', 'KZ')
            ->networkCodes('910', '911')
            ->minLength(10)
            ->maxLength(10),
    ],
]);

Validation failures translate the following keys, which you can publish or override in your own language files:

  • validation.msisdn.invalid
  • validation.msisdn.country
  • validation.msisdn.min_length (receives :min)
  • validation.msisdn.max_length (receives :max)
  • validation.msisdn.network_code

Overriding the default rule

MsisdnRule::defaults() lets you swap in a custom resolver used by Rule::msisdn():

use MoonlyDays\MNO\Rules\MsisdnRule;

MsisdnRule::defaults(fn () => (new MsisdnRule())
    ->country('RU')
    ->minLength(10)
    ->maxLength(10));

Request macro

The service provider registers a msisdn macro on Illuminate\Http\Request:

$phone = $request->msisdn('phone');           // Msisdn or null
$phone = $request->msisdn('phone', $default); // with fallback (value or closure)

Eloquent cast

Since Msisdn implements Castable, you can use it directly as an Eloquent cast. MsisdnCast is also available if you prefer to be explicit:

use Illuminate\Database\Eloquent\Model;
use MoonlyDays\MNO\Values\Msisdn;

class User extends Model
{
    protected $casts = [
        'phone' => Msisdn::class, // or MsisdnCast::class
    ];
}

$user->phone = '+79101234567';
$user->save(); // Stored as unsigned bigInteger: 79101234567

$user->phone instanceof Msisdn; // true
$user->phone->national();            // "8 (910) 123-45-67"

The cast accepts a string, integer, or Msisdn instance when setting, and persists the E.164 digits as an unsigned integer (the leading + is stripped). When reading back, the configured MNO_COUNTRY is used as the default region for parsing, so make sure it is set.

Back the cast with an unsigned bigInteger column (e.g., $table->unsignedBigInteger('phone')). A VARCHAR column will break writes.

Faker provider

When the Faker generator resolves from the container, the package registers a provider for generating valid numbers within the configured MNO (country, network codes, and length constraints):

$faker = fake();

$faker->msisdn();             // Msisdn value object
$faker->msisdn()->e164();     // "+79101234567"
$faker->msisdn()->national(); // "8 (910) 123-45-67"

JSON resource

MsisdnFormatResource exposes the operator's format metadata as a JSON resource, for API responses that need to tell clients about expected number shape:

use MoonlyDays\MNO\Resources\MsisdnFormatResource;

return [
    'format' => MsisdnFormatResource::make(),
];
// {
//   "countryCode": 7,
//   "country": "RU",
//   "minLength": 10,
//   "maxLength": 10,
//   "networkCodes": ["910", "911", "912"]
// }

MNO facade

use MoonlyDays\MNO\Facades\MNO;

MNO::countryIsoCode(); // "RU"
MNO::country();        // Country instance for "RU"
MNO::countryCode();    // 7
MNO::carrierName();    // "MTS"
MNO::carrier();        // Carrier instance for the configured MNO
MNO::networkCodes();   // ["910", "911", "912"]
MNO::minLength();      // 10
MNO::maxLength();      // 10
MNO::exampleNumber();  // Msisdn|null
MNO::numberTypes();    // array<NumberType>

The facade resolves the MnoService singleton, which is also bound to the container alias mno and can be injected directly.

Country and Carrier value objects

use MoonlyDays\MNO\Values\Country;
use MoonlyDays\MNO\Values\Carrier;

// Country — wraps an ISO 3166-1 alpha-2 code
$country = Country::from('RU');       // throws InvalidCountryException on unknown code
$country = Country::tryFrom('RU');    // returns null on failure

$country->isoCode();                // "RU"
$country->countryCode();            // 7
$country->name();                   // "Russia"
$country->exampleNumber();          // Msisdn|null
$country->isMobileNumberPortable(); // bool
$country->carriers();               // array<string, Carrier> — all carriers with allocations

// Carrier — a carrier within a country
$carrier = Carrier::from('RU', 'MTS');    // throws InvalidCarrierException on miss
$carrier = Carrier::tryFrom('RU', 'MTS'); // returns null on failure

$carrier->name();             // "MTS"
$carrier->country();          // Country instance
$carrier->networkCodes();     // ["910", "911", "912"] — NDC prefixes
$carrier->prefixes();         // ["7910", "7911", "7912"] — with country code
$carrier->matches($phone);    // true if the phone number belongs to this carrier
$carrier->owns('910');        // true if the carrier owns this NDC

Artisan command

Inspect the configured MNO, a country, or a specific carrier:

php artisan mno:show              # show configured operator details
php artisan mno:show RU           # show country info with carrier list
php artisan mno:show RU MTS       # show carrier details with network codes

Extending via macros

Msisdn uses the Macroable trait, so you can add project-specific helpers:

use MoonlyDays\MNO\Values\Msisdn;

Msisdn::macro('isRussian', function (): bool {
    /** @var Msisdn $this */
    return $this->countryIso() === 'RU';
});

Msisdn::from('+79101234567')->isRussian(); // true

moonlydays/laravel-mno 适用场景与选型建议

moonlydays/laravel-mno 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 58 次下载、GitHub Stars 达 2, 最近一次更新时间为 2026 年 04 月 11 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「operator」 「phone」 「laravel」 「msisdn」 「mno」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 moonlydays/laravel-mno 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 moonlydays/laravel-mno 我们能提供哪些服务?
定制开发 / 二次开发

基于 moonlydays/laravel-mno 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 58
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 2
  • 点击次数: 36
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 2
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-04-11