Skip to content

Commit

Permalink
Merge pull request #1 from cs278/initial-version
Browse files Browse the repository at this point in the history
Initial version
  • Loading branch information
cs278 committed Feb 7, 2016
2 parents cfcb72c + 330a2ad commit 51b5984
Show file tree
Hide file tree
Showing 53 changed files with 4,378 additions and 13 deletions.
1 change: 1 addition & 0 deletions .php_cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ return (new Cs278\CsFixer\ConfigBuilder)
->finder(
Symfony\CS\Finder\DefaultFinder::create()
->in(__DIR__)
->notPath('src/Spec/VocaLinkV380Data.php')
)
->build()
;
9 changes: 9 additions & 0 deletions .scrutinizer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
tools:
external_code_coverage:
timeout: 600
runs: 2

filter:
excluded_paths:
- tests/*
- src/Spec/VocaLinkV380Data.php
39 changes: 28 additions & 11 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,33 @@ language: php

sudo: false

php:
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
cache:
directories:
- $HOME/.composer/cache/files

install:
- composer self-update
- composer install
matrix:
include:
- php: 5.4
- php: 5.5
- php: 5.6
env: COVERAGE=yes
- php: hhvm
- php: nightly
- php: 7.0
env: COVERAGE=yes
- php: 7.0
env: COMPOSER_FLAGS='--prefer-lowest --prefer-stable'
allow_failures:
- php: hhvm
- php: nightly
fast_finish: true

script:
- '[ -f vendor/bin/phpunit ] && vendor/bin/phpunit --coverage-text'
before_install:
- if [ "$TRAVIS_PHP_VERSION" != "hhvm" ] && [ "$COVERAGE" != "yes" ]; then phpenv config-rm xdebug.ini; fi;
- composer self-update

install: composer update $COMPOSER_FLAGS --prefer-dist --no-interaction

script: if [ "$COVERAGE" = "yes" ]; then vendor/bin/phpunit --verbose --coverage-clover=coverage.clover --coverage-text; else vendor/bin/phpunit --verbose; fi

after_script: if [ "$COVERAGE" = "yes" ]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
"issues": "https://github.com/cs278/bank-modulus/issues"
},
"require": {
"php": "^5.4.0 | ^7.0.0"
"php": "^5.4.0 | ^7.0.0",
"webmozart/assert": "^1.0.2"
},
"require-dev": {
"cs278/coding-standard": "^1"
"cs278/coding-standard": "^1",
"phpunit/phpunit": "^4.8.21"
},
"autoload": {
"psr-4": {
Expand Down
27 changes: 27 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="vendor/autoload.php"
>
<testsuites>
<testsuite name="Test Suite">
<directory>./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src</directory>
<exclude>
<file>src/Spec/VocaLinkV380Generator.php</file>
</exclude>
</whitelist>
</filter>
</phpunit>
47 changes: 47 additions & 0 deletions src/BankAccount.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace Cs278\BankModulus;

use Cs278\BankModulus\Exception\Util as E;
use Webmozart\Assert\Assert;

final class BankAccount implements BankAccountInterface
{
private $sortCode;
private $accountNumber;

/**
* @param string|SortCode $sortCode
* @param string $accountNumber
*/
public function __construct($sortCode, $accountNumber)
{
try {
if (!$sortCode instanceof SortCode) {
Assert::string($sortCode, 'Sort code must be a string or instance of SortCode');

$sortCode = SortCode::create($sortCode);
}

Assert::string($accountNumber, 'Account number must be a string');
Assert::regex($accountNumber, '{^(?:.*\d.*){6}$}', 'Account number must contain at least 6 digits');
} catch (\InvalidArgumentException $e) {
throw E::wrap($e);
}

$this->sortCode = $sortCode;
$this->accountNumber = preg_replace('{[^0-9]}', '', $accountNumber);
}

/** @return SortCode */
public function getSortCode()
{
return $this->sortCode;
}

/** @return string */
public function getAccountNumber()
{
return $this->accountNumber;
}
}
12 changes: 12 additions & 0 deletions src/BankAccountInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Cs278\BankModulus;

interface BankAccountInterface
{
/** @return SortCode */
public function getSortCode();

/** @return string */
public function getAccountNumber();
}
76 changes: 76 additions & 0 deletions src/BankAccountNormalized.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace Cs278\BankModulus;

use Cs278\BankModulus\Exception\Util as E;
use Webmozart\Assert\Assert;

