Skip to content

Commit

Permalink
Merge branch 'feature/grid'
Browse files Browse the repository at this point in the history
  • Loading branch information
olivervogel committed May 26, 2024
2 parents 81877e6 + b3e1f1b commit a69f5c8
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 0 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ Checks for a valid [European Article Number](https://en.wikipedia.org/wiki/Inter

Optional integer length (8 or 13) to check only for EAN-8 or EAN-13.

### Global Release Identifier (GRid)

The field under validation must be a [Global Release Identifier](https://en.wikipedia.org/wiki/Global_Release_Identifier).

public Intervention\Validation\Rules\Grid::__construct()

### Global Trade Item Number (GTIN)

Checks for a valid [Global Trade Item Number](https://en.wikipedia.org/wiki/Global_Trade_Item_Number).
Expand Down
79 changes: 79 additions & 0 deletions src/Rules/Grid.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

declare(strict_types=1);

namespace Intervention\Validation\Rules;

use Intervention\Validation\AbstractRegexRule;

class Grid extends AbstractRegexRule
{
/**
* {@inheritdoc}
*
* @see AbstractRegexRule::pattern()
*/
protected function pattern(): string
{
return "/^(GRID:)?(?P<grid>A1-?[A-Z0-9]{5}-?[A-Z0-9]{10}-?[A-Z0-9])$/";
}

/**
* Determine if the validation rule passes.
*
* @param mixed $value
* @return bool
*/
public function isValid(mixed $value): bool
{
return is_string($value)
&& parent::isValid(strtoupper($value))
&& $this->hasValidChecksum($value);
}

/**
* Calculate checksum from given grid number
*
* @param string $value
* @return bool
*/
private function hasValidChecksum(string $value): bool
{
// get GRid from value
preg_match($this->pattern(), strtoupper($value), $matches);

// split GRid into single characters (without dashes)
$characters = str_split(
str_replace('-', '', $matches['grid'])
);

// extract last (check) character
$checkCharacter = array_pop($characters);

$m = 36;
$n = 37;
$product = $m;
$sum = 0;

// calculate checksum
foreach ($characters as $char) {
$sum = ($product + $this->charValue($char)) % $m;
$sum = $sum === 0 ? $m : $sum;
$product = ($sum * 2) % $n;
}

// compare checksum to check character value
return $n - $product === $this->charValue($checkCharacter);
}

/**
* Get character value according to GRid standard v2.1
*
* @param string $char
* @return int
*/
private function charValue(string $char): int
{
return is_numeric($char) ? (int) $char : (int) str_replace(range('A', 'Z'), range(10, 35), strtoupper($char));
}
}
44 changes: 44 additions & 0 deletions tests/Rules/GridTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Intervention\Validation\Tests\Rules;

use PHPUnit\Framework\Attributes\DataProvider;
use Intervention\Validation\Rules\Grid;
use PHPUnit\Framework\TestCase;

final class GridTest extends TestCase
{
#[DataProvider('dataProvider')]
public function testValidation($result, $value): void
{
$valid = (new Grid())->isValid($value);
$this->assertEquals($result, $valid);
}

public static function dataProvider(): array
{
return [
[true, 'A12425GABC1234002M'],
[true, 'a12425gabc1234002m'], // lowercase valid
[true, 'GRid:A12425GABC1234002M'],
[true, 'GRID:A12425GABC1234002M'],
[true, 'A1-2425G-ABC1234002-M'],
[true, 'A1-2425GABC1234002M'], // only one dash valid
[true, 'GRid:A1-2425G-ABC1234002-M'],
[true, 'GRID:A1-2425G-ABC1234002-M'],
[true, 'A11244BC12345678DP'],
[true, 'A1-1244B-C12345678D-P'],
[true, 'GRid:A11244BC12345678DP'],
[true, 'GRID:A11244BC12345678DP'],
[true, 'GRid:A1-1244B-C12345678D-P'],
[true, 'GRID:A1-1244B-C12345678D-P'],
[false, 'FOO:A1-1244B-C12345678D-P'], // false prefix
[false, 'B1-1244B-C12345678D-P'], // false Identifier Scheme element
[false, 'A1-1244B-C12345678D-A'], // false Check Character
[false, 'ZA9382189201'], // no grid
[false, ''], // empty
];
}
}

0 comments on commit a69f5c8

Please sign in to comment.