laravel-6 support

This commit is contained in:
RafficMohammed
2023-01-08 01:17:22 +05:30
parent 1a5c16ae4b
commit 774eed8b0e
4962 changed files with 279380 additions and 297961 deletions

View File

@@ -1,4 +0,0 @@
/vendor
/.idea
composer.phar
composer.lock

View File

@@ -1,18 +0,0 @@
filter:
paths:
- 'src/*'
excluded_paths:
- 'tests/*'
- 'bin/*'
- 'spec/*'
- 'stub/*'
- 'coverage/*'
- 'vendor/*'
checks:
php: true
tools:
external_code_coverage:
timeout: 1200
runs: 3

View File

@@ -1,49 +0,0 @@
language: php
cache:
directories:
- $HOME/.composer/cache/files
matrix:
include:
# Test lowest possible PHP version for all Laravel releases
- php: 5.4
env: ILLUMINATE_VERSION=4.0.*
- php: 5.4
env: ILLUMINATE_VERSION=4.1.*
- php: 5.4
env: ILLUMINATE_VERSION=4.2.*
- php: 5.4
env: ILLUMINATE_VERSION=5.0.*
- php: 5.5
env: ILLUMINATE_VERSION=5.1.*
- php: 5.5
env: ILLUMINATE_VERSION=5.2.*
- php: 5.6
env: ILLUMINATE_VERSION=5.3.*
- php: 5.6
env: ILLUMINATE_VERSION=5.4.*
# Test remaining PHP versions on the latest release
- php: 7.0
env: ILLUMINATE_VERSION=5.4.*
- php: 7.1
env: ILLUMINATE_VERSION=5.4.*
- php: hhvm
env: ILLUMINATE_VERSION=5.4.*
before_install:
- composer require "illuminate/support:${ILLUMINATE_VERSION}" --no-update
- composer require "illuminate/validation:${ILLUMINATE_VERSION}" --no-update
install:
- travis_wait composer install --prefer-dist --no-suggest --no-interaction
before_script:
- if [[ $TRAVIS_PHP_VERSION =~ ^hhvm ]]; then echo 'xdebug.enable = On' >> /etc/hhvm/php.ini; fi
script:
- vendor/bin/phpunit --coverage-clover=coverage.clover
after_script:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover coverage.clover

View File

