Skip to content

Instantly share code, notes, and snippets.

@eristoddle
Created January 10, 2020 00:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eristoddle/eddc17707cd6c44dbeaf6014cda8339b to your computer and use it in GitHub Desktop.
Save eristoddle/eddc17707cd6c44dbeaf6014cda8339b to your computer and use it in GitHub Desktop.
Laravel CSV Import Controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Log;
class adminController extends Controller
{
use RegistersUsers;
protected $redirectTo = '/bsladmin/dashboard';
// NOTE: To add another import type just add more to this array and the
// rest will be handled by the code.
protected $importTypes = [
'Discounts' => [
'model' => 'App\Branch',
'id' => 'item_id',
'attributes' => [
'item_id',
'item_name',
'discount_percentage',
'discount_deadline',
'discount_description',
'discount_active_date',
'low_base_rate',
'high_base_rate',
'low_care_rate',
'high_care_rate',
'community_fee',
'real_rates_active',
],
'ignore' => [
'item_name'
]
]
];
protected $updateNulls = false;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function dashboard(Request $request) {
$imports = array_keys($this->importTypes);
return view('admin.dashboard', compact('imports'));
}
public function downloadTemplate(Request $request) {
$importType = $request->input('import');
return $this->generateImportTemplate($importType);
}
public function runImport(Request $request) {
$file = $request->file('csv_file');
if ($file == null) {
return redirect()->route('bsladmin/dashboard')
->with('error','You forgot to choose a file to import!');
}
$path = $file->getRealPath();
$importType = $request->input('import');
// TODO: Figure out why backup is empty or store csv file for restore
// $this->backup();
return $this->import($importType, $path);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\User
*/
protected function newUser(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password'])
]);
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
]);
}
protected function backup() {
Artisan::call('db:dump');
$output = Artisan::output();
Log::info("Database Backup -- new backup started before data import \r\n" . $output);
}
protected function listBackups() {
}
protected function restoreBackup() {
}
protected function generateImportTemplate(String $importType) {
$headers = [
"Content-type" => "text/csv",
"Content-Disposition" => "attachment; filename=".$importType."-import-template.csv",
"Pragma" => "no-cache",
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
"Expires" => "0"
];
$importModel = $this->importTypes[$importType];
$columnNames = $importModel['attributes'];
$dbModel = $importModel['model'];
$rows = $dbModel::get();
$callback = function() use ($columnNames, $rows ) {
$file = fopen('php://output', 'w');
fputcsv($file, $columnNames);
foreach ($rows as $row) {
$record = $row->toArray();
$trimmed = $this->arrayOnly($record, $columnNames);
fputcsv($file, $trimmed);
}
fclose($file);
};
return response()->stream($callback, 200, $headers);
}
protected function import(String $importType, String $path) {
$data = array_map('str_getcsv', file($path));
$attributes = array_shift($data);
$importModel = $this->importTypes[$importType];
$columnsCorrect = (count($attributes) == count($importModel['attributes'])) && !array_diff( $attributes, $importModel['attributes']);
if ($data == null || $attributes == null || $columnsCorrect != 1) {
return redirect()->route('bsladmin/dashboard')
->with('error','Incorrect import file!');
}
$dbModel = $importModel['model'];
$instance = new $dbModel();
$modelTable = $instance->getTable();
$importMap = array_combine($attributes, range(0, count($attributes) - 1));
foreach($data as $row) {
try {
$instance = $dbModel::where(
$importModel['id'],
$row[$importMap[$importModel['id']]])->first();
foreach($importModel['attributes'] as $key) {
if ($key == $importModel['id']) {
continue;
}
if (in_array($key, $importModel['ignore'])) {
continue;
}
if ((!$this->updateNulls && empty($row[$importMap[$key]]))) {
continue;
}
$columnType = Schema::getColumnType($modelTable, $key);
switch ($columnType) {
case "date":
$date = null;
if (!empty($row[$importMap[$key]])) {
$date = new \Carbon\Carbon($row[$importMap[$key]]);
}
$instance->{$key} = $date;
break;
default:
$instance->{$key} = $row[$importMap[$key]];
}
}
$instance->save();
} catch (Exception $e) {
Log::info('Import Error', (array)$e);
}
}
return redirect()->route('bsladmin/dashboard')
->with('success','Data imported!');
}
protected function arrayOnly($array, $keys) {
$remove = array_diff(array_keys($array), $keys);
foreach($remove as $key){
unset($array[$key]);
}
return $array;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment