diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 988beb6b..437e9d23 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,18 +14,37 @@ jobs: matrix: include: - php: '7.4' + symfony-require: 4.4.* - php: '8.0' + symfony-require: 5.3.* + - php: '8.0' + symfony-require: 6.0.* + stability: dev - php: '8.1' mode: experimental + fail-fast: false steps: - name: Checkout uses: actions/checkout@v2 - - name: "Install dependencies with Composer" - uses: "ramsey/composer-install@v1" + - name: Setup PHP + uses: shivammathur/setup-php@v2 with: - composer-options: "--prefer-dist" + php-version: "${{ matrix.php }}" + coverage: none + + - name: Configure Composer minimum stability + if: matrix.stability + run: composer config minimum-stability ${{ matrix.stability }} + + - name: Install symfony/flex + run: composer global require symfony/flex + + - name: Install dependencies + env: + SYMFONY_REQUIRE: "${{ matrix.symfony-require }}" + run: composer update --prefer-dist - name: "Run PHPUnit" run: "vendor/bin/phpunit" diff --git a/composer.json b/composer.json index 53ddbada..db39ce55 100644 --- a/composer.json +++ b/composer.json @@ -14,17 +14,18 @@ "require": { "php": ">=7.4", "giggsey/libphonenumber-for-php": "^8.0", - "symfony/framework-bundle": "^4.4|^5.3", - "symfony/intl": "^4.4|^5.3" + "symfony/framework-bundle": "^4.4|^5.3|^6.0", + "symfony/intl": "^4.4|^5.3|^6.0" }, "require-dev": { "doctrine/doctrine-bundle": "^1.12|^2.0", - "phpunit/phpunit": "^8.4", - "symfony/form": "^4.4|^5.3", - "symfony/property-access": "^4.4|^5.3", - "symfony/serializer": "^4.4|^5.3", - "symfony/twig-bundle": "^4.4|^5.3", - "symfony/validator": "^4.4|^5.3" + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "symfony/form": "^4.4|^5.3|^6.0", + "symfony/property-access": "^4.4|^5.3|^6.0", + "symfony/serializer": "^4.4|^5.3|^6.0", + "symfony/twig-bundle": "^4.4|^5.3|^6.0", + "symfony/validator": "^4.4|^5.3|^6.0" }, "suggest": { "doctrine/doctrine-bundle": "Add a DBAL mapping type", diff --git a/src/Serializer/Normalizer/PhoneNumberNormalizer.php b/src/Serializer/Normalizer/PhoneNumberNormalizer.php index 7a2af51d..2cc22866 100644 --- a/src/Serializer/Normalizer/PhoneNumberNormalizer.php +++ b/src/Serializer/Normalizer/PhoneNumberNormalizer.php @@ -11,96 +11,100 @@ namespace Misd\PhoneNumberBundle\Serializer\Normalizer; -use libphonenumber\NumberParseException; -use libphonenumber\PhoneNumber; -use libphonenumber\PhoneNumberFormat; -use libphonenumber\PhoneNumberUtil; use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Exception\UnexpectedValueException; +use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; -/** - * Phone number serialization for Symfony serializer. - */ -class PhoneNumberNormalizer implements NormalizerInterface, DenormalizerInterface -{ +if (class_exists(ArrayDenormalizer::class) && !method_exists(ArrayDenormalizer::class, 'setSerializer')) { + // Symfony >= 6.0 /** - * Region code. - * - * @var string + * Phone number serialization for Symfony serializer. */ - private $region; + class PhoneNumberNormalizer implements NormalizerInterface, DenormalizerInterface + { + use PhoneNumberNormalizerTrait; - /** - * Display format. - * - * @var int - */ - private $format; + /** + * {@inheritdoc} + * + * @throws InvalidArgumentException + */ + public function normalize(mixed $object, string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null + { + return $this->doNormalize($object, $format, $context); + } - /** - * Display format. - * - * @var PhoneNumberUtil - */ - private $phoneNumberUtil; + /** + * {@inheritdoc} + */ + public function supportsNormalization(mixed $data, string $format = null): bool + { + return $this->doSupportsNormalization($data, $format); + } - /** - * Constructor. - * - * @param PhoneNumberUtil $phoneNumberUtil phone number utility - * @param string $region region code - * @param int $format display format - */ - public function __construct(PhoneNumberUtil $phoneNumberUtil, $region = PhoneNumberUtil::UNKNOWN_REGION, $format = PhoneNumberFormat::E164) - { - $this->phoneNumberUtil = $phoneNumberUtil; - $this->region = $region; - $this->format = $format; - } + /** + * {@inheritdoc} + * + * @throws UnexpectedValueException + */ + public function denormalize(mixed $data, string $type, string $format = null, array $context = []): mixed + { + return $this->doDenormalize($data, $type, $format, $context); + } - /** - * {@inheritdoc} - * - * @throws InvalidArgumentException - */ - public function normalize($object, $format = null, array $context = []) - { - return $this->phoneNumberUtil->format($object, $this->format); + /** + * {@inheritdoc} + */ + public function supportsDenormalization(mixed $data, string $type, string $format = null): bool + { + return $this->doSupportsDenormalization($data, $type, $format); + } } - +} else { + // Symfony < 6.0 /** - * {@inheritdoc} + * Phone number serialization for Symfony serializer. */ - public function supportsNormalization($data, $format = null) + class PhoneNumberNormalizer implements NormalizerInterface, DenormalizerInterface { - return $data instanceof PhoneNumber; - } + use PhoneNumberNormalizerTrait; - /** - * {@inheritdoc} - * - * @throws UnexpectedValueException - */ - public function denormalize($data, $class, $format = null, array $context = []) - { - if (null === $data) { - return; + /** + * {@inheritdoc} + * + * @throws InvalidArgumentException + */ + public function normalize($object, $format = null, array $context = []) + { + return $this->doNormalize($object, $format, $context); } - try { - return $this->phoneNumberUtil->parse($data, $this->region); - } catch (NumberParseException $e) { - throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e); + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return $this->doSupportsNormalization($data, $format); } - } - /** - * {@inheritdoc} - */ - public function supportsDenormalization($data, $type, $format = null) - { - return 'libphonenumber\PhoneNumber' === $type && \is_string($data); + /** + * {@inheritdoc} + * + * @throws UnexpectedValueException + */ + public function denormalize($data, $class, $format = null, array $context = []) + { + return $this->doDenormalize($data, $class, $format, $context); + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + return $this->doSupportsDenormalization($data, $type, $format); + } } } diff --git a/src/Serializer/Normalizer/PhoneNumberNormalizerTrait.php b/src/Serializer/Normalizer/PhoneNumberNormalizerTrait.php new file mode 100644 index 00000000..15795d73 --- /dev/null +++ b/src/Serializer/Normalizer/PhoneNumberNormalizerTrait.php @@ -0,0 +1,80 @@ += 6. + */ +trait PhoneNumberNormalizerTrait +{ + /** + * Region code. + * + * @var string + */ + private $region; + + /** + * Display format. + * + * @var int + */ + private $format; + + /** + * Display format. + * + * @var PhoneNumberUtil + */ + private $phoneNumberUtil; + + /** + * Constructor. + * + * @param PhoneNumberUtil $phoneNumberUtil phone number utility + * @param string $region region code + * @param int $format display format + */ + public function __construct(PhoneNumberUtil $phoneNumberUtil, $region = PhoneNumberUtil::UNKNOWN_REGION, $format = PhoneNumberFormat::E164) + { + $this->phoneNumberUtil = $phoneNumberUtil; + $this->region = $region; + $this->format = $format; + } + + private function doNormalize($object, $format = null, array $context = []) + { + return $this->phoneNumberUtil->format($object, $this->format); + } + + private function doSupportsNormalization($data, $format = null) + { + return $data instanceof PhoneNumber; + } + + private function doDenormalize($data, $class, $format = null, array $context = []) + { + if (null === $data) { + return null; + } + + try { + return $this->phoneNumberUtil->parse($data, $this->region); + } catch (NumberParseException $e) { + throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e); + } + } + + private function doSupportsDenormalization($data, $type, $format = null) + { + return 'libphonenumber\PhoneNumber' === $type && \is_string($data); + } +} diff --git a/tests/Doctrine/DBAL/Types/PhoneNumberTypeTest.php b/tests/Doctrine/DBAL/Types/PhoneNumberTypeTest.php index d6c5fbe2..ba5e64ed 100644 --- a/tests/Doctrine/DBAL/Types/PhoneNumberTypeTest.php +++ b/tests/Doctrine/DBAL/Types/PhoneNumberTypeTest.php @@ -18,12 +18,15 @@ use libphonenumber\PhoneNumberUtil; use Misd\PhoneNumberBundle\Doctrine\DBAL\Types\PhoneNumberType; use PHPUnit\Framework\TestCase; +use Prophecy\PhpUnit\ProphecyTrait; /** * Phone number type test. */ class PhoneNumberTypeTest extends TestCase { + use ProphecyTrait; + /** * @var AbstractPlatform */ diff --git a/tests/Serializer/Normalizer/PhoneNumberNormalizerTest.php b/tests/Serializer/Normalizer/PhoneNumberNormalizerTest.php index 36626ace..20abdebe 100644 --- a/tests/Serializer/Normalizer/PhoneNumberNormalizerTest.php +++ b/tests/Serializer/Normalizer/PhoneNumberNormalizerTest.php @@ -18,6 +18,7 @@ use Misd\PhoneNumberBundle\Serializer\Normalizer\PhoneNumberNormalizer; use PHPUnit\Framework\TestCase; use Prophecy\Argument; +use Prophecy\PhpUnit\ProphecyTrait; use Symfony\Component\Serializer\Exception\UnexpectedValueException; use Symfony\Component\Serializer\Serializer; @@ -26,6 +27,8 @@ */ class PhoneNumberNormalizerTest extends TestCase { + use ProphecyTrait; + protected function setUp(): void { if (!class_exists(Serializer::class)) { diff --git a/tests/Templating/Helper/PhoneNumberHelperTest.php b/tests/Templating/Helper/PhoneNumberHelperTest.php index 7a923cad..4a97b986 100644 --- a/tests/Templating/Helper/PhoneNumberHelperTest.php +++ b/tests/Templating/Helper/PhoneNumberHelperTest.php @@ -17,12 +17,15 @@ use Misd\PhoneNumberBundle\Exception\InvalidArgumentException; use Misd\PhoneNumberBundle\Templating\Helper\PhoneNumberHelper; use PHPUnit\Framework\TestCase; +use Prophecy\PhpUnit\ProphecyTrait; /** * Phone number templating helper test. */ class PhoneNumberHelperTest extends TestCase { + use ProphecyTrait; + protected $phoneNumberUtil; protected $helper; diff --git a/tests/Validator/Constraints/PhoneNumberValidatorTest.php b/tests/Validator/Constraints/PhoneNumberValidatorTest.php index 654555f2..d417455d 100644 --- a/tests/Validator/Constraints/PhoneNumberValidatorTest.php +++ b/tests/Validator/Constraints/PhoneNumberValidatorTest.php @@ -14,8 +14,8 @@ use libphonenumber\PhoneNumberUtil; use Misd\PhoneNumberBundle\Validator\Constraints\PhoneNumber; use Misd\PhoneNumberBundle\Validator\Constraints\PhoneNumberValidator; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Prophecy\Argument; use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Mapping\ClassMetadata; @@ -28,7 +28,7 @@ class PhoneNumberValidatorTest extends TestCase { /** - * @var \Symfony\Component\Validator\Context\ExecutionContextInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Symfony\Component\Validator\Context\ExecutionContextInterface|MockObject */ protected $context; @@ -39,12 +39,12 @@ class PhoneNumberValidatorTest extends TestCase protected function setUp(): void { - $this->context = $this->prophesize(ExecutionContextInterface::class); + $this->context = $this->createMock(ExecutionContextInterface::class); $this->validator = new PhoneNumberValidator(PhoneNumberUtil::getInstance()); - $this->validator->initialize($this->context->reveal()); + $this->validator->initialize($this->context); - $this->context->getObject()->willReturn(new Foo()); + $this->context->method('getObject')->willReturn(new Foo()); } /** @@ -67,14 +67,28 @@ public function testValidate($value, $violates, $type = null, $defaultRegion = n } if (true === $violates) { - $constraintViolationBuilder = $this->prophesize(ConstraintViolationBuilderInterface::class); - $constraintViolationBuilder->setParameter(Argument::type('string'), Argument::type('string'))->willReturn($constraintViolationBuilder->reveal()); - $constraintViolationBuilder->setCode(Argument::type('string'))->willReturn($constraintViolationBuilder->reveal()); - $constraintViolationBuilder->addViolation()->willReturn($constraintViolationBuilder->reveal()); - - $this->context->buildViolation($constraint->getMessage())->shouldBeCalledTimes(1)->willReturn($constraintViolationBuilder->reveal()); + $constraintViolationBuilder = $this->createMock(ConstraintViolationBuilderInterface::class); + $constraintViolationBuilder + ->expects($this->exactly(2)) + ->method('setParameter') + ->with($this->isType('string'), $this->isType('string')) + ->willReturn($constraintViolationBuilder); + $constraintViolationBuilder + ->expects($this->once()) + ->method('setCode') + ->with($this->isType('string')) + ->willReturn($constraintViolationBuilder); + $constraintViolationBuilder + ->method('addViolation') + ->willReturn($constraintViolationBuilder); + + $this->context + ->expects($this->once()) + ->method('buildViolation') + ->with($constraint->getMessage()) + ->willReturn($constraintViolationBuilder); } else { - $this->context->buildViolation()->shouldNotBeCalled(); + $this->context->expects($this->never())->method('buildViolation'); } $this->validator->validate($value, $constraint);