@@ -1,81 +1,86 @@
# Laravel Phone
[![Build Status](https://travis-ci.org/Propaganistas/Laravel-Phone.svg?branch=master)](https://travis-ci.org/Propaganistas/Laravel-Phone)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/Propaganistas/Laravel-Phone/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/Propaganistas/Laravel-Phone/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/Propaganistas/Laravel-Phone/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/Propaganistas/Laravel-Phone/?branch=master)
![Tests](https://github.com/Propaganistas/Laravel-Phone/workflows/Tests/badge.svg?branch=master)
[![Latest Stable Version](https://poser.pugx.org/propaganistas/laravel-phone/v/stable)](https://packagist.org/packages/propaganistas/laravel-phone)
[![Total Downloads](https://poser.pugx.org/propaganistas/laravel-phone/downloads)](https://packagist.org/packages/propaganistas/laravel-phone)
[![License](https://poser.pugx.org/propaganistas/laravel-phone/license)](https://packagist.org/packages/propaganistas/laravel-phone)
Adds a phone validator & formatter to Laravel 4 & 5 and Lumen based on the [PHP port](https://github.com/giggsey/libphonenumber-for-php) of [Google's libphonenumber API](https://github.com/googlei18n/libphonenumber) by [giggsey](https://github.com/giggsey).
Adds phone number functionality to Laravel and Lumen based on the [PHP port](https://github.com/giggsey/libphonenumber-for-php) of [Google's libphonenumber API](https://github.com/googlei18n/libphonenumber) by [giggsey](https://github.com/giggsey).
### Installation
## Table of Contents
Run the following command to install the latest version of the package
- [Demo](#demo)
- [Installation](#installation)
- [Laravel](#laravel)
- [Lumen](#lumen)
- [Validation](#validation)
- [Utility class](#utility-phonenumber-class)
- [Formatting](#formatting)
- [Number information](#number-information)
- [Helper function](#helper-function)
## Demo
Check out the behavior of this package in the [demo](https://laravel-phone.herokuapp.com).
## Installation
Run the following command to install the latest applicable version of the package:
```bash
composer require propaganistas/laravel-phone
```
**Laravel**
### Laravel
In your app config, add the Service Provider to the `$providers` array *(only for Laravel 5.4 or below)*:
The Service Provider gets discovered automatically.
```php
'providers' => [
...
Propaganistas\LaravelPhone\LaravelPhoneServiceProvider::class,
],
```
In your languages directory, add for each language an extra language line for the validator:
In your languages directory, add an extra line for each language file:
```php
"phone" => "The :attribute field contains an invalid number.",
'phone' => 'The :attribute field contains an invalid number.',
```
**Lumen**
### Lumen
In `bootstrap/app.php`, register the Service Provider
```php
$app->register(Propaganistas\LaravelPhone\LaravelPhoneServiceProvider::class);
$app->register(Propaganistas\LaravelPhone\PhoneServiceProvider::class);
```
### Validator
## Validation
To validate a field using the phone validator, use the `phone` keyword in your validation rules array. The phone validator is able to operate in **three** ways.
To validate a phone number, use the `phone` keyword in your validation rules array or use the `Phone` rule class to define the rule in an expressive way. The phone validator is able to operate in **three** ways.
- You either specify [*ISO 3166-1 alpha-2 compliant*](http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements) country codes yourself as parameters for the validator, e.g.:
```php
'phonefield' => 'phone:US,BE',
'phonefield' => 'phone:US,BE',
// 'phonefield' => Rule::phone()->country(['US', 'BE'])
```
The validator will check if the number is valid in at least one of provided countries, so feel free to add as many country codes as you like.
- You don't specify any parameters but you plug in a dedicated country input field (keyed by *ISO 3166-1 compliant* country codes) to allow end users to supply a country on their own. The easiest method by far is to install the [Laravel-Intl](https://github.com/Propaganistas/Laravel-Intl) package. Make sure the country field is named similar as the phone field but with *_country* appended for automatic discovery, or provide your custom country field name as a parameter to the validator:
- You provide a dedicated country input field (keyed by *ISO 3166-1 compliant* country codes) to allow end users to supply a country on their own. Make sure the country field has the same name as the phone field but with *_country* appended for automatic discovery, or provide your custom country field name as a parameter to the validator:
```php
'phonefield' => 'phone',
// 'phonefield' => Rule::phone()
'phonefield_country' => 'required_with:phonefield',
```
```php
'phonefield' => 'phone:custom_country_field',
// 'phonefield' => Rule::phone()->countryField('custom_country_field')
'custom_country_field' => 'required_with:phonefield',
```
If using [Laravel-Intl](https://github.com/Propaganistas/Laravel-Intl), you could then use the following snippet to populate a country selection list. It will automatically present translated country names according to your application locale:
```php
Country::all()
```
- You instruct the validator to detect which country the number belongs to using the `AUTO` keyword (and optionally any fallback countries):
```php
'phonefield' => 'phone:AUTO,US',
'phonefield' => 'phone:AUTO,US',
// 'phonefield' => Rule::phone()->detect()->country('US')
```
The validator will try to extract the country from the number itself and then check if the number is valid for that country. If the country could not be guessed it will be validated using the fallback countries if provided. Note that country guessing will only work when phone numbers are entered in *international format* (prefixed with a `+` sign, e.g. +32 ....). Leading double zeros will **NOT** be parsed correctly as this isn't an established consistency.
@@ -83,21 +88,67 @@ To validate a field using the phone validator, use the `phone` keyword in your v
To specify constraints on the number type, just append the allowed types to the end of the parameters, e.g.:
```php
'phonefield' => 'phone:US,BE,mobile',
'phonefield' => 'phone:US,BE,mobile',
// 'phonefield' => Rule::phone()->country(['US', 'BE'])->type('mobile')
// 'phonefield' => Rule::phone()->country('US', 'BE')->mobile()
```
The most common types are `mobile` and `fixed_line`, but feel free to use any of the types defined [here](https://github.com/giggsey/libphonenumber-for-php/blob/master/src/PhoneNumberType.php).
You can also enable more lenient validation (for example, fixed lines without area codes) by using the `LENIENT` parameter. This feature inherently doesn't play well with country autodetection and number type validation, so use such combo at own risk.
```php
'phonefield' => 'phone:LENIENT,US',
'phonefield' => 'phone:LENIENT,US',
// 'phonefield' => Rule::phone()->lenient()->country('US')
```
### Formatter
Format a phone number using the `phone()` helper function. `$country_code` is the country the phone number belongs to.
## Utility PhoneNumber class
A phone number can be wrapped in the `Propaganistas\LaravelPhone\PhoneNumber` class to enhance it with useful utility methods. It's safe to directly reference these objects in views or when saving to the database as they will degrade gracefully to the E164 format.
```php
phone($phone_number, $country_code = null, $format = PhoneNumberFormat::INTERNATIONAL)
use Propaganistas\LaravelPhone\PhoneNumber;
(string) PhoneNumber::make('+3212/34.56.78'); // +3212345678
(string) PhoneNumber::make('012 34 56 78', 'BE'); // +3212345678
(string) PhoneNumber::make('012345678')->ofCountry('BE'); // +3212345678
```
### Formatting
A PhoneNumber can be formatted in various ways:
```php
PhoneNumber::make('012 34 56 78', 'BE')->format($format); // See libphonenumber\PhoneNumberFormat
PhoneNumber::make('012 34 56 78', 'BE')->formatE164(); // +3212345678
PhoneNumber::make('012 34 56 78', 'BE')->formatInternational(); // +32 12 34 56 78
PhoneNumber::make('012 34 56 78', 'BE')->formatRFC3966(); // +32-12-34-56-78
PhoneNumber::make('012/34.56.78', 'BE')->formatNational(); // 012 34 56 78
// Formats so the number can be called straight from the provided country.
PhoneNumber::make('012 34 56 78', 'BE')->formatForCountry('BE'); // 012 34 56 78
PhoneNumber::make('012 34 56 78', 'BE')->formatForCountry('NL'); // 00 32 12 34 56 78
PhoneNumber::make('012 34 56 78', 'BE')->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.
PhoneNumber::make('012 34 56 78', 'BE')->formatForMobileDialingInCountry('BE'); // 012345678
PhoneNumber::make('012 34 56 78', 'BE')->formatForMobileDialingInCountry('NL'); // +3212345678
PhoneNumber::make('012 34 56 78', 'BE')->formatForMobileDialingInCountry('US'); // +3212345678
```
### Number information
Get some information about the phone number:
```php
PhoneNumber::make('012 34 56 78', 'BE')->getType(); // 'fixed_line'
PhoneNumber::make('012 34 56 78', 'BE')->isOfType('fixed_line'); // true
PhoneNumber::make('012 34 56 78', 'BE')->getCountry(); // 'BE'
PhoneNumber::make('012 34 56 78', 'BE')->isOfCountry('BE'); // true
PhoneNumber::make('+32 12 34 56 78')->isOfCountry('BE'); // true
```
### Helper function
The package exposes the `phone()` helper function that returns a `Propaganistas\LaravelPhone\PhoneNumber` instance or the formatted string if `$format` was provided:
```php
phone($number, $country = [], $format = null)
```
Always try to provide a `$country_code` in order for the phone number to be recognized correctly. If no `$country_code` was given, the current application locale will be used as a sensible default.
The `$format` parameter defines the output format and is optional. The format defaults to international format but can be any constant of `libphonenumber\PhoneNumberFormat`.

View File

@@ -1,6 +1,6 @@
{
"name": "propaganistas/laravel-phone",
"description": "Adds a phone validator to Laravel and Lumen based on Google's libphonenumber API.",
"description": "Adds phone number functionality to Laravel and Lumen based on Google's libphonenumber API.",
"keywords": [
"laravel",
"lumen",
@@ -16,14 +16,15 @@
}
],
"require": {
"illuminate/support": "^4.0|^5.0",
"illuminate/validation": "^4.0|^5.0",
"php": "^7.1|^8.0",
"illuminate/support": "^6.0|^7.0|^8.0",
"illuminate/validation": "^6.0|^7.0|^8.0",
"giggsey/libphonenumber-for-php": "^7.0|^8.0",
"julien-c/iso3166": "^2.0"
"league/iso3166": "^2.0|^3.0"
},
"require-dev": {
"orchestra/testbench": "^2.0|^3.0",
"phpunit/phpunit": "^4.0|^5.2"
"orchestra/testbench": "*",
"phpunit/phpunit": "*"
},
"autoload": {
"psr-4": {
@@ -38,13 +39,10 @@
"Propaganistas\\LaravelPhone\\Tests\\": "tests/"
}
},
"suggest": {
"propaganistas/laravel-intl": "Adds internationalization functions, including a compatible and fully translated country list API."
},
"extra": {
"laravel": {
"providers": [
"Propaganistas\\LaravelPhone\\LaravelPhoneServiceProvider"
"Propaganistas\\LaravelPhone\\PhoneServiceProvider"
]
}
}

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false">
<testsuites>
<testsuite name="Package Test Suite">
<directory suffix=".php">./tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -0,0 +1,15 @@
<?php namespace Propaganistas\LaravelPhone\Exceptions;
class CountryCodeException extends \Exception
{
/**
* Invalid country code static constructor.
*
* @param string $country
* @return static
*/
public static function invalid($country)
{
return new static('Invalid country code "' . $country . '".');
}
}

View File

@@ -1,3 +1,17 @@
<?php namespace Propaganistas\LaravelPhone\Exceptions;
class InvalidParameterException extends \Exception {}
use Illuminate\Support\Collection;
class InvalidParameterException extends \Exception
{
/**
* Ambiguous parameter static constructor.
*
* @param string $parameter
* @return static
*/
public static function ambiguous($parameter)
{
return new static('Ambiguous phone validation parameter: "' . $parameter . '". This parameter is recognized as an input field and as a phone type. Please rename the input field.');
}
}

View File

@@ -1,3 +0,0 @@
<?php namespace Propaganistas\LaravelPhone\Exceptions;
class NoValidCountryFoundException extends \Exception {}

View File

@@ -0,0 +1,15 @@
<?php namespace Propaganistas\LaravelPhone\Exceptions;
class NumberFormatException extends \Exception
{
/**
* Invalid number format static constructor.
*
* @param string $format
* @return static
*/
public static function invalid($format)
{
return new static('Invalid number format "' . $format . '".');
}
}

View File

@@ -0,0 +1,73 @@
<?php namespace Propaganistas\LaravelPhone\Exceptions;
use Illuminate\Support\Str;
use libphonenumber\NumberParseException as libNumberParseException;
class NumberParseException extends libNumberParseException
{
/**
* @var string
*/
protected $number;
/**
* @var array
*/
protected $countries = [];
/**
* Country specification required static constructor.
*
* @param string $number
* @return static
*/
public static function countryRequired($number)
{
$exception = new static(
libNumberParseException::INVALID_COUNTRY_CODE,
'Number requires a country to be specified.'
);
$exception->number = $number;
return $exception;
}
/**
* Country mismatch static constructor.
*
* @param string $number
* @param string|array $country
* @return static
*/
public static function countryMismatch($number, $countries)
{
$countries = array_filter(is_array($countries) ? $countries : [$countries]);
$exception = new static(
libNumberParseException::INVALID_COUNTRY_CODE,
'Number does not match the provided '. Str::plural('country', count($countries)).'.'
);
$exception->number = $number;
$exception->countries = $countries;
return $exception;
}
/**
* @return string
*/
public function getNumber()
{
return $this->number;
}
/**
* @return array
*/
public function getCountries()
{
return $this->countries;
}
}

View File

@@ -1,16 +0,0 @@
<?php namespace Propaganistas\LaravelPhone;
use Illuminate\Support\Facades\Facade;
class LaravelPhoneFacade extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'libphonenumber';
}
}

View File

@@ -1,46 +0,0 @@
<?php namespace Propaganistas\LaravelPhone;
use Illuminate\Support\ServiceProvider;
use libphonenumber\PhoneNumberUtil;
use ReflectionClass;
class LaravelPhoneServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application events.
*
* @return void
*/
public function boot()
{
$extend = static::canUseDependentValidation() ? 'extendDependent' : 'extend';
$this->app['validator']->{$extend}('phone', 'Propaganistas\LaravelPhone\PhoneValidator@validatePhone');
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->singleton('libphonenumber', function ($app) {
return PhoneNumberUtil::getInstance();
});
$this->app->alias('libphonenumber', 'libphonenumber\PhoneNumberUtil');
}
/**
* Determine whether we can register a dependent validator.
*
* @return bool
*/
public static function canUseDependentValidation()
{
$validator = new ReflectionClass('\Illuminate\Validation\Factory');
return $validator->hasMethod('extendDependent');
}
}

View File

@@ -0,0 +1,417 @@
<?php namespace Propaganistas\LaravelPhone;
use Exception;
use Illuminate\Contracts\Support\Jsonable;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\Macroable;
use JsonSerializable;
use libphonenumber\NumberParseException as libNumberParseException;
use libphonenumber\PhoneNumberFormat;
use libphonenumber\PhoneNumberType;
use libphonenumber\PhoneNumberUtil;
use Propaganistas\LaravelPhone\Exceptions\NumberFormatException;
use Propaganistas\LaravelPhone\Exceptions\CountryCodeException;
use Propaganistas\LaravelPhone\Exceptions\NumberParseException;
use Propaganistas\LaravelPhone\Traits\ParsesCountries;
use Propaganistas\LaravelPhone\Traits\ParsesFormats;
use Propaganistas\LaravelPhone\Traits\ParsesTypes;
use Serializable;
class PhoneNumber implements Jsonable, JsonSerializable, Serializable
{
use Macroable,
ParsesCountries,
ParsesFormats,
ParsesTypes;
/**
* The provided phone number.
*
* @var string
*/
protected $number;
/**
* The provided phone country.
*
* @var array
*/
protected $countries = [];
/**
* The detected phone country.
*
* @var string
*/
protected $country;
/**
* Whether to allow lenient checks (i.e. landline numbers without area codes).
*
* @var bool
*/
protected $lenient = false;
/**
* @var \libphonenumber\PhoneNumberUtil
*/
protected $lib;
/**
* Phone constructor.
*
* @param string $number
*/
public function __construct($number)
{
$this->number = $number;
$this->lib = PhoneNumberUtil::getInstance();
}
/**
* Create a phone instance.
*
* @param string $number
* @param string|array $country
* @return static
*/
public static function make($number, $country = [])
{
$instance = new static($number);
return $instance->ofCountry($country);
}
/**
* Set the country to which the phone number belongs to.
*
* @param string|array $country
* @return static
*/
public function ofCountry($country)
{
$countries = is_array($country) ? $country : func_get_args();
$instance = clone $this;
$instance->countries = array_unique(
array_merge($instance->countries, static::parseCountries($countries))
);
return $instance;
}
/**
* Format the phone number in international format.
*
* @return string
*/
public function formatInternational()
{
return $this->format(PhoneNumberFormat::INTERNATIONAL);
}
/**
* Format the phone number in national format.
*
* @return string
*/
public function formatNational()
{
return $this->format(PhoneNumberFormat::NATIONAL);
}
/**
* Format the phone number in E164 format.
*
* @return string
*/
public function formatE164()
{
return $this->format(PhoneNumberFormat::E164);
}
/**
* Format the phone number in RFC3966 format.
*
* @return string
*/
public function formatRFC3966()
{
return $this->format(PhoneNumberFormat::RFC3966);
}
/**
* Format the phone number in a given format.
*
* @param string $format
* @return string
* @throws \Propaganistas\LaravelPhone\Exceptions\NumberFormatException
*/
public function format($format)
{
$parsedFormat = static::parseFormat($format);
if (is_null($parsedFormat)) {
throw NumberFormatException::invalid($format);
}
return $this->lib->format(
$this->getPhoneNumberInstance(),
$parsedFormat
);
}
/**
* Format the phone number in a way that it can be dialled from the provided country.
*
* @param string $country
* @return string
* @throws \Propaganistas\LaravelPhone\Exceptions\CountryCodeException
*/
public function formatForCountry($country)
{
if (! static::isValidCountryCode($country)) {
throw CountryCodeException::invalid($country);
}
return $this->lib->formatOutOfCountryCallingNumber(
$this->getPhoneNumberInstance(),
$country
);
}
/**
* Format the phone number in a way that it can be dialled from the provided country using a cellphone.
*
* @param string $country
* @param bool $withFormatting
* @return string
* @throws \Propaganistas\LaravelPhone\Exceptions\CountryCodeException
*/
public function formatForMobileDialingInCountry($country, $withFormatting = false)
{
if (! static::isValidCountryCode($country)) {
throw CountryCodeException::invalid($country);
}
return $this->lib->formatNumberForMobileDialing(
$this->getPhoneNumberInstance(),
$country,
$withFormatting
);
}
/**
* Get the phone number's country.
*
* @return string
*/
public function getCountry()
{
if (! $this->country) {
$this->country = $this->filterValidCountry($this->countries);
}
return $this->country;
}
/**
* Check if the phone number is of (a) given country(ies).
*
* @param string|array $country
* @return bool
*/
public function isOfCountry($country)
{
$countries = static::parseCountries($country);
return in_array($this->getCountry(), $countries);
}
/**
* Filter the provided countries to the one that is valid for the number.
*
* @param string|array $countries
* @return string
* @throws \Propaganistas\LaravelPhone\Exceptions\NumberParseException
*/
protected function filterValidCountry($countries)
{
$result = Collection::make($countries)
->filter(function ($country) {
try {
$instance = $this->lib->parse($this->number, $country);
return $this->lenient
? $this->lib->isPossibleNumber($instance, $country)
: $this->lib->isValidNumberForRegion($instance, $country);
} catch (libNumberParseException $e) {
return false;
}
})->first();
// If we got a new result, return it.
if ($result) {
return $result;
}
// Last resort: try to detect it from an international number.
if ($this->numberLooksInternational()) {
$countries[] = null;
}
foreach ($countries as $country) {
$instance = $this->lib->parse($this->number, $country);
if ($this->lib->isValidNumber($instance)) {
return $this->lib->getRegionCodeForNumber($instance);
}
}
if ($countries = array_filter($countries)) {
throw NumberParseException::countryMismatch($this->number, $countries);
}
throw NumberParseException::countryRequired($this->number);
}
/**
* Get the phone number's type.
*
* @param bool $asConstant
* @return string|int|null
*/
public function getType($asConstant = false)
{
$type = $this->lib->getNumberType($this->getPhoneNumberInstance());
if ($asConstant) {
return $type;
}
$stringType = Arr::get(static::parseTypesAsStrings($type), 0);
return $stringType ? strtolower($stringType) : null;
}
/**
* Check if the phone number is of (a) given type(s).
*
* @param string $type
* @return bool
*/
public function isOfType($type)
{
$types = static::parseTypes($type);
// Add the unsure type when applicable.
if (array_intersect([PhoneNumberType::FIXED_LINE, PhoneNumberType::MOBILE], $types)) {
$types[] = PhoneNumberType::FIXED_LINE_OR_MOBILE;
}
return in_array($this->getType(true), $types, true);
}
/**
* Get the raw provided number.
*
* @return string
*/
public function getRawNumber()
{
return $this->number;
}
/**
* Get the PhoneNumber instance of the current number.
*
* @return \libphonenumber\PhoneNumber
*/
public function getPhoneNumberInstance()
{
return $this->lib->parse($this->number, $this->getCountry());
}
/**
* Determine whether the phone number seems to be in international format.
*
* @return bool
*/
protected function numberLooksInternational()
{
return Str::startsWith($this->number, '+');
}
/**
* Enable lenient number parsing.
*
* @return $this
*/
public function lenient()
{
$this->lenient = true;
return $this;
}
/**
* Convert the phone instance to JSON.
*
* @param int $options
* @return string
*/
public function toJson($options = 0)
{
return json_encode($this->jsonSerialize(), $options);
}
/**
* Convert the phone instance into something JSON serializable.
*
* @return string
*/
public function jsonSerialize()
{
return $this->formatE164();
}
/**
* Convert the phone instance into a string representation.
*
* @return string
*/
public function serialize()
{
return $this->formatE164();
}
/**
* Reconstructs the phone instance from a string representation.
*
* @param string $serialized
*/
public function unserialize($serialized)
{
$this->lib = PhoneNumberUtil::getInstance();
$this->number = $serialized;
$this->country = $this->lib->getRegionCodeForNumber($this->getPhoneNumberInstance());
}
/**
* Convert the phone instance to a formatted number.
*
* @return string
*/
public function __toString()
{
// Formatting the phone number could throw an exception, but __toString() doesn't cope well with that.
// Let's just return the original number in that case.
try {
return $this->formatE164();
} catch (Exception $exception) {
return (string) $this->number;
}
}
}

View File

@@ -0,0 +1,38 @@
<?php namespace Propaganistas\LaravelPhone;
use Illuminate\Support\ServiceProvider;
use Illuminate\Validation\Rule;
use libphonenumber\PhoneNumberUtil;
use Propaganistas\LaravelPhone\Rules;
use Propaganistas\LaravelPhone\Validation;
class PhoneServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
$this->app->singleton('libphonenumber', function ($app) {
return PhoneNumberUtil::getInstance();
});
$this->app->alias('libphonenumber', PhoneNumberUtil::class);
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
$this->app['validator']->extendDependent('phone', Validation\Phone::class . '@validate');
Rule::macro('phone', function () {
return new Rules\Phone;
});
}
}

View File

@@ -1,255 +0,0 @@
<?php namespace Propaganistas\LaravelPhone;
use Iso3166\Codes as ISO3166;
use libphonenumber\NumberParseException;
use libphonenumber\PhoneNumberType;
use libphonenumber\PhoneNumberUtil;
use Propaganistas\LaravelPhone\Exceptions\NoValidCountryFoundException;
use Propaganistas\LaravelPhone\Exceptions\InvalidParameterException;
class PhoneValidator
{
/**
* @var \libphonenumber\PhoneNumberUtil
*/
protected $lib;
/**
* Dotted validator data.
*
* @var array
*/
protected $data;
/**
* Whether the country should be auto-detected.
*
* @var bool
*/
protected $autodetect = false;
/**
* Whether to allow lenient checking of numbers (i.e. landline without area codes).
*
* @var bool
*/
protected $lenient = false;
/**
* The field to use for country if not passed as a parameter.
*
* @var string|null
*/
protected $countryField = null;
/**
* Countries to validate against.
*
* @var array
*/
protected $countries = [];
/**
* Transformed phone number types to validate against.
*
* @var array
*/
protected $types = [];
/**
* PhoneValidator constructor.
*/
public function __construct(PhoneNumberUtil $lib)
{
$this->lib = $lib;
}
/**
* Validates a phone number.
*
* @param string $attribute
* @param mixed $value
* @param array $parameters
* @param object $validator
* @return bool
* @throws \Propaganistas\LaravelPhone\Exceptions\InvalidParameterException
* @throws \Propaganistas\LaravelPhone\Exceptions\NoValidCountryFoundException
*/
public function validatePhone($attribute, $value, array $parameters, $validator)
{
$this->data = array_dot($validator->getData());
$this->assignParameters($parameters);
$this->checkCountries($attribute);
// If autodetecting, let's first try without a country.
// Otherwise use provided countries as default.
if ($this->autodetect || ($this->lenient && empty($this->countries))) {
array_unshift($this->countries, null);
}
foreach ($this->countries as $country) {
if ($this->isValidNumber($value, $country)) {
return true;
}
}
// All specified country validations have failed.
return false;
}
/**
* Parses the supplied validator parameters.
*
* @param array $parameters
* @throws \Propaganistas\LaravelPhone\Exceptions\InvalidParameterException
*/
protected function assignParameters(array $parameters)
{
$types = [];
foreach ($parameters as $parameter) {
// First check if the parameter is some phone type configuration.
if ($this->isPhoneType($parameter)) {
$types[] = strtoupper($parameter);
} elseif ($this->isPhoneCountry($parameter)) {
$this->countries[] = strtoupper($parameter);
} elseif ($parameter == 'AUTO') {
$this->autodetect = true;
} elseif ($parameter == 'LENIENT') {
$this->lenient = true;
} // Lastly check if it is an input field containing the country.
elseif ($this->isInputField($parameter)) {
$this->countryField = $parameter;
} else {
// Force developers to write proper code.
throw new InvalidParameterException($parameter);
}
}
$this->types = $this->parseTypes($types);
}
/**
* Checks the detected countries. Overrides countries if a country field is present.
* When using a country field, we should validate to false if country is empty so no exception
* will be thrown.
*
* @param string $attribute
* @throws \Propaganistas\LaravelPhone\Exceptions\NoValidCountryFoundException
*/
protected function checkCountries($attribute)
{
$countryField = (is_null($this->countryField) ? $attribute . '_country' : $this->countryField);
if ($this->isInputField($countryField)) {
$this->countries = [array_get($this->data, $countryField)];
} elseif (! $this->autodetect && ! $this->lenient && empty($this->countries)) {
throw new NoValidCountryFoundException;
}
}
/**
* Performs the actual validation of the phone number.
*
* @param mixed $number
* @param null $country
* @return bool
*/
protected function isValidNumber($number, $country = null)
{
try {
// Throws NumberParseException if not parsed correctly against the supplied country.
// If no country was given, tries to discover the country code from the number itself.
$phoneNumber = $this->lib->parse($number, $country);
// Check if type is allowed.
if (empty($this->types) || in_array($this->lib->getNumberType($phoneNumber), $this->types)) {
// Lenient validation.
if ($this->lenient) {
return $this->lib->isPossibleNumber($phoneNumber, $country);
}
// For automatic detection, the number should have a country code.
if ($phoneNumber->hasCountryCode()) {
// Automatic detection:
if ($this->autodetect) {
// Validate if the international phone number is valid for its contained country.
return $this->lib->isValidNumber($phoneNumber);
}
// Validate number against the specified country.
return $this->lib->isValidNumberForRegion($phoneNumber, $country);
}
}
} catch (NumberParseException $e) {
// Proceed to default validation error.
}
return false;
}
/**
* Parses the supplied phone number types.
*
* @param array $types
* @return array
*/
protected function parseTypes(array $types)
{
// Transform types to their namespaced class constant.
array_walk($types, function (&$type) {
$type = constant('\libphonenumber\PhoneNumberType::' . $type);
});
// Add in the unsure number type if applicable.
if (array_intersect([PhoneNumberType::FIXED_LINE, PhoneNumberType::MOBILE], $types)) {
$types[] = PhoneNumberType::FIXED_LINE_OR_MOBILE;
}
return $types;
}
/**
* Checks if the given field is an actual input field.
*
* @param string $field
* @return bool
*/
public function isInputField($field)
{
return ! is_null(array_get($this->data, $field));
}
/**
* Checks if the supplied string is a valid country code.
*
* @param string $country
* @return bool
*/
public function isPhoneCountry($country)
{
return ISO3166::isValid(strtoupper($country));
}
/**
* Checks if the supplied string is a valid phone number type.
*
* @param string $type
* @return bool
*/
public function isPhoneType($type)
{
// Legacy support.
$type = ($type == 'LANDLINE' ? 'FIXED_LINE' : $type);
return defined('\libphonenumber\PhoneNumberType::' . strtoupper($type));
}
}

View File

@@ -0,0 +1,154 @@
<?php namespace Propaganistas\LaravelPhone\Rules;
use libphonenumber\PhoneNumberType;
use Propaganistas\LaravelPhone\Traits\ParsesCountries;
use Propaganistas\LaravelPhone\Traits\ParsesTypes;
class Phone
{
use ParsesTypes;
/**
* The provided phone countries.
*
* @var array
*/
protected $countries = [];
/**
* The input field name to check for a country value.
*
* @var string
*/
protected $countryField;
/**
* The provided phone types.
*
* @var array
*/
protected $types = [];
/**
* Whether the number's country should be auto-detected.
*
* @var bool
*/
protected $detect = false;
/**
* Whether to allow lenient checks (i.e. landline numbers without area codes).
*
* @var bool
*/
protected $lenient = false;
/**
* Set the phone countries.
*
* @param string|array $country
* @return $this
*/
public function country($country)
{
$countries = is_array($country) ? $country : func_get_args();
$this->countries = array_merge($this->countries, $countries);
return $this;
}
/**
* Set the country input field.
*
* @param string $name
* @return $this
*/
public function countryField($name)
{
$this->countryField = $name;
return $this;
}
/**
* Set the phone types.
*
* @param string|array $type
* @return $this
*/
public function type($type)
{
$types = is_array($type) ? $type : func_get_args();
$this->types = array_merge($this->types, $types);
return $this;
}
/**
* Shortcut method for mobile type restriction.
*
* @return $this
*/
public function mobile()
{
$this->type(PhoneNumberType::MOBILE);
return $this;
}
/**
* Shortcut method for fixed line type restriction.
*
* @return $this
*/
public function fixedLine()
{
$this->type(PhoneNumberType::FIXED_LINE);
return $this;
}
/**
* Enable automatic country detection.
*
* @return $this
*/
public function detect()
{
$this->detect = true;
return $this;
}
/**
* Enable lenient number checking.
*
* @return $this
*/
public function lenient()
{
$this->lenient = true;
return $this;
}
/**
* Convert the rule to a validation string.
*
* @return string
*/
public function __toString()
{
$parameters = implode(',', array_merge(
$this->countries,
static::parseTypes($this->types),
($this->countryField ? [$this->countryField]: []),
($this->detect ? ['AUTO'] : []),
($this->lenient ? ['LENIENT'] : [])
));
return 'phone' . (! empty($parameters) ? ":$parameters" : '');
}
}

View File

@@ -0,0 +1,43 @@
<?php namespace Propaganistas\LaravelPhone\Traits;
use Illuminate\Support\Collection;
use League\ISO3166\ISO3166;
trait ParsesCountries
{
/**
* Determine whether the given country code is valid.
*
* @param string $country
* @return bool
*/
public static function isValidCountryCode($country)
{
$iso3166 = new ISO3166;
try {
$iso3166->alpha2($country);
return true;
} catch (\Exception $e) {
return false;
}
}
/**
* Parse the provided phone countries to a valid array.
*
* @param string|array $countries
* @return array
*/
protected function parseCountries($countries)
{
return Collection::make(is_array($countries) ? $countries : func_get_args())
->map(function ($country) {
return strtoupper($country);
})
->filter(function ($value) {
return static::isValidCountryCode($value);
})->toArray();
}
}

View File

@@ -0,0 +1,55 @@
<?php namespace Propaganistas\LaravelPhone\Traits;
use Illuminate\Support\Arr;
use libphonenumber\PhoneNumberFormat;
use ReflectionClass;
trait ParsesFormats
{
/**
* Array of available phone formats.
*
* @var array
*/
protected static $formats;
/**
* Determine whether the given format is valid.
*
* @param string $format
* @return bool
*/
public static function isValidFormat($format)
{
return ! is_null(static::parseFormat($format));
}
/**
* Parse a phone format.
*
* @param string $format
* @return string
*/
protected static function parseFormat($format)
{
static::loadFormats();
// If the format equals a constant's value, just return it.
if (in_array($format, static::$formats, true)) {
return $format;
}
// Otherwise we'll assume the format is the constant's name.
return Arr::get(static::$formats, strtoupper($format));
}
/**
* Load all available formats once.
*/
private static function loadFormats()
{
if (! static::$formats) {
static::$formats = with(new ReflectionClass(PhoneNumberFormat::class))->getConstants();
}
}
}

View File

@@ -0,0 +1,80 @@
<?php namespace Propaganistas\LaravelPhone\Traits;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use libphonenumber\PhoneNumberType;
use ReflectionClass;
trait ParsesTypes
{
/**
* Array of available phone types.
*
* @var array
*/
protected static $resolvedTypes;
/**
* Determine whether the given type is valid.
*
* @param string $type
* @return bool
*/
public static function isValidType($type)
{
return ! empty(static::parseTypes($type));
}
/**
* Parse a phone type into constant's value.
*
* @param string|array $types
* @return array
*/
protected static function parseTypes($types)
{
static::loadTypes();
return Collection::make(is_array($types) ? $types : func_get_args())
->map(function ($type) {
// If the type equals a constant's value, just return it.
if (is_numeric($type) && in_array($type, static::$resolvedTypes)) {
return (int) $type;
}
// Otherwise we'll assume the type is the constant's name.
return Arr::get(static::$resolvedTypes, strtoupper($type));
})
->reject(function ($value) {
return is_null($value) || $value === false;
})->toArray();
}
/**
* Parse a phone type into its string representation.
*
* @param string|array $types
* @return array
*/
protected static function parseTypesAsStrings($types)
{
static::loadTypes();
return array_keys(
array_intersect(
static::$resolvedTypes,
static::parseTypes($types)
)
);
}
/**
* Load all available formats once.
*/
private static function loadTypes()
{
if (! static::$resolvedTypes) {
static::$resolvedTypes = with(new ReflectionClass(PhoneNumberType::class))->getConstants();
}
}
}

View File

@@ -0,0 +1,132 @@
<?php namespace Propaganistas\LaravelPhone\Validation;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use libphonenumber\PhoneNumberUtil;
use Propaganistas\LaravelPhone\Exceptions\InvalidParameterException;
use libphonenumber\NumberParseException;
use Propaganistas\LaravelPhone\PhoneNumber;
use Propaganistas\LaravelPhone\Traits\ParsesCountries;
use Propaganistas\LaravelPhone\Traits\ParsesTypes;
class Phone
{
use ParsesCountries,
ParsesTypes;
/**
* @var \libphonenumber\PhoneNumberUtil
*/
protected $lib;
/**
* Phone constructor.
*/
public function __construct()
{
$this->lib = PhoneNumberUtil::getInstance();
}
/**
* Validates a phone number.
*
* @param string $attribute
* @param mixed $value
* @param array $parameters
* @param object $validator
* @return bool
*/
public function validate($attribute, $value, array $parameters, $validator)
{
$data = $validator->getData();
list(
$countries,
$types,
$detect,
$lenient) = $this->extractParameters($attribute, $parameters, $data);
// A "null" country is prepended:
// 1. In case of auto-detection to have the validation run first without supplying a country.
// 2. In case of lenient validation without provided countries; we still might have some luck...
if ($detect || ($lenient && empty($countries))) {
array_unshift($countries, null);
}
foreach ($countries as $country) {
try {
// Parsing the phone number also validates the country, so no need to do this explicitly.
// It'll throw a PhoneCountryException upon failure.
$phoneNumber = PhoneNumber::make($value, $country);
// Type validation.
if (! empty($types) && ! $phoneNumber->isOfType($types)) {
continue;
}
$lenientPhoneNumber = $phoneNumber->lenient()->getPhoneNumberInstance();
// Lenient validation.
if ($lenient && $this->lib->isPossibleNumber($lenientPhoneNumber, $country)) {
return true;
}
$phoneNumberInstance = $phoneNumber->getPhoneNumberInstance();
// Country detection.
if ($detect && $this->lib->isValidNumber($phoneNumberInstance)) {
return true;
}
// Default number+country validation.
if ($this->lib->isValidNumberForRegion($phoneNumberInstance, $country)) {
return true;
}
} catch (NumberParseException $e) {
continue;
}
}
return false;
}
/**
* Parse and extract parameters in the appropriate validation arguments.
*
* @param string $attribute
* @param array $parameters
* @param array $data
* @return array
* @throws \Propaganistas\LaravelPhone\Exceptions\InvalidParameterException
*/
protected function extractParameters($attribute, array $parameters, array $data)
{
// Discover if an input field was provided. If not, guess the field's name.
$inputField = Collection::make($parameters)
->intersect(array_keys(Arr::dot($data)))
->first() ?: "${attribute}_country";
// Attempt to retrieve the field's value.
if ($inputCountry = Arr::get($data, $inputField)) {
if (static::isValidType($inputField)) {
throw InvalidParameterException::ambiguous($inputField);
}
// Invalid country field values should just validate to false.
// This will also prevent parameter hijacking through the country field.
if (static::isValidCountryCode($inputCountry)) {
$parameters[] = $inputCountry;
}
}
$parameters = array_map('strtolower', $parameters);
return [
static::parseCountries($parameters),
static::parseTypes($parameters),
in_array('auto', $parameters),
in_array('lenient', $parameters)
];
}
}

View File

@@ -1,46 +1,24 @@
<?php
use Illuminate\Support\Facades\App;
use libphonenumber\PhoneNumberFormat;
use Propaganistas\LaravelPhone\PhoneNumber;
if (! function_exists('phone')) {
/**
* Get the PhoneNumberUtil or format a phone number for display.
* Get a PhoneNumber instance or a formatted string.
*
* @return \libphonenumber\PhoneNumberUtil|string
* @param string $number
* @param string|array $country
* @param string $format
* @return string|Propaganistas\LaravelPhone\PhoneNumber
*/
function phone()
function phone($number, $country = [], $format = null)
{
$lib = App::make('libphonenumber');
$phone = PhoneNumber::make($number, $country);
if (! $arguments = func_get_args()) {
return $lib;
if (! is_null($format)) {
return $phone->format($format);
}
$phone = $arguments[0];
$country = isset($arguments[1]) ? $arguments[1] : App::getLocale();
$format = isset($arguments[2]) ? $arguments[2] : PhoneNumberFormat::INTERNATIONAL;
return $lib->format(
$lib->parse($phone, $country),
$format
);
}
}
if (! function_exists('phone_format')) {
/**
* Formats a phone number and country for display.
*
* @param string $phone
* @param string $country
* @param int|null $format
* @return string
*
* @deprecated 2.8.0
*/
function phone_format($phone, $country = null, $format = PhoneNumberFormat::INTERNATIONAL)
{
return phone($phone, $country, $format);
return $phone;
}
}

View File

@@ -1,468 +0,0 @@
<?php namespace Propaganistas\LaravelPhone\Tests;
use Illuminate\Foundation\Application;
use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberFormat;
use libphonenumber\PhoneNumberUtil;
use Orchestra\Testbench\TestCase;
use Phone;
use Propaganistas\LaravelPhone\LaravelPhoneServiceProvider;
class PhoneValidatorTest extends TestCase
{
protected $validator;
protected function getPackageProviders()
{
return [
'Propaganistas\LaravelPhone\LaravelPhoneServiceProvider',
];
}
protected function getPackageAliases()
{
return [
'Phone' => 'Propaganistas\LaravelPhone\LaravelPhoneFacade',
];
}
public function setUp()
{
parent::setUp();
$this->validator = $this->app['validator'];
}
public function testFacade()
{
$phoneNumber = Phone::parse('650-429-2057', 'US');
$this->assertTrue($phoneNumber instanceof PhoneNumber);
}
public function testValidatePhoneWithDefaultCountryNoType()
{
// Validator with correct country field.
$this->assertTrue($this->validator->make(
['field' => '016123456'],
['field' => 'phone:BE'])->passes()
);
// Validator with wrong country value.
$this->assertFalse($this->validator->make(
['field' => '016123456'],
['field' => 'phone:NL'])->passes()
);
// Validator with multiple country values, one correct.
$this->assertTrue($this->validator->make(
['field' => '016123456'],
['field' => 'phone:BE,NL'])->passes()
);
// Validator with multiple country values, value correct for second country in list.
$this->assertTrue($this->validator->make(
['field' => '016123456'],
['field' => 'phone:NL,BE'])->passes()
);
// Validator with multiple wrong country values.
$this->assertFalse($this->validator->make(
['field' => '016123456'],
['field' => 'phone:DE,NL'])->passes()
);
}
public function testValidatePhoneWithCountryFieldNoType()
{
// Validator with correct country field supplied.
$this->assertTrue($this->validator->make(
['field' => '016123456', 'field_country' => 'BE'],
['field' => 'phone'])->passes()
);
// Validator with wrong country field supplied.
$this->assertFalse($this->validator->make(
['field' => '016123456', 'field_country' => 'NL'],
['field' => 'phone'])->passes()
);
}
public function testValidatePhoneWithDefaultCountryWithType()
{
// Validator with correct country value, correct type.
$this->assertTrue($this->validator->make(
['field' => '0499123456'],
['field' => 'phone:BE,mobile'])->passes()
);
// Validator with correct country value, wrong type.
$this->assertFalse($this->validator->make(
['field' => '016123456'],
['field' => 'phone:BE,mobile'])->passes()
);
// Validator with wrong country value, correct type.
$this->assertFalse($this->validator->make(
['field' => '0499123456'],
['field' => 'phone:NL,mobile'])->passes()
);
// Validator with wrong country value, wrong type.
$this->assertFalse($this->validator->make(
['field' => '016123456'],
['field' => 'phone:NL,mobile'])->passes()
);
// Validator with multiple country values, one correct, correct type.
$this->assertTrue($this->validator->make(
['field' => '0499123456'],
['field' => 'phone:BE,NL,mobile'])->passes()
);
// Validator with multiple country values, one correct, wrong type.
$this->assertFalse($this->validator->make(
['field' => '016123456'],
['field' => 'phone:BE,NL,mobile'])->passes()
);
// Validator with multiple country values, none correct, correct type.
$this->assertFalse($this->validator->make(
['field' => '0499123456'],
['field' => 'phone:DE,NL,mobile'])->passes()
);
// Validator with multiple country values, none correct, wrong type.
$this->assertFalse($this->validator->make(
['field' => '016123456'],
['field' => 'phone:DE,NL,mobile'])->passes()
);
}
public function testValidatePhoneWithCountryFieldWithType()
{
// Validator with correct country field supplied, correct type.
$this->assertTrue($this->validator->make(
['field' => '0499123456', 'field_country' => 'BE'],
['field' => 'phone:mobile'])->passes()
);
// Validator with correct country field supplied, wrong type.
$this->assertFalse($this->validator->make(
['field' => '016123456', 'field_country' => 'BE'],
['field' => 'phone:mobile'])->passes()
);
// Validator with wrong country field supplied, correct type.
$this->assertFalse($this->validator->make(
['field' => '0499123456', 'field_country' => 'NL'],
['field' => 'phone:mobile'])->passes()
);
// Validator with wrong country field supplied, wrong type.
$this->assertFalse($this->validator->make(
['field' => '016123456', 'field_country' => 'NL'],
['field' => 'phone:mobile'])->passes()
);
}
public function testValidatePhoneWithCustomCountryField()
{
// Validator with correct country field supplied, correct type.
$this->assertTrue($this->validator->make(
['field' => '0499123456', 'country_code' => 'BE'],
['field' => 'phone:mobile,country_code'])->passes()
);
// Validator with correct country field supplied, wrong type.
$this->assertFalse($this->validator->make(
['field' => '016123456', 'country_code' => 'BE'],
['field' => 'phone:mobile,country_code'])->passes()
);
// Validator with wrong country field supplied, correct type.
$this->assertFalse($this->validator->make(
['field' => '0499123456', 'country_code' => 'NL'],
['field' => 'phone:mobile,country_code'])->passes()
);
// Validator with wrong country field supplied, wrong type.
$this->assertFalse($this->validator->make(
['field' => '016123456', 'country_code' => 'NL'],
['field' => 'phone:mobile,country_code'])->passes()
);
}
public function testValidatePhoneAutomaticDetectionFromInternationalInput()
{
// Validator with correct international input.
$this->assertTrue($this->validator->make(
['field' => '+3216123456'],
['field' => 'phone:AUTO'])->passes()
);
// Validator with wrong international input.
$this->assertFalse($this->validator->make(
['field' => '003216123456'],
['field' => 'phone:AUTO'])->passes()
);
// Validator with wrong international input.
$this->assertFalse($this->validator->make(
['field' => '+321234'],
['field' => 'phone:AUTO'])->passes()
);
// Validator with wrong international input but correct default country.
$this->assertTrue($this->validator->make(
['field' => '016123456'],
['field' => 'phone:AUTO,NL,BE'])->passes()
);
// Validator with wrong international input and wrong default country.
$this->assertFalse($this->validator->make(
['field' => '016123456'],
['field' => 'phone:AUTO,DE,NL'])->passes()
);
}
public function testValidatePhoneNoDefaultCountryNoCountryField()
{
$this->setExpectedException('Propaganistas\LaravelPhone\Exceptions\NoValidCountryFoundException');
// Validator with no country field or given country.
$this->validator->make(
['field' => '016123456'],
['field' => 'phone']
)->passes();
// Validator with no country field or given country, wrong type.
$this->validator->make(
['field' => '016123456'],
['field' => 'phone:mobile']
)->passes();
// Validator with no country field or given country, correct type.
$this->validator->make(
['field' => '0499359308'],
['field' => 'phone:mobile']
)->passes();
// Validator with no country field or given country, correct type, faulty parameter.
$this->validator->make(
['field' => '0499359308'],
['field' => 'phone:mobile,xyt']
)->passes();
}
public function testValidatePhoneLenient()
{
// Validator with AU area code, lenient off
$this->assertFalse($this->validator->make(
['field' => '88885555'],
['field' => 'phone:AU'])->passes()
);
// Validator with AU area code, lenient on
$this->assertTrue($this->validator->make(
['field' => '88885555'],
['field' => 'phone:LENIENT,AU'])->passes()
);
// Validator with correct country field supplied, lenient on
$this->assertTrue($this->validator->make(
['field' => '88885555', 'field_country' => 'AU'],
['field' => 'phone:LENIENT'])->passes()
);
// Validator with wrong country field supplied, lenient on
$this->assertTrue($this->validator->make(
['field' => '88885555', 'field_country' => 'BE'],
['field' => 'phone:LENIENT'])->passes()
);
// Validator with no area code, lenient on
$this->assertTrue($this->validator->make(
['field' => '+16502530000'],
['field' => 'phone:LENIENT'])->passes()
);
// Validator with US area code, lenient on
$this->assertTrue($this->validator->make(
['field' => '+16502530000'],
['field' => 'phone:LENIENT,US'])->passes()
);
// Validator with no area code, lenient off
$this->assertFalse($this->validator->make(
['field' => '6502530000'],
['field' => 'phone:LENIENT'])->passes()
);
// Validator with US area code, lenient on
$this->assertTrue($this->validator->make(
['field' => '6502530000'],
['field' => 'phone:LENIENT,US'])->passes()
);
// Validator with US area code, lenient off
$this->assertFalse($this->validator->make(
['field' => '2530000'],
['field' => 'phone:LENIENT'])->passes()
);
// Validator with US area code, lenient on
$this->assertTrue($this->validator->make(
['field' => '2530000'],
['field' => 'phone:LENIENT,US'])->passes()
);
}
public function testValidatePhoneFaultyParameters()
{
$this->setExpectedException('Propaganistas\LaravelPhone\Exceptions\InvalidParameterException');
// Validator with given country, correct type, faulty parameter.
$this->validator->make(
['field' => '016123456'],
['field' => 'phone:BE,mobile,xyz']
)->passes();
// Validator with country field, correct type, faulty parameter.
$this->validator->make(
['field' => '016123456', 'field_country' => 'BE'],
['field' => 'phone:mobile,xyz']
)->passes();
}
public function testValidatePhoneWithArrayInput()
{
if (LaravelPhoneServiceProvider::canUseDependentValidation()) {
// Validator with correct country value.
$this->assertTrue($this->validator->make(
[
'container' => [
['field' => '016123456'],
['field' => '0499123456']
]
],
['container.*.field' => 'phone:BE'])->passes()
);
// Validator with wrong country value.
$this->assertFalse($this->validator->make(
[
'container' => [
['field' => '016123456'],
['field' => '0499123456']
]
],
['container.*.field' => 'phone:NL'])->passes()
);
// Validator with correct country value, one wrong input.
$this->assertFalse($this->validator->make(
[
'container' => [
['field' => '01612'],
['field' => '0499123456']
]
],
['container.*.field' => 'phone:BE'])->passes()
);
// Validator with correct country value, one wrong input.
$this->assertFalse($this->validator->make(
[
'container' => [
['field' => '016123456'],
['field' => '049912']
]
],
['container.*.field' => 'phone:BE'])->passes()
);
// Validator with correct country value.
$this->assertTrue($this->validator->make(
[
'container' => [
['field' => '0477123456'],
['field' => '0499123456']
]
],
['container.*.field' => 'phone:BE,mobile'])->passes()
);
// Validator with correct country value, one input wrong type.
$this->assertFalse($this->validator->make(
[
'container' => [
['field' => '016123456'],
['field' => '0499123456']
]
],
['container.*.field' => 'phone:BE,mobile'])->passes()
);
// Validator with correct country fields.
$this->assertTrue($this->validator->make(
[
'container' => [
['field' => '016123456', 'field_country' => 'BE'],
['field' => '6502530000', 'field_country' => 'US']
]
],
['container.*.field' => 'phone'])->passes()
);
// Validator with correct country fields.
$this->assertFalse($this->validator->make(
[
'container' => [
['field' => '016123456', 'field_country' => 'BE'],
['field' => '6502530000', 'field_country' => 'BE']
]
],
['container.*.field' => 'phone'])->passes()
);
// Validator with correct custom country fields.
$this->assertTrue($this->validator->make(
[
'container' => [
['field' => '016123456', 'country_code' => 'BE'],
['field' => '6502530000', 'country_code' => 'US']
]
],
['container.*.field' => 'phone:container.*.country_code'])->passes()
);
// Validator with wrong custom country fields.
$this->assertFalse($this->validator->make(
[
'container' => [
['field' => '016123456', 'country_code' => 'BE'],
['field' => '6502530000', 'country_code' => 'BE']
]
],
['container.*.field' => 'phone:container.*.country_code'])->passes()
);
}
}
public function testHelperFunction()
{
// Test landline number without format parameter.
$actual = phone('016123456', 'BE');
$expected = '+32 16 12 34 56';
$this->assertEquals($expected, $actual);
// Test landline number with format parameter.
$actual = phone('016123456', 'BE', PhoneNumberFormat::NATIONAL);
$expected = '016 12 34 56';
$this->assertEquals($expected, $actual);
// Test fetching of util.
$this->assertTrue(phone() instanceof PhoneNumberUtil);
}
}