From 0e6ba89a1f4e69daa4deae47b41b4a5101a1bda0 Mon Sep 17 00:00:00 2001 From: thewilkybarkid Date: Tue, 7 Oct 2014 16:28:42 +0100 Subject: [PATCH] Validate phone number type --- Form/Type/PhoneNumberType.php | 2 +- README.md | 7 ++++ Resources/translations/validators.en.xlf | 19 +++++++++ Resources/translations/validators.en_CA.xlf | 11 +++++ Resources/translations/validators.en_PH.xlf | 11 +++++ Resources/translations/validators.en_SG.xlf | 11 +++++ Resources/translations/validators.en_US.xlf | 11 +++++ Resources/translations/validators.en_ZA.xlf | 11 +++++ .../Validator/Constraints/PhoneNumberTest.php | 34 ++++++++++++++++ .../Constraints/PhoneNumberValidatorTest.php | 40 ++++++++++++++++--- Validator/Constraints/PhoneNumber.php | 39 +++++++++++++++++- .../Constraints/PhoneNumberValidator.php | 28 ++++++++++++- 12 files changed, 214 insertions(+), 10 deletions(-) create mode 100644 Resources/translations/validators.en.xlf create mode 100644 Resources/translations/validators.en_CA.xlf create mode 100644 Resources/translations/validators.en_PH.xlf create mode 100644 Resources/translations/validators.en_SG.xlf create mode 100644 Resources/translations/validators.en_US.xlf create mode 100644 Resources/translations/validators.en_ZA.xlf diff --git a/Form/Type/PhoneNumberType.php b/Form/Type/PhoneNumberType.php index 47184f70..00e9d0f6 100644 --- a/Form/Type/PhoneNumberType.php +++ b/Form/Type/PhoneNumberType.php @@ -55,7 +55,7 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) 'compound' => false, 'default_region' => PhoneNumberUtil::UNKNOWN_REGION, 'format' => PhoneNumberFormat::INTERNATIONAL, - 'invalid_message' => 'This is not a valid phone number.', + 'invalid_message' => 'This value is not a valid phone number.', ) ); } diff --git a/README.md b/README.md index 74e6cd01..38379629 100644 --- a/README.md +++ b/README.md @@ -146,3 +146,10 @@ You can set the default region through the `defaultRegion` property: * @AssertPhoneNumber(defaultRegion="GB") */ private $phoneNumber; + +By default any valid phone number will be accepted. You can restrict the type through the `type` property, recognised values are `mobile` and `fixed_line`. (Note the libphonenumber cannot always distinguish between mobile and fixed-line numbers (eg in the USA), in which case it will be accepted.) + + /** + * @AssertPhoneNumber(type="mobile") + */ + private $mobilePhoneNumber; diff --git a/Resources/translations/validators.en.xlf b/Resources/translations/validators.en.xlf new file mode 100644 index 00000000..6657896e --- /dev/null +++ b/Resources/translations/validators.en.xlf @@ -0,0 +1,19 @@ + + + + + + This value is not a valid phone number. + This value is not a valid phone number. + + + This value is not a valid fixed-line number. + This value is not a valid fixed-line number. + + + This value is not a valid mobile number. + This value is not a valid mobile number. + + + + diff --git a/Resources/translations/validators.en_CA.xlf b/Resources/translations/validators.en_CA.xlf new file mode 100644 index 00000000..9f1e45ea --- /dev/null +++ b/Resources/translations/validators.en_CA.xlf @@ -0,0 +1,11 @@ + + + + + + This value is not a valid mobile number. + This value is not a valid cell number. + + + + diff --git a/Resources/translations/validators.en_PH.xlf b/Resources/translations/validators.en_PH.xlf new file mode 100644 index 00000000..44f1f642 --- /dev/null +++ b/Resources/translations/validators.en_PH.xlf @@ -0,0 +1,11 @@ + + + + + + This value is not a valid mobile number. + This value is not a valid handphone number. + + + + diff --git a/Resources/translations/validators.en_SG.xlf b/Resources/translations/validators.en_SG.xlf new file mode 100644 index 00000000..44f1f642 --- /dev/null +++ b/Resources/translations/validators.en_SG.xlf @@ -0,0 +1,11 @@ + + + + + + This value is not a valid mobile number. + This value is not a valid handphone number. + + + + diff --git a/Resources/translations/validators.en_US.xlf b/Resources/translations/validators.en_US.xlf new file mode 100644 index 00000000..9f1e45ea --- /dev/null +++ b/Resources/translations/validators.en_US.xlf @@ -0,0 +1,11 @@ + + + + + + This value is not a valid mobile number. + This value is not a valid cell number. + + + + diff --git a/Resources/translations/validators.en_ZA.xlf b/Resources/translations/validators.en_ZA.xlf new file mode 100644 index 00000000..9f1e45ea --- /dev/null +++ b/Resources/translations/validators.en_ZA.xlf @@ -0,0 +1,11 @@ + + + + + + This value is not a valid mobile number. + This value is not a valid cell number. + + + + diff --git a/Tests/Validator/Constraints/PhoneNumberTest.php b/Tests/Validator/Constraints/PhoneNumberTest.php index abeb8795..cc4ee3b0 100644 --- a/Tests/Validator/Constraints/PhoneNumberTest.php +++ b/Tests/Validator/Constraints/PhoneNumberTest.php @@ -29,4 +29,38 @@ public function testProperties() $this->assertObjectHasAttribute('type', $phoneNumber); $this->assertObjectHasAttribute('defaultRegion', $phoneNumber); } + + /** + * @dataProvider messageProvider + */ + public function testMessage($message = null, $type = null, $expectedMessage) + { + $phoneNumber = new PhoneNumber(); + + if (null !== $message) { + $phoneNumber->message = $message; + } + if (null !== $type) { + $phoneNumber->type = $type; + } + + $this->assertSame($expectedMessage, $phoneNumber->getMessage()); + } + + /** + * 0 => Message (optional) + * 1 => Type (optional) + * 2 => Expected message + */ + public function messageProvider() + { + return array( + array(null, null, 'This value is not a valid phone number.'), + array(null, 'fixed_line', 'This value is not a valid fixed-line number.'), + array(null, 'mobile', 'This value is not a valid mobile number.'), + array('foo', null, 'foo'), + array('foo', 'fixed_line', 'foo'), + array('foo', 'mobile', 'foo'), + ); + } } diff --git a/Tests/Validator/Constraints/PhoneNumberValidatorTest.php b/Tests/Validator/Constraints/PhoneNumberValidatorTest.php index e9d93b9c..37737cdb 100644 --- a/Tests/Validator/Constraints/PhoneNumberValidatorTest.php +++ b/Tests/Validator/Constraints/PhoneNumberValidatorTest.php @@ -11,6 +11,8 @@ namespace Misd\PhoneNumberBundle\Tests\Validator\Constraints; +use libphonenumber\PhoneNumber as PhoneNumberObject; +use libphonenumber\PhoneNumberFormat; use libphonenumber\PhoneNumberUtil; use Misd\PhoneNumberBundle\Validator\Constraints\PhoneNumber; use Misd\PhoneNumberBundle\Validator\Constraints\PhoneNumberValidator; @@ -33,17 +35,32 @@ public function testInstanceOf() /** * @dataProvider validateProvider */ - public function testValidate($value, $violates, $defaultRegion = PhoneNumberUtil::UNKNOWN_REGION) + public function testValidate($value, $violates, $type = null, $defaultRegion = null) { $validator = new PhoneNumberValidator(); $context = $this->getMock('Symfony\Component\Validator\ExecutionContextInterface'); $validator->initialize($context); $constraint = new PhoneNumber(); - $constraint->defaultRegion = $defaultRegion; + if (null !== $type) { + $constraint->type = $type; + } + if (null !== $defaultRegion) { + $constraint->defaultRegion = $defaultRegion; + } if (true === $violates) { - $context->expects($this->once())->method('addViolation'); + if ($value instanceof PhoneNumberObject) { + $constraintValue = PhoneNumberUtil::getInstance()->format($value, PhoneNumberFormat::INTERNATIONAL); + } else { + $constraintValue = (string) $value; + } + + $context->expects($this->once())->method('addViolation') + ->with( + $constraint->getMessage(), + array('{{ type }}' => $constraint->type, '{{ value }}' => $constraintValue) + ); } else { $context->expects($this->never())->method('addViolation'); } @@ -54,7 +71,8 @@ public function testValidate($value, $violates, $defaultRegion = PhoneNumberUtil /** * 0 => Value * 1 => Violates? - * 2 => Default region (optional) + * 2 => Type (optional) + * 3 => Default region (optional) */ public function validateProvider() { @@ -62,9 +80,21 @@ public function validateProvider() array(null, false), array('', false), array(PhoneNumberUtil::getInstance()->parse('+441234567890', PhoneNumberUtil::UNKNOWN_REGION), false), + array(PhoneNumberUtil::getInstance()->parse('+441234567890', PhoneNumberUtil::UNKNOWN_REGION), false, 'fixed_line'), + array(PhoneNumberUtil::getInstance()->parse('+441234567890', PhoneNumberUtil::UNKNOWN_REGION), true, 'mobile'), array(PhoneNumberUtil::getInstance()->parse('+44123456789', PhoneNumberUtil::UNKNOWN_REGION), true), array('+441234567890', false), - array('01234 567890', false, 'GB'), + array('+441234567890', false, 'fixed_line'), + array('+441234567890', true, 'mobile'), + array('+44123456789', true), + array('+44123456789', true, 'mobile'), + array('+12015555555', false), + array('+12015555555', false, 'fixed_line'), + array('+12015555555', false, 'mobile'), + array('2015555555', false, null, 'US'), + array('2015555555', false, 'fixed_line', 'US'), + array('2015555555', false, 'mobile', 'US'), + array('01234 567890', false, null, 'GB'), array('foo', true), ); } diff --git a/Validator/Constraints/PhoneNumber.php b/Validator/Constraints/PhoneNumber.php index 2af9cfac..68260eab 100644 --- a/Validator/Constraints/PhoneNumber.php +++ b/Validator/Constraints/PhoneNumber.php @@ -23,7 +23,42 @@ */ class PhoneNumber extends Constraint { - public $message = 'This value is not a valid {{ type }} number.'; - public $type = 'phone'; + const ANY = 'any'; + const FIXED_LINE = 'fixed_line'; + const MOBILE = 'mobile'; + + private $anyMessage = 'This value is not a valid phone number.'; + private $fixedLineMessage = 'This value is not a valid fixed-line number.'; + private $mobileMessage = 'This value is not a valid mobile number.'; + + public $message = null; + public $type = self::ANY; public $defaultRegion = PhoneNumberUtil::UNKNOWN_REGION; + + public function getType() + { + switch ($this->type) { + case self::FIXED_LINE: + case self::MOBILE: + return $this->type; + } + + return self::ANY; + } + + public function getMessage() + { + if (null !== $this->message) { + return $this->message; + } + + switch ($this->type) { + case self::FIXED_LINE: + return $this->fixedLineMessage; + case self::MOBILE: + return $this->mobileMessage; + } + + return $this->anyMessage; + } } diff --git a/Validator/Constraints/PhoneNumberValidator.php b/Validator/Constraints/PhoneNumberValidator.php index 74665601..2bcce9f2 100644 --- a/Validator/Constraints/PhoneNumberValidator.php +++ b/Validator/Constraints/PhoneNumberValidator.php @@ -14,6 +14,7 @@ use libphonenumber\NumberParseException; use libphonenumber\PhoneNumber as PhoneNumberObject; use libphonenumber\PhoneNumberFormat; +use libphonenumber\PhoneNumberType; use libphonenumber\PhoneNumberUtil; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; @@ -61,6 +62,29 @@ public function validate($value, Constraint $constraint) return; } + + switch ($constraint->getType()) { + case PhoneNumber::FIXED_LINE: + $validTypes = array(PhoneNumberType::FIXED_LINE, PhoneNumberType::FIXED_LINE_OR_MOBILE); + break; + case PhoneNumber::MOBILE: + $validTypes = array(PhoneNumberType::MOBILE, PhoneNumberType::FIXED_LINE_OR_MOBILE); + break; + default: + $validTypes = array(); + break; + } + + if (count($validTypes)) { + $type = $phoneUtil->getNumberType($phoneNumber); + + if (false === in_array($type, $validTypes)) { + $this->addViolation($value, $constraint); + + return; + } + + } } /** @@ -72,8 +96,8 @@ public function validate($value, Constraint $constraint) private function addViolation($value, Constraint $constraint) { $this->context->addViolation( - $constraint->message, - array('{{ type }}' => $constraint->type, '{{ value }}' => $value) + $constraint->getMessage(), + array('{{ type }}' => $constraint->getType(), '{{ value }}' => $value) ); } }