final class BankAccountNormalized implements BankAccountInterface
{
private $bankAccount;
private $sortCode;
private $accountNumber;

const LENGTH = 8;

/**
* @param BankAccountInterface $bankAccount
* @param string|SortCode $sortCode
* @param string $accountNumber
*/
public function __construct(BankAccountInterface $bankAccount, $sortCode, $accountNumber)
{
try {
if (!$sortCode instanceof SortCode) {
Assert::string($sortCode, 'Sort code must be a string or instance of SortCode');

$sortCode = SortCode::create($sortCode);
}

Assert::string($accountNumber, 'Account number must be a string');
} catch (\InvalidArgumentException $e) {
throw E::wrap($e);
}

$this->bankAccount = $bankAccount;
$this->sortCode = $sortCode;
$this->accountNumber = preg_replace('{[^0-9]}', '', $accountNumber);

if (self::LENGTH !== strlen($this->accountNumber)) {
throw Exception\AccountNumberInvalidException::create($accountNumber);
}
}

public static function createFromBankAccount(BankAccountInterface $bankAccount)
{
return new self(
$bankAccount,
$bankAccount->getSortCode(),
$bankAccount->getAccountNumber()
);
}

/** @return BankAccountInterface */
public function getOriginalBankAccount()
{
return $this->bankAccount;
}

/** @return SortCode */
public function getSortCode()
{
return $this->sortCode;
}

/** @return string */
public function getAccountNumber()
{
return $this->accountNumber;
}

/** @return string */
public function __toString()
{
return $this->sortCode->format('%s%s%s').$this->accountNumber;
}
}
31 changes: 31 additions & 0 deletions src/BankAccountNormalizer/CoOperativeBankNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Cs278\BankModulus\BankAccountNormalizer;

use Cs278\BankModulus\BankAccountInterface;
use Cs278\BankModulus\BankAccountNormalized;
use Cs278\BankModulus\SortCode;

final class CoOperativeBankNormalizer implements NormalizerInterface
{
/** @return BankAccountInterface */
public function normalize(BankAccountInterface $bankAccount)
{
return new BankAccountNormalized(
$bankAccount,
$bankAccount->getSortCode(),
substr($bankAccount->getAccountNumber(), 0, 8)
);
}

/** @return bool */
public function supports(BankAccountInterface $bankAccount)
{
$accountNumber = $bankAccount->getAccountNumber();
$sortCode = $bankAccount->getSortCode();

return 10 === strlen($accountNumber)
&& $sortCode->isBetween(new SortCode('080000'), new SortCode('090000'))
&& !$sortCode->isBetween(new SortCode('083000'), new SortCode('084000')); // Exclude Citibank
}
}
45 changes: 45 additions & 0 deletions src/BankAccountNormalizer/DefaultNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace Cs278\BankModulus\BankAccountNormalizer;

use Cs278\BankModulus\BankAccountInterface;
use Cs278\BankModulus\BankAccountNormalized;

final class DefaultNormalizer implements NormalizerInterface
{
private $normalizers = [];

public function __construct(array $normalizers = null)
{
if (null === $normalizers) {
$normalizers = [
new SixDigitNormalizer(),
new SevenDigitNormalizer(),
new SantanderNormalizer(),
new NatWestNormalizer(),
new CoOperativeBankNormalizer(),
];
}

$this->normalizers = $normalizers;
}

/** @return BankAccountInterface */
public function normalize(BankAccountInterface $bankAccount)
{
foreach ($this->normalizers as $normalizer) {
if ($normalizer->supports($bankAccount)) {
return $normalizer->normalize($bankAccount);
}
}

return BankAccountNormalized::createFromBankAccount($bankAccount);
}

/** @return bool */
public function supports(BankAccountInterface $bankAccount)
{
// Supports anything because it checks before normalizing.
return true;
}
}
34 changes: 34 additions & 0 deletions src/BankAccountNormalizer/NatWestNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Cs278\BankModulus\BankAccountNormalizer;

use Cs278\BankModulus\BankAccountInterface;
use Cs278\BankModulus\BankAccountNormalized;
use Cs278\BankModulus\SortCode;

final class NatWestNormalizer implements NormalizerInterface
{
/** @return BankAccountInterface */
public function normalize(BankAccountInterface $bankAccount)
{
return new BankAccountNormalized(
$bankAccount,
$bankAccount->getSortCode(),
substr($bankAccount->getAccountNumber(), -8)
);
}

/** @return bool */
public function supports(BankAccountInterface $bankAccount)
{
$accountNumber = $bankAccount->getAccountNumber();
$sortCode = $bankAccount->getSortCode();

return 10 === strlen($accountNumber)
&& (
$sortCode->isBetween(new SortCode('010000'), new SortCode('020000')) // ex. District Bank
|| $sortCode->isBetween(new SortCode('500000'), new SortCode('600000')) // ex. National Provincial Bank
|| $sortCode->isBetween(new SortCode('600000'), new SortCode('670000')) // ex. Westminster Bank
);
}
}
14 changes: 14 additions & 0 deletions src/BankAccountNormalizer/NormalizerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Cs278\BankModulus\BankAccountNormalizer;

use Cs278\BankModulus\BankAccountInterface;

interface NormalizerInterface
{
/** @return BankAccountInterface */
public function normalize(BankAccountInterface $bankAccount);

/** @return bool */
public function supports(BankAccountInterface $bankAccount);
}

0 comments on commit 51b5984

Please sign in to comment.