feature #15519 [Validator] added BIC (SWIFT-BIC) validation constraint (mvhirsch)

This PR was squashed before being merged into the 2.8 branch (closes #15519).

Discussion
----------

[Validator] added BIC (SWIFT-BIC) validation constraint

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | none
| License       | MIT
| Doc PR        | https://github.com/symfony/symfony-docs/pull/5623

I've added the BIC validator, because we do often need validation for IBAN and BIC values. Since the IBAN validation was already included into Symfony, I was asking myself: why not contribute my  BIC validator to the community? So here we go ...

It depends on ISO 9362 as described on [Wikipedia](https://en.wikipedia.org/wiki/ISO_9362#Structure). It validates the structure based on alphabetic/alphanumeric values and the value's length.

Todo-list:
- [x] submit changes to the documentation

Commits
-------

d6471b3 [Validator] added BIC (SWIFT-BIC) validation constraint
This commit is contained in:
Fabien Potencier 2015-09-25 14:16:01 +02:00
commit 06b4938046
6 changed files with 210 additions and 0 deletions

View File

@ -1,6 +1,11 @@
CHANGELOG
=========
2.8.0
-----
* added the BIC (SWIFT-Code) validator
2.7.0
-----

View File

@ -0,0 +1,32 @@
<?php
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @author Michael Hirschler <michael.vhirsch@gmail.com>
*
* @api
*/
class Bic extends Constraint
{
const INVALID_LENGTH_ERROR = '66dad313-af0b-4214-8566-6c799be9789c';
const INVALID_CHARACTERS_ERROR = 'f424c529-7add-4417-8f2d-4b656e4833e2';
const INVALID_BANK_CODE_ERROR = '00559357-6170-4f29-aebd-d19330aa19cf';
const INVALID_COUNTRY_CODE_ERROR = '1ce76f8d-3c1f-451c-9e62-fe9c3ed486ae';
const INVALID_CASE_ERROR = '11884038-3312-4ae5-9d04-699f782130c7';
protected static $errorNames = array(
self::INVALID_LENGTH_ERROR => 'INVALID_LENGTH_ERROR',
self::INVALID_CHARACTERS_ERROR => 'INVALID_CHARACTERS_ERROR',
self::INVALID_BANK_CODE_ERROR => 'INVALID_BANK_CODE_ERROR',
self::INVALID_COUNTRY_CODE_ERROR => 'INVALID_COUNTRY_CODE_ERROR',
self::INVALID_CASE_ERROR => 'INVALID_CASE_ERROR',
);
public $message = 'This is not a valid Business Identifier Code (BIC).';
}

View File

@ -0,0 +1,68 @@
<?php
namespace Symfony\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* @author Michael Hirschler <michael.vhirsch@gmail.com>
*
* @link https://en.wikipedia.org/wiki/ISO_9362#Structure
*
* @api
*/
class BicValidator extends ConstraintValidator
{
/**
* {@inheritdoc}
*/
public function validate($value, Constraint $constraint)
{
if (null === $value || '' === $value) {
return;
}
$canonicalize = str_replace(' ', '', $value);
// the bic must be either 8 or 11 characters long
if (!in_array(strlen($canonicalize), array(8, 11))) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Bic::INVALID_LENGTH_ERROR)
->addViolation();
}
// must contain alphanumeric values only
if (!ctype_alnum($canonicalize)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Bic::INVALID_CHARACTERS_ERROR)
->addViolation();
}
// first 4 letters must be alphabetic (bank code)
if (!ctype_alpha(substr($canonicalize, 0, 4))) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Bic::INVALID_BANK_CODE_ERROR)
->addViolation();
}
// next 2 letters must be alphabetic (country code)
if (!ctype_alpha(substr($canonicalize, 4, 2))) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Bic::INVALID_COUNTRY_CODE_ERROR)
->addViolation();
}
// should contain uppercase characters only
if (strtoupper($canonicalize) !== $canonicalize) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->setCode(Bic::INVALID_CASE_ERROR)
->addViolation();
}
}
}

