Skip to content

Commit

Permalink
Add CompositeCityDecoderList
Browse files Browse the repository at this point in the history
  • Loading branch information
robertogallea committed Jul 2, 2021
1 parent ddcd319 commit a464b48
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 11 deletions.
73 changes: 63 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,24 @@ Laravel-FiscalCode is a package for the management of the Italian <code>CodiceFi
The package allows easy validation and parsing of the CodiceFiscale. It is also suited for Laravel since it provides a
convenient custom validator for request validation.

## 1. Installation
- [Installation](#installation)
- [Validation](#validation)
- [Utility CodiceFiscale class](#utility-codicefiscale-class)
- [Codice fiscale Generation](#codice-fiscale-generation)
- [City code parsing](#city-code-parsing)
- [Integrate your own cities](#integrate-your-own-cities)



## Installation

Run the following command to install the latest applicable version of the package:

```bash
composer require robertogallea/laravel-codicefiscale
```

### 1.1 Laravel
### Laravel

In your app config, add the Service Provider to the `$providers` array *(only for Laravel 5.4 or below)*:

Expand All @@ -35,23 +44,23 @@ In your languages directory, add for each language an extra language entry for t
],
```

### 1.2 Lumen
### Lumen

In `bootstrap/app.php`, register the Service Provider

```php
$app->register(robertogallea\LaravelCodiceFiscale\CodiceFiscaleServiceProvider::class);
```

## 2. Validation
## Validation

To validate a codice fiscale, use the `codice_fiscale` keyword in your validation rules array

```php
'codice_fiscale_field' => 'codice_fiscale',
```

## 3. Utility CodiceFiscale class
## Utility CodiceFiscale class

A codice fiscale can be wrapped in the `robertogallea\LaravelCodiceFiscale\CodiceFiscale` class to enhance it with
useful utility methods.
Expand Down Expand Up @@ -83,8 +92,8 @@ produces the following result:
```


in case of error, <code>CodiceFiscale::parse()</code> returns false, and you will find information about the error using
<code>CodiceFiscale::getError()</code>, which returns one of the defined constants among the following:<br>
in case of error, `CodiceFiscale::parse()` returns false, and you will find information about the error using
`CodiceFiscale::getError()`, which returns one of the defined constants among the following:

- `CodiceFiscale::NO_ERROR`
- `CodiceFiscale::NO_CODE`
Expand Down Expand Up @@ -115,14 +124,17 @@ $gender = 'M';
$cf_string = CodiceFiscale::generate($first_name, $last_name, $birth_date, $birth_place, $gender);
```

# City code parsing
## City code parsing
There are three strategies for decoding the city code:

- `InternationalCitiesStaticList`: a static list of Italian cities;
- `ItalianCitiesStaticList`: a static list of International cities;
- `IstatRemoteCSVList`: a dynamic (loaded from web) list of Italian cities loaded from official ISTAT csv file.
Please note that the list is cached (one day by default, see config to change).

- `CompositeCitiesList`: merge the results from two `CityDecoderInterface` classes (for example `IstatRemoteCSVList` and
`InternationalCitiesStaticList`) using the base `CityDecoderInterface` in the config key
`codicefiscale.cities-decoder-list`.

By default, the package uses the class `InternationalCitiesStaticList` to lookup the city from the code and viceversa.
However you could use your own class to change the strategy used.

Expand All @@ -144,4 +156,45 @@ class MyCityList implements CityDecoderInterface
...
$cf = new CodiceFiscale(new MyCityList)
...
```
```

## Integrate your own cities

_Note_: if you find missing cities, please make a PR!

If you want to integrate the cities list, you can use the `CompositeCitiesList` by merging the results of one of the
decoders provided and a custom decoder.

For example:

```
// conf/codicefiscale.php
return [
'city-decoder' => '\robertogallea\LaravelCodiceFiscale\CityCodeDecoders\InternationalCitiesStaticList',
...
'cities-decoder-list' => [
'\robertogallea\LaravelCodiceFiscale\CityCodeDecoders\InternationalCitiesStaticList',
'YourNamespace\MyCustomList',
]
```

where `YourCustomList` is defined as:

```
...
class MyCustomList implements CityDecoderInterface
{
public function getList()
{
return [
'XYZ1' => 'My city 1',
'XYZ2' => 'My city 2',
]
}
}
```

12 changes: 11 additions & 1 deletion config/codicefiscale.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,21 @@
return [
'city-decoder' => '\robertogallea\LaravelCodiceFiscale\CityCodeDecoders\InternationalCitiesStaticList',

// The following parameters are used when using IstatRemoveCSVList city decoder class


// The following parameters are used when using IstatRemoveCSVList city decoder class
// The url where the CSV provided by ISTAT is served (should never change)
'istat-csv-url' => env('CF_ISTAT_CSV_URL', 'https://www.istat.it/storage/codici-unita-amministrative/Elenco-comuni-italiani.csv'),

// Cache duration (in seconds) for storing the list downloaded from the CSV
'cache-duration' => env('CF_CACHE_DURATION', 60*60*24),




// When using CompositeCitiesList, you may specify the CityDecoders to merge the results from
'cities-decoder-list' => [
// '\robertogallea\LaravelCodiceFiscale\CityCodeDecoders\ISTATRemoteCSVList',
// '\robertogallea\LaravelCodiceFiscale\CityCodeDecoders\InternationalCitiesStaticList',
]
];
21 changes: 21 additions & 0 deletions src/CityCodeDecoders/CompositeCitiesList.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php


namespace robertogallea\LaravelCodiceFiscale\CityCodeDecoders;


class CompositeCitiesList implements CityDecoderInterface
{

public static function getList()
{
$result = [];

foreach (config('codicefiscale.cities-decoder-list') as $citiesList) {
$list = (new $citiesList())->getList();
$result = $list + $result;
}

return $result;
}
}
88 changes: 88 additions & 0 deletions tests/CityCodeDecoders/CompositeCitiesListTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php


namespace Tests\CityCodeDecoders;


use Illuminate\Support\Facades\Config;
use Orchestra\Testbench\TestCase;
use robertogallea\LaravelCodiceFiscale\CityCodeDecoders\CityDecoderInterface;
use robertogallea\LaravelCodiceFiscale\CityCodeDecoders\CompositeCitiesList;
use robertogallea\LaravelCodiceFiscale\CodiceFiscaleServiceProvider;

class CompositeCitiesListTest extends TestCase
{
/** @test */
public function if_empty_returns_empty_array()
{
Config::set('codicefiscale.cities-lists', []);
$citiesList = new CompositeCitiesList();

$list = $citiesList->getList();

$this->assertEquals([], $list);
}

/** @test */
public function it_merges_two_cities_list_results()
{
$citiesList = $this->getMockedComposedList(['A001' => 'AAA'], ['B001' => 'BBB']);

$list = $citiesList->getList();

$this->assertEquals([
'A001' => 'AAA',
'B001' => 'BBB',
], $list);
}

/** @test */
public function when_merging_last_decoder_has_precedence()
{
$citiesList = $this->getMockedComposedList(['A001' => 'AAA'], ['A001' => 'BBB']);

$list = $citiesList->getList();

$this->assertEquals([
'A001' => 'BBB',
], $list);
}

/**
* @return array|mixed
*/
private function getMockedComposedList($firstArray, $secondArray)
{
$list1 = \Mockery::namedMock(
'FirstDecoder',
CityDecoderInterface::class,
function ($mock) use ($firstArray) {
$mock->shouldReceive('getList')->once()->andReturn($firstArray);
}
);

$list2 = \Mockery::namedMock(
'SecondDecoder',
CityDecoderInterface::class,
function ($mock) use ($secondArray) {
$mock->shouldReceive('getList')->once()->andReturn($secondArray);
}
);

Config::set('codicefiscale.cities-decoder-list', $citiesListDecoders = [
get_class($list1),
get_class($list2),
]);

$citiesList = new CompositeCitiesList();

return $citiesList;
}

public function getPackageProviders($application)
{
return [
CodiceFiscaleServiceProvider::class,
];
}
}

0 comments on commit a464b48

Please sign in to comment.