---
# System prepended metadata

title: laravel排程下載外部Url檔案，及更新進資料庫資料
tags: [PHP, ' Backend', ' Laravel']

---

---
tags: PHP, Laravel, Backend
disqus: HackMD
---

# laravel排程下載外部Url檔案，及更新進資料庫資料

## 如何下載外部公開URL
首先利用Client套件下載外部url的csv檔案。

本文撰寫使用抓取此網址`https://od.cdc.gov.tw/acute/幼兒常規疫苗接種時間試算表.csv`為範例

```php=
public function download()
{
    $client = new \GuzzleHttp\Client();
    $a = $client->get('https:/example/example.csv', ['save_to' => resource_path() . '/download/file.csv']); 
    return response(200);
}
```

## 如何將下載檔案匯進資料庫
使用laravel-excel套件將下載的檔案import進資料庫

[laravel-excel安裝](https://docs.laravel-excel.com/3.1/getting-started/installation.html)

因為等等會用到先說說laravel ORM的firstOrCreate方法

功能 : 將嘗試使用給定的列/值對定位數據庫記錄。如果在數據庫中找不到模型，則會插入一條記錄，其中包含將第一個數組參數與可選的第二個數組參數合併後的屬性

以下為文檔範例:

```php=
use App\Models\Flight;

// Retrieve flight by name or create it if it doesn't exist...
$flight = Flight::firstOrCreate([
    'name' => 'London to Paris'
]);

// Retrieve flight by name or create it with the name, delayed, and arrival_time attributes...
$flight = Flight::firstOrCreate(
    ['name' => 'London to Paris'],
    ['delayed' => 1, 'arrival_time' => '11:30']
);

```

再來先創建要傳遞的類
檔案可以放在 app/imports/ExampleImport.php
```php=
<?php

namespace App\Imports;

use App\Vaccination;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;

class VaccinationImport implements ToCollection
{
    public function collection(Collection $rows)
    {
        foreach ($rows as $k => $row) 
        {
            if ($k < 1) continue; // 跳過標題

            Vaccination::firstOrCreate([ // 
            'age' => $row[0], 'kind' => $row[1], 'remark' => $row[3]
            ]);
        }
    }
}
```
將 VaccinationImport 對像傳遞給Excel::import()方法，將告訴包如何導入作為第二個參數傳遞的文件，第二個參數的文件就是上面程式碼下載下來的csv檔案放置位置。

該文件應該位於您的默認文件系統磁盤中（參考資料config/filesystems.php）。

```php=
public function import() 
{
    // 我沒有讓它找默認的，讓他尋找resource資料夾底下檔案
    Excel::import(new VaccinationImport, resource_path('/download/file.csv'));
}
```
## 功能合併新增排程
在cmd輸入以下指令，創建command檔案，算是一個可以自己寫命令(shell)的檔案

```cmake=
php artisan make:command DownloadCSV
```

接著在DownloadCSV.php中修改
```php=
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Imports\VaccinationImport;
use Maatwebsite\Excel\Facades\Excel;

class DownloadCSV extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'download:vaccination';  // 定義一個命令

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '排程自動下載資料，對比資料庫寫入';  // 一些介紹

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle() // 主要程式碼
    {
        $this->download(); // 下載外部csv
        
        $this->import(); // 對比資料庫更新及新增
    }

    public function download()
    {
        $client = new \GuzzleHttp\Client();
        $client->get('https:/example/example.csv', ['save_to' => resource_path() . '/download/file.csv']); 

        return response(200);
    }

    public function import() 
    {
        Excel::import(new VaccinationImport, resource_path('/download/file.csv'));
    }
}
```

修改完成接下來到app/Console/Kernel.php

修改及導入命令程式碼

```php=
<?php

namespace App\Console;

use App\Console\Commands\DownloadCSV; // 導入
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        DownloadCSV::class
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    // 定義要排程的指令或流程
    protected function schedule(Schedule $schedule)
    {
        // 這邊就會跑command檔案handle函式
        // 設定為一個小時跑一次
        $schedule->command('download:vaccination')->hourly();
    }

    /**
     * Register the commands for the application.
     *
     * @return void
     */
    protected function commands()
    {
        $this->load(__DIR__.'/Commands');

        require base_path('routes/console.php');
    }
}
```

程式碼部分就算完成了，接下來就是要設定排程工作

我是在Linux上面做開發，如要要讓它排程就要加入 CronJob

在Linux上輸入

`crontab -e`

按i編輯，輸入以下這行，它是告訴這個package每一分鐘run一次`php artisan schedule:run` 就是跑排程的意思。

```
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
```

`path-to-your-project`改成你的專案路徑

輸入完畢按下esc，然後輸入:wq離開並儲存，跑出以下這行表示成功拉

`crontab: installing new crontab`
## 參考資料
更多相關排程時間參考[這裡](https://laravel.com/docs/8.x/scheduling#schedule-frequency-options)

更多排程相關資料請參照[laravel Task Scheduling 文檔](https://laravel.com/docs/8.x/scheduling)