View File

@ -310,6 +310,10 @@
<source>This value does not match the expected {{ charset }} charset.</source>
<target>Dieser Wert entspricht nicht dem erwarteten Zeichensatz {{ charset }}.</target>
</trans-unit>
<trans-unit id="81">
<source>This is not a valid Business Identifier Code (BIC).</source>
<target>Dieser Wert ist kein gültiger BIC.</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -310,6 +310,10 @@
<source>This value does not match the expected {{ charset }} charset.</source>
<target>This value does not match the expected {{ charset }} charset.</target>
</trans-unit>
<trans-unit id="81">
<source>This is not a valid Business Identifier Code (BIC).</source>
<target>This is not a valid Business Identifier Code (BIC).</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -0,0 +1,97 @@
<?php
namespace Symfony\Component\Validator\Tests\Constraints;
use Symfony\Component\Validator\Constraints\BicValidator;
use Symfony\Component\Validator\Constraints\Bic;
class BicValidatorTest extends AbstractConstraintValidatorTest
{
protected function createValidator()
{
return new BicValidator();
}
public function testNullIsValid()
{
$this->validator->validate(null, new Bic());
$this->assertNoViolation();
}
public function testEmptyStringIsValid()
{
$this->validator->validate('', new Bic());
$this->assertNoViolation();
}
/**
* @dataProvider getValidBics
*/
public function testValidBics($bic)
{
$this->validator->validate($bic, new Bic());
$this->assertNoViolation();
}
public function getValidBics()
{
// http://formvalidation.io/validators/bic/
return array(
array('ASPKAT2LXXX'),
array('ASPKAT2L'),
array('DSBACNBXSHA'),
array('UNCRIT2B912'),
array('DABADKKK'),
array('RZOOAT2L303'),
);
}
/**
* @dataProvider getInvalidBics
*/
public function testInvalidBics($bic, $code)
{
$constraint = new Bic(array(
'message' => 'myMessage',
));
$this->validator->validate($bic, $constraint);
$this->buildViolation('myMessage')
->setParameter('{{ value }}', '"'.$bic.'"')
->setCode($code)
->assertRaised();
}
public function getInvalidBics()
{
return array(
array('DEUTD', Bic::INVALID_LENGTH_ERROR),
array('ASPKAT2LXX', Bic::INVALID_LENGTH_ERROR),
array('ASPKAT2LX', Bic::INVALID_LENGTH_ERROR),
array('ASPKAT2LXXX1', Bic::INVALID_LENGTH_ERROR),
array('DABADKK', Bic::INVALID_LENGTH_ERROR),
array('1SBACNBXSHA', Bic::INVALID_BANK_CODE_ERROR),
array('RZ00AT2L303', Bic::INVALID_BANK_CODE_ERROR),
array('D2BACNBXSHA', Bic::INVALID_BANK_CODE_ERROR),
array('DS3ACNBXSHA', Bic::INVALID_BANK_CODE_ERROR),
array('DSB4CNBXSHA', Bic::INVALID_BANK_CODE_ERROR),
array('DEUT12HH', Bic::INVALID_COUNTRY_CODE_ERROR),
array('DSBAC6BXSHA', Bic::INVALID_COUNTRY_CODE_ERROR),
array('DSBA5NBXSHA', Bic::INVALID_COUNTRY_CODE_ERROR),
// branch code error
array('THISSVAL1D]', Bic::INVALID_CHARACTERS_ERROR),
// location code error
array('DEUTDEF]', Bic::INVALID_CHARACTERS_ERROR),
// lower case values are invalid
array('DeutAT2LXXX', Bic::INVALID_CASE_ERROR),
array('DEUTAT2lxxx', Bic::INVALID_CASE_ERROR),
);
}
}