I am using Laravel Excel package to import data from csv file to database. one of my filed is containing Japanese character(2-byte character). but when data is inserted to database all Japanese field is empty.
here is my code from controller
public function import( Request $request)
{
if ($request->hasFile('import_file')) {
Excel::import(new UsersImport, request()->file('import_file'));
}
return redirect('/')->with('success', 'All good!');
}
UsersImport function:
use App\Item;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
class UsersImport implements ToModel
{
public function model(array $row)
{
$row = collect($row);
$chunks = $row->noHeading()->chunk(100);
foreach($chunks as $chunk){
return new Item([
'title' => $chunk[0],
'description' => $chunk[1],
]);
}
}
/*public function chunkSize(): int
{
return 100;
}*/
}
when i am putting english character inserting is working well.
one more problem, i can not exclude the heading of my excel sheet.
Related
While importing/uploading an excel file, if the data is already present in the excel file then update it in the Database or else insert it. This means before inserting should check with the database. So, anyone please help to solve with this issue:
This is the Import class for customers:
<?php
namespace App\Imports;
use App\Customer;
use Illuminate\Validation\Rule;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\Importable;
class ImportCustomers implements ToModel, WithHeadingRow, WithValidation
{
use Importable;
/**
* #param array $row
*
* #return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
// Check mobile already exists
/* $count = Customer::where('mobile',$row['mobile'])->count();
dd($count);
if($count > 0){
return null;
} */
return new Customer([
'customer_name' => $row['customer_name'],
'mobile' => $row['mobile'],
'email' => $row['email']
]);
}
public function rules(): array
{
return [
'*.customer_name' => 'required',
'*.mobile' => 'required|unique:customers',
'*.email' => 'required',
];
}
}
/* This is Controller:*/
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Requests\CustomerImportRequest;
use App\Imports\ImportCustomers;
use App\Exports\ExportCustomers;
use Maatwebsite\Excel\Facades\Excel;
use DB;
use App\Customer;
use Illuminate\Support\Arr;
class ImportExportExcelController extends Controller
{
protected $customers;
public function __construct(Customer $customers){
$this->customers = $customers;
}
public function index()
{
$customers = $this->customers->orderBy('id', 'desc')->get();
return view('ImportExportExcel', compact('customers'));
}
public function importExcel(CustomerImportRequest $request)
{
try {
if ($request->hasFile('import_file'))
{
$file = $request->file('import_file');
$columnRead = (new ImportCustomers)->toArray($file);
$customerCheck = $this->customers->where('mobile',$columnRead[0][1]["mobile"])->first(); //**here not getting result, rather shows null**
//dd($customerCheck);
if($customerCheck)
{
$customers = $customerCheck;
/*
**How to update if duplicates are found and display old values updated. How to achieve this?**
*/
}else{
$customers = new $this->customers;
Excel::import(new ImportCustomers, $file);
return redirect()->back()->with('success','Data imported successfully.');
}
}
} catch (\Maatwebsite\Excel\Validators\ValidationException $e) {
$failures = $e->failures();
//dd($failures);
return redirect()->back()->with('import_errors', $failures);
}
}
public function exportExcel()
{
$customers = Customer::select(["customer_name", "mobile", "email"])->get();
return Excel::download(new ExportCustomers($customers), 'customers.xlsx');
}
}
/This is the database migration schema:/
public function up()
{
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->string('customer_name');
$table->string('mobile', 13)->unique();
$table->string('email')->nullable();
$table->timestamps();
});
}
Here "mobile" is unique, So if values like customer_name, and email are with modified values in an excel sheet with the same mobile no. then while importing, values should be updated.
excel sheet
I have used maatwebsite with Laravel 6
Controller :
Excel::import(new ImportCustomers(), $file);
then you could apply your logic at the Import class for customers:
public function model(array $row)
{
try {
$mobile = $row[1]; // referenced by row
$customer_name = $row[0];
$email = $row[1];
$customer = Customer::where('mobile', $mobile)->first();
//apply your logic
if (!$customer) { // you may not need if else, if no customer exists then create a new record and assign mobile
$customer = new Customer();
$customer->mobile = $mobile;
}
$customer->customer_name = $customer_name;
$customer->email = $email;
$customer->save();
return $customer;
} catch (\Exception $ex) {
dd($ex);
return;
}
}
Also please remove the rule about mobile, I think this should work
"*.mobile' => 'required',"
because your logic handles that mobile is unique.
//Check for the existing value in database and if result is found do this.
public function model(array $row)
{
// Check mobile already exists
$count = Customer::where('mobile',$row['mobile'])->first();
if($count){
return;
}
else{
return new Customer([
'customer_name' => $row['customer_name'],
'mobile' => $row['mobile'],
'email' => $row['email']
]);
}
}
I am using excel 3.1 in Laravel for importing excel files. I have included a validation for the name field. So whenever the name field is duplicating it will not import that row data to DB. everything works fine up to here. but the problem is I want to show success message in the controller. But the message is not showing and not showing any other error messages.
This is my import function
namespace App\Imports;
use App\Products;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithStartRow;
use Maatwebsite\Excel\Concerns\SkipsOnError;
use Maatwebsite\Excel\Concerns\SkipsErrors;
use Maatwebsite\Excel\Concerns\Importable;
use App\Categories;
use App\Brand;
use App\Unit;
use Maatwebsite\Excel\Concerns\WithValidation;
// use Illuminate\Validation\Rule;
// use Throwable;
class ExcelImport implements ToModel, WithStartRow, WithValidation, SkipsOnError
{
use Importable, SkipsErrors;
/**
* #param array $row
*
* #return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
$name = $row[0];
$des = $row[1];
$product = new Products([
'name' => $row[0],
'description' => $row[1],
]);
return $product;
}
public function startRow(): int
{
return 2;
}
public function rules(): array{
return[
'0' => 'unique:products,name',
];
}
}
this is my controller
public function uploadfile(Request $request)
{
$this->validate($request, [
'file' => 'required',
]);
if($request->hasfile('file'))
{
foreach($request->file('file') as $file)
{
$import = new ExcelImport;
$import = $import->import($file);
}
//if the import is successful then I want to show some messages here
}
else{
return back()->with('error','File contains invalid data. Please upload a valid file.');
}
}
I am trying to delete data by using a foreign key but unfortunately not deleting from FreeDownloadFiles tables how can I delete data from this table please help me thanks.
Note: data is successfully deleting from freedownload table but not deleting from FreeDownloadFiles tables
free_download table
id | name | images
free_download_files table
id | free_download_id | images
Controller
public function destroy(Request $request)
{
$freedownload = FreeDownload::findOrFail($request->deleteId);
$freedownloadfiles = FreeDownloadFiles::where('free_download_id', $request->deleteId)->get();
foreach ($freedownloadfiles as $key => $value) {
$delete = $value->delete();
}
// apply your conditional check here
if (false) {
$response['error'] = 'This FreeDownload has something assigned to it.';
return response()->json($response, 409);
} else {
Storage::disk('yourstitchart')->delete($freedownload->icon);
$response = $freedownload->delete();
return response()->json($response, 200);
}
}
You can automate the deleting of the images/files associated with the FreeDownloadFiles records by hooking into the model deleting event in the FreeDownloadFiles model definition.
class FreeDownloadFile extends Model
{
protected static function booted()
{
static::deleting(function ($record) {
/**
* if images field contains string with comma separated paths to image files
* convert to array explode(',', $record->images)
* replace comma with whatever separator is used eg ;
*/
foreach(explode(',', $record->images) as $image) {
Storage::delete($image);
}
});
}
}
Similarly to automate deleting of FreeDownloadFiles associated with a FreeDownload we can hook into the deleting event for FreeDownload
class FreeDownload extends Model
{
protected static function booted()
{
static::deleting(function ($record) {
//can also use higher order magic
//$record->freeDownloadFiles->each->delete();
foreach($record->freeDownloadFiles as $file) {
$file->delete();
}
});
}
}
Then the controller method can become simple as
public function destroy(Request $request)
{
$freedownload = FreeDownload::findOrFail($request->deleteId);
// apply your conditional check here
if (false) {
$response['error'] = 'This FreeDownload has something assigned to it.';
return response()->json($response, 409);
} else {
Storage::disk('yourstitchart')->delete($freedownload->icon);
$response = $freedownload->delete();
return response()->json($response, 200);
}
}
Hi I have a large csv file with 130.000 rows
I use laravel excel 3.1 and lavaravel 5.8
Import class:
<?php
namespace App\Imports;
use App\UsoSuelo;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
class UsoSueloImport implements ToModel, WithHeadingRow, WithChunkReading, WithBatchInserts
{
/**
* #param array $row
*
* #return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
return new UsoSuelo([
'cod_pais' => $row['cod_pais'],
'cod_fundo' => $row['cod_fundo'],
'nom_fundo' => $row['nom_fundo'],
]);
}
public function batchSize(): int
{
return 1000;
}
public function chunkSize(): int
{
return 1000;
}
}
And I use a trait class from my controller:
trait storeTrait{
public function storeUsoSuelo($archivo) {
Excel::import(new UsoSueloImport,$archivo);
}
public function storeFundo($archivo) {
Excel::import(new FundosImport,$archivo);
}
public function storeFundoGrilla($archivo) {
Excel::import(new FundosGrillasImport,$archivo);
}
public function storeCuadrante($archivo) {
Excel::import(new CuadrantesImport,$archivo);
}
}
This is my ImportController
class ImportController extends Controller
{
use storeTrait {
storeUsoSuelo as storeUsoSuelos;
storeFundo as storeFundos;
storeFundoGrilla as storeFundoGrillas;
storeCuadrante as storeCuadrantes;
}
public function store(Request $request)
{
$usoSuelo = 'uso_suelo.csv';
$this->storeUsoSuelos($usoSuelo);
$cuadrante = 'cuadrantes.csv';
$this->storeCuadrantes($cuadrante);
$fundo = 'mv_qav_fundos.csv';
$this->storeFundos($fundo);
$fundoGrilla = 'fundos_grilla.csv';
$this->storeFundoGrillas($fundoGrilla);
}
}
I have done tests and my code works with a csv of less than 100 rows
but when I try with the 130,000 rows it takes too long, and I end up getting the following error:
"Maximum execution time of 60 seconds exceeded"
And after 1 minute only 4000 rows have been inserted in the database (postgresql)
I put these 2 lines in my controller, at the beginning of the script:
ini_set ('max_execution_time', 3600);
ini_set ('memory_limit', '2048M');
With this I solved it, I also changed the chunk from 1000 to 5000, but it still takes too long, at least 5 minutes
Have you tried this package league/csv from The League of Extraordinary Packages.
If you only need support for CSV that is, and not xlsx or other excel types.
From what I read this package might give you a better performance, this comment from one of the Maatwebsite team members (the package you are currently using) also confirms this.
I have upgraded the laravel excel library (Maatswebsite) from 2x to 3.1 (running Laravel 5.6/php 7.1) and trying to make my old data work (download exported file) and cannot work out how to pass my $data (which is an array from a foreach DB query (not eloquent) in controller) to the UsersExport.php class...
If I manually create a test collection (mirroring my $data array) in the class:
return collect([
[
'name' => 'F Name 1',
'surname' => 'Last Name 1',
'email' => 'Email 1'
'date_completed' => 'xx/xx/xx'
],
[
'name' => 'F Name 2',
'surname' => 'Last Name 2',
'email' => 'Email 2',
'date_completed' => 'xx/xx/xx'
]
]);
the above works perfect and the file is created and downloads when I run:
return Excel::download(new UsersExport, 'Test.xlsx');
But I want to pass my array ($data) from the controller to the class and not sure HOW I do this... I am trying to get something like this to work:
return Excel::download(new UsersExport($data), 'Test.xlsx');
From reading the specific posts I could find, I believe I need to create a constructor in the Class to accept my $data - but not sure how, and how to return that data if I succeed in my class accepting the data etc... Is the FromCollection the right option?
private $data;
public function __construct($data)
{
$this->data = $data;
}
Appreciate any assistance.... Thanks in advance.
Your approach is right. then use the collection() function to return that data.
private $data;
public function __construct($data)
{
$this->data = $data;
}
public function collection()
{
return $this->data;
}
if you want passing param data to class you use construct.
Example Controller:
<?php
namespace App\Http\Controllers\Reports;
use App\Http\Controllers\Controller;
use Maatwebsite\Excel\Facades\Excel;
use App\Exports\CustomerinvoiceExport;
use App\Model\OrderInvoiceList;
use Illuminate\Http\Request;
class CustomerInvoiceController extends Controller
{
public function index(Request $request)
{
if ($request->has('start_date')) {
$start_date = $request->start_date;
} else {
$date_now = Carbon::now();
$start_date = $date_now->toDateString();
}
if ($request->has('end_date')) {
$end_date = $request->end_date;
} else {
$date_now = Carbon::now();
$end_date = $date_now->toDateString();
}
$customer_invs = OrderInvoiceList::customer_invoice($start_date, $end_date);
return Excel::download(new CustomerinvoiceExport($customer_invs), 'Customer_Invoice_Report.xlsx');
}
}
}
Class Export
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromCollection;
class CustomerinvoiceExport implements FromCollection
{
protected $customer_invs;
/**
* Customer Invoice Report
*/
public function __construct($customer_invs)
{
$this->customer_invs = $customer_invs;
}
/**
* #return invoice_list
*/
public function collection(): array
{
$invoice_list = $this->invoice_list;
...........your logic here....
}
}