hakanispirli/laravel-turkey-geo-database

Laravel package for Turkish geographic data (cities, districts, neighborhoods) based on PTT database. Includes 81 cities, 900+ districts, and 50,000+ neighborhoods with postal codes.

Maintainers

Package info

github.com/hakanispirli/laravel-turkey-geo-database

Homepage

pkg:composer/hakanispirli/laravel-turkey-geo-database

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.3 2026-01-31 13:18 UTC

This package is auto-updated.

Last update: 2026-03-29 01:14:17 UTC


README

Latest Version Total Downloads License

Complete Turkish geographic data package for Laravel applications. Get all Turkish cities, districts, and neighborhoods with postal codes in your database with just a few commands.

Installation

Install the package via Composer:

composer require hakanispirli/laravel-turkey-geo-database

Setup Options

Choose the installation method that fits your needs:

Option 1: Standard Installation (Most Common)

Use this if you want the default database structure without modifications.

# 1. Publish migrations (creates timestamped migration files)
php artisan vendor:publish --tag=turkey-geo-migrations

# 2. Publish data files
php artisan vendor:publish --tag=turkey-geo-data

# 3. Run migrations
php artisan migrate

# 4. Seed the database
php artisan db:seed --class="Webmarka\TurkeyGeo\Database\Seeders\TurkeyGeoSeeder"

That's it! Your database now contains all Turkish geographic data.

Option 2: Custom Installation

Use this if you need to modify the database structure (add columns, change types, etc.).

# 1. Publish migrations
php artisan vendor:publish --tag=turkey-geo-migrations

# 2. Customize the migration files in database/migrations/
# Add your custom columns, indexes, or modifications

# 3. Publish data files
php artisan vendor:publish --tag=turkey-geo-data

# 4. Run migrations
php artisan migrate

# 5. Seed the database
php artisan db:seed --class="Webmarka\TurkeyGeo\Database\Seeders\TurkeyGeoSeeder"

💡 Pro Tip: Migration files are published with current timestamps, so they'll run after your existing migrations without conflicts.

⏱️ Seeding Time: Approximately 30-60 seconds to insert all data with progress tracking.

Basic Usage

Get All Cities

use Webmarka\TurkeyGeo\Models\City;

$cities = City::all();

Get Districts for a City

$ankara = City::where('name', 'ANKARA')->first();
$districts = $ankara->districts;

Get Neighborhoods for a District

use Webmarka\TurkeyGeo\Models\District;

$district = District::find(1);
$neighborhoods = $district->neighborhoods;

Search by Postal Code

use Webmarka\TurkeyGeo\Models\Neighborhood;

$neighborhoods = Neighborhood::where('postal_code', '06100')->get();

Common Use Cases

1. City Dropdown for Forms

// Controller
public function create()
{
    $cities = City::orderBy('name')->get();
    return view('address.create', compact('cities'));
}
<!-- Blade View -->
<select name="city_id">
    <option value="">Select City</option>
    @foreach($cities as $city)
        <option value="{{ $city->id }}">{{ $city->name }}</option>
    @endforeach
</select>

2. Dynamic District Loading (AJAX)

// Route
Route::get('/api/districts/{cityId}', function ($cityId) {
    return District::where('city_id', $cityId)
        ->orderBy('name')
        ->get(['id', 'name']);
});
// JavaScript
$('#city_id').change(function() {
    let cityId = $(this).val();
    $.get(`/api/districts/${cityId}`, function(districts) {
        $('#district_id').html('<option value="">Select District</option>');
        districts.forEach(district => {
            $('#district_id').append(`<option value="${district.id}">${district.name}</option>`);
        });
    });
});

3. Get Full Address Details

$neighborhood = Neighborhood::with('district.city')->find($id);

echo $neighborhood->name; // Neighborhood name
echo $neighborhood->district->name; // District name
echo $neighborhood->district->city->name; // City name
echo $neighborhood->postal_code; // Postal code

Database Structure

cities

  • id - City ID (1-81)
  • name - City name

districts

  • id - District ID
  • city_id - Belongs to city
  • name - District name

neighborhoods

  • id - Neighborhood ID
  • district_id - Belongs to district
  • name - Neighborhood name
  • area - Area/region information
  • postal_code - PTT postal code

Configuration (Optional)

You can customize table names, seeding batch size, and other options:

php artisan vendor:publish --tag=turkey-geo-config

Edit config/turkey-geo.php to customize:

  • Table names
  • Seeding batch size
  • Progress display options

Advanced Features

Eager Loading Relationships

// Load city with all its districts
$city = City::with('districts')->find(7);

// Load district with neighborhoods
$district = District::with('neighborhoods')->find(1);

Validation Example

use Illuminate\Validation\Rule;

public function rules()
{
    return [
        'city_id' => 'required|exists:cities,id',
        'district_id' => [
            'required',
            Rule::exists('districts', 'id')->where('city_id', $this->city_id),
        ],
        'neighborhood_id' => [
            'required',
            Rule::exists('neighborhoods', 'id')->where('district_id', $this->district_id),
        ],
    ];
}

Caching for Performance

use Illuminate\Support\Facades\Cache;

$cities = Cache::remember('turkish-cities', 3600, function () {
    return City::orderBy('name')->get();
});

Troubleshooting

Seeder Class Not Found

Run composer autoload dump:

composer dump-autoload

Data Files Not Found Error

Make sure you published the data files:

php artisan vendor:publish --tag=turkey-geo-data

Verify files exist in database/data/turkey-geo/ directory.

Memory Issues During Seeding

Reduce batch size in config file:

// config/turkey-geo.php
'seeding' => [
    'batch_size' => 500, // Default is 1000
],

Requirements

  • PHP ^8.2
  • Laravel ^11.0 or ^12.0

What's Included

  • 81 Turkish Cities (İller)
  • 900+ Districts (İlçeler)
  • 50,000+ Neighborhoods (Mahalleler)
  • PTT Postal Codes for all neighborhoods
  • Optimized Performance with indexed database columns
  • Eloquent Models with pre-configured relationships
  • Progress Tracking during data seeding

Contributing

Contributions are welcome! Please submit a Pull Request.

Security

If you discover any security issues, please email destek@webmarka.com.

Credits

License

The MIT License (MIT). See License File for more information.

Made with ❤️ by Webmarka