Backup dữ liệu hàng ngày với Laravel Excel
Xem thêm : Top website rèn luyện thuật toán tốt nhất cho sinh viên
Dữ liệu là một phần quan trọng cũng như là trái tim của một hệ thống vì vậy việc sao lưu dữ liệu để sử dụng lại khi cần thiết là việc rất quan trọng. Trong bài viết này mình hướng dẫn tạo một project đơn giản để backup dữ liệu sử dụng Laravel Excel.
Tại sao lại phải là excel, sao mình không backup file .sql
hay backup thư mục data, vì đây là yêu cầu backup dữ liệu từ khách hàng "Tự động backup dữ liệu hàng ngày (file csv)" vì vậy phải backup ra file .csv
hoặc .xlsx
thì khách hàng mới có thể sử dụng được.
Cài đặt Laravel Exel
Cài đặt Laravel Excel thông qua command:
composer require maatwebsite/excel:^3.1
Xem chi tiết docs cài đặt của Laravel Excel tại https://docs.laravel-excel.com/3.1/getting-started/installation.html
Tạo Exporting collections
Tạo class
Export với câu lệnh:
php artisan make:export AccountExport
Chỉnh sửa hàm AccountExport phù hợp với nghiệp vụ, dữ liệu muốn đồng bộ:
<?php
namespace App\Exports;
use App\Http\Helpers;
use App\Models\Account;
use DateTime;
use Exception;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
class AccountExport implements FromCollection, WithHeadings, ShouldAutoSize, WithMapping
{
use Exportable;
private $stt;
public function __construct()
{
$this->stt = 0;
}
/**
* @return Collection
*/
public function collection(): Collection
{
return Account::query()->select([
'name',
'name_org',
'phone_number',
'email',
'class',
'status',
'created_at'
])->where('deleted_at', null)
->get();
}
public function headings(): array
{
return [
'STT',
'Tên',
'Tên tổ chức',
'Số điện thoại',
'Email',
'Lớp',
'Trạng thái',
'Tạo ngày'
];
}
/**
* @throws Exception
*/
public function map($row): array
{
return [
$this->stt++,
$row->name,
$row->name_org,
$row->phone_number,
$row->email,
$row->class,
$row->status == 1? 'Hoạt động' : 'Khóa',
$row->created_at->format('d/m/Y H:i')
];
}
}
$this->stt++
thêm vào để đánh số thứ tự cho từng dòng
Mua Cloud VPS tại iNET, nhấn vào banner ở phía trên. Nhập mã TRANNGUYENHAN để được giảm giá thêm 10% khi mua dịch vụ Cloud VPS tại iNET.
Tạo job backup data
Tạo một bảng lưu trữ account_backups
để lưu lại tên file cũng như thời gian sao lưu của từng file để làm chức năng trên giao diện, tạo bảng bằng migrate với hàm up
như sau:
Schema::create('account_backups', function (Blueprint $table) {
$table->id();
$table->string('file_name');
$table->timestamps();
});
Tạo job BackupAccountDataJob
Tạo job bằng câu lệnh artisan:
php artisan make:job BackupAccountDataJob
Chỉnh sửa hàm handle
trong job để sao lưu dữ liệu và lưu kết quả sau khi sao lưu vào bảng account_backups
đã tạo ở trên:
public function handle()
{
$folder = 'backup/';
$name = 'account-' . now()->format('Y-m-d') . '.csv';
$path = $folder . $name;
Excel::store(new AccountExport(), $path, 'public', \Maatwebsite\Excel\Excel::CSV);
$backupFile = new AccountBackup();
$backupFile->fill([
'file_name' => $name
]);
$backupFile->save();
}
Vậy là cứ mỗi lần job này được chạy thì sẽ sinh ra 1 file csv ở trong thư mục storage/app/public/backup/*
và job sẽ tự đồng chèn một bản ghi là tên file vào trong bảng account_backups
.
Tạo command để chạy job
Tạo command chạy job bằng câu lệnh artisan:
php artisan make:command BackupAccountDataCommand
Tạo signature
cho command và viết hàm handle
như dưới:
<?php
namespace App\Console\Commands;
use App\Jobs\BackupAccountDataJob;
use Illuminate\Console\Command;
class BackupAccountDataCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'account:backup';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return void
*/
public function handle()
{
BackupAccountDataJob::dispatch();
}
}
Lập lịch để định kỳ Laravel sẽ gọi tới command chạy job đồng bộ dữ liệu, trong file App\Console\Kernel.php
thêm vào trong hàm schedule
dòng sau:
$schedule->command('account:backup')->daily();
Update crontab
để crontab gọi tới Job trong project, chạy crontab -e
và dán câu lệnh sau vào:
* * * * * php /home/trannguyenhan/CodeFolder/demoproject/artisan schedule:run
Lưu ý đổi /home/trannguyenhan/CodeFolder/demoproject
thành đường dẫn project của bạn.
Hiển thị dữ liệu backup cho phép người dùng tải về dữ liệu backup
Tạo 2 route, một là route để liệt kê danh sách file đã backup, một route là tải file backup tương ứng về, trong routes/web.php
thêm vào 2 routes:
Route::group(['namespace' => 'App\Http\Controllers', 'prefix' => 'account-backup'], function (){
Route::get('/', 'AccountBackupController@index')->name('account_backup');
Route::get('/download/{id}', 'AccountBackupController@download')->name('account_backup.download');
});
Tạo AccountBackupController
với 2 function tương ứng đã được định nghĩa trong web.php
:
<?php
namespace App\Http\Controllers;
use App\Models\AccountBackup;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
class AccountBackupController extends Controller
{
public function index()
{
$files = AccountBackup::query()
->orderBy('created_at', 'desc')
->paginate(15);
return view('account_backup.index',compact('files'));
}
public function download($id){
$file = AccountBackup::query()->where('id',$id)->first();
if($file == null){
$this->flashMessage('warning', __('messages.alert.add.not_found'), 'danger');
return redirect()->route('account_backup');
}
$fileName = $file->file_name;
$path = storage_path('app/public') . '/' . AccountBackup::BACKUP_FOLDER . '/' . $fileName;
$response = new BinaryFileResponse($path);
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
basename($path)
);
return $response;
}
}
Tạo file resources/views/account_backup/index.blade.php
:
@extends('layouts.admin.index')
@section('title', 'Danh sách sao lưu')
@section('content')
<div class="box box-primary">
<div class="box-body">
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table id="tabelapadrao" class="table table-condensed table-bordered table-hover">
<thead>
<tr>
<th>Tên file</th>
<th>Tạo ngày</th>
<th class="text-center">Hành động</th>
</tr>
</thead>
<tbody>
@foreach($files as $file)
<tr>
<td>{{ $file->file_name }}</td>
<td>{{ $file->created_at->format('d/m/Y H:i') }}</td>
<td class="text-center">
<a class="btn btn-warning btn-xs" href="{{ route('account_backup.download', $file->id) }}" title="Edit {{ $file->file_name }}"><i class="fa fa-download"></i></a>
</td>
</tr>
@endforeach
</tbody>
<tfoot>
<tr>
<th>Tên</th>
<th>Tạo ngày</th>
<th class="text-center">Hành động</th>
</tr>
</tfoot>
</table>
</div>
</div>
<div class="col-md-12 text-center">
{{ $files->links() }}
</div>
</div>
</div>
</div>
@endsection
- với
layouts.admin.index
là layout tương ứng của từng website phát triển, phần này mình chỉ đề cập tới nội dung được liệt kê trong trang là phần@section('content')
.
Dưới đây là kết quả sau khi hoàn thành:
Xem thêm : Top website rèn luyện thuật toán tốt nhất cho sinh viên
All rights reserved