Compare commits
10 Commits
b858b89d5b
...
9a181aafbd
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a181aafbd | |||
| 8d5b060acf | |||
|
|
f1b14d4d40 | ||
|
|
ef32d3d7c0 | ||
|
|
bf51a443be | ||
|
|
2cda4451a4 | ||
| ea092c24d7 | |||
| b4f4fe25b9 | |||
| 0ad94c4944 | |||
| 4566a4e4cc |
1
.dev/.gitignore
vendored
Normal file
1
.dev/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
coverage
|
||||||
50
.dev/docker/php/Dockerfile
Normal file
50
.dev/docker/php/Dockerfile
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
FROM alpine:3.18 as base
|
||||||
|
|
||||||
|
ARG UID=1000
|
||||||
|
ARG USER=mnavarro
|
||||||
|
ARG COMPOSER_VERSION=2.7.0
|
||||||
|
|
||||||
|
# Create a development user
|
||||||
|
RUN adduser $USER --disabled-password --home /$USER --uid $UID
|
||||||
|
|
||||||
|
# Install PHP Extensions
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
php82-cli \
|
||||||
|
php82-phar \
|
||||||
|
php82-mbstring \
|
||||||
|
php82-json \
|
||||||
|
php82-zip \
|
||||||
|
php82-openssl \
|
||||||
|
php82-dom \
|
||||||
|
php82-xml \
|
||||||
|
php82-soap \
|
||||||
|
php82-session \
|
||||||
|
php82-xmlwriter \
|
||||||
|
php82-sockets \
|
||||||
|
php82-simplexml \
|
||||||
|
php82-bcmath \
|
||||||
|
php82-xmlreader \
|
||||||
|
php82-tokenizer \
|
||||||
|
php82-iconv \
|
||||||
|
php82-sodium \
|
||||||
|
php82-fileinfo \
|
||||||
|
php82-curl \
|
||||||
|
php82-ctype \
|
||||||
|
php82-pcntl \
|
||||||
|
php82-posix
|
||||||
|
|
||||||
|
# Link php82 to php
|
||||||
|
RUN ln -s /usr/bin/php82 /usr/bin/php
|
||||||
|
|
||||||
|
# Add wget to make requests
|
||||||
|
RUN apk add --no-cache wget
|
||||||
|
|
||||||
|
# Download and install composer
|
||||||
|
RUN wget -O /usr/bin/composer https://github.com/composer/composer/releases/download/$COMPOSER_VERSION/composer.phar && \
|
||||||
|
chmod +x /usr/bin/composer
|
||||||
|
|
||||||
|
FROM base as dev
|
||||||
|
|
||||||
|
# Install and Configure XDebug
|
||||||
|
RUN apk add --no-cache php82-pecl-xdebug
|
||||||
|
COPY ./xdebug.ini /etc/php82/conf.d/60_xdebug.ini
|
||||||
6
.dev/docker/php/xdebug.ini
Normal file
6
.dev/docker/php/xdebug.ini
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
zend_extension=xdebug.so
|
||||||
|
|
||||||
|
[xdebug]
|
||||||
|
xdebug.mode=debug,develop,coverage
|
||||||
|
xdebug.client_host=host.docker.internal
|
||||||
|
xdebug.output_dir=/castor/context/.dev/debug
|
||||||
7
.dev/init
Executable file
7
.dev/init
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
mkdir -p .dev/coverage
|
||||||
|
|
||||||
|
composer install
|
||||||
12
.gitattributes
vendored
Normal file
12
.gitattributes
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/.idea export-ignore
|
||||||
|
/vendor export-ignore
|
||||||
|
/tests export-ignore
|
||||||
|
/.dev export-ignore
|
||||||
|
/.php-cs-fixer.dist.php export-ignore
|
||||||
|
/compose.yml export-ignore
|
||||||
|
/composer.lock export-ignore
|
||||||
|
/phpunit.xml export-ignore
|
||||||
|
/psalm.xml export-ignore
|
||||||
|
/psalm-baseline.xml export-ignore
|
||||||
|
/.gitignore export-ignore
|
||||||
|
/README.md export-ignore
|
||||||
25
.github/workflows/ci.yml
vendored
Normal file
25
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
name: "Chilean Rut CI"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: ['master']
|
||||||
|
paths:
|
||||||
|
- '**.php'
|
||||||
|
- 'composer.json'
|
||||||
|
- '.github/workflows/ci.yml'
|
||||||
|
- '.github/workflows/php.yml'
|
||||||
|
push:
|
||||||
|
branches: ['master']
|
||||||
|
paths:
|
||||||
|
- '**.php'
|
||||||
|
- 'composer.json'
|
||||||
|
- '.github/workflows/ci.yml'
|
||||||
|
- '.github/workflows/php.yml'
|
||||||
|
jobs:
|
||||||
|
ci:
|
||||||
|
name: 'CI'
|
||||||
|
uses: ./.github/workflows/php.yml
|
||||||
|
with:
|
||||||
|
php-version: 8.2
|
||||||
|
composer-cmd: install --ansi --no-interaction --no-progress --no-suggest --prefer-dist
|
||||||
|
secrets: inherit
|
||||||
60
.github/workflows/php.yml
vendored
Normal file
60
.github/workflows/php.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
name: "PHP Checks"
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
php-version:
|
||||||
|
description: 'The version of PHP to use'
|
||||||
|
default: '8.2'
|
||||||
|
type: string
|
||||||
|
composer-cmd:
|
||||||
|
description: 'Command to install dependencies'
|
||||||
|
type: string
|
||||||
|
default: 'install --ansi --no-interaction --no-progress --no-suggest --prefer-dist'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
php-checks:
|
||||||
|
name: "PHP Checks"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
steps:
|
||||||
|
- name: "Checkout Code"
|
||||||
|
uses: "actions/checkout@v2"
|
||||||
|
- name: "Install PHP"
|
||||||
|
uses: "shivammathur/setup-php@v2"
|
||||||
|
with:
|
||||||
|
coverage: "pcov"
|
||||||
|
php-version: "${{ inputs.php-version }}"
|
||||||
|
ini-values: memory_limit=-1
|
||||||
|
tools: composer:v2
|
||||||
|
- name: Get Composer Cache Directory
|
||||||
|
id: composer-cache
|
||||||
|
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||||
|
- name: "Cache dependencies"
|
||||||
|
uses: "actions/cache@v2"
|
||||||
|
with:
|
||||||
|
path: ${{ steps.composer-cache.outputs.dir }}
|
||||||
|
key: "${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}"
|
||||||
|
restore-keys: "${{ runner.os }}-composer-"
|
||||||
|
- name: "Install dependencies"
|
||||||
|
run: "composer ${{ inputs.composer-cmd }}"
|
||||||
|
- name: "Check Code Style"
|
||||||
|
run: "composer fmt:check"
|
||||||
|
- name: "Run Psalm"
|
||||||
|
run: "composer psalm:gh"
|
||||||
|
- name: "Run Test Suite"
|
||||||
|
run: "composer test"
|
||||||
|
- name: Setup Pages
|
||||||
|
uses: actions/configure-pages@v4
|
||||||
|
if: ${{ github.ref_name == 'master' }}
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
if: ${{ github.ref_name == 'master' }}
|
||||||
|
with:
|
||||||
|
path: '.dev/coverage'
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
if: ${{ github.ref_name == 'master' }}
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,5 +1,3 @@
|
|||||||
vendor
|
vendor
|
||||||
composer.lock
|
.env
|
||||||
.idea
|
compose.override.yml
|
||||||
.php_cs.cache
|
|
||||||
build
|
|
||||||
37
.php-cs-fixer.dist.php
Normal file
37
.php-cs-fixer.dist.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use PhpCsFixer\Fixer\FunctionNotation\NativeFunctionInvocationFixer;
|
||||||
|
|
||||||
|
$header = <<<EOF
|
||||||
|
@project Chilean RUT
|
||||||
|
@link https://github.com/mnavarrocarter/chilean-rut
|
||||||
|
@package castor/log
|
||||||
|
@author Matias Navarro-Carter mnavarrocarter@gmail.com
|
||||||
|
@license MIT
|
||||||
|
@copyright 2024 Matias Navarro-Carter
|
||||||
|
|
||||||
|
For the full copyright and license information, please view the LICENSE
|
||||||
|
file that was distributed with this source code.
|
||||||
|
EOF;
|
||||||
|
|
||||||
|
|
||||||
|
return (new PhpCsFixer\Config())
|
||||||
|
->setCacheFile('/tmp/php-cs-fixer')
|
||||||
|
->setRiskyAllowed(true)
|
||||||
|
->setRules([
|
||||||
|
'@PhpCsFixer' => true,
|
||||||
|
'declare_strict_types' => true,
|
||||||
|
'header_comment' => ['header' => $header, 'comment_type' => 'PHPDoc'],
|
||||||
|
'yoda_style' => false,
|
||||||
|
'php_unit_internal_class' => false,
|
||||||
|
'php_unit_test_class_requires_covers' => false,
|
||||||
|
'native_function_invocation' => [
|
||||||
|
'include' => [NativeFunctionInvocationFixer::SET_ALL],
|
||||||
|
'scope' => 'namespaced',
|
||||||
|
]
|
||||||
|
])
|
||||||
|
->setFinder(
|
||||||
|
PhpCsFixer\Finder::create()
|
||||||
|
->in(["src", "tests"])
|
||||||
|
)
|
||||||
|
;
|
||||||
33
.php_cs.dist
33
.php_cs.dist
@@ -1,32 +1,35 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$header = <<<EOF
|
$header = <<<EOF
|
||||||
This file is part of the MNC\ChileanRut library.
|
@project Chilean Rut
|
||||||
|
@link https://github.com/mnavarrocarter/chilean-rut
|
||||||
|
@package mnavarrocarter/chilean-rut
|
||||||
|
@author Matias Navarro-Carter mnavarrocarter@gmail.com
|
||||||
|
@license MIT
|
||||||
|
@copyright 2020 Matias Navarro Carter
|
||||||
|
|
||||||
(c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
For the full copyright and license information, please view the LICENSE
|
For the full copyright and license information, please view the LICENSE
|
||||||
file that was distributed with this source code.
|
file that was distributed with this source code.
|
||||||
EOF;
|
EOF;
|
||||||
|
|
||||||
return PhpCsFixer\Config::create()
|
return PhpCsFixer\Config::create()
|
||||||
|
->setRiskyAllowed(true)
|
||||||
->setRules([
|
->setRules([
|
||||||
'@Symfony' => true,
|
'@Symfony' => true,
|
||||||
'array_syntax' => ['syntax' => 'short'],
|
'array_syntax' => ['syntax' => 'short'],
|
||||||
'combine_consecutive_unsets' => true,
|
'declare_strict_types' => true,
|
||||||
'header_comment' => ['header' => $header],
|
'strict_comparison' => true,
|
||||||
'linebreak_after_opening_tag' => true,
|
'phpdoc_no_empty_return' => true,
|
||||||
'no_php4_constructor' => true,
|
'header_comment' => ['header' => $header, 'comment_type' => 'PHPDoc'],
|
||||||
'no_useless_else' => true,
|
'yoda_style' => [
|
||||||
'ordered_class_elements' => true,
|
'equal' => false,
|
||||||
'ordered_imports' => true,
|
'identical' => false,
|
||||||
'php_unit_construct' => true,
|
'less_and_greater' => false,
|
||||||
'php_unit_strict' => true,
|
'always_move_variable' => true
|
||||||
'phpdoc_no_empty_return' => false,
|
],
|
||||||
])
|
])
|
||||||
->setUsingCache(true)
|
|
||||||
->setRiskyAllowed(true)
|
|
||||||
->setFinder(
|
->setFinder(
|
||||||
PhpCsFixer\Finder::create()
|
PhpCsFixer\Finder::create()
|
||||||
->in(__DIR__)
|
->in(__DIR__.'/src')
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
30
.travis.yml
30
.travis.yml
@@ -1,30 +0,0 @@
|
|||||||
language: php
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- CC_TEST_REPORTER_ID=$CC_TEST_REPORTER_ID
|
|
||||||
dist: precise
|
|
||||||
php:
|
|
||||||
- '7.1'
|
|
||||||
- '7.2'
|
|
||||||
- nightly
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
allow_failures:
|
|
||||||
- php: nightly
|
|
||||||
|
|
||||||
sudo: false
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $HOME/.composer/cache
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- travis_retry composer self-update
|
|
||||||
- travis_retry composer install --no-interaction --prefer-dist
|
|
||||||
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
|
||||||
- chmod +x ./cc-test-reporter
|
|
||||||
- ./cc-test-reporter before-build
|
|
||||||
|
|
||||||
script: composer run test
|
|
||||||
|
|
||||||
after_script:
|
|
||||||
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
|
||||||
18
CHANGELOG.md
18
CHANGELOG.md
@@ -1,18 +0,0 @@
|
|||||||
# CHANGELOG
|
|
||||||
|
|
||||||
## v1.0.0 (08.08.2018)
|
|
||||||
- Create Initial Classes (Rut, Validator, ChainRutValidator)
|
|
||||||
- Tested Rut
|
|
||||||
- Tested SimpleRutValidator
|
|
||||||
- Tested Symfony Form Type
|
|
||||||
|
|
||||||
## v2.0.0 (12.10.2018)
|
|
||||||
This is a major version because api changes and class renaming took place.
|
|
||||||
Also, all features were properly tested with CI/CD pipelines.
|
|
||||||
|
|
||||||
- Changed ChainRutValidator constructor signature. Now uses argument spreading.
|
|
||||||
- Added tests for ChainRutValidator
|
|
||||||
- SimpleRutValidator renamed to Module11RutValidator
|
|
||||||
- Now class Rut always validates itself with the SimpleRutValidator if no validator
|
|
||||||
is passed. This ensures object consistency.
|
|
||||||
- Added test coverage reports, code quality and CI testing
|
|
||||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2018 Matías Navarro Carter
|
Copyright (c) 2020 Matías Navarro Carter
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
237
README.md
237
README.md
@@ -1,220 +1,117 @@
|
|||||||
Rut Chileno
|
Rut Chileno
|
||||||
===========
|
===========
|
||||||
|
|
||||||
[](https://travis-ci.org/mnavarrocarter/chilean-rut)
|
Esta librería implementa una clase Rut como un sencillo *value object* inmutable.
|
||||||
[](https://codeclimate.com/github/mnavarrocarter/chilean-rut/maintainability)
|
|
||||||
[](https://codeclimate.com/github/mnavarrocarter/chilean-rut/test_coverage)
|
|
||||||
[](https://packagist.org/packages/mnavarrocarter/chilean-rut)
|
|
||||||
[](https://packagist.org/packages/mnavarrocarter/chilean-rut)
|
|
||||||
[](https://packagist.org/packages/mnavarrocarter/chilean-rut)
|
|
||||||
[](https://packagist.org/packages/mnavarrocarter/chilean-rut)
|
|
||||||
|
|
||||||
Esta librería implementa una clase Rut como un *value object* inmutable, incluyendo
|
Además, posee dos *types* para `doctrine/dbal`.
|
||||||
una api de validación flexible y extendible.
|
|
||||||
|
|
||||||
Además, posee un validador para `symfony/validator`, un *form type* para `symfony/form`
|
|
||||||
y un *type* para `doctrine/dbal`.
|
|
||||||
|
|
||||||
Sólo es compatible con PHP 7.1 o superior.
|
|
||||||
|
|
||||||
## Instalación
|
## Instalación
|
||||||
|
|
||||||
Esta libería funciona con composer:
|
Esta puede ser instalada mediante composer:
|
||||||
|
|
||||||
```
|
```
|
||||||
composer require mnavarrocarter/chilean-rut
|
composer require mnavarrocarter/chilean-rut
|
||||||
```
|
```
|
||||||
|
|
||||||
## Uso
|
## Uso
|
||||||
Simplemente instancia una nueva clase con un rut en cualquier formato:
|
|
||||||
|
### Parseando un Rut
|
||||||
|
|
||||||
|
La clase Rut es capaz de parsear cualquier tipo de rut sin importar el formato usando
|
||||||
|
el método `Rut::parse()`. Confiadamente, puedes poner el valor directamente de un
|
||||||
|
formulario web y `parse` se encargará de sanitizar el string y ver si el RUT es válido.
|
||||||
|
|
||||||
|
> NOTA: Un Rut se considera válido cuando su dígito verificador es algorítmicamente válido
|
||||||
|
> para el número. Esta libreria no puede validar que el Rut existe realmente.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use MNC\ChileanRut\Rut;
|
use MNC\Rut;
|
||||||
|
|
||||||
$rut = new Rut('23.546.565-4');
|
$rut = Rut::parse('23.546.565-4');
|
||||||
|
|
||||||
// Si prefieres, puedes usar el factory method
|
|
||||||
|
|
||||||
$rut = Rut::fromString('23546565-4');
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Por defecto, la clase Rut se valida usando el `Module11RutValidator` si no se pasa
|
### Validando el RUT
|
||||||
un validador personalizado al momento de instanciación. Esto es para asegurar la
|
|
||||||
integridad del objeto.
|
|
||||||
|
|
||||||
Si quieres, por alguna extraña razón, deshacerte de esa validación, puedes crear
|
> TLDR: Un objeto `Rut` siempre será valido.
|
||||||
un `AlwaysValidRutValidator` implementando la interfaz `RutValidator`. El método
|
|
||||||
validate estaría en blanco, lo que haría pasar la validación sin problema.
|
|
||||||
|
|
||||||
```php
|
Si tu RUT no es válido, el método `parse` lanzara una excepción de tipo
|
||||||
<?php
|
`MNC\Rut\IsInvalid`. Esto es para seguir buenos principios de *objects
|
||||||
use MNC\ChileanRut\Rut;
|
calisthenics*: un objeto de valor siempre se crea en un estado válido, y se mantiene
|
||||||
use MNC\ChileanRut\Validator\RutValidator;
|
válido a través de todo su ciclo de vida. No se permiten mutaciones que dejen el
|
||||||
|
objeto en un estado inválido.
|
||||||
|
|
||||||
class AlwaysValidRutValidator implements RutValidator
|
Por esta razón el objeto `MNC\Rut\IsInvalid` es completamente inmutable. Esto quiere decir
|
||||||
{
|
que una vez creado no puedes cambiar su estado interno: solo puedes leer información.
|
||||||
public function validate(Rut $rut) : void
|
Estos son los unicos métodos que puedes usar:
|
||||||
{
|
|
||||||
// Vacío a propósito
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Asi, la validación pasa sin problema.
|
|
||||||
$rut = new Rut('23.546.565-4', new AlwaysValidRutValidator());
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### Validación Personalizada de Rut
|
|
||||||
El `Module11RutValidator` no es más que la implementación del validador clásico de Rut,
|
|
||||||
el algoritmo de módulo 11. Esto verifica que un Rut es algoritmicamente correcto, pero
|
|
||||||
no valida que es real.
|
|
||||||
|
|
||||||
Por ello, proveemos la interfaz `RutValidator`. Con ella, puedes crear tus propias
|
|
||||||
reglas de validación, como llamar a un web service o consultar una base de datos
|
|
||||||
para verificar si un Rut es real o no. Te recomiendo mirar la interfaz para
|
|
||||||
implementarla correctamente.
|
|
||||||
|
|
||||||
De todas formas, aquí hay un ejemplo que va a buscar un rut a un web service.
|
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use MNC\ChileanRut\Validator\RutValidator;
|
use MNC\Rut;
|
||||||
use MNC\ChileanRut\Rut;
|
|
||||||
use MNC\ChileanRut\Exception\InvalidRutException;
|
|
||||||
use App\Rut\WebServiceRutChecker;
|
|
||||||
|
|
||||||
class MyCustomRutValidator implements RutValidator
|
$rut = Rut::parse('23.546.565-4');
|
||||||
{
|
|
||||||
private $rutChecker;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MyCustomRutValidator constructor.
|
|
||||||
* @param WebServiceRutChecker $rutChecker
|
|
||||||
*/
|
|
||||||
public function __construct(WebServiceRutChecker $rutChecker)
|
|
||||||
{
|
|
||||||
$this->rutChecker = $rutChecker;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Rut $rut
|
|
||||||
*/
|
|
||||||
public function validate(Rut $rut) : void
|
|
||||||
{
|
|
||||||
// Por debajo, esta clase ficticia haría una llamada a un web service preguntando
|
|
||||||
// si el Rut existe.
|
|
||||||
if ($this->rutChecker->doesRutExist($rut->format())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new InvalidRutException($rut, 'This rut does not exist');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
$rut->number; // (int) 23546565
|
||||||
|
$rut->verifier; // (MNC\Rut\Verifier::Four) 4
|
||||||
```
|
```
|
||||||
|
|
||||||
> NOTA: La implementación de cualquier validador DEBE arrojar un InvalidRutException cuando
|
### Formateando el Rut
|
||||||
el Rut no es válido. De lo contrario, el Rut se toma como válido.
|
|
||||||
|
|
||||||
### Usando múltiples validadores
|
Existen muchas formas distintas de formatear un RUT y esta librería soporta muchas
|
||||||
Proveemos un `ChainRutValidator` que puedes usar para validar un rut contra múltiples
|
de ellas. El método format devuelve un objeto al cual puedes encadenar llamadas para
|
||||||
validadores. Esto permite ejecutar cadenas de validación, como ver primero si un rut es
|
formatear el RUT y extraer su información de diversas maneras.
|
||||||
válido algorítmicamente antes de verificarlo contra un web service.
|
|
||||||
|
|
||||||
Usarlo es simple:
|
He aquí algunos ejemplos:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use MNC\ChileanRut\Rut;
|
use MNC\Rut;
|
||||||
use MNC\ChileanRut\Validator\ChainRutValidator;
|
|
||||||
use MNC\ChileanRut\Validator\SimpleRutValidator;
|
|
||||||
use App\Rut\DatabaseRutValidator;
|
|
||||||
|
|
||||||
$chainValidator = new ChainRutValidator(
|
$rut = Rut::parse('23.546.565-4');
|
||||||
new SimpleRutValidator(),
|
|
||||||
new DatabaseRutValidator()
|
|
||||||
);
|
|
||||||
|
|
||||||
$rut = new Rut('14.245.245-2');
|
echo $rut->toString(); // 235465654
|
||||||
|
echo $rut->toSimple(); // 23546565-4
|
||||||
$chainValidator->validate($rut);
|
echo $rut->toHuman(); // 23.546.565-4
|
||||||
|
echo $rut->last(4); // 6565
|
||||||
|
echo $rut->last(4, pad: '*'); // ****6565
|
||||||
|
echo $rut->first(4); // 2354
|
||||||
|
echo $rut->first(4, pad: '*'); // 2354****
|
||||||
```
|
```
|
||||||
|
|
||||||
### Formateando Ruts a String
|
## Integraciones con Librerías de Terceros
|
||||||
|
|
||||||
Una vez creado el objeto Rut, puedes formatearlo a string en el formato que tu quieras.
|
|
||||||
Esto se hace a través del método format y cómo parámetro acepta el valor
|
|
||||||
de una de las constantes `FORMAT_` de la clase Rut.
|
|
||||||
|
|
||||||
```php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
use MNC\ChileanRut\Rut;
|
|
||||||
|
|
||||||
$rut = new Rut('34244223-4');
|
|
||||||
|
|
||||||
echo $rut->format(Rut::FORMAT_CLEAR); // Va a imprimir 342442234
|
|
||||||
echo $rut->format(Rut::FORMAT_READABLE); // Va a imprimir 34.244.223-4
|
|
||||||
echo $rut->format(Rut::FORMAT_HYPHENED); // Va a imprimir 34244223-4
|
|
||||||
echo $rut->format(Rut::FORMAT_HIDDEN); // Va a imprimir 34.***.***-4
|
|
||||||
```
|
|
||||||
|
|
||||||
### Utilidades
|
|
||||||
Esta librería provee una clase llamada `CorrelativeUtils` que tiene algunas utilidades
|
|
||||||
interesantes. Posee tres métodos:
|
|
||||||
|
|
||||||
```php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
use MNC\ChileanRut\Util\CorrelativeUtils;
|
|
||||||
|
|
||||||
// Este método devuelve el digito verificador de un correlativo.
|
|
||||||
CorrelativeUtils::findVerifierDigit('34525252');
|
|
||||||
|
|
||||||
// Este método devuelve una instancia de Rut válida, sólo con el correlativo.
|
|
||||||
CorrelativeUtils::createValidRutOnlyFromCorrelative('34525252');
|
|
||||||
|
|
||||||
// Este método devuelve instancia de Rut autogenerada algoritmicamente válida.
|
|
||||||
CorrelativeUtils::autoGenerateValidRut();
|
|
||||||
```
|
|
||||||
|
|
||||||
## Integraciones con Liberías de Terceros
|
|
||||||
|
|
||||||
### Doctrine DBAL
|
### Doctrine DBAL
|
||||||
Esta libería provee un custom type para doctrine llamado `RutType`. Puedes registrarla
|
Esta librería provee dos [*Custom Types*](https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/cookbook/custom-mapping-types.html)
|
||||||
en el Dbal para usarla en tus mappings de doctrine y automáticamente mappear tu
|
para Doctrine, con el objetivo de que puedas mapear tus objetos `Rut` fácilmente
|
||||||
el valor de tu db a un objeto rut.
|
a una base de datos relacional.
|
||||||
|
|
||||||
### Symfony Validator
|
`MNC\Rut\Doctrine\RutType` mapea tu RUT a una columna VARCHAR.
|
||||||
Además, esta libería cuenta con un validador para Symfony Validator, que te
|
El string se guarda con puntos y guion. Ex: `16.894.365-2`. Es una forma no tan
|
||||||
permite beneficiarte de las anotaciones del componente de validación de Symfony.
|
eficiente de guardar los RUTS (en términos de espacio), pero ayuda mucho cuando
|
||||||
Como dependencia opcional necesita una instancia de `RutValidator`. Si ninguna es proveída,
|
se visualiza o exporta la base de datos a otras fuentes.
|
||||||
se utiliza el `SimpleRutValidator`. Solo puedes usar el validador contra una instancia de `Rut`.
|
|
||||||
|
|
||||||
### Symfony Form Type
|
`MNC\Rut\Doctrine\NumericRutType` mapea tu RUT a una columna INTEGER.
|
||||||
Por último, esta libería cuenta con un Symfony Form Type que puedes añadir en tus
|
El número se guarda sin dígito verificador y es recalculado cuando la columna
|
||||||
formularios HTML, para que puedas autoinstanciar la clase y poner lógica de
|
es transformada a un valor PHP. Esta forma de guardar ruts es muy eficiente (en
|
||||||
validación en ella sin problema, y añadirla a tus otros tipos.
|
términos de espacio), pero cuesta comparar y leer los números si visualizas o
|
||||||
|
exportas los registros en la base de datos.
|
||||||
|
|
||||||
|
Por supuesto, puedes elegir el `Type` que más se ajuste a tus necesidades.
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
### ¿Cómo nació y por qué esta librería?
|
### ¿Por qué esta librería?
|
||||||
Esta libería nace de la necesidad de estandarizar una clase Rut común para todos mis proyectos
|
Esta librería nace de la necesidad de estandarizar una clase Rut común para todos
|
||||||
PHP.
|
mis proyectos PHP.
|
||||||
Si bien es cierto, hay muchas liberías con implementaciones de Rut chilenos en PHP,
|
|
||||||
|
Si bien es cierto, hay muchas librerías con implementaciones de Rut chilenos en PHP,
|
||||||
muchas de ellas tienen notorias deficiencias:
|
muchas de ellas tienen notorias deficiencias:
|
||||||
|
|
||||||
1. No están testeadas unitariamente,
|
1. No están testeadas unitariamente.
|
||||||
2. No separan bien responsabilidades, como la lógica de validación con la de instanciación.
|
2. No estan tipadas apropiadamente
|
||||||
3. No proveen validación extensible por medio de interfaces, limitando la validación
|
3. No tienen un buen diseño y sus apis tienen efectos secundarios.
|
||||||
solo a ser algorítmica.
|
4. Están acopladas a un framework (Laravel Rut y otras hierbas)
|
||||||
4. Están acopladas a un framework
|
5. No proveen herramientas ni integraciones con librerías de terceros, como Doctrine.
|
||||||
5. No proveen herramientas ni integraciones con librerías de terceros.
|
|
||||||
|
|
||||||
### ¿Por qué PHP 7.1?
|
|
||||||
El fin del soporte de PHP 5.6 será a fines de 2018. PHP 7.1 es una de las últimas
|
|
||||||
versiones estables, y me beneficio mucho de su sistema de tipado estricto en esta libería.
|
|
||||||
|
|
||||||
|
|||||||
27
compose.yml
Normal file
27
compose.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
name: "mnavarro"
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
chilean-rut: &php
|
||||||
|
image: mnavarro/chilean-rut:dev
|
||||||
|
build:
|
||||||
|
context: .dev/docker/php
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
target: dev
|
||||||
|
args:
|
||||||
|
UID: ${UID:-1000}
|
||||||
|
user: ${UID:-1000}
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
chilean-rut-init:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
working_dir: /mnavarro/chilean-rut
|
||||||
|
volumes:
|
||||||
|
- ./:/mnavarro/chilean-rut
|
||||||
|
command: ["php", "-S", "0.0.0.0:8000", "-t", ".dev/coverage"]
|
||||||
|
|
||||||
|
chilean-rut-init:
|
||||||
|
<<: *php
|
||||||
|
depends_on: []
|
||||||
|
restart: no
|
||||||
|
command: [".dev/init"]
|
||||||
@@ -3,36 +3,46 @@
|
|||||||
"description": "PHP Rut Value Object with validation utilities, doctrine type, and other cool features.",
|
"description": "PHP Rut Value Object with validation utilities, doctrine type, and other cool features.",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"prefer-stable": true,
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Matias Navarro Carter",
|
"name": "Matias Navarro-Carter",
|
||||||
"email": "mnavarro@option.cl"
|
"email": "mnavarrocarter@gmail.com",
|
||||||
|
"role": "Lead Maintainer"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"minimum-stability": "stable",
|
|
||||||
"require": {
|
|
||||||
"php": "^7.1"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"friendsofphp/php-cs-fixer": "^2.12",
|
|
||||||
"phpunit/phpunit": "^7.3",
|
|
||||||
"doctrine/dbal": "^2.5",
|
|
||||||
"symfony/form": "^3.4|^4.0",
|
|
||||||
"symfony/validator": "^3.4|^4.0",
|
|
||||||
"symfony/var-dumper": "^4.1"
|
|
||||||
},
|
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"MNC\\ChileanRut\\": "src/"
|
"MNC\\": "src"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"MNC\\ChileanRut\\Tests\\": "tests"
|
"MNC\\": "tests"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^10.5",
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.49",
|
||||||
|
"vimeo/psalm": "^5.22",
|
||||||
|
"doctrine/dbal": "^2.10.1|^3.0"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "@php vendor/bin/phpunit --verbose --coverage-text --coverage-clover build/logs/clover.xml",
|
"pr": ["@fmt", "@psalm", "@test"],
|
||||||
"style": "@php vendor/bin/php-cs-fixer fix"
|
"ci": ["@fmt:check", "@psalm:gh", "@test"],
|
||||||
|
"fmt": "php-cs-fixer fix --diff --ansi",
|
||||||
|
"fmt:check": "php-cs-fixer fix --dry-run --diff --ansi",
|
||||||
|
"test": ["phpunit --colors"],
|
||||||
|
"test:unit": "phpunit --colors --exclude-group=integration --exclude-group=e2e",
|
||||||
|
"test:e2e": "phpunit --colors --group=e2e",
|
||||||
|
"test:integration": "phpunit --colors --group=integration",
|
||||||
|
"psalm": "psalm --no-cache --threads=5 --use-baseline",
|
||||||
|
"psalm:gh": "psalm --no-cache --threads=5 --long-progress --output-format=github --use-baseline",
|
||||||
|
"psalm:fix": "psalm --update-baseline",
|
||||||
|
"psalm:allow": "psalm --set-baseline=psalm-baseline.xml"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4635
composer.lock
generated
Normal file
4635
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
29
phpunit.xml
Normal file
29
phpunit.xml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
|
||||||
|
bootstrap="vendor/autoload.php"
|
||||||
|
executionOrder="depends,defects"
|
||||||
|
requireCoverageMetadata="true"
|
||||||
|
beStrictAboutCoverageMetadata="true"
|
||||||
|
beStrictAboutOutputDuringTests="true"
|
||||||
|
failOnRisky="true"
|
||||||
|
cacheResultFile="/tmp/phpunit.result.cache"
|
||||||
|
failOnWarning="true">
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="main">
|
||||||
|
<directory>tests</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<source restrictDeprecations="true" restrictNotices="true" restrictWarnings="true">
|
||||||
|
<include>
|
||||||
|
<directory>src</directory>
|
||||||
|
</include>
|
||||||
|
</source>
|
||||||
|
|
||||||
|
<coverage>
|
||||||
|
<report>
|
||||||
|
<html outputDirectory=".dev/coverage"/>
|
||||||
|
</report>
|
||||||
|
</coverage>
|
||||||
|
</phpunit>
|
||||||
@@ -1,25 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" backupStaticAttributes="false"
|
||||||
<phpunit backupGlobals="false"
|
colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true"
|
||||||
backupStaticAttributes="false"
|
convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false"
|
||||||
colors="true"
|
bootstrap="vendor/autoload.php" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
|
||||||
convertErrorsToExceptions="true"
|
<coverage>
|
||||||
convertNoticesToExceptions="true"
|
<include>
|
||||||
convertWarningsToExceptions="true"
|
<directory>./src</directory>
|
||||||
processIsolation="false"
|
</include>
|
||||||
stopOnFailure="false"
|
</coverage>
|
||||||
bootstrap="vendor/autoload.php"
|
|
||||||
>
|
|
||||||
<testsuites>
|
<testsuites>
|
||||||
<testsuite name="Test Suite">
|
<testsuite name="Test Suite">
|
||||||
<directory suffix="Test.php">./tests</directory>
|
<directory suffix="Test.php">./tests</directory>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
||||||
<filter>
|
|
||||||
<whitelist>
|
|
||||||
<directory>./src</directory>
|
|
||||||
</whitelist>
|
|
||||||
</filter>
|
|
||||||
|
|
||||||
</phpunit>
|
</phpunit>
|
||||||
8
psalm-baseline.xml
Normal file
8
psalm-baseline.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<files psalm-version="5.22.2@d768d914152dbbf3486c36398802f74e80cfde48">
|
||||||
|
<file src="src/Rut/Doctrine/NumericRutType.php">
|
||||||
|
<ImplementedReturnTypeMismatch>
|
||||||
|
<code><![CDATA[?Rut]]></code>
|
||||||
|
</ImplementedReturnTypeMismatch>
|
||||||
|
</file>
|
||||||
|
</files>
|
||||||
17
psalm.xml
Normal file
17
psalm.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<psalm
|
||||||
|
errorLevel="1"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="https://getpsalm.org/schema/config"
|
||||||
|
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
|
||||||
|
findUnusedBaselineEntry="true"
|
||||||
|
findUnusedCode="false"
|
||||||
|
errorBaseline="psalm-baseline.xml"
|
||||||
|
>
|
||||||
|
<projectFiles>
|
||||||
|
<directory name="src" />
|
||||||
|
<ignoreFiles>
|
||||||
|
<directory name="vendor" />
|
||||||
|
</ignoreFiles>
|
||||||
|
</projectFiles>
|
||||||
|
</psalm>
|
||||||
54
psalm.xml.dist
Normal file
54
psalm.xml.dist
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<psalm
|
||||||
|
totallyTyped="false"
|
||||||
|
resolveFromConfigFile="true"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="https://getpsalm.org/schema/config"
|
||||||
|
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
|
||||||
|
>
|
||||||
|
<projectFiles>
|
||||||
|
<directory name="src" />
|
||||||
|
<ignoreFiles>
|
||||||
|
<directory name="vendor" />
|
||||||
|
</ignoreFiles>
|
||||||
|
</projectFiles>
|
||||||
|
|
||||||
|
<issueHandlers>
|
||||||
|
<LessSpecificReturnType errorLevel="info" />
|
||||||
|
|
||||||
|
<!-- level 3 issues - slightly lazy code writing, but provably low false-negatives -->
|
||||||
|
|
||||||
|
<DeprecatedMethod errorLevel="info" />
|
||||||
|
<DeprecatedProperty errorLevel="info" />
|
||||||
|
<DeprecatedClass errorLevel="info" />
|
||||||
|
<DeprecatedConstant errorLevel="info" />
|
||||||
|
<DeprecatedFunction errorLevel="info" />
|
||||||
|
<DeprecatedInterface errorLevel="info" />
|
||||||
|
<DeprecatedTrait errorLevel="info" />
|
||||||
|
|
||||||
|
<InternalMethod errorLevel="info" />
|
||||||
|
<InternalProperty errorLevel="info" />
|
||||||
|
<InternalClass errorLevel="info" />
|
||||||
|
|
||||||
|
<MissingClosureReturnType errorLevel="info" />
|
||||||
|
<MissingReturnType errorLevel="info" />
|
||||||
|
<MissingPropertyType errorLevel="info" />
|
||||||
|
<InvalidDocblock errorLevel="info" />
|
||||||
|
|
||||||
|
<PropertyNotSetInConstructor errorLevel="info" />
|
||||||
|
<MissingConstructor errorLevel="info" />
|
||||||
|
<MissingClosureParamType errorLevel="info" />
|
||||||
|
<MissingParamType errorLevel="info" />
|
||||||
|
|
||||||
|
<RedundantCondition errorLevel="info" />
|
||||||
|
|
||||||
|
<DocblockTypeContradiction errorLevel="info" />
|
||||||
|
<RedundantConditionGivenDocblockType errorLevel="info" />
|
||||||
|
|
||||||
|
<UnresolvableInclude errorLevel="info" />
|
||||||
|
|
||||||
|
<RawObjectIteration errorLevel="info" />
|
||||||
|
|
||||||
|
<InvalidStringClass errorLevel="info" />
|
||||||
|
</issueHandlers>
|
||||||
|
</psalm>
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
*
|
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MNC\ChileanRut\Bridge\Doctrine\DBAL\Types;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
|
||||||
use Doctrine\DBAL\Types\ConversionException;
|
|
||||||
use Doctrine\DBAL\Types\StringType;
|
|
||||||
use MNC\ChileanRut\Rut;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class RutType.
|
|
||||||
*
|
|
||||||
* @author Matías Navarro Carter <mnavarro@option.cl>
|
|
||||||
*/
|
|
||||||
class RutType extends StringType
|
|
||||||
{
|
|
||||||
public const NAME = 'rut';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getName(): string
|
|
||||||
{
|
|
||||||
return self::NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mixed $value
|
|
||||||
* @param AbstractPlatform $platform
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*
|
|
||||||
* @throws ConversionException
|
|
||||||
*/
|
|
||||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
|
||||||
{
|
|
||||||
if (null === $value) {
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($value instanceof Rut) {
|
|
||||||
return $value->format(Rut::FORMAT_HYPHENED);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', Rut::class]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mixed $value
|
|
||||||
* @param AbstractPlatform $platform
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function convertToPHPValue($value, AbstractPlatform $platform)
|
|
||||||
{
|
|
||||||
if (null === $value || $value instanceof Rut) {
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Rut($value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
*
|
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MNC\ChileanRut\Bridge\Symfony\Form;
|
|
||||||
|
|
||||||
use MNC\ChileanRut\Rut;
|
|
||||||
use Symfony\Component\Form\AbstractType;
|
|
||||||
use Symfony\Component\Form\DataTransformerInterface;
|
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
|
||||||
use Symfony\Component\Form\FormInterface;
|
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class RutType.
|
|
||||||
*
|
|
||||||
* @author Matías Navarro Carter <mnavarro@option.cl>
|
|
||||||
*/
|
|
||||||
class RutType extends AbstractType implements DataTransformerInterface
|
|
||||||
{
|
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
|
||||||
{
|
|
||||||
$builder->addModelTransformer($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param OptionsResolver $resolver
|
|
||||||
*/
|
|
||||||
public function configureOptions(OptionsResolver $resolver): void
|
|
||||||
{
|
|
||||||
$resolver->setDefaults([
|
|
||||||
'compound' => false,
|
|
||||||
'data_class' => Rut::class,
|
|
||||||
'empty_data' => function (FormInterface $form) {
|
|
||||||
return new Rut($form->getData());
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function getBlockPrefix(): ?string
|
|
||||||
{
|
|
||||||
return 'rut';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mixed $value
|
|
||||||
*
|
|
||||||
* @return mixed|string
|
|
||||||
*/
|
|
||||||
public function transform($value)
|
|
||||||
{
|
|
||||||
if ($value instanceof Rut) {
|
|
||||||
return $value->format(Rut::FORMAT_READABLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mixed $value
|
|
||||||
*
|
|
||||||
* @return mixed|Rut
|
|
||||||
*/
|
|
||||||
public function reverseTransform($value)
|
|
||||||
{
|
|
||||||
return new Rut((string) $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
*
|
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MNC\ChileanRut\Bridge\Symfony\Validator;
|
|
||||||
|
|
||||||
use Symfony\Component\Validator\Constraint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
*/
|
|
||||||
class IsValidRut extends Constraint
|
|
||||||
{
|
|
||||||
public $message = '"{{value}}" is not a valid Rut.';
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
*
|
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MNC\ChileanRut\Bridge\Symfony\Validator;
|
|
||||||
|
|
||||||
use MNC\ChileanRut\Exception\InvalidRutException;
|
|
||||||
use MNC\ChileanRut\Rut;
|
|
||||||
use MNC\ChileanRut\Validator\Module11RutValidator;
|
|
||||||
use MNC\ChileanRut\Validator\RutValidator;
|
|
||||||
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
|
||||||
use Symfony\Component\Validator\Constraint;
|
|
||||||
use Symfony\Component\Validator\ConstraintValidator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class IsValidRutValidator.
|
|
||||||
*
|
|
||||||
* @author Matías Navarro Carter <mnavarro@option.cl>
|
|
||||||
*/
|
|
||||||
class IsValidRutValidator extends ConstraintValidator
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var RutValidator
|
|
||||||
*/
|
|
||||||
private $validator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IsValidRutValidator constructor.
|
|
||||||
*
|
|
||||||
* @param RutValidator|null $validator
|
|
||||||
*/
|
|
||||||
public function __construct(RutValidator $validator = null)
|
|
||||||
{
|
|
||||||
$this->validator = $validator ?? new Module11RutValidator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mixed $value
|
|
||||||
* @param Constraint $constraint
|
|
||||||
*/
|
|
||||||
public function validate($value, Constraint $constraint): void
|
|
||||||
{
|
|
||||||
if (null === $value || '' === $value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$value instanceof Rut) {
|
|
||||||
throw new UnexpectedTypeException($value, Rut::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->validator->validate($value);
|
|
||||||
} catch (InvalidRutException $exception) {
|
|
||||||
$this->context->buildViolation($constraint->message)
|
|
||||||
->setParameter('{{ value }}', $value->format(Rut::FORMAT_CLEAR))
|
|
||||||
->addViolation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
*
|
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MNC\ChileanRut\Exception;
|
|
||||||
|
|
||||||
use MNC\ChileanRut\Rut;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class InvalidRutException.
|
|
||||||
*
|
|
||||||
* @author Matías Navarro Carter <mnavarro@option.cl>
|
|
||||||
*/
|
|
||||||
class InvalidRutException extends \LogicException
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var Rut
|
|
||||||
*/
|
|
||||||
private $rut;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* InvalidRutException constructor.
|
|
||||||
*
|
|
||||||
* @param Rut $rut
|
|
||||||
* @param string|null $message
|
|
||||||
*/
|
|
||||||
public function __construct(Rut $rut, string $message = null)
|
|
||||||
{
|
|
||||||
if (null === $message) {
|
|
||||||
$message = sprintf('Rut %s is not a valid rut.', $rut->format(Rut::FORMAT_READABLE));
|
|
||||||
}
|
|
||||||
$this->rut = $rut;
|
|
||||||
parent::__construct($message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Rut
|
|
||||||
*/
|
|
||||||
public function getRut(): Rut
|
|
||||||
{
|
|
||||||
return $this->rut;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
268
src/Rut.php
268
src/Rut.php
@@ -1,193 +1,175 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
declare(strict_types=1);
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
|
/**
|
||||||
|
* @project Chilean RUT
|
||||||
|
* @link https://github.com/mnavarrocarter/chilean-rut
|
||||||
|
* @package castor/log
|
||||||
|
* @author Matias Navarro-Carter mnavarrocarter@gmail.com
|
||||||
|
* @license MIT
|
||||||
|
* @copyright 2024 Matias Navarro-Carter
|
||||||
*
|
*
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
* For the full copyright and license information, please view the LICENSE
|
||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace MNC\ChileanRut;
|
namespace MNC;
|
||||||
|
|
||||||
use MNC\ChileanRut\Validator\Module11RutValidator;
|
use MNC\Rut\Verifier;
|
||||||
use MNC\ChileanRut\Validator\RutValidator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rut represents a the Chilean National ID Number.
|
* Esta clase representa un RUT.
|
||||||
*
|
*
|
||||||
* All residents of Chile are uniquely identified by one of these.
|
* Una vez creado, el RUT es siempre valido
|
||||||
*
|
|
||||||
* @author Matías Navarro Carter <mnavarro@option.cl>
|
|
||||||
*/
|
*/
|
||||||
class Rut
|
final readonly class Rut
|
||||||
{
|
{
|
||||||
public const FORMAT_HYPHENED = 0; // 14533535-5
|
private const MAX_NUMBER = 999_999_999;
|
||||||
public const FORMAT_CLEAR = 1; // 145335355
|
private const MIN_NUMBER = 0;
|
||||||
public const FORMAT_READABLE = 2; // 14.533.535-5
|
|
||||||
public const FORMAT_HIDDEN = 3; // 17.***.***-5
|
private function __construct(
|
||||||
|
public int $number,
|
||||||
|
public Verifier $verifier
|
||||||
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* Parsea un objeto RUT a partir de una cadena de texto.
|
||||||
*/
|
|
||||||
private $value;
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $dv;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rut constructor.
|
|
||||||
*
|
*
|
||||||
* @param string $rut
|
* El RUT DEBE contener el digito verificador.
|
||||||
* @param RutValidator|null $validator if provided validates the Rut
|
*
|
||||||
|
* Si no se cuenta con el verificador, el metodo create debe ser usado.
|
||||||
|
*
|
||||||
|
* @see Rut::create
|
||||||
|
*
|
||||||
|
* @throws Rut\IsInvalid si el RUT no es valido
|
||||||
*/
|
*/
|
||||||
public function __construct(string $rut, RutValidator $validator = null)
|
public static function parse(string $rut): Rut
|
||||||
{
|
{
|
||||||
$sanitized = $this->sanitize($rut);
|
// Remove space, dots and hyphens
|
||||||
$this->value = substr($sanitized, 0, -1);
|
$rut = \str_replace([' ', '.', '-'], '', $rut);
|
||||||
$this->dv = $sanitized[\strlen($sanitized) - 1];
|
|
||||||
|
|
||||||
if (!$validator instanceof RutValidator) {
|
return self::create(
|
||||||
$validator = new Module11RutValidator();
|
(int) \substr($rut, 0, -1),
|
||||||
}
|
Verifier::fromString(\substr($rut, -1))
|
||||||
$validator->validate($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Casts the Rut object into a string.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString(): string
|
|
||||||
{
|
|
||||||
return $this->format(self::FORMAT_READABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Rut instance from the correlative and the verifier digit.
|
|
||||||
*
|
|
||||||
* @param string $correlative
|
|
||||||
* @param string $verifierDigit
|
|
||||||
* @param RutValidator|null $validator
|
|
||||||
*
|
|
||||||
* @return Rut
|
|
||||||
*/
|
|
||||||
public static function fromParts(string $correlative, string $verifierDigit, RutValidator $validator = null): Rut
|
|
||||||
{
|
|
||||||
return new self($correlative.$verifierDigit, $validator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance of Rut from a string.
|
|
||||||
*
|
|
||||||
* @param string $rut
|
|
||||||
* @param RutValidator|null $validator
|
|
||||||
*
|
|
||||||
* @return Rut
|
|
||||||
*/
|
|
||||||
public static function fromString(string $rut, RutValidator $validator = null): Rut
|
|
||||||
{
|
|
||||||
return new self($rut, $validator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares whether a Rut is equal to another or not.
|
|
||||||
*
|
|
||||||
* @param Rut $rut
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isEqualTo(Rut $rut): bool
|
|
||||||
{
|
|
||||||
return $this->format() === $rut->format();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats a Rut to a string.
|
|
||||||
*
|
|
||||||
* @param int $format one of the FORMAT_ constants
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function format(int $format = 0): string
|
|
||||||
{
|
|
||||||
switch ($format) {
|
|
||||||
case self::FORMAT_HYPHENED:
|
|
||||||
return $this->value.'-'.$this->dv;
|
|
||||||
break;
|
|
||||||
case self::FORMAT_CLEAR:
|
|
||||||
return $this->value.$this->dv;
|
|
||||||
break;
|
|
||||||
case self::FORMAT_READABLE:
|
|
||||||
return $this->formatReadable();
|
|
||||||
break;
|
|
||||||
case self::FORMAT_HIDDEN:
|
|
||||||
return $this->formatHidden();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new \InvalidArgumentException(
|
|
||||||
sprintf(
|
|
||||||
'Argument provided for %s method of class %s is invalid.',
|
|
||||||
__METHOD__,
|
|
||||||
__CLASS__
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea un objeto RUT.
|
||||||
|
*
|
||||||
|
* El digito verificador es opcional. Cuando es recibido, es validado.
|
||||||
|
*
|
||||||
|
* Si el digito verificador no es provisto, es generado automáticamente.
|
||||||
|
*
|
||||||
|
* @throws Rut\IsInvalid si el Rut es invalido
|
||||||
|
*/
|
||||||
|
public static function create(int $number, ?Verifier $verifier = null): self
|
||||||
|
{
|
||||||
|
if ($number < self::MIN_NUMBER) {
|
||||||
|
throw Rut\IsInvalid::numberTooSmall($number);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($number > self::MAX_NUMBER) {
|
||||||
|
throw Rut\IsInvalid::numberTooBig($number);
|
||||||
|
}
|
||||||
|
|
||||||
|
$computed = self::computeVerifier($number);
|
||||||
|
if ($verifier === null) {
|
||||||
|
return new self($number, $computed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($computed !== $verifier) {
|
||||||
|
throw Rut\IsInvalid::rut($number, $verifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new self($number, $verifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the correlative number of the Rut.
|
* Compara si un RUT es igual a otro o no.
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function getCorrelative(): string
|
public function equals(Rut $rut): bool
|
||||||
{
|
{
|
||||||
return $this->value;
|
return $this->number === $rut->number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the verifier digit of the Rut.
|
* Retorna el RUT en formato "12345678K".
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function getVerifierDigit(): string
|
public function toString(): string
|
||||||
{
|
{
|
||||||
return $this->dv;
|
return $this->number.$this->verifier->toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sanitizes a Rut string.
|
* Retorna el RUT en formato "12345678-K".
|
||||||
*
|
|
||||||
* @param string $value
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
private function sanitize(string $value): string
|
public function toSimple(): string
|
||||||
{
|
{
|
||||||
return str_replace(['.', ',', '-'], '', strtoupper(trim($value)));
|
return $this->number.'-'.$this->verifier->toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to format the Rut as FORMAT_READABLE.
|
* Retorna el RUT en formato "12.345.678-K".
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
private function formatReadable(): string
|
public function toHuman(): string
|
||||||
{
|
{
|
||||||
return sprintf('%s-%s', number_format($this->value, 0, '', '.'), $this->dv);
|
return \number_format($this->number, 0, ',', '.').'-'.$this->verifier->toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to format the Rut as FORMAT_HIDDEN.
|
* Retorna los $n ultimos numeros del RUT.
|
||||||
*
|
*
|
||||||
* @return string
|
* El digito verificador no es considerado.
|
||||||
*/
|
*/
|
||||||
private function formatHidden(): string
|
public function last(int $n, string $pad = ''): string
|
||||||
{
|
{
|
||||||
$readable = $this->formatReadable();
|
$number = (string) $this->number;
|
||||||
$exploded = explode('.', $readable);
|
$last = \substr($number, -$n);
|
||||||
|
if ($pad !== '') {
|
||||||
|
$last = \str_repeat($pad, \strlen($number) - $n).$last;
|
||||||
|
}
|
||||||
|
|
||||||
return sprintf('%s.***.***-%s', $exploded[0], $this->dv);
|
return $last;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retorna los $n primeros numeros del RUT.
|
||||||
|
*
|
||||||
|
* El digito verificador no es considerado.
|
||||||
|
*/
|
||||||
|
public function first(int $n, string $pad = ''): string
|
||||||
|
{
|
||||||
|
$number = (string) $this->number;
|
||||||
|
$first = \substr($number, 0, $n);
|
||||||
|
if ($pad !== '') {
|
||||||
|
$first .= \str_repeat($pad, \strlen($number) - $n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $first;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computa el digito verificador de un RUT a partir del numero.
|
||||||
|
*/
|
||||||
|
public static function computeVerifier(int $number): Verifier
|
||||||
|
{
|
||||||
|
$sequence = \array_reverse(\array_map(
|
||||||
|
static fn (string $d): int => (int) $d,
|
||||||
|
\str_split((string) $number)
|
||||||
|
));
|
||||||
|
|
||||||
|
$x = 2;
|
||||||
|
$s = 0;
|
||||||
|
foreach ($sequence as $digit) {
|
||||||
|
if ($x > 7) {
|
||||||
|
$x = 2;
|
||||||
|
}
|
||||||
|
$s += $digit * $x;
|
||||||
|
++$x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Verifier::from(11 - ($s % 11));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
74
src/Rut/Doctrine/NumericRutType.php
Normal file
74
src/Rut/Doctrine/NumericRutType.php
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @project Chilean RUT
|
||||||
|
* @link https://github.com/mnavarrocarter/chilean-rut
|
||||||
|
* @package castor/log
|
||||||
|
* @author Matias Navarro-Carter mnavarrocarter@gmail.com
|
||||||
|
* @license MIT
|
||||||
|
* @copyright 2024 Matias Navarro-Carter
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MNC\Rut\Doctrine;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||||
|
use Doctrine\DBAL\Types\ConversionException;
|
||||||
|
use Doctrine\DBAL\Types\IntegerType;
|
||||||
|
use MNC\Rut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapea el Rut a una columna integer.
|
||||||
|
*/
|
||||||
|
class NumericRutType extends IntegerType
|
||||||
|
{
|
||||||
|
public const NAME = 'numeric-rut';
|
||||||
|
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
return self::NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
*
|
||||||
|
* @throws ConversionException
|
||||||
|
*/
|
||||||
|
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
|
||||||
|
{
|
||||||
|
if ($value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value instanceof Rut) {
|
||||||
|
return (string) $value->number;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', Rut::class]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
*
|
||||||
|
* @throws ConversionException
|
||||||
|
*/
|
||||||
|
public function convertToPHPValue($value, AbstractPlatform $platform): ?Rut
|
||||||
|
{
|
||||||
|
$value = parent::convertToPHPValue($value, $platform);
|
||||||
|
|
||||||
|
if ($value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Rut::create($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requiresSQLCommentHint(AbstractPlatform $platform): true
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
76
src/Rut/Doctrine/RutType.php
Normal file
76
src/Rut/Doctrine/RutType.php
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @project Chilean RUT
|
||||||
|
* @link https://github.com/mnavarrocarter/chilean-rut
|
||||||
|
* @package castor/log
|
||||||
|
* @author Matias Navarro-Carter mnavarrocarter@gmail.com
|
||||||
|
* @license MIT
|
||||||
|
* @copyright 2024 Matias Navarro-Carter
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MNC\Rut\Doctrine;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||||
|
use Doctrine\DBAL\Types\ConversionException;
|
||||||
|
use Doctrine\DBAL\Types\StringType;
|
||||||
|
use MNC\Rut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapea el RUT a una columna VARCHAR.
|
||||||
|
*/
|
||||||
|
class RutType extends StringType
|
||||||
|
{
|
||||||
|
public const NAME = 'rut';
|
||||||
|
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
return self::NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
*
|
||||||
|
* @throws ConversionException
|
||||||
|
*/
|
||||||
|
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
|
||||||
|
{
|
||||||
|
if ($value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value instanceof Rut) {
|
||||||
|
return $value->toHuman();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', Rut::class]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
*
|
||||||
|
* @throws ConversionException
|
||||||
|
*/
|
||||||
|
public function convertToPHPValue($value, AbstractPlatform $platform): ?Rut
|
||||||
|
{
|
||||||
|
if ($value === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\is_string($value)) {
|
||||||
|
return Rut::parse($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'string']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requiresSQLCommentHint(AbstractPlatform $platform): true
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/Rut/IsInvalid.php
Normal file
53
src/Rut/IsInvalid.php
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @project Chilean RUT
|
||||||
|
* @link https://github.com/mnavarrocarter/chilean-rut
|
||||||
|
* @package castor/log
|
||||||
|
* @author Matias Navarro-Carter mnavarrocarter@gmail.com
|
||||||
|
* @license MIT
|
||||||
|
* @copyright 2024 Matias Navarro-Carter
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MNC\Rut;
|
||||||
|
|
||||||
|
class IsInvalid extends \InvalidArgumentException
|
||||||
|
{
|
||||||
|
public static function numberTooBig(int $number): IsInvalid
|
||||||
|
{
|
||||||
|
return new self(\sprintf(
|
||||||
|
'El RUT numero %d es mayor a 99.999.999',
|
||||||
|
$number
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function numberTooSmall(int $number): IsInvalid
|
||||||
|
{
|
||||||
|
return new self(\sprintf(
|
||||||
|
'El RUT numero %d es menor a cero',
|
||||||
|
$number
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function rut(int $number, Verifier $verifier): IsInvalid
|
||||||
|
{
|
||||||
|
return new self(\sprintf(
|
||||||
|
'El digito verificador %s no es valido para el rut %d',
|
||||||
|
$verifier->toString(),
|
||||||
|
$number
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function verifier(string $verifier): IsInvalid
|
||||||
|
{
|
||||||
|
return new self(\sprintf(
|
||||||
|
'Encontrado un digito verificador invalido con valor %s',
|
||||||
|
$verifier,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
78
src/Rut/Verifier.php
Normal file
78
src/Rut/Verifier.php
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @project Chilean RUT
|
||||||
|
* @link https://github.com/mnavarrocarter/chilean-rut
|
||||||
|
* @package castor/log
|
||||||
|
* @author Matias Navarro-Carter mnavarrocarter@gmail.com
|
||||||
|
* @license MIT
|
||||||
|
* @copyright 2024 Matias Navarro-Carter
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MNC\Rut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representa el digito verificador de un RUT.
|
||||||
|
*
|
||||||
|
* Internamente, se guarda el modulo del RUT, y no su valor como texto.
|
||||||
|
*/
|
||||||
|
enum Verifier: int
|
||||||
|
{
|
||||||
|
case One = 1;
|
||||||
|
case Two = 2;
|
||||||
|
case Three = 3;
|
||||||
|
case Four = 4;
|
||||||
|
case Five = 5;
|
||||||
|
case Six = 6;
|
||||||
|
case Seven = 7;
|
||||||
|
case Eight = 8;
|
||||||
|
case Nine = 9;
|
||||||
|
case K = 10;
|
||||||
|
case Zero = 11;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws IsInvalid si el verificador es invalido
|
||||||
|
*/
|
||||||
|
public static function fromString(string $v): Verifier
|
||||||
|
{
|
||||||
|
return match ($v) {
|
||||||
|
'1' => self::One,
|
||||||
|
'2' => self::Two,
|
||||||
|
'3' => self::Three,
|
||||||
|
'4' => self::Four,
|
||||||
|
'5' => self::Five,
|
||||||
|
'6' => self::Six,
|
||||||
|
'7' => self::Seven,
|
||||||
|
'8' => self::Eight,
|
||||||
|
'9' => self::Nine,
|
||||||
|
'0' => self::Zero,
|
||||||
|
'K' => self::K,
|
||||||
|
default => throw IsInvalid::verifier($v)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retorna la representacion textual del digito verificador.
|
||||||
|
*/
|
||||||
|
public function toString(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::One => '1',
|
||||||
|
self::Two => '2',
|
||||||
|
self::Three => '3',
|
||||||
|
self::Four => '4',
|
||||||
|
self::Five => '5',
|
||||||
|
self::Six => '6',
|
||||||
|
self::Seven => '7',
|
||||||
|
self::Eight => '8',
|
||||||
|
self::Nine => '9',
|
||||||
|
self::K => 'K',
|
||||||
|
self::Zero => '0',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
*
|
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MNC\ChileanRut\Util;
|
|
||||||
|
|
||||||
use MNC\ChileanRut\Rut;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class provides utils for a Rut correlative.
|
|
||||||
*
|
|
||||||
* @author Matías Navarro Carter <mnavarro@option.cl>
|
|
||||||
*/
|
|
||||||
class CorrelativeUtils
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Finds the verifier digit of a correlative.
|
|
||||||
*
|
|
||||||
* @param string $correlative
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function findVerifierDigit(string $correlative): string
|
|
||||||
{
|
|
||||||
$x = 2;
|
|
||||||
$s = 0;
|
|
||||||
|
|
||||||
for ($i = \strlen($correlative) - 1; $i >= 0; --$i) {
|
|
||||||
if ($x > 7) {
|
|
||||||
$x = 2;
|
|
||||||
}
|
|
||||||
$s += $correlative[$i] * $x;
|
|
||||||
++$x;
|
|
||||||
}
|
|
||||||
|
|
||||||
$dv = 11 - ($s % 11);
|
|
||||||
|
|
||||||
if (10 === $dv) {
|
|
||||||
$dv = 'K';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (11 === $dv) {
|
|
||||||
$dv = '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (string) $dv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiates a valid Rut object just providing a correlative.
|
|
||||||
*
|
|
||||||
* @param string $correlative
|
|
||||||
*
|
|
||||||
* @return Rut
|
|
||||||
*/
|
|
||||||
public static function createValidRutOnlyFromCorrelative(string $correlative): Rut
|
|
||||||
{
|
|
||||||
return Rut::fromParts($correlative, static::findVerifierDigit($correlative));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Auto-generates an algorithmically valid Rut, because why not.
|
|
||||||
*
|
|
||||||
* @return Rut
|
|
||||||
*/
|
|
||||||
public static function autoGenerateValidRut(): Rut
|
|
||||||
{
|
|
||||||
$correlative = \random_int(1000000, 40000000);
|
|
||||||
|
|
||||||
return static::createValidRutOnlyFromCorrelative($correlative);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
*
|
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MNC\ChileanRut\Validator;
|
|
||||||
|
|
||||||
use MNC\ChileanRut\Exception\InvalidRutException;
|
|
||||||
use MNC\ChileanRut\Rut;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A ChainRutValidator.
|
|
||||||
*
|
|
||||||
* Use this implementation when you want to validate a Rut against multiple
|
|
||||||
* validators. Add the validators in order by calling addValidator().
|
|
||||||
*
|
|
||||||
* @author Matías Navarro Carter <mnavarro@option.cl>
|
|
||||||
*/
|
|
||||||
class ChainRutValidator implements RutValidator
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var RutValidator[]
|
|
||||||
*/
|
|
||||||
private $validators;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ChainRutValidator constructor.
|
|
||||||
*
|
|
||||||
* @param RutValidator[] $validators
|
|
||||||
*/
|
|
||||||
public function __construct(RutValidator ...$validators)
|
|
||||||
{
|
|
||||||
$this->validators = $validators;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Rut $rut
|
|
||||||
*
|
|
||||||
* @throws InvalidRutException on invalid Rut
|
|
||||||
*/
|
|
||||||
public function validate(Rut $rut): void
|
|
||||||
{
|
|
||||||
foreach ($this->validators as $validator) {
|
|
||||||
$validator->validate($rut);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
*
|
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MNC\ChileanRut\Validator;
|
|
||||||
|
|
||||||
use MNC\ChileanRut\Exception\InvalidRutException;
|
|
||||||
use MNC\ChileanRut\Rut;
|
|
||||||
use MNC\ChileanRut\Util\CorrelativeUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the Rut using the Module 11 algorithm.
|
|
||||||
*
|
|
||||||
* @author Matías Navarro Carter <mnavarro@option.cl>
|
|
||||||
*/
|
|
||||||
class Module11RutValidator implements RutValidator
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @param Rut $rut
|
|
||||||
*
|
|
||||||
* @throws InvalidRutException
|
|
||||||
*/
|
|
||||||
public function validate(Rut $rut): void
|
|
||||||
{
|
|
||||||
$digit = CorrelativeUtils::findVerifierDigit($rut->getCorrelative());
|
|
||||||
|
|
||||||
if ($digit !== $rut->getVerifierDigit()) {
|
|
||||||
throw new InvalidRutException($rut);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
*
|
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MNC\ChileanRut\Validator;
|
|
||||||
|
|
||||||
use MNC\ChileanRut\Exception\InvalidRutException;
|
|
||||||
use MNC\ChileanRut\Rut;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the base contract for a Rut validator.
|
|
||||||
*
|
|
||||||
* You can implement any logic here that you can use to validate a Rut.
|
|
||||||
* For example, the Module11RutValidator only validates that a Rut is algorithmically
|
|
||||||
* correct, but not that it actually exists.
|
|
||||||
*
|
|
||||||
* You could create a HTTPRutValidator that performs a request to validate that a
|
|
||||||
* Rut exists against a Rest Api or a third party service.
|
|
||||||
*
|
|
||||||
* @author Matías Navarro Carter <mnavarro@option.cl>
|
|
||||||
*/
|
|
||||||
interface RutValidator
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Validates a Rut.
|
|
||||||
*
|
|
||||||
* The implementation MUST throw an InvalidRutException if validation fails.
|
|
||||||
*
|
|
||||||
* The different clients CAN catch that exception and handle the validation
|
|
||||||
* error according to their business rules.
|
|
||||||
*
|
|
||||||
* @param Rut $rut
|
|
||||||
*
|
|
||||||
* @throws InvalidRutException on invalid Rut
|
|
||||||
*/
|
|
||||||
public function validate(Rut $rut): void;
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
*
|
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MNC\ChileanRut\Tests\Bridge\Symfony\Form;
|
|
||||||
|
|
||||||
use MNC\ChileanRut\Bridge\Symfony\Form\RutType;
|
|
||||||
use MNC\ChileanRut\Rut;
|
|
||||||
use Symfony\Component\Form\Test\TypeTestCase;
|
|
||||||
|
|
||||||
class RutTypeTest extends TypeTestCase
|
|
||||||
{
|
|
||||||
public function testSubmitValidData()
|
|
||||||
{
|
|
||||||
$objectToCompare = new Rut('16.894.365-2');
|
|
||||||
|
|
||||||
// $objectToCompare will retrieve data from the form submission; pass it as the second argument
|
|
||||||
$form = $this->factory->create(RutType::class);
|
|
||||||
|
|
||||||
// submit the data to the form directly
|
|
||||||
$form->submit('16.894.365-2');
|
|
||||||
|
|
||||||
$this->assertTrue($form->isSynchronized());
|
|
||||||
|
|
||||||
$formData = $form->getData();
|
|
||||||
|
|
||||||
// check that $objectToCompare was modified as expected when the form was submitted
|
|
||||||
$this->assertInstanceOf(Rut::class, $formData);
|
|
||||||
$this->assertTrue($formData->isEqualTo($objectToCompare));
|
|
||||||
|
|
||||||
$view = $form->createView();
|
|
||||||
|
|
||||||
$this->assertSame('16.894.365-2', $view->vars['value']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
83
tests/Rut/Doctrine/NumericRutTypeTest.php
Normal file
83
tests/Rut/Doctrine/NumericRutTypeTest.php
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @project Chilean RUT
|
||||||
|
* @link https://github.com/mnavarrocarter/chilean-rut
|
||||||
|
* @package castor/log
|
||||||
|
* @author Matias Navarro-Carter mnavarrocarter@gmail.com
|
||||||
|
* @license MIT
|
||||||
|
* @copyright 2024 Matias Navarro-Carter
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MNC\Rut\Doctrine;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||||
|
use Doctrine\DBAL\Types\ConversionException;
|
||||||
|
use Doctrine\DBAL\Types\Type;
|
||||||
|
use MNC\Rut;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
#[CoversClass(NumericRutType::class)]
|
||||||
|
#[CoversClass(Rut::class)]
|
||||||
|
#[CoversClass(Rut\Verifier::class)]
|
||||||
|
class NumericRutTypeTest extends TestCase
|
||||||
|
{
|
||||||
|
public static function setUpBeforeClass(): void
|
||||||
|
{
|
||||||
|
Type::addType(NumericRutType::NAME, NumericRutType::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItConvertsNullFromDatabaseValue(): void
|
||||||
|
{
|
||||||
|
$platform = $this->createMock(AbstractPlatform::class);
|
||||||
|
$type = Type::getType(NumericRutType::NAME);
|
||||||
|
$result = $type->convertToPHPValue(null, $platform);
|
||||||
|
self::assertNull($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItConvertsStringFromDatabaseValue(): void
|
||||||
|
{
|
||||||
|
$platform = $this->createMock(AbstractPlatform::class);
|
||||||
|
$type = Type::getType(NumericRutType::NAME);
|
||||||
|
$result = $type->convertToPHPValue(16894365, $platform);
|
||||||
|
self::assertInstanceOf(Rut::class, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItConvertsNullToDatabaseValue(): void
|
||||||
|
{
|
||||||
|
$platform = $this->createMock(AbstractPlatform::class);
|
||||||
|
$type = Type::getType(NumericRutType::NAME);
|
||||||
|
$result = $type->convertToDatabaseValue(null, $platform);
|
||||||
|
self::assertNull($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItConvertsRutToDatabaseValue(): void
|
||||||
|
{
|
||||||
|
$platform = $this->createMock(AbstractPlatform::class);
|
||||||
|
$type = Type::getType(NumericRutType::NAME);
|
||||||
|
$result = $type->convertToDatabaseValue(Rut::parse('168943652'), $platform);
|
||||||
|
self::assertSame('16894365', $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItCannotConvertToDatabaseValue(): void
|
||||||
|
{
|
||||||
|
$platform = $this->createMock(AbstractPlatform::class);
|
||||||
|
$type = Type::getType(NumericRutType::NAME);
|
||||||
|
$this->expectException(ConversionException::class);
|
||||||
|
$type->convertToDatabaseValue(new \DateTime(), $platform);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_returns_true_for_comment(): void
|
||||||
|
{
|
||||||
|
$platform = $this->createMock(AbstractPlatform::class);
|
||||||
|
$this->assertTrue(Type::getType(NumericRutType::NAME)->requiresSQLCommentHint($platform));
|
||||||
|
}
|
||||||
|
}
|
||||||
91
tests/Rut/Doctrine/RutTypeTest.php
Normal file
91
tests/Rut/Doctrine/RutTypeTest.php
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @project Chilean RUT
|
||||||
|
* @link https://github.com/mnavarrocarter/chilean-rut
|
||||||
|
* @package castor/log
|
||||||
|
* @author Matias Navarro-Carter mnavarrocarter@gmail.com
|
||||||
|
* @license MIT
|
||||||
|
* @copyright 2024 Matias Navarro-Carter
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MNC\Rut\Doctrine;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||||
|
use Doctrine\DBAL\Types\ConversionException;
|
||||||
|
use Doctrine\DBAL\Types\Type;
|
||||||
|
use MNC\Rut;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
#[CoversClass(RutType::class)]
|
||||||
|
#[CoversClass(Rut::class)]
|
||||||
|
#[CoversClass(Rut\Verifier::class)]
|
||||||
|
class RutTypeTest extends TestCase
|
||||||
|
{
|
||||||
|
public static function setUpBeforeClass(): void
|
||||||
|
{
|
||||||
|
Type::addType(RutType::NAME, RutType::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItConvertsNullFromDatabaseValue(): void
|
||||||
|
{
|
||||||
|
$platform = $this->createMock(AbstractPlatform::class);
|
||||||
|
$type = Type::getType(RutType::NAME);
|
||||||
|
$result = $type->convertToPHPValue(null, $platform);
|
||||||
|
self::assertNull($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItConvertsStringFromDatabaseValue(): void
|
||||||
|
{
|
||||||
|
$platform = $this->createMock(AbstractPlatform::class);
|
||||||
|
$type = Type::getType(RutType::NAME);
|
||||||
|
$result = $type->convertToPHPValue('16.894.365-2', $platform);
|
||||||
|
self::assertInstanceOf(Rut::class, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItCannotConvertFromDatabaseValue(): void
|
||||||
|
{
|
||||||
|
$platform = $this->createMock(AbstractPlatform::class);
|
||||||
|
$type = Type::getType(RutType::NAME);
|
||||||
|
$this->expectException(ConversionException::class);
|
||||||
|
$type->convertToPHPValue(true, $platform);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItConvertsNullToDatabaseValue(): void
|
||||||
|
{
|
||||||
|
$platform = $this->createMock(AbstractPlatform::class);
|
||||||
|
$type = Type::getType(RutType::NAME);
|
||||||
|
$result = $type->convertToDatabaseValue(null, $platform);
|
||||||
|
self::assertNull($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItConvertsRutToDatabaseValue(): void
|
||||||
|
{
|
||||||
|
$platform = $this->createMock(AbstractPlatform::class);
|
||||||
|
$type = Type::getType(RutType::NAME);
|
||||||
|
$result = $type->convertToDatabaseValue(Rut::parse('168943652'), $platform);
|
||||||
|
self::assertSame('16.894.365-2', $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItCannotConvertToDatabaseValue(): void
|
||||||
|
{
|
||||||
|
$platform = $this->createMock(AbstractPlatform::class);
|
||||||
|
$type = Type::getType(RutType::NAME);
|
||||||
|
$this->expectException(ConversionException::class);
|
||||||
|
$type->convertToDatabaseValue(new \DateTime(), $platform);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_returns_true_for_comment(): void
|
||||||
|
{
|
||||||
|
$platform = $this->createMock(AbstractPlatform::class);
|
||||||
|
$this->assertTrue(Type::getType(RutType::NAME)->requiresSQLCommentHint($platform));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
*
|
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MNC\ChileanRut\Tests\Rut;
|
|
||||||
|
|
||||||
use MNC\ChileanRut\Exception\InvalidRutException;
|
|
||||||
use MNC\ChileanRut\Rut;
|
|
||||||
use MNC\ChileanRut\Validator\Module11RutValidator;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
|
|
||||||
class RutTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testThatRutIsSanitizedProperlyOnInstantiation()
|
|
||||||
{
|
|
||||||
$rut = Rut::fromString('16.894.365-2');
|
|
||||||
|
|
||||||
$this->assertSame('16894365', $rut->getCorrelative());
|
|
||||||
$this->assertSame('2', $rut->getVerifierDigit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testThatRutsInstantiatedDifferentFormatButWithEqualValueAreIndeedEqual()
|
|
||||||
{
|
|
||||||
$rut1 = new Rut('16.894.365-2');
|
|
||||||
$rut2 = new Rut('16894365-2');
|
|
||||||
$this->assertTrue($rut1->isEqualTo($rut2));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testThatFormatClearWorks()
|
|
||||||
{
|
|
||||||
$rut = new Rut('16.894.365-2');
|
|
||||||
$this->assertSame('168943652', $rut->format(Rut::FORMAT_CLEAR));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testThatFormatWithHyphenWorks()
|
|
||||||
{
|
|
||||||
$rut = new Rut('16.894.365-2');
|
|
||||||
$this->assertSame('16894365-2', $rut->format(Rut::FORMAT_HYPHENED));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testThatFormatReadableWorks()
|
|
||||||
{
|
|
||||||
$rut = new Rut('168943652');
|
|
||||||
$this->assertSame('16.894.365-2', $rut->format(Rut::FORMAT_READABLE));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testThatFormatHiddenWorks()
|
|
||||||
{
|
|
||||||
$rut = new Rut('168943652');
|
|
||||||
$this->assertSame('16.***.***-2', $rut->format(Rut::FORMAT_HIDDEN));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testThatIntegratedValidationThrowsExceptionOnInvalidRut()
|
|
||||||
{
|
|
||||||
$this->expectException(InvalidRutException::class);
|
|
||||||
|
|
||||||
$validator = new Module11RutValidator();
|
|
||||||
$rut = new Rut('4444444-2', $validator);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testThatIntegratedValidationDoesNotThrowExceptionOnValidRut()
|
|
||||||
{
|
|
||||||
$validator = new Module11RutValidator();
|
|
||||||
$rut = new Rut('16.894.365-2', $validator);
|
|
||||||
|
|
||||||
$this->assertInstanceOf(Rut::class, $rut);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testInvalidFormatValueRaisesException()
|
|
||||||
{
|
|
||||||
$rut = new Rut('16.894.365-2');
|
|
||||||
|
|
||||||
$this->expectException(\InvalidArgumentException::class);
|
|
||||||
$rut->format(23);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
107
tests/RutTest.php
Normal file
107
tests/RutTest.php
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @project Chilean RUT
|
||||||
|
* @link https://github.com/mnavarrocarter/chilean-rut
|
||||||
|
* @package castor/log
|
||||||
|
* @author Matias Navarro-Carter mnavarrocarter@gmail.com
|
||||||
|
* @license MIT
|
||||||
|
* @copyright 2024 Matias Navarro-Carter
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MNC;
|
||||||
|
|
||||||
|
use MNC\Rut\IsInvalid;
|
||||||
|
use MNC\Rut\Verifier;
|
||||||
|
use PHPUnit\Framework\Attributes\CoversClass;
|
||||||
|
use PHPUnit\Framework\Attributes\DataProvider;
|
||||||
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
#[CoversClass(Rut::class)]
|
||||||
|
#[CoversClass(IsInvalid::class)]
|
||||||
|
#[CoversClass(Verifier::class)]
|
||||||
|
class RutTest extends TestCase
|
||||||
|
{
|
||||||
|
#[Test]
|
||||||
|
#[DataProvider('getParseData')]
|
||||||
|
public function it_parses_ruts(string $raw, int $expectedNumber, Verifier $expectedVerifier): void
|
||||||
|
{
|
||||||
|
$rut = Rut::parse($raw);
|
||||||
|
$this->assertSame($expectedNumber, $rut->number);
|
||||||
|
$this->assertSame($expectedVerifier, $rut->verifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
#[DataProvider('getParseWithErrorData')]
|
||||||
|
public function it_parses_with_error(string $raw, string $expectedError): void
|
||||||
|
{
|
||||||
|
$this->expectException(IsInvalid::class);
|
||||||
|
$this->expectExceptionMessage($expectedError);
|
||||||
|
Rut::parse($raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_cannot_be_negative(): void
|
||||||
|
{
|
||||||
|
$this->expectException(IsInvalid::class);
|
||||||
|
$this->expectExceptionMessage('El RUT numero -22224525 es menor a cero');
|
||||||
|
Rut::create(-22_224_525);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_checks_for_equality(): void
|
||||||
|
{
|
||||||
|
$rut1 = Rut::parse('168943652');
|
||||||
|
$rut2 = Rut::parse('16.894.365-2');
|
||||||
|
$rut3 = Rut::create(22_224_525);
|
||||||
|
$this->assertTrue($rut1->equals($rut2));
|
||||||
|
$this->assertFalse($rut1->equals($rut3));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_creates_with_no_verifier(): void
|
||||||
|
{
|
||||||
|
$rut = Rut::create(22_457_309);
|
||||||
|
$this->assertSame(22_457_309, $rut->number);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Test]
|
||||||
|
public function it_formats(): void
|
||||||
|
{
|
||||||
|
$rut = Rut::create(22_457_309);
|
||||||
|
$this->assertSame('22457309K', $rut->toString());
|
||||||
|
$this->assertSame('22457309-K', $rut->toSimple());
|
||||||
|
$this->assertSame('22.457.309-K', $rut->toHuman());
|
||||||
|
$this->assertSame('7309', $rut->last(4));
|
||||||
|
$this->assertSame('****7309', $rut->last(4, '*'));
|
||||||
|
$this->assertSame('2245', $rut->first(4));
|
||||||
|
$this->assertSame('2245****', $rut->first(4, '*'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getParseData(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['16.894.365-2', 16_894_365, Verifier::Two],
|
||||||
|
['24 736.7322', 24_736_732, Verifier::Two],
|
||||||
|
[' 24 232.. 442 -- 0', 24_232_442, Verifier::Zero],
|
||||||
|
['35323325', 3_532_332, Verifier::Five],
|
||||||
|
['22.457.309K', 22_457_309, Verifier::K],
|
||||||
|
['15450088K', 15_450_088, Verifier::K],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getParseWithErrorData(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['212321312321-1', 'El RUT numero 212321312321 es mayor a 99.999.999'],
|
||||||
|
['23.232.123-K', 'El digito verificador K no es valido para el rut 23232123'],
|
||||||
|
['12.2324.232-P', 'Encontrado un digito verificador invalido con valor P'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
*
|
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MNC\ChileanRut\Tests\Validator;
|
|
||||||
|
|
||||||
use MNC\ChileanRut\Exception\InvalidRutException;
|
|
||||||
use MNC\ChileanRut\Util\CorrelativeUtils;
|
|
||||||
use MNC\ChileanRut\Validator\ChainRutValidator;
|
|
||||||
use MNC\ChileanRut\Validator\Module11RutValidator;
|
|
||||||
use MNC\ChileanRut\Validator\RutValidator;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ChainRutValidatorTest.
|
|
||||||
*/
|
|
||||||
class ChainRutValidatorTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testThatChainValidatorFails(): void
|
|
||||||
{
|
|
||||||
$rut = CorrelativeUtils::autoGenerateValidRut();
|
|
||||||
|
|
||||||
$normalValidator = new Module11RutValidator();
|
|
||||||
$mockValidator = $this->createMock(RutValidator::class);
|
|
||||||
$mockValidator->expects($this->once())
|
|
||||||
->method('validate')
|
|
||||||
->willThrowException(new InvalidRutException($rut));
|
|
||||||
|
|
||||||
$chainValidator = new ChainRutValidator($normalValidator, $mockValidator);
|
|
||||||
|
|
||||||
$this->expectException(InvalidRutException::class);
|
|
||||||
$chainValidator->validate($rut);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testThatChainValidatorPasses(): void
|
|
||||||
{
|
|
||||||
$rut = CorrelativeUtils::autoGenerateValidRut();
|
|
||||||
|
|
||||||
$normalValidator = new Module11RutValidator();
|
|
||||||
$mockValidator = $this->createMock(RutValidator::class);
|
|
||||||
$mockValidator->expects($this->once())
|
|
||||||
->method('validate')
|
|
||||||
->willReturn(null);
|
|
||||||
|
|
||||||
$chainValidator = new ChainRutValidator($normalValidator, $mockValidator);
|
|
||||||
|
|
||||||
$chainValidator->validate($rut);
|
|
||||||
$this->assertTrue(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the MNC\ChileanRut library.
|
|
||||||
*
|
|
||||||
* (c) Matías Navarro Carter <mnavarrocarter@gmail.com>
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace MNC\ChileanRut\Tests\Validator;
|
|
||||||
|
|
||||||
use MNC\ChileanRut\Exception\InvalidRutException;
|
|
||||||
use MNC\ChileanRut\Rut;
|
|
||||||
use MNC\ChileanRut\Validator\Module11RutValidator;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
|
|
||||||
class SimpleRutValidatorTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testValidationPassesOnValidRut()
|
|
||||||
{
|
|
||||||
$rut = new Rut('16.894.365-2');
|
|
||||||
$validator = new Module11RutValidator();
|
|
||||||
|
|
||||||
$validator->validate($rut);
|
|
||||||
|
|
||||||
$this->assertInstanceOf(Rut::class, $rut);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidationFailsOnInvalidRut()
|
|
||||||
{
|
|
||||||
$this->expectException(InvalidRutException::class);
|
|
||||||
|
|
||||||
$rut = new Rut('34.4534.353-1');
|
|
||||||
$validator = new Module11RutValidator();
|
|
||||||
|
|
||||||
$validator->validate($rut);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user