Skip to content

Instantly share code, notes, and snippets.

@holantomas
Last active May 22, 2018 11:24
Show Gist options
  • Save holantomas/e2f51069d72e5625928b9b89ac07b5b6 to your computer and use it in GitHub Desktop.
Save holantomas/e2f51069d72e5625928b9b89ac07b5b6 to your computer and use it in GitHub Desktop.
Nette/Forms rodné číslo
<?php
namespace Holabs\Utils;
use Nette\InvalidArgumentException;
use Nette\Utils\Strings;
/**
* @author Tomáš Holan <[email protected]>
* @copyright Copyright © 2017, Tomáš Holan [www.tomasholan.eu]
*/
class BirthNumber {
const REGEXP = '~^\s*(\d\d)(\d\d)(\d\d)[ /]*(\d\d)(\d)(\d?)\s*$~';
/** @var string */
private $number;
/** @var int */
private $year;
/** @var int */
private $month;
/** @var int */
private $day;
/** @var int */
private $hospital;
/** @var int */
private $order;
/** @var int */
private $checker;
/** @var bool */
private $male;
public function __construct(string $number) {
if (!$matches = self::explode($number)) {
throw new InvalidArgumentException("{$number} is not valid birth number");
}
list($this->number, $this->year, $this->month, $this->day, $this->hospital, $this->order, $this->checker, $this->male) = $matches;
}
/**
* @return int
*/
public function getYear(): int {
return $this->year;
}
/**
* @return int
*/
public function getMonth(): int {
return $this->month;
}
/**
* @return int
*/
public function getDay(): int {
return $this->day;
}
/**
* @return int
*/
public function getHospital(): int {
return $this->hospital;
}
/**
* @return int
*/
public function getOrder(): int {
return $this->order;
}
/**
* @return int
*/
public function getChecker(): int {
return $this->checker;
}
/**
* @return bool
*/
public function isMale(): bool {
return $this->male;
}
/**
* @return string
*/
public function toString(): string {
return (string)$this;
}
/**
* @return string
*/
public function __toString() {
return $this->number;
}
/**
* @param string $number
* @return bool
*/
public static function validate(string $number): bool {
return self::explode($number) !== NULL;
}
/**
* @param string $number
* @return array|null [int|string $number, int year, int $month, int $day, int $hospital, int $order, int $checker, bool $male]
*/
public static function explode(string $number): ?array {
// be liberal in what you receive
if (!$matches = Strings::match($number, self::REGEXP)) {
return NULL;
}
list(, $year, $month, $day, $hospital, $order, $c) = $matches;
$male = TRUE;
$tmp = "{$year}{$month}{$day}/{$hospital}{$order}{$c}";
if ($c === '') {
$year += $year < 54 ? 1900 : 1800;
} else {
// kontrolní číslice
$mod = ($year . $month . $day . $hospital . $order) % 11;
if ($mod === 10) {
$mod = 0;
}
if ($mod !== (int)$c) {
return NULL;
}
$year += $year < 54 ? 2000 : 1900;
}
// k měsíci může být připočteno 20, 50 nebo 70
if ($month > 70 && $year > 2003) {
$month -= 70;
$male = FALSE;
} elseif ($month > 50) {
$month -= 50;
$male = FALSE;
} elseif ($month > 20 && $year > 2003) {
$month -= 20;
}
// kontrola data
if (!checkdate($month, $day, $year)) {
return NULL;
}
return [$tmp, (int) $year, (int) $month, (int) $day, (int) $hospital, (int) $order, (int) $c, $male];
}
}
<?php
namespace Holabs\UI\Forms\Controls;
use Holabs\UI\Forms\Form;
use Holabs\UI\Forms\Validator;
use Holabs\Utils\BirthNumber;
use Nette\Forms\Controls\TextInput;
/**
* @author Tomáš Holan <[email protected]>
* @package asis/core
* @copyright Copyright © 2017, Tomáš Holan [www.tomasholan.eu]
*/
class BirthNumberInput extends TextInput {
/**
* @inheritDoc
*/
public function __construct($label = NULL, $maxLength = NULL) {
parent::__construct($label, $maxLength);
$this->addRule(Form::BIRTH_NUMBER, Validator::$messages[Form::BIRTH_NUMBER]);
}
/**
* @inheritDoc
*/
public function getValue() {
$value = parent::getValue();
return $value === NULL ? NULL : new BirthNumber((string) $value);
}
}
<?php
namespace Holabs\UI\Forms;
use Nette\Application\UI\Form as NetteForm;
/**
* @author Tomáš Holan <[email protected]>
* @package asis/ui
* @copyright Copyright © 2017, Tomáš Holan [www.tomasholan.eu]
*/
class Form extends NetteForm {
/** CUSTOM VALIDATORS */
const BIRTH_NUMBER = Validator::class . '::validateBirthNumber';
/**
* @param string
* @param string|object
* @return TextInput
*/
public function addBirthNumber($name, $label = null){
return $this[$name] = (new BirthNumberInput($label))
->setRequired(false);
}
}
(function ($, undefined) {
if (typeof $ !== 'function') {
return console.error('jQuery is missing.');
}
if (typeof Nette !== 'object') {
return console.error('Nette is missing.');
}
function checkdate(m, d, y) {
return m > 0 && m < 13 && y > 0 && y < 32768 && d > 0 && d <= (new Date(y, m, 0)).getDate()
}
function isUndefined(x) {
return typeof x === typeof undefined;
}
var validator = {
// This name is important!!!
HolabsUIFormsValidator_validateBirthNumber: function (elem, args, val) {
var matches = val.match(/^\s*(\d\d)(\d\d)(\d\d)[ /]*(\d\d)(\d)(\d?)\s*$/);
if (matches === null) return false;
[,year,month,day,hosp,ord,checker] = matches;
checker = isUndefined(checker) ? null : parseInt(checker, 10);
var ext = hosp.toString() + ord.toString();
if (checker === null) {
year = parseInt(year, 10);
year += year < 54 ? 1900 : 1800;
} else {
var m = parseInt(year.toString() + month.toString() + day.toString() + ext, 10) % 11;
if (m === 10) m = 0;
if (m !== checker) return false;
year = parseInt(year, 10);
year += year < 54 ? 2000 : 1900;
}
month = parseInt(month, 10);
day = parseInt(day, 10);
if (month > 70 && year > 2003)month -= 70;
else if (month > 50) month -= 50;
else if (month > 20 && year > 2003) month -= 20;
return checkdate(month, day, year);
}
}
Nette.validators = $.extend(Nette.validators, validator);
})(jQuery);
<?php
namespace Holabs\UI\Forms;
use Holabs\Utils\Validators;
use Nette\Forms\IControl;
use Nette\StaticClass;
/**
* @author Tomáš Holan <[email protected]>
* @package asis/core
* @copyright Copyright © 2017, Tomáš Holan [www.tomasholan.eu]
*/
class Validator {
use StaticClass;
/** @var array */
public static $messages = [
Form::BIRTH_NUMBER => 'Nevalidní rodné číslo.',
];
/**
* @param IControl $control
* @param $arg
* @return bool
*/
public static function validateBirthNumber(IControl $control, $arg) {
return Validators::isBirthNumber($control->getValue());
}
}
<?php
namespace Holabs\Utils;
use Nette\StaticClass;
/**
* @author Tomáš Holan <[email protected]>
* @copyright Copyright © 2017, Tomáš Holan [www.tomasholan.eu]
*/
class Validators {
use StaticClass;
/**
* @param string $number
* @return bool
*/
public static function isBirthNumber(string $number): bool {
return BirthNumber::validate($number);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment