plin-code / laravel-istat-geography
Laravel package for importing and managing Italian geography data from ISTAT
Package info
github.com/plin-code/laravel-istat-geography
pkg:composer/plin-code/laravel-istat-geography
Fund package maintenance!
Requires
- php: ^8.3
- guzzlehttp/guzzle: ^7.0
- illuminate/contracts: ^12.0
- league/csv: ^9.24
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^2.9||^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.1.1||^7.10.0
- orchestra/testbench: ^10.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-arch: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
- phpstan/extension-installer: ^1.3
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
This package is not auto-updated.
Last update: 2026-02-28 16:23:39 UTC
README
A Laravel package for importing and managing Italian geographical data from ISTAT.
Features
- ๐ฎ๐น Import Italian regions, provinces, and municipalities from ISTAT
- ๐ Incremental updates: add new records, update changes, soft-delete removed ones
- ๐ Daily CSV caching to avoid unnecessary requests
- ๐ Eloquent models with hierarchical relationships
- โก Artisan commands for easy data import and synchronization
- ๐ง Fully configurable via configuration file
- ๐ UUID primary keys and soft deletes support
- ๐งช Comprehensive test suite with mocked HTTP requests
Requirements
- PHP 8.3+
- Laravel 11.0+ or 12.0+
- league/csv 9.0+
- guzzlehttp/guzzle 7.0+
Installation
composer require plin-code/laravel-istat-geography
Quick Start
- Install the package:
composer require plin-code/laravel-istat-geography
- Publish the configuration:
php artisan vendor:publish --provider="PlinCode\IstatGeography\IstatGeographyServiceProvider"
- Run migrations:
php artisan migrate
- Import the data:
php artisan geography:import
That's it! You now have all Italian geographical data in your database.
Commands
geography:import
Performs a full import of all geographical data from ISTAT. Use this for the initial data load.
php artisan geography:import
geography:update
Incrementally synchronizes your database with the latest ISTAT data. It compares the current ISTAT CSV against your existing records and applies only the differences: new records are added, changed records are updated, and records no longer present in ISTAT are soft-deleted.
php artisan geography:update
Options
| Option | Description |
|---|---|
--dry-run |
Simulate the update without making any database changes. Shows what would be added, modified, or deleted. |
--force |
Continue execution even if non-critical errors occur (errors are logged as warnings). |
Verbosity Levels
| Flag | Output |
|---|---|
| (none) | Final summary only (e.g. 3 added, 1 modified, 0 deleted) |
-v |
Download progress, list of new/modified/suppressed records, progress bar |
-vv |
Field-level change details (e.g. name: Old Name โ New Name) |
-vvv |
Debug output with timing information for each operation |
Examples
# Preview changes without applying them php artisan geography:update --dry-run # Run with verbose output php artisan geography:update -v # Run with full debug output php artisan geography:update -vvv # Force continue on non-critical errors php artisan geography:update --force
All database operations are wrapped in a transaction. If any error occurs (and --force is not set), all changes are automatically rolled back.
Configuration
Publish the configuration file:
php artisan vendor:publish --provider="PlinCode\IstatGeography\IstatGeographyServiceProvider"
The config/istat-geography.php file allows you to customize:
- Table names: Customize the database table names
- Model classes: Use your own model classes by extending the base ones
- CSV URL: Change the ISTAT data source URL
- Temporary file name: Customize the cache file name
Example Configuration
return [ 'tables' => [ 'regions' => 'my_regions', 'provinces' => 'my_provinces', 'municipalities' => 'my_municipalities', ], 'models' => [ 'region' => \App\Models\Region::class, 'province' => \App\Models\Province::class, 'municipality' => \App\Models\Municipality::class, ], 'import' => [ 'csv_url' => 'https://custom-url.com/data.csv', 'temp_filename' => 'my_istat_data.csv', ], ];
Models
The package provides three Eloquent models:
Region
use PlinCode\IstatGeography\Models\Geography\Region; $region = Region::where('name', 'Piemonte')->first(); $provinces = $region->provinces;
Province
use PlinCode\IstatGeography\Models\Geography\Province; $province = Province::where('code', 'TO')->first(); $municipalities = $province->municipalities; $region = $province->region;
Municipality
use PlinCode\IstatGeography\Models\Geography\Municipality; $municipality = Municipality::where('name', 'Torino')->first(); $province = $municipality->province;
ISTAT Fields
Each model exposes a static istatFields() method that returns the list of fields managed by ISTAT data. These are the fields that the geography:update command is allowed to overwrite. Any additional fields you add to your extended models will not be touched during updates.
Region::istatFields(); // ['name', 'istat_code'] Province::istatFields(); // ['name', 'code', 'istat_code', 'region_id'] Municipality::istatFields(); // ['name', 'istat_code', 'province_id']
Extending Models
If you want to use the package models in your main project, you can extend them:
// app/Models/Region.php namespace App\Models; use PlinCode\IstatGeography\Models\Geography\Region as BaseRegion; class Region extends BaseRegion { // Add your project-specific logic here public function customMethod() { return $this->provinces()->count(); } }
// app/Models/Province.php namespace App\Models; use PlinCode\IstatGeography\Models\Geography\Province as BaseProvince; class Province extends BaseProvince { // Add your project-specific logic here }
// app/Models/Municipality.php namespace App\Models; use PlinCode\IstatGeography\Models\Geography\Municipality as BaseMunicipality; class Municipality extends BaseMunicipality { // Add your project-specific logic here }
Remember to update the models section in the configuration file to point to your custom classes.
Database Structure
Regions
id(UUID, primary key)name(string)istat_code(string, unique)created_at,updated_at,deleted_at
Provinces
id(UUID, primary key)region_id(UUID, foreign key)name(string)code(string, unique)istat_code(string, unique)created_at,updated_at,deleted_at
Municipalities
id(UUID, primary key)province_id(UUID, foreign key)name(string)istat_code(string, unique)created_at,updated_at,deleted_at
Relationships
RegionโhasManyโProvinceProvinceโbelongsToโRegionProvinceโhasManyโMunicipalityMunicipalityโbelongsToโProvince
Replacing Existing Command
If you already have a geography:import command in your project, you can replace it with the package's command:
// In app/Console/Kernel.php or in your existing command Artisan::command('geography:import', function () { $this->info('Starting geographical data import...'); try { $count = \PlinCode\IstatGeography\Facades\IstatGeography::import(); $this->info("Import completed successfully! Imported {$count} municipalities."); } catch (\Exception $e) { $this->error('Error during import: ' . $e->getMessage()); } })->purpose('Import regions, provinces and municipalities from ISTAT');
Testing
Run the test suite:
composer test
The package includes:
- โ Unit tests for models and relationships
- โ Feature tests for the import service
- โ Feature tests for the update command and services
- โ Mocked HTTP requests (no external dependencies)
- โ PHPStan static analysis
- โ Pest PHP testing framework
Test Coverage
- Models and their relationships
- Import service with CSV processing
- Compare service for detecting changes
- Update service for applying changes
- Artisan command functionality (import and update)
- Configuration handling
Contributing
- Fork the project
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
The MIT License (MIT). Please see License File for more information.
