Skip to content

Validator For Real World

Shesh Ghimire edited this page Sep 15, 2024 · 6 revisions

This example uses valid Payment Cards from library and assumes Luhn Validator package is installed.

💡 Even if Luhn package is not installed, the validation returns the same result. Its just Luhn Validation is skipped.

Recommended to use Validator with both Resolvers based on payload ($allowedCards).

Using Normal Resolver

Corresponding PHPUnit Test for below validation.

namespace App\Validation;

use TheWebSolver\Codegarage\PaymentCard\Traits\CardResolver;
use TheWebSolver\Codegarage\PaymentCard\CardInterface as Card;
use TheWebSolver\Codegarage\PaymentCard\CardFactory as Factory;

class DefaultValidator {
    use CardResolver {
        getCards as public;
    }

    private const PAYLOAD = 'Resource/paymentCards.json';

    /** @param ?string[] $allowedCards */
    public function __construct(?array $allowedCards = null, Factory $factory = new Factory()) {
        if (empty($allowedCards)) {
            return;
        }

        $this->withoutDefaults()->setCards(
            ...array_map( $factory->withPayload( self::PAYLOAD )->createCard( ... ), $allowedCards )
        );
    }

    public function validate(string|int $cardNumber): bool {
        return $this->resolveCardFromNumber($cardNumber) instanceof Card;
    }
}

// All default cards are allowed.
$validator = new DefaultValidator();
$isValid   = $validator->validate(cardNumber: /*Mastercard*/ 5105105105105100); // true

// Only three cards are allowed.
$validator = new DefaultValidator(allowedCards: ['americanExpress', 'dinersClub', 'visa']);
$NoOfCards = count( $validator->getCards() );                                        // 3
$isValid   = $validator->validate(cardNumber: /*Mastercard*/ 5105105105105100);      // false
$isValid   = $validator->validate(cardNumber: /*American Express*/ 378282246310005); // true

Using Batch Resolver

Corresponding PHPUnit Test for below validation. Here, two batches of allowed Cards are used for validation.

namespace App\Validation;

use TheWebSolver\Codegarage\PaymentCard\Traits\BatchResolver;

class BatchValidator {
    use BatchResolver {
        getCoveredCards as public;
        resetCoveredCards as public;
    }

    /** @var array{first:string,second:string} */
    private array $batches;

    public function __construct() {
        // Define file paths for allowed Cards to resolve Card in batch.
        $this->batches = array(
            'first'  => 'Tests/Resource/Cards.json',
            'second' => 'Resource/paymentCards.json',
        );
    }

    public function validate( string|int $cardNumber ): bool {
        $firstBatch = Factory::createFromJsonFile( path: $this->batches['first'], lazyload: true );

        if ( $this->resolveCardFromNumberIn( $firstBatch, $cardNumber ) ) {
            return true;
        }

        $secondBatch = Factory::createFromJsonFile( path: $this->batches['second'], lazyload: true );

        return $this->resolveCardFromNumberIn( $secondBatch, $cardNumber ) ? true : false;
    }
};

$validator = new BatchValidator();
$validator->validate(/*American Express*/ 378282246310005); // true
count($validator->getCoveredCards());                       // 4

var_dump($validator->getCoveredCards());
// Loaded all cards in memory from the first batch to validate but loaded
// only American Express Card in second batch (valid Card Number).
array(4) {
  'napas' =>
  string(7) "invalid"
  'gpn' =>
  string(7) "invalid"
  'humo' =>
  string(7) "invalid"
  'american-express' =>
  string(5) "valid"
}

$validator->resetCoveredCards();

$validator->validate(/*Mastercard*/ 5105105105105100); // true
count($validator->getCoveredCards());                  // 6

var_dump($validator->getCoveredCards());
// Loaded all cards in memory from the first batch to validate but loaded
// only three cards in second batch up-to Mastercard (valid Card Number).
array(6) {
  'napas' =>
  string(7) "invalid"
  'gpn' =>
  string(7) "invalid"
  'humo' =>
  string(7) "invalid"
  'american-express' =>
  string(7) "invalid"
  'diners-club' =>
  string(7) "invalid"
  'mastercard' =>
  string(5) "valid"
}

$validator->resetCoveredCards();

$validator->validate('invalid card number'); // false
count($validator->getCoveredCards());        // 13

var_dump($validator->getCoveredCards());
// Loaded all cards from both batches but no match found.
array(13) {
  'napas' =>
  string(7) "invalid"
  'gpn' =>
  string(7) "invalid"
  'humo' =>
  string(7) "invalid"
  'american-express' =>
  string(7) "invalid"
  'diners-club' =>
  string(7) "invalid"
  'mastercard' =>
  string(7) "invalid"
  'troy' =>
  string(7) "invalid"
  'discover' =>
  string(7) "invalid"
  'unionpay' =>
  string(7) "invalid"
  'maestro' =>
  string(7) "invalid"
  'visa' =>
  string(7) "invalid"
  'jcb' =>
  string(7) "invalid"
  'mir' =>
  string(7) "invalid"
}

Using Both Resolvers

Corresponding PHPUnit Test for below validation. Here, both resolver traits are used. If only allowed Cards are provided as payload, then validation is performed in batch. Otherwise, validation is performed using default Cards.

namespace App\Validation;

use TheWebSolver\Codegarage\PaymentCard\Traits\CardResolver;
use TheWebSolver\Codegarage\PaymentCard\Traits\BatchResolver;
use TheWebSolver\Codegarage\PaymentCard\CardInterface as Card;
use TheWebSolver\Codegarage\PaymentCard\CardFactory as Factory;

class Validator {
    use CardResolver, BatchResolver {
        BatchResolver::getCoveredCards as public;
    }

    private bool $useBatch = false;

    /** @param string|mixed[]|null $allowedCards */
    public function __construct(
        string|array|null $allowedCards,
        private readonly Factory $factory = new Factory()
    ) {
        if ( empty( $allowedCards ) ) {
            return;
        }

        $this->useBatch = true;

        $factory->withPayload( $allowedCards );
    }

    public function validate( string|int $cardNumber ): bool {
        $card = ! $this->useBatch
            ? $this->resolveCardFromNumber( $cardNumber )
            : $this->resolveCardFromNumberIn( batch: $this->factory->lazyLoadCards(), number: $cardNumber );

        return $card instanceof Card;
    }
}

$validator = new Validator(allowedCards: null);

$validator->validate(/*American Express*/ 378282246310005); // true
count($validator->getCoveredCards());                       // 0

$validator = new Validator(allowedCards: 'Resource/paymentCards.json');

$validator->validate(/*American Express*/ 378282246310005); // true
count($validator->getCoveredCards());                       // 1

$validator = new Validator(allowedCards: 'Resource/paymentCards.json');

$validator->validate(/*Mastercard*/ 5105105105105100); // true
count($validator->getCoveredCards());                  // 3
Clone this wiki locally