زمانی که بر روی پروژههای بزرگ تجارت آنلاین یا پروژههای مشابه کار میکنید، نیاز دارید تا قابلیت Export و Import اطلاعات دیتابیس در قالب فایلهای CSV یا اکسل را در پروژهی خود داشته باشید. در لاراول، شما میتوانید این کار را با استفاده از پکیج maatwebsite/excel انجام دهید. این پکیج متدهای فراوانی را برای نیازمندیهای مختلف، در اختیار توسعهدهندگان لاراول قرار میدهد. در این مقاله قصد داریم نحوهی نصب و استفاده از این پکیج را به شما آموزش دهیم تا بتوانید با استفاده از آن، هم فایلهای اکسل یا CSV را به دیتابیس خود اضافه کنید و هم از دیتابیس خود Backup بگیرید. پس تا انتهای این مقاله با ما همراه باشید.
پیشنیاز
برای شروع آموزش ورودی و خروجی اکسل و CSV در لاراول، به دانش کافی در زمینهی لاراول نیاز دارید.
نصب لاراول
ابتدا یک پروژهی جدید لاراول را ایجاد میکنیم. برای این منظور دستور زیر را در مسیر دلخواه خود اجرا کنید:
سپس با دستور زیر وارد پوشهی پروژهای که ایجاد کردهاید، شوید:
cd laravel-excel-csv
سپس دستور زیر را اجرا کنید:
php artisan serve
پس از اجرای این دستور، پروژه بر روی پورت 8000 لوکال هاست در دسترس است. با وارد کردن آدرس http://localhost:8000 در نوار آدرس مرورگر، با این صفحه مواجه میشوید:
برقراری ارتباط با دیتابیس
قدم بعدی، برقراری ارتباط با دیتابیس است. ابتدا یک دیتابیس دلخواه را ایجاد کنید و سپس مقادیر متغیرهای زیر را در فایل env. پروژه بهروز کنید:
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
ایجاد جداول
با استفاده از دستور زیر، جداول پیشفرض لاراول را ایجاد کنید:
php artisan migrate
نصب پکیج
اکنون وقت آن رسیده که پکیج maatwebsite/excel را در پروژهی لاراول خود نصب کنیم. برای نصب این پکیج از دستور زیر استفاده کنید:
composer require maatwebsite/excel
برای Publish کردن فایل پیکربندی پکیج، دستور زیر را اجرا کنید:
پس از اجرای این دستور، میتوانید با مراجعه به پوشهی config و فایل excel.php، تنظیمات مربوط به پیکربندی پکیج را مشاهده کنید یا در صورت لزوم، تغییر دهید.
ایجاد کاربر
اکنون میخواهیم تعدادی کاربر تصادفی را به جدول Users اضافه کنیم. برای این منظور، با استفاده از دستور زیر به محیط Tinker وارد شوید:
php artisan tinker
سپس دستور زیر را برای ایجاد کاربران تصادفی اجرا کنید:
User::factory()->count(50)->create();
اکنون میتوانید با دستور زیر از محیط Tinker خارج شوید:
exit
ایجاد مسیرها
نوبت آن رسیده که مسیرهای مورد نظر خود را ایجاد کنیم. به پوشهی routes و فایل web.php مراجعه کنید و سه مسیر زیر را برای Import و Export فایلهای اکسل و CSV تعریف کنید:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('file-import-export', [UserController::class, 'fileImportExport']);
Route::post('file-import', [UserController::class, 'fileImport'])->name('file-import');
Route::get('file-export', [UserController::class, 'fileExport'])->name('file-export');
Import
پکیج maatwebsite یک دستور را برای ایجاد کلاس Import در نظر گرفته است. از کلاس ایجاد شده در کنترلر دلخواه برای Import کردن فایل اکسل یا CSV به جدول موردنظرمان در دیتابیس استفاده میکنیم. حالا یک کلاس Import با نام UsersImport را برای جدول Users ایجاد کنید:
php artisan make:import UsersImport --model=User
با اجرای دستور فوق، کلاس UsersImport در مسیر app/Imports ایجاد میشود. به این فایل مراجعه کرده و از کدهای زیر در آن استفاده کنید:
<?php
namespace App\Imports;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
class UsersImport implements ToModel
{
/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
return new User([
'name' => $row[0],
'email' => $row[1],
'password' => Hash::make($row[2])
]);
}
}
Upserting
اگر بخواهیم ردیفهایی با ایمیل تکراری وارد جدول کاربران نشوند، باید Interface با نام WithUpserts را در کلاس Import فوق Implement کرده و از متد زیر استفاده کنیم:
class UsersImport implements ToModel, WithUpserts
{
/**
* @return string|array
*/
public function uniqueBy()
{
return 'email';
}
}
Skipping
اگر برای مثال بخواهیم از ردیفهایی که email ندارند، صرف نظر شود، میتوانیم مقدار null را در متد model برگردانیم:
public function model(array $row)
{
if (!isset($row[1])) {
return null;
}
return new User([
'name' => $row[0],
'email' => $row[1],
'password' => Hash::make($row[2])
]);
}
Batch
زمانی که فایل اکسل موردنظر، حاوی تعداد زیادی ردیف است، فرایند Import کردن میتواند زمانبر شود؛ چرا که برای هر ردیف یک کوئری Insert باید اجرا شود. شما میتوانید مشخص کنید که حداکثر چه تعداد ردیف در هر بار، میتواند به دیتابیس وارد شود. برای این کار لازم است که کلاس Import ایجاد شده، قرارداد WithBatchInserts را Implement کند:
<?php
namespace App\Imports;
use App\Models\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
class UsersImport implements ToModel, WithBatchInserts
{
/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
return new User([
'name' => $row[0],
'email' => $row[1],
'password' => Hash::make($row[2])
]);
}
public function batchSize(): int
{
return 1000;
}
}
همانطور که میبینید، در متد batchSize، تعداد حداکثر 1000 ردیف را برای هر بار Import کردن، مشخص کردهایم.
Chunking
هنگامی که حجم فایل اکسل بالا باشد، ممکن است فرایند Import کردن، تاثیر زیادی بر روی Memory Usage داشته باشد. برای رفع این مشکل، میتوانیم با Implement کردن قرارداد WithChunkReading در کلاس Import، فایل را به صورت تکه تکه، Import کنیم:
<?php
namespace App\Imports;
use App\Models\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithChunkReading;
class UsersImport implements ToModel, WithBatchInserts, WithChunkReading
{
/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
return new User([
'name' => $row[0],
'email' => $row[1],
'password' => Hash::make($row[2])
]);
}
public function batchSize(): int
{
return 1000;
}
public function chunkSize(): int
{
return 1000;
}
}
میبینید که در متد chunkSize، تعداد 1000 ردیف را به هر تکه اختصاص دادهایم. بهترین حالت برای فایلهای با حجم بالا، استفادهی همزمان از هر دو قرارداد WithBatchInserts و WithChunkReading میباشد.
Queue
میتوانید فرایند Import کردن را در صف یا Queue قرار دهید. برای این کار نیاز است که کلاس Import ایجاد شده، قرارداد ShouldQueue را Implement کند. این قرارداد باید با قرارداد WithChunkReading استفاده شود:
<?php
namespace App\Imports;
use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\WithChunkReading;
class UsersImport implements ToModel, WithChunkReading, ShouldQueue
{
...
}
Export
پکیج maatwebsite یک دستور دیگر را نیز برای ایجاد کلاس Export در نظر گرفته است. از کلاس ایجاد شده برای Export کردن اطلاعات دیتابیس، در قالب فایل اکسل یا CSV استفاده میکنیم. حالا یک کلاس Export با نام UsersExport را برای جدول Users ایجاد کنید:
php artisan make:export UsersExport --model=User
با اجرای دستور فوق کلاس UsersExport در مسیر app/Exports ایجاد میشود. به این فایل مراجعه کرده و از کدهای زیر در آن استفاده کنید:
<?php
namespace App\Exports;
use App\Models\User;
use Maatwebsite\Excel\Concerns\FromCollection;
class UsersExport implements FromCollection
{
/**
* @return \Illuminate\Support\Collection
*/
public function collection()
{
return User::all();
}
}
FromQuery
برای کوئریهای بزرگ، بهتر است که قرارداد FromQuery را به جای قرارداد FromCollection در کلاس فوق، Implement کنیم تا کوئری به صورت تکه تکه اجرا شود:
<?php
namespace App\Exports;
use App\Models\User;
use Maatwebsite\Excel\Concerns\FromQuery;
class UsersExport implements FromQuery
{
public function query()
{
return User::query();
}
}
Queue
اگر حجم داده بالا باشد، بهتر است فرایند Export، در صف یا Queue قرار گیرد. برای این منظور، باید کلاس Export، قرارداد ShouldQueue را Implement کند.
Mapping
با Implement کردن قرارداد WithMapping، میتوانید فقط ستونهای دلخواه را در فایل خروجی داشته باشید یا مقادیر آنها را Customize کنید:
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\WithMapping;
use App\Models\User;
use Maatwebsite\Excel\Concerns\FromQuery;
class UsersExport implements FromQuery, WithMapping
{
public function query()
{
return User::query();
}
/**
* @return array
* @var User $users
*/
public function map($users): array
{
return [
ucwords($users->name),
$users->email,
$users->created_at
];
}
}
Heading
اگر بخواهید که هر ستون در فایل اکسل یا CSV خروجی، عنوان داشته باشد، باید قرارداد WithHeadings را Implement کنید:
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithHeadings;
use App\Models\User;
use Maatwebsite\Excel\Concerns\FromQuery;
class UsersExport implements FromQuery, WithMapping, WithHeadings
{
public function query()
{
return User::query();
}
/**
* @return array
* @var User $users
*/
public function map($users): array
{
return [
$users->id,
ucwords($users->name),
$users->email,
$users->created_at
];
}
public function headings(): array
{
return [
'#',
'Name',
'Email',
'Date Registered',
];
}
}
ایجاد کنترلر
اکنون باید یک کنترلر را برای اجرای عملیات موردنظرمان ایجاد کنیم. با استفاده از دستور زیر، یک کنترلر با نام UsersController ایجاد کنید:
php artisan make:controller UserController
اکنون متدهای موردنظرمان را که در مسیرها تعریف کردیم، پیادهسازی میکنیم:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;
use App\Imports\UsersImport;
use App\Exports\UsersExport;
class UserController extends Controller
{
/**
* @return \Illuminate\Support\Collection
*/
public function fileImportExport()
{
return view('file-import');
}
/**
* @return \Illuminate\Support\Collection
*/
public function fileImport(Request $request)
{
Excel::import(new UsersImport, $request->file('file')->store('temp'));
return back();
}
/**
* @return \Illuminate\Support\Collection
*/
public function fileExport()
{
return Excel::download(new UsersExport, 'users-collection.xlsx');
}
}
همانطور که میبینید، سه متد fileImportExport، fileImport و fileExport را ایجاد کردهایم.
متد fileImportExport
متد fileImportExport برای نمایش صفحهی مربوط به عملیات Import و Export کاربرد دارد.
متد fileImport
این متد پس از ذخیرهی موقت فایل، عملیات Import را انجام میدهد. این عملیات با استفاده از Excel Facade و متد import صورت میگیرد. اگر کلاس Import ایجاد شده، از Trait با نام Maatwebsite\Excel\Concerns\Importable استفاده کند، میتوان بدون استفاده از Facade و به شکل زیر عملیات Import را انجام داد:
(new UsersImport)->import($request->file('file')->store('temp'));
فایل ذخیره شده
میتوانید ابتدا فایل آپلود شده توسط کاربر را ذخیره کرده و سپس فایل ذخیره شده را به شکل زیر Import کنید:
به طور پیشفرض، فرمت فایل از Extention آن خوانده میشود. اگر میخواهید که خودتان فرمت فایل را مشخص کنید، میتوانید آن را به عنوان پارامتر سوم، به متد import پاس دهید. مثلا برای فرمت اکسل:
(new UsersImport)->import($request->file('file')->store('temp'), null, \Maatwebsite\Excel\Excel::XLSX);
یا برای فرمت CSV:
(new UsersImport)->import($request->file('file')->store('temp'), null, \Maatwebsite\Excel\Excel::CSV);
متد fileExport
این متد نیز با استفاده از Excel Facade و متد download، فایل اکسل خروجی را دانلود میکند. اگر کلاس Export ایجاد شده، از Trait با نام Maatwebsite\Excel\Concerns\Exportable استفاده کند، میتوان بدون استفاده از Facade و به شکل زیر عملیات Export را انجام داد:
return (new UsersExport)->download('users-collection.xlsx');
میتوانید در پارامتر دوم متد فوق، نوع فایل خروجی را نیز مشخص کنید. به صورت پیشفرض، نوع فایل از Extension موجود در پارامتر اول مشخص میشود:
return (new UsersExport)->download('users-collection.csv', \Maatwebsite\Excel\Excel::CSV);
ایجاد View
حالا قالب Blade موردنظرمان را برای انجام عملیات Import و Export، در مسیر resources/views ایجاد میکنیم:
در مقالهی خروجی اکسل و CSV در لاراول از مجموعه مقالات آموزش لاراول، با نحوهی Import و Export کردن فایلهای اکسل و CSV از دیتابیس در لاراول آشنا شدیم و برای این منظور از بهترین پکیج لاراول در این زمینه، یعنی پکیج maatwebsite/excel استفاده کردیم. برای مشاهدهی مستندات کامل خروجی اکسل و CSV در لاراول، میتوانید به وب سایت پکیج maatwebsite/excel مراجعه کنید.
امیدوار هستیم که این مقاله برای شما مفید بوده باشد. خوشحال میشویم نظرات، تجربیات و سوالات خود را با ما و سایر کاربران سون لرن به اشتراک بگذارید.
اگر به یادگیری بیشتر لاراول علاقه داری میتوانی در دوره آموزش لاراول کاربردی (بسته پروژه محور) شرکت کنی، این دوره شامل ۱۲ پروژه کاربردی و پر استفاده در دنیای واقعی است، که تمامی پروژهها به صورت کامل برنامه نویسی خواهند شد، تا دانشجو بتواند با روند ایجاد و تکمیل پروژه به صورت کامل آشنا شود.
۵ دیدگاه
۰۸ دی ۱۴۰۰، ۱۱:۱۲
سلام ممنون مفید بود اما یک سوال
ما یک یوزر داریم ک تعداد زیادی پست ساخته
با روابط چند به چند دریافت کردیم پستهای هر کاربر رو
هدف اینه وقتی به ستون پست رسیدیم rowهای جدیدی زیر row اطلاعات کاربر ایجاد شه که تنها و تنها ستون پست ان پر شود تا به اخرین پست میرسیم
در نهایت هم که row کاربر جدید
نازنین کریمی مقدم۱۱ دی ۱۴۰۰، ۱۴:۳۲
درود
شاید کتابخانهها هم توابعی در این خصوص داشته باشند که چون من خیلی تسلط ندارم در این مورد دوستان دیگر بهتر میتونند کمک کنند،
اما به طور کلی، شما باید قبل از هرکاری دیتا رو براساس آیدی کاربر مرتب کنید، بعد یک حلقه بنویسید که توش بیاد آیدی کاربر ردیف فعلی رو با قبلی مقایسه کنه. بعد یک شرط اینجا بنویسید که اگر یکی بود بیاد فقط ستون پست رو مقداردهی کنه و اگر نبود داده ردیف به طور کامل بشینه.
علی۲۱ شهریور ۱۴۰۰، ۱۲:۲۸
سلام
یه سوالی داشتم هرچی گشتم سرچ کردم راه حلی پیدا نشد
زمان import کردن چطور بگیبم اولین ردیف رو که هدینگ هست نادیده بگیره؟
بسیار علی و کاربردی بود. من از این پکیج استفاده میکردم اما از قابلیتهای اصلیش مثلChunking و ... نمیدونستم چطوری استفاده میشه. بنظرم این مقاله خیلی کاربردی هست