Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 41 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<div align="center">
<img src="docs/package-social-preview-readme.png" width="600" alt="Laravel Algerian Cities">
<div align="center">
<a href="https://packagist.org/packages/kossa/algerian-cities"><img src="https://poser.pugx.org/piteurstudio/satim-php/require/php" alt="PHP Version Require"></a>
<a href="https://github.com/kossa/algerian-cities/blob/master/phpstan.neon"><img src="https://img.shields.io/badge/PHPStan-max-blue.svg?style=flat" alt="PHPStan"></a>
<a href="https://github.com/kossa/algerian-cities/blob/master/composer.json#L51"><img src="https://img.shields.io/badge/Coverage-100%25-blue" alt="Test coverage"></a>
<a href="https://github.com/kossa/algerian-cities/actions"><img alt="GitHub Workflow Status (master)" src="https://img.shields.io/github/actions/workflow/status/kossa/algerian-cities/laravel.yml?branch=master&label=Tests"></a>
<a href="https://packagist.org/packages/kossa/algerian-cities"><img alt="Total Downloads" src="https://img.shields.io/packagist/dt/kossa/algerian-cities"></a>
<a href="https://packagist.org/packages/kossa/algerian-cities"><img alt="Latest Version" src="https://img.shields.io/packagist/v/kossa/algerian-cities"></a>
<a href="https://github.com/kossa/algerian-cities/actions"><img alt="GitHub Workflow Status (master)" src="https://img.shields.io/github/actions/workflow/status/kossa/algerian-cities/fix-php-code-style-issues.yml?branch=master&label=Code Style"></a>
<a href="https://packagist.org/packages/kossa/algerian-cities"><img alt="License" src="https://img.shields.io/packagist/l/kossa/algerian-cities"></a>
<a href="https://packagist.org/packages/kossa/algerian-cities"><img alt="Total Downloads" src="https://img.shields.io/packagist/dt/kossa/algerian-cities"></a>
<a href="https://packagist.org/packages/kossa/algerian-cities"><img src="https://poser.pugx.org/piteurstudio/satim-php/license" alt="License"></a>
</div>
</div>

Expand All @@ -20,6 +22,7 @@ It provides functionality to load Wilayas (provinces) and Communes (municipaliti
- Wilaya and Commune Eloquent models with relationships.
- Supports Arabic and French languages.
- Includes postal codes and latitude/longitude for each commune.
- [`HasWilaya` and `HasCommune` traits to simplify model associations](#usage-of-traits).
- [Helper functions for easy integration in Blade views](#using-helper-functions).
- [Available as API endpoints](#using-the-package-as-an-api).

Expand Down Expand Up @@ -134,6 +137,38 @@ This package includes `api.php` routes, allowing you to interact with the data t
| GET | `/api/search/wilaya/{q}` | Search Wilayas by name or Arabic name |
| GET | `/api/search/commune/{q}` | Search Communes by name or Arabic name |

### Usage of Traits

The package provides **`HasWilaya`** and **`HasCommune`** traits to easily associate models with **Wilayas (provinces)** and **Communes (municipalities)**.

```php
use Illuminate\Database\Eloquent\Model;
use Kossa\AlgerianCities\Traits\HasWilaya;
use Kossa\AlgerianCities\Traits\HasCommune;

class User extends Model
{
use HasWilaya, HasCommune;
}
```

#### **Access Wilaya & Commune Data**
```php
$user = User::find(1);

echo $user->wilaya->name; // Example: "Alger"
echo $user->commune->name; // Example: "Bab El Oued"
```

✔ **Ensure `wilaya_id` and `commune_id` exist in the `users` table:**
```php
Schema::table('users', function (Blueprint $table) {
$table->foreignId('wilaya_id')->nullable()->constrained('wilayas');
$table->foreignId('commune_id')->nullable()->constrained('communes');
});
```

## Config
### API Availability Toggle

You can enable or disable the Algerian Cities API endpoints by setting the following option in your `.env` file:
Expand All @@ -144,13 +179,12 @@ ALGERIAN_CITIES_API_ENABLED=false # Default: true

----

## Future Planned Features
## Goals

- [ ] Add support for Dairas (districts), including relationships with Wilayas and Communes
- [ ] Add support for additional languages
- [ ] Add support for Dairas, including relationships with Wilayas and Communes
- [ ] Add a configuration file to allow customizing package behaviors
- [ ] Add support for caching to optimize API responses
- [ ] fix PHPUnit Deprecations
- [ ] support no database usage

## Contribution

Expand Down
27 changes: 21 additions & 6 deletions baseline-8.1.neon
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
parameters:
ignoreErrors:
-
message: "#^Method Kossa\\\\AlgerianCities\\\\Commune\\:\\:wilaya\\(\\) should return Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\BelongsTo\\<Kossa\\\\AlgerianCities\\\\Wilaya, \\$this\\(Kossa\\\\AlgerianCities\\\\Commune\\)\\> but returns Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\BelongsTo\\<Kossa\\\\AlgerianCities\\\\Wilaya, Kossa\\\\AlgerianCities\\\\Commune\\>\\.$#"
message: "#^Method Kossa\\\\AlgerianCities\\\\Models\\\\Commune\\:\\:wilaya\\(\\) should return Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\BelongsTo\\<Kossa\\\\AlgerianCities\\\\Models\\\\Wilaya, \\$this\\(Kossa\\\\AlgerianCities\\\\Models\\\\Commune\\)\\> but returns Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\BelongsTo\\<Kossa\\\\AlgerianCities\\\\Models\\\\Wilaya, Kossa\\\\AlgerianCities\\\\Models\\\\Commune\\>\\.$#"
count: 1
path: src/Commune.php
path: src/Models/Commune.php

-
message: "#^Generic type Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasMany\\<Kossa\\\\AlgerianCities\\\\Commune, \\$this\\(Kossa\\\\AlgerianCities\\\\Wilaya\\)\\> in PHPDoc tag @return specifies 2 template types, but class Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasMany supports only 1\\: TRelatedModel$#"
message: "#^PHPDoc tag @use contains generic type Illuminate\\\\Database\\\\Eloquent\\\\Factories\\\\HasFactory\\<Kossa\\\\AlgerianCities\\\\Database\\\\Factories\\\\CommuneFactory\\> but trait Illuminate\\\\Database\\\\Eloquent\\\\Factories\\\\HasFactory is not generic\\.$#"
count: 1
path: src/Wilaya.php
path: src/Models/Commune.php

-
message: "#^Method Kossa\\\\AlgerianCities\\\\Wilaya\\:\\:communes\\(\\) should return Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasMany\\<Kossa\\\\AlgerianCities\\\\Commune, \\$this\\(Kossa\\\\AlgerianCities\\\\Wilaya\\)\\> but returns Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasMany\\<Kossa\\\\AlgerianCities\\\\Commune\\>\\.$#"
message: "#^Generic type Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasMany\\<Kossa\\\\AlgerianCities\\\\Models\\\\Commune, \\$this\\(Kossa\\\\AlgerianCities\\\\Models\\\\Wilaya\\)\\> in PHPDoc tag @return specifies 2 template types, but class Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasMany supports only 1\\: TRelatedModel$#"
count: 1
path: src/Wilaya.php
path: src/Models/Wilaya.php

-
message: "#^Method Kossa\\\\AlgerianCities\\\\Models\\\\Wilaya\\:\\:commune\\(\\) should return Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\BelongsTo\\<Kossa\\\\AlgerianCities\\\\Models\\\\Commune, \\$this\\(Kossa\\\\AlgerianCities\\\\Models\\\\Wilaya\\)\\> but returns Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\BelongsTo\\<Kossa\\\\AlgerianCities\\\\Models\\\\Commune, Kossa\\\\AlgerianCities\\\\Models\\\\Wilaya\\>\\.$#"
count: 1
path: src/Models/Wilaya.php

-
message: "#^Method Kossa\\\\AlgerianCities\\\\Models\\\\Wilaya\\:\\:communes\\(\\) should return Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasMany\\<Kossa\\\\AlgerianCities\\\\Models\\\\Commune, \\$this\\(Kossa\\\\AlgerianCities\\\\Models\\\\Wilaya\\)\\> but returns Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\HasMany\\<Kossa\\\\AlgerianCities\\\\Models\\\\Commune\\>\\.$#"
count: 1
path: src/Models/Wilaya.php

-
message: "#^PHPDoc tag @use contains generic type Illuminate\\\\Database\\\\Eloquent\\\\Factories\\\\HasFactory\\<Kossa\\\\AlgerianCities\\\\Database\\\\Factories\\\\WilayaFactory\\> but trait Illuminate\\\\Database\\\\Eloquent\\\\Factories\\\\HasFactory is not generic\\.$#"
count: 1
path: src/Models/Wilaya.php
29 changes: 21 additions & 8 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,28 @@
"homepage": "https://github.com/kossa/algerian-cities",
"require": {
"php": "^8.1",
"laravel/framework": "^10.0 | ^11.0 | ^12.0"
"spatie/laravel-package-tools": "^1.19",
"illuminate/contracts": "^10.0||^11.0||^12.0"
},
"require-dev": {
"orchestra/testbench": "^8.0 | ^9.0 | ^10.0",
"laravel/pint": "^1.18",
"larastan/larastan": "^2.9 | ^3.0",
"laravel/pint": "^1.14",
"nunomaduro/collision": "^8.1.1||^7.10.0",
"larastan/larastan": "^2.9||^3.0",
"orchestra/testbench": "^10.0.0||^9.0.0||^8.22.0",
"pestphp/pest-plugin-arch": "^2.7 || ^3.0",
"pestphp/pest-plugin-laravel": "^2.4 || ^3.0",
"phpstan/extension-installer": "^1.3||^2.0",
"phpstan/phpstan-deprecation-rules": "^1.1||^2.0",
"phpstan/phpstan-phpunit": "^1.3||^2.0",

"rector/rector": "^1.0 | ^2.0",
"pestphp/pest": "^2.36 | ^3.0"
},
"license": "MIT",
"autoload": {
"psr-4": {
"Kossa\\AlgerianCities\\": "src/",
"Kossa\\AlgerianCities\\Database\\Factories\\": "database/factories/",
"Database\\Migrations\\": "database/migrations/",
"Database\\Seeders\\": "database/seeders/"
},
Expand All @@ -39,15 +48,17 @@
"extra": {
"laravel": {
"providers": [
"Kossa\\AlgerianCities\\Providers\\AlgerianCitiesServiceProvider"
"Kossa\\AlgerianCities\\AlgerianCitiesServiceProvider"
]
}
},
"scripts": {
"post-install-cmd": [
"Kossa\\AlgerianCities\\Console\\Commands\\AlgerianCitiesCommand::handle"
"echo 'Run php artisan algerian-cities:install to complete the setup.';"
],
"test:unit": "pest --parallel --coverage --min=54",
"post-autoload-dump": "@composer run prepare",
"prepare": "@php vendor/bin/testbench package:discover --ansi",
"test:unit": "pest --parallel --coverage --min=100",
"test:format": "pint --test",
"test:refactor": "rector --dry-run",
"test:types": "vendor/bin/phpstan analyse --memory-limit=256M",
Expand All @@ -63,8 +74,10 @@
"minimum-stability": "dev",
"prefer-stable": true,
"config": {
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true
"pestphp/pest-plugin": true,
"phpstan/extension-installer": true
}
}
}
25 changes: 25 additions & 0 deletions database/factories/CommuneFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Kossa\AlgerianCities\Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use Kossa\AlgerianCities\Models\Commune;
use Kossa\AlgerianCities\Models\Wilaya;

class CommuneFactory extends Factory
{
protected $model = Commune::class;

public function definition(): array
{
return [
'name' => $this->faker->city,
'wilaya_id' => Wilaya::factory(),
'arabic_name' => $this->faker->city,
'post_code' => $this->faker->postcode,
'longitude' => $this->faker->longitude,
'latitude' => $this->faker->latitude,

];
}
}
21 changes: 21 additions & 0 deletions database/factories/WilayaFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Kossa\AlgerianCities\Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use Kossa\AlgerianCities\Models\Wilaya;

class WilayaFactory extends Factory
{
protected $model = Wilaya::class;

public function definition(): array
{
return [
'name' => $this->faker->city,
'arabic_name' => $this->faker->city,
'longitude' => $this->faker->longitude,
'latitude' => $this->faker->latitude,
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,9 @@
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
public function up(): void
{
if (Schema::hasTable('wilayas') || Schema::hasTable('communes')) {
return;
}

Schema::create('wilayas', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('arabic_name');
$table->decimal('longitude', 9, 6);
$table->decimal('latitude', 9, 6);
$table->timestamps();
});

Schema::create('communes', function (Blueprint $table) {
$table->id();
$table->string('name');
Expand All @@ -40,12 +25,9 @@ public function up()

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
public function down(): void
{
Schema::dropIfExists('communes');
Schema::dropIfExists('wilayas');
}
};
32 changes: 32 additions & 0 deletions database/migrations/create_wilayas_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('wilayas', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('arabic_name');
$table->decimal('longitude', 9, 6);
$table->decimal('latitude', 9, 6);
$table->timestamps();
});

}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('wilayas');
}
};
3 changes: 3 additions & 0 deletions database/seeders/WilayaCommuneSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public function run(): void
$this->command->comment('Wilayas/Communes already loaded');
}

/**
* Load and insert Wilayas and Communes data.
*/
protected function loadData(): void
{
$this->insertWilayas();
Expand Down
2 changes: 0 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
includes:
- vendor/larastan/larastan/extension.neon
- ignore-by-php-version.neon.php
parameters:
level: max
paths:
- src/
- tests/
- routes/
36 changes: 20 additions & 16 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,25 @@
use Kossa\AlgerianCities\Controllers\Api\CommuneController;
use Kossa\AlgerianCities\Controllers\Api\WilayaController;

Route::prefix('api')
->middleware('api')
->group(function (): void {
// Wilayas
Route::controller(WilayaController::class)->group(function (): void {
Route::get('wilayas', 'index'); // Get all wilayas
Route::get('wilayas/{id}', 'show'); // Get specific wilaya
Route::get('wilayas/{id}/communes', 'communes'); // Get communes by wilaya
Route::get('search/wilaya/{q}', 'search'); // Search wilayas
});
if (config('algerian-cities.api_enabled')) {

Route::prefix('api')
->middleware('api')
->group(function (): void {
// Wilayas
Route::controller(WilayaController::class)->group(function (): void {
Route::get('wilayas', 'index'); // Get all wilayas
Route::get('wilayas/{id}', 'show'); // Get specific wilaya
Route::get('wilayas/{id}/communes', 'communes'); // Get communes by wilaya
Route::get('search/wilaya/{q}', 'search'); // Search wilayas
});

// Communes
Route::controller(CommuneController::class)->group(function (): void {
Route::get('communes', 'index'); // Get all communes
Route::get('communes/{id}', 'show'); // Get specific commune
Route::get('search/commune/{q}', 'search'); // Search communes
// Communes
Route::controller(CommuneController::class)->group(function (): void {
Route::get('communes', 'index'); // Get all communes
Route::get('communes/{id}', 'show'); // Get specific commune
Route::get('search/commune/{q}', 'search'); // Search communes
});
});
});

}
Loading