Skip to content

Instantly share code, notes, and snippets.

@BerezhniyDmitro
Created May 27, 2021 09:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BerezhniyDmitro/9dcb843b85775892a2f50cb61ea94fee to your computer and use it in GitHub Desktop.
Save BerezhniyDmitro/9dcb843b85775892a2f50cb61ea94fee to your computer and use it in GitHub Desktop.
<?php
declare(strict_types=1);
namespace App\VO;
use InvalidArgumentException;
/**
* VinCode class.
*/
final class VinCode
{
/**
* @var string[]
*/
private $availableChar = [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'j',
'k',
'l',
'm',
'n',
'p',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
];
/**
* @var int[]
*/
private $weights = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2];
/**
* @var int[]
*/
private $transliterations = [
"a" => 1,
"b" => 2,
"c" => 3,
"d" => 4,
"e" => 5,
"f" => 6,
"g" => 7,
"h" => 8,
"j" => 1,
"k" => 2,
"l" => 3,
"m" => 4,
"n" => 5,
"p" => 7,
"r" => 9,
"s" => 2,
"t" => 3,
"u" => 4,
"v" => 5,
"w" => 6,
"x" => 7,
"y" => 8,
"z" => 9,
];
/**
* @var string $code
*/
private $code;
/**
* VinCode constructor.
* @param string $code Code.
*/
private function __construct(string $code)
{
$this->checkNotValidChar($code);
$this->checkHashSumVinCode($code);
$upperCaseVinCode = strtoupper($code);
$this->code = $upperCaseVinCode;
}
/**
* Create VinCode from string.
* @param string $vinCode VinCode.
* @return VinCode
* @throws InvalidArgumentException Exception.
*/
public static function createFromString(string $vinCode) : self
{
$trimCode = trim($vinCode);
$clearDashCode = str_replace('-', '', $trimCode);
$clearSpaceCode = str_replace(' ', '', $clearDashCode);
$lowerCaseVinCode = strtolower($clearSpaceCode);
$splitVin = str_split($lowerCaseVinCode);
$countChar = count($splitVin);
if ($countChar !== 17) {
throw new InvalidArgumentException(
'VinCodeInvalid length mast be 17 characters. You - ' . $countChar,
102
);
}
return new self($lowerCaseVinCode);
}
/**
* VinCode to string form.
* @return string
*/
public function __toString(): string
{
return $this->code;
}
/**
* Checking for valid chars.
* @param string $code Code.
* @return void
* @throws InvalidArgumentException Exception.
*/
private function checkNotValidChar(string $code): void
{
$arrayCode = str_split($code);
foreach ($arrayCode as $char) {
if (in_array($char, $this->availableChar)) {
continue;
}
throw new InvalidArgumentException(
sprintf(
'Vincode Invalid. It must not contain the letters O (o), I (i) and Q (q).
Use 0, 1, and 9. Invalid character %s. Vin - %s',
$char,
$code
),
101
);
}
}
/**
* Check for valid hash sum.
* @param string $vin VinCode.
* @return void
* @throws InvalidArgumentException Exception.
*/
private function checkHashSumVinCode(string $vin) : void
{
$sum = 0;
$vinCodeChars = str_split($vin);
foreach ($vinCodeChars as $key => $vinCodeChar) {
if (is_numeric($vinCodeChar)) {
$sum += (int) $vinCodeChar * $this->weights[$key];
continue;
}
$sum += $this->transliterations[$vinCodeChar] * $this->weights[$key];
}
$checkDigit = $sum % 11;
if ($checkDigit === 10 && $vinCodeChars[8] === 'x') {
return;
}
if ($checkDigit === (int) $vinCodeChars[8]) {
return;
}
throw new InvalidArgumentException(
'Vincode Invalid. Checksum failed verification, check vincode please! ' . $vin,
103
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment