Laravel5.8で都道府県/市区町村データをAPIを使ってmigration/seederで一括紐付け登録

# たまに必要になる都道府県と市区町村のマスタデータ登録

APIを使ってmigrationとseederだけで一括紐付け登録が出来るようにしました。

## メリット

- コピペで動く
- APIで市区町村情報を取得するので実行するたびに最新情報ゲッツ
- 都道府県コードをIDに変換してるが、都道府県コードをprimary_keyにすることも可能（こっちのが良いかも）

## 概要

都道府県と市区町村を紐づけてDBにマスタとして登録したかったのですが、
Excelが嫌いなのでプログラムで書くことにした。

## やりたいこと

親テーブルの都道府県に子テーブルの市区町村を紐づけてマスタとして使いたかった。

> Qiitaに都道府県とか一括で登録するライブラリ作ってる方がいましたが、
とりあえず今回は自作しました。
時間ない方はどうぞ
[日本の住所関連のマスターデータをライブラリにしてみた](https://qiita.com/yamaji_daisuke/items/63a77374588b3671d854)

## Migration作成

まずはMigrationから作っていきます。

ターミナルを開いてファイルを作成！

```terminal
php artisan make:migration create_prefectures_table
php artisan make:migration create_cities_table
```

### 都道府県（prefectures）

とりあえずup()だけ

```php:2020_01_01_123456_create_prerfectures_table.php
    public function up()
    {
        Schema::create('prefectures', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name')->comment('都道府県名');
        });
    }
```

### 市区町（cities）

こっちもup()だけ
`prefectures`のidと`cities`のprefecture_idで外部キーを設定してます。

```php:2020_01_01_123456_create_cities_table.php
    public function up()
    {
            $table->increments('id');
            $table->unsignedInteger('prefecture_id');
            $table->string('city_code')->comment('市区町村コード');
            $table->string('name')->comment('市区町村名');

            $table->index('prefecture_id');
            $table->index('name');

            $table->foreign('prefecture_id')
            ->references('id')
            ->on('prefectures')
            ->onDelete('cascade')
            ->onUpdate('cascade');
    }
```

## 外部APIを使うので必要なライブラリをインストール

全国地方公共団体というところが提供しているAPIに市区町村コードが入ったものがあったのでそれを使う。
外部APIなのでライブラリをインストールする

### Guzzleをインストール

PHPで外部APIを叩けるモジュールである`Guzzle`をインストール

ターミナルを開いて...

```terminal
composer require guzzlehttp/guzzle
```

これで準備OK

## Seederで登録

Seederファイルを作成しましょう。

またターミナル開いて...

```terminal
php artisan make:seed PrefecturesTableSeeder
php artisan make:seed CitiesTableSeeder
```

### 都道府県（prefectures）

ここは数が少ないので配列で順次保存してマスタを作成

**※重要**　今回idを都道府県コードに見立てて使っていくので順番ずれたら終わりです。
下記の配列通りにしてください。

> それか別で都道府県コード持ってもいいです

```php:PrefecturesTableSeeder.php
<?php

use Illuminate\Database\Seeder;

class PrefecturesTableSeeder extends Seeder
{
    private $prefectures = [
        "北海道",
        "青森県",
        "岩手県",
        "宮城県",
        "秋田県",
        "山形県",
        "福島県",
        "茨城県",
        "栃木県",
        "群馬県",
        "埼玉県",
        "千葉県",
        "東京都",
        "神奈川県",
        "新潟県",
        "富山県",
        "石川県",
        "福井県",
        "山梨県",
        "長野県",
        "岐阜県",
        "静岡県",
        "愛知県",
        "三重県",
        "滋賀県",
        "京都府",
        "大阪府",
        "兵庫県",
        "奈良県",
        "和歌山県",
        "鳥取県",
        "島根県",
        "岡山県",
        "広島県",
        "山口県",
        "徳島県",
        "香川県",
        "愛媛県",
        "高知県",
        "福岡県",
        "佐賀県",
        "長崎県",
        "熊本県",
        "大分県",
        "宮崎県",
        "鹿児島県",
        "沖縄県"
    ];

    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        foreach ($this->prefectures as $prefecture) {
            DB::table("prefectures")->insert([
                "name" => $prefecture
            ]);
        }
    }
}
```

### 市区町（cities）

本題の市区町村マスタの登録です。

```php:CitiesTableSeeder.php
<?php

use Illuminate\Database\Seeder;
use GuzzleHttp\Client;
use App\Prefecture;
use App\City;

class CitiesTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run(Client $client, Prefecture $prefecture, City $city)
    {
        // 都道府県取得
        $prefectures = $prefecture->all();

        foreach ($prefectures->pluck('id') as $prefecture_id) {
            // 外部API全国地方公共団体コード
            $api = 'https://www.land.mlit.go.jp/webland/api/CitySearch?area=' .str_pad($prefecture_id, 2, 0, STR_PAD_LEFT);
            $respone_datas = $client->request('GET', $api);
            $respone_bodys = json_decode($respone_datas->getBody()->getContents(), true);

            // APIのステータスがOKなら実行
            if ($respone_bodys['status'] === 'OK') {
                foreach ($respone_bodys['data'] as $respone_body) {
                    // 都道府県の外部キーを指定して市区町村を登録
                    $city->create([
                        'prefecture_id' => $prefecture_id,
                        'city_code'     => $respone_body['id'],
                        'name'          => $respone_body['name']
                    ]);
                }
            }
        }
    }
}
```

あとは`DatabasesSeeder`に登録

```php:DatabasesSeeder.php
<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call([
            PrefecturesTableSeeder::class,
            CitiesTableSeeder::class
        ]);
    }
}
```

またターミナルを開いてmigrationとseederを実行！！

```terminal
php artisan migrate --seed
```

ちなみにテストはしてないので悪しからず
終わり