Skip to content

Commit

Permalink
Allow rejecting certain phone number types (#238)
Browse files Browse the repository at this point in the history
* Allow rejecting certain phone number types

* Throw custom exception if allowed and blocked types are both provided
  • Loading branch information
dwightwatson authored Dec 22, 2023
1 parent 99e14d7 commit 1083634
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 4 deletions.
11 changes: 11 additions & 0 deletions src/Exceptions/IncompatibleTypesException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Propaganistas\LaravelPhone\Exceptions;

class IncompatibleTypesException extends \Exception
{
public static function invalid()
{
return new static('Cannot use type and notType at the same time.');
}
}
30 changes: 26 additions & 4 deletions src/Rules/Phone.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Propaganistas\LaravelPhone\Aspects\PhoneNumberCountry;
use Propaganistas\LaravelPhone\Aspects\PhoneNumberType;
use Propaganistas\LaravelPhone\Exceptions\NumberParseException;
use Propaganistas\LaravelPhone\Exceptions\IncompatibleTypesException;
use Propaganistas\LaravelPhone\PhoneNumber;

class Phone implements Rule, ValidatorAwareRule
Expand All @@ -20,7 +21,9 @@ class Phone implements Rule, ValidatorAwareRule

protected array $countries = [];

protected array $types = [];
protected array $allowedTypes = [];

protected array $blockedTypes = [];

protected bool $international = false;

Expand All @@ -33,7 +36,8 @@ public function passes($attribute, $value)
...$this->countries,
]);

$types = PhoneNumberType::sanitize($this->types);
$allowedTypes = PhoneNumberType::sanitize($this->allowedTypes);
$blockedTypes = PhoneNumberType::sanitize($this->blockedTypes);

try {
$phone = (new PhoneNumber($value, $countries))->lenient($this->lenient);
Expand All @@ -43,8 +47,17 @@ public function passes($attribute, $value)
return false;
}

if (! empty($allowedTypes) && ! empty($blockedTypes)) {
throw IncompatibleTypesException::invalid();
}

// Is the type within the allowed list (if applicable)?
if (! empty($types) && ! $phone->isOfType($types)) {
if (! empty($allowedTypes) && ! $phone->isOfType($allowedTypes)) {
return false;
}

// Is the type within the blocked list (if applicable)?
if (! empty($blockedTypes) && $phone->isOfType($blockedTypes)) {
return false;
}

Expand Down Expand Up @@ -74,7 +87,16 @@ public function type($type)
{
$types = is_array($type) ? $type : func_get_args();

$this->types = array_merge($this->types, $types);
$this->allowedTypes = array_merge($this->allowedTypes, $types);

return $this;
}

public function notType($type)
{
$types = is_array($type) ? $type : func_get_args();

$this->blockedTypes = array_merge($this->blockedTypes, $types);

return $this;
}
Expand Down
55 changes: 55 additions & 0 deletions tests/PhoneRuleValidatorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace Propaganistas\LaravelPhone\Tests;

use Illuminate\Validation\Validator;
use libphonenumber\PhoneNumberType;
use Propaganistas\LaravelPhone\Rules\Phone;
use Propaganistas\LaravelPhone\Exceptions\IncompatibleTypesException;

class PhoneRuleValidatorTest extends TestCase
{
protected function validate(array $data, array $rules): Validator
{
return $this->app['validator']->make($data, $rules);
}

/** @test */
public function it_validates_type()
{
$this->assertTrue($this->validate(
['field' => '+32470123456'],
['field' => (new Phone)->type(PhoneNumberType::MOBILE)]
)->passes());

$this->assertFalse($this->validate(
['field' => '+3212345678'],
['field' => (new Phone)->type(PhoneNumberType::MOBILE)]
)->passes());
}

/** @test */
public function it_validates_negative_type()
{
$this->assertFalse($this->validate(
['field' => '+32470123456'],
['field' => (new Phone)->notType(PhoneNumberType::MOBILE)]
)->passes());

$this->assertTrue($this->validate(
['field' => '+3212345678'],
['field' => (new Phone)->notType(PhoneNumberType::MOBILE)]
)->passes());
}

/** @test */
public function it_doesnt_allow_type_and_not_type()
{
$this->expectException(IncompatibleTypesException::class);

$this->validate(
['field' => '+3212345678'],
['field' => (new Phone)->type(PhoneNumberType::MOBILE)->notType(PhoneNumberType::MOBILE)]
)->passes();
}
}

0 comments on commit 1083634

Please sign in to comment.