PHPackages                             moonlydays/laravel-mno - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. moonlydays/laravel-mno

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

moonlydays/laravel-mno
======================

Utilities for configuring interactions with operator phone numbers and subscribers.

2.0.2(3mo ago)274[2 PRs](https://github.com/MoonlyDays/laravel-mno/pulls)MITPHPPHP ^8.2CI passing

Since Apr 11Pushed 1mo agoCompare

[ Source](https://github.com/MoonlyDays/laravel-mno)[ Packagist](https://packagist.org/packages/moonlydays/laravel-mno)[ Docs](https://github.com/MoonlyDays/laravel-mno)[ RSS](/packages/moonlydays-laravel-mno/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (10)Dependencies (11)Versions (16)Used By (0)

Laravel MNO
===========

[](#laravel-mno)

[![Tests](https://camo.githubusercontent.com/b6fa72d6819a080a0daf7fc14094acf54fde7adf72f6c46256ca531587f2932f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f4d6f6f6e6c79446179732f6c61726176656c2d6d6e6f2f74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265266c6f676f3d676974687562)](https://github.com/MoonlyDays/laravel-mno/actions/workflows/tests.yml)[![Latest Version](https://camo.githubusercontent.com/e851728cfc0d1966a40535e96f48ca0fa71964f30fd979a9ae9cda97d31690f2/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d6f6f6e6c79646179732f6c61726176656c2d6d6e6f2e7376673f7374796c653d666c61742d737175617265266c6f676f3d7061636b6167697374266c6f676f436f6c6f723d7768697465)](https://packagist.org/packages/moonlydays/laravel-mno)[![Total Downloads](https://camo.githubusercontent.com/b256ad79965c7a357d514872f5ccbdbfd70a57f7253d7069e1abdee5c0a14a7a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d6f6f6e6c79646179732f6c61726176656c2d6d6e6f2e7376673f7374796c653d666c61742d737175617265266c6f676f3d7061636b6167697374266c6f676f436f6c6f723d7768697465)](https://packagist.org/packages/moonlydays/laravel-mno)[![PHP Version](https://camo.githubusercontent.com/eb311c944ad79c2daf7b02700196675c59bd5cd4e6a052785620b4910deb57f6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6d6f6f6e6c79646179732f6c61726176656c2d6d6e6f2e7376673f7374796c653d666c61742d737175617265266c6f676f3d706870266c6f676f436f6c6f723d7768697465)](https://packagist.org/packages/moonlydays/laravel-mno)[![Laravel](https://camo.githubusercontent.com/37f3d5a5a787401d3dbec5a32a7de6a6e973ea266309e69a97e184d1ef4ef57f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d3131253230253743253230313225323025374325323031332d4646324432303f7374796c653d666c61742d737175617265266c6f676f3d6c61726176656c266c6f676f436f6c6f723d7768697465)](https://laravel.com)[![License](https://camo.githubusercontent.com/fa90945b0d7f3a644fa6b59b7a35326dcd369d93f4aceabf2f85f75e8d57675c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6d6f6f6e6c79646179732f6c61726176656c2d6d6e6f2e7376673f7374796c653d666c61742d737175617265)](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`](https://github.com/giggsey/libphonenumber-for-php) with integration into Laravel's validation system, Eloquent casts, Faker, schema builder, and facades.

Released under the [MIT License](LICENSE).

Requirements
------------

[](#requirements)

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

Installation
------------

[](#installation)

```
composer require moonlydays/laravel-mno
```

Publish the configuration file:

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

Configuration
-------------

[](#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
```

VariableDescription`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
-----

[](#usage)

### Creating a Msisdn

[](#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

[](#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

[](#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

[](#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

[](#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

[](#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

[](#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

[](#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

[](#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

[](#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

[](#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
```

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

[](#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 — 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

[](#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

[](#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
```

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance89

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

13

Last Release

91d ago

Major Versions

1.4.0 → 2.0.02026-04-22

### Community

Maintainers

![](https://www.gravatar.com/avatar/87d541941e03738e9760a7ea35c5ce19347b67e29eb81a216e872b4158b6dc61?d=identicon)[MoonlyDays](/maintainers/MoonlyDays)

---

Top Contributors

[![MoonlyDays](https://avatars.githubusercontent.com/u/32462579?v=4)](https://github.com/MoonlyDays "MoonlyDays (25 commits)")

---

Tags

laravelphonemsisdnoperatormno

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/moonlydays-laravel-mno/health.svg)

```
[![Health](https://phpackages.com/badges/moonlydays-laravel-mno/health.svg)](https://phpackages.com/packages/moonlydays-laravel-mno)
```

###  Alternatives

[spatie/laravel-pdf

Create PDFs in Laravel apps

1.0k4.8M48](/packages/spatie-laravel-pdf)[codewithdennis/filament-select-tree

The multi-level select field enables you to make single selections from a predefined list of options that are organized into multiple levels or depths.

330530.5k30](/packages/codewithdennis-filament-select-tree)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.8k](/packages/rawilk-profile-filament-plugin)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
