Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.10% covered (success)
93.10%
27 / 29
87.50% covered (warning)
87.50%
7 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
PhoneNumber
93.10% covered (success)
93.10%
27 / 29
87.50% covered (warning)
87.50%
7 / 8
14.06
0.00% covered (danger)
0.00%
0 / 1
 fromCountry
n/a
0 / 0
n/a
0 / 0
0
 getUtil
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 toE164
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toInternational
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toNational
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toRFC3966
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 convert
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 validate
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
4.59
 createRandom
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2namespace Apie\CountryAndPhoneNumber;
3
4use Apie\Core\Attributes\Description;
5use Apie\Core\Attributes\FakeMethod;
6use Apie\Core\ValueObjects\Exceptions\InvalidStringForValueObjectException;
7use Apie\Core\ValueObjects\Interfaces\StringValueObjectInterface;
8use Apie\Core\ValueObjects\IsStringValueObject;
9use Apie\CountryAndPhoneNumber\Factories\PhoneNumberFactory;
10use Faker\Generator;
11use libphonenumber\NumberParseException;
12use libphonenumber\PhoneNumber as LibPhoneNumber;
13use libphonenumber\PhoneNumberFormat;
14use libphonenumber\PhoneNumberUtil;
15use PrinsFrank\Standards\Country\CountryAlpha2;
16use ReflectionClass;
17
18#[FakeMethod('createRandom')]
19#[Description('Represents a phone number in proper formatting')]
20abstract class PhoneNumber implements StringValueObjectInterface
21{
22    use IsStringValueObject;
23
24    private static PhoneNumberUtil $util;
25
26    private LibPhoneNumber $phoneNumber;
27
28    abstract public static function fromCountry(): CountryAlpha2;
29
30    final protected static function getUtil(): PhoneNumberUtil
31    {
32        if (!isset(self::$util)) {
33            self::$util = PhoneNumberUtil::getInstance();
34        }
35        return self::$util;
36    }
37
38    final public function toE164(): string
39    {
40        return self::getUtil()->format($this->phoneNumber, PhoneNumberFormat::E164);
41    }
42
43    final public function toInternational(): string
44    {
45        return self::getUtil()->format($this->phoneNumber, PhoneNumberFormat::INTERNATIONAL);
46    }
47
48    final public function toNational(): string
49    {
50        return self::getUtil()->format($this->phoneNumber, PhoneNumberFormat::NATIONAL);
51    }
52
53    final public function toRFC3966(): string
54    {
55        return self::getUtil()->format($this->phoneNumber, PhoneNumberFormat::RFC3966);
56    }
57
58    final protected function convert(string $input): string
59    {
60        $phoneNumberUtil = self::getUtil();
61        try {
62            $this->phoneNumber = $phoneNumberUtil->parse($input, static::fromCountry()->value);
63        } catch (NumberParseException $error) {
64            throw new InvalidStringForValueObjectException($input, new ReflectionClass(static::class), $error);
65        }
66        return $phoneNumberUtil->format($this->phoneNumber, PhoneNumberFormat::E164);
67    }
68
69    public static function validate(string $input): void
70    {
71        $phoneNumberUtil = self::getUtil();
72        try {
73            $phoneNumber = $phoneNumberUtil->parse($input, static::class === PhoneNumber::class ? null : static::fromCountry()->value);
74        } catch (NumberParseException $error) {
75            throw new InvalidStringForValueObjectException($input, new ReflectionClass(static::class), $error);
76        }
77        if (!$phoneNumberUtil->isValidNumberForRegion($phoneNumber, static::fromCountry()->value)) {
78            throw new InvalidStringForValueObjectException($input, new ReflectionClass(static::class));
79        }
80    }
81
82    public static function createRandom(Generator $generator): self
83    {
84        $phoneNumber = '';
85        do {
86            $country = $generator->randomElement(CountryAlpha2::cases());
87            $phoneNumberUtil = self::getUtil();
88            $phoneNumberObject = $phoneNumberUtil->getExampleNumber($country->value);
89            if ($phoneNumberObject) {
90                $phoneNumber = $phoneNumberUtil->format($phoneNumberObject, PhoneNumberFormat::E164);
91            }
92        } while ($phoneNumber === '');
93        return PhoneNumberFactory::createFrom(
94            $phoneNumber,
95            $country
96        );
97    }
98}