├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── composer.json ├── config └── data-bringin.php ├── img.png ├── img_1.png ├── resources └── views │ └── import.blade.php ├── routes └── web.php └── src ├── Http ├── Controllers │ ├── Controller.php │ └── ImportController.php └── Requests │ ├── ImportRequest.php │ └── StoreImportRequest.php ├── Providers └── ImportServiceProvider.php └── Services └── ImportService.php /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | /vendor 3 | /.idea 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-data-bringin` will be documented in this file 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/vcian/laravel-data-bringin). 6 | 7 | Please read and understand the contribution guide before creating an issue or pull request. 8 | 9 | ## Protocol 10 | 11 | This project is open source, and as such, the maintainers give their free time to build and maintain the source code 12 | held within. They make the code freely available in the hope that it will be of use to other developers. It would be 13 | extremely unfair for them to suffer abuse or anger for their hard work. 14 | 15 | ## Pull Requests 16 | 17 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). 18 | 19 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 20 | 21 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 22 | 23 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 24 | 25 | - **Create feature branches** - Don't ask us to pull from your master branch. 26 | 27 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 28 | 29 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 30 | 31 | **Happy coding**! 32 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) ViitorCloud (https://viitorcloud.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Data Bringin 2 | 3 | [![Packagist](https://img.shields.io/packagist/l/vcian/laravel-data-bringin?style=for-the-badge)](https://packagist.org/packages/vcian/laravel-data-bringin) 4 | [![Total Downloads](https://img.shields.io/packagist/dt/vcian/laravel-data-bringin?style=for-the-badge)](https://packagist.org/packages/vcian/laravel-data-bringin) 5 | 6 | ## What It Does 7 | 8 | This package provides an easy and flexible way to import any kind of dynamic CSV files to a Laravel application's database. 9 | With this package, you can define your import mappings, which allows you to map columns in your CSV files to specific fields in your database tables. 10 | 11 | ## Installation & Usage 12 | 13 | > **Requires [PHP 8.0+](https://php.net/releases/) | [Laravel 8.0+](https://laravel.com/docs/8.x)** 14 | 15 | Require Laravel Data Bringin using [Composer](https://getcomposer.org): 16 | 17 | ```bash 18 | composer require vcian/laravel-data-bringin 19 | ``` 20 | ## Usage: 21 | 22 | You can access Data Brigin view via below route 23 | 24 | **Access Route:** http://yourdomain.com/data-bringin 25 | 26 | ![img_1.png](img_1.png) 27 | 28 | **Note:** 29 | 30 | 1) Don't forget to replace your actual domain with "yourdomain.com" 31 | 32 | 2) You can also update your custom route with config/data-brigin.php 33 | ![img.png](img.png) 34 | 35 | 3) By default, data-bringin support import data upto **10,000** records. 36 | If you want to upgrade more capacity than you have to make changes in php.ini file below parameter values. 37 | ```bash 38 | max_execution_time 39 | post_max_size 40 | memory_limit 41 | max_input_vars 42 | ``` 43 | 44 | 45 | 46 | ## Changelog 47 | 48 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. 49 | 50 | ## Contributing 51 | 52 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 53 | 54 | ## Security 55 | 56 | If you discover any security-related issues, please email ruchit.patel@viitor.cloud instead of using the issue tracker. 57 | 58 | ## Credits 59 | 60 | - [All Contributors](../../contributors) 61 | 62 | ## License 63 | 64 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 65 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vcian/laravel-data-bringin", 3 | "description": "Dynamic import csv and column mapping to a Laravel application mysql database.", 4 | "keywords": [ 5 | "laravel", 6 | "import", 7 | "csv-import", 8 | "dynamic-import", 9 | "datamapping", 10 | "csv import to mysql database", 11 | "database", 12 | "dynamic", 13 | "larage data import", 14 | "csv bulk data import", 15 | "csv", 16 | "csv data import", 17 | "mysql" 18 | ], 19 | "type": "library", 20 | "license": "MIT", 21 | "authors": [ 22 | { 23 | "name": "Vcian - ViitorCloud", 24 | "homepage": "https://github.com/vcian", 25 | "role": "Developer" 26 | } 27 | ], 28 | "require": { 29 | "php": "^8.0" 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "Vcian\\LaravelDataBringin\\": "src/" 34 | } 35 | }, 36 | "minimum-stability": "dev", 37 | "extra": { 38 | "laravel": { 39 | "providers": [ 40 | "Vcian\\LaravelDataBringin\\Providers\\ImportServiceProvider" 41 | ] 42 | } 43 | }, 44 | "require-dev": { 45 | "laravel/pint": "dev-main" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /config/data-bringin.php: -------------------------------------------------------------------------------- 1 | env('DATA_BRINGIN_PATH', 'data-bringin'), 15 | 16 | /* 17 | |-------------------------------------------------------------------------- 18 | | Data Bringin Route Middleware 19 | |-------------------------------------------------------------------------- 20 | | 21 | | These middleware will be assigned to every Data Bringin route, giving you 22 | | the chance to add your own middleware to this list or change any of 23 | | the existing middleware. Or, you can simply stick with this list. 24 | | 25 | */ 26 | 27 | 'middleware' => [ 28 | 'web', 29 | ], 30 | ]; 31 | -------------------------------------------------------------------------------- /img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vcian/laravel-data-bringin/34bebf6b764ca09738bd83f0e8560548b18d28d3/img.png -------------------------------------------------------------------------------- /img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vcian/laravel-data-bringin/34bebf6b764ca09738bd83f0e8560548b18d28d3/img_1.png -------------------------------------------------------------------------------- /resources/views/import.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Laravel - Data Bringin 7 | 9 | 10 | 833 | 834 | 835 |
836 |
837 |

Laravel Data Bringin 838 |

839 |
840 |
841 |
842 |
843 | 886 |
887 |
888 |
890 |
891 |
892 |
893 |
(request()->step ?? 1) == 1, 'tab-pane', 'first-step']) role="tabpanel" 895 | id="step1"> 896 |
897 | @csrf 898 | 899 |
900 |
901 |
902 |
903 |
904 |

Import CSV File

905 |
906 |
907 |
908 | 909 |
910 |
911 | 916 | @error('file') 917 |
{{ $message }}
918 | @enderror 919 |
920 |
921 |
922 |
923 |
924 |
925 | 928 |
929 |
930 |
931 |

932 |
933 |
934 |
935 |
936 |
937 |
938 |
939 | @if(request()->step == 2) 940 |
request()->step == 2, 'tab-pane']) role="tabpanel" id="step2"> 941 |
942 |
943 |
944 | NOTE! 945 | Please match column with the original form value. 946 |
947 |
948 |
949 |
950 |
951 | 952 |
953 |
954 |
955 |
956 |
957 |
958 | 959 |
960 | 961 | 969 | @error('table') 970 |
{{ $message }}
971 | @enderror 972 |
973 |
974 |
975 |
976 |
977 |
978 | @csrf 979 | 980 | 981 |
982 |
983 | @if($selectedTable) 984 |
985 |
986 |
989 |
992 | 995 | 996 | 997 | 998 | 999 | 1000 | @foreach($tableColumns as $column) 1001 | 1002 | 1008 | 1021 | 1022 | @endforeach 1023 | 1024 |
Database Table ColumnCSV File Column
1003 | {{ $column['name'] }} 1004 | @if($column['required']) 1005 | * 1006 | @endif 1007 | 1009 |
1010 | 1019 |
1020 |
1025 |
1026 |
1027 |
1028 |
1029 | @endif 1030 |
1031 |
1032 |
1033 |
1034 |
1035 |
    1036 |
  • 1037 | Previous 1039 |
  • 1040 |
  • 1041 | 1044 |
  • 1045 |
1046 |
1047 |
1048 |
1049 |
1050 |
1051 | @endif 1052 | @if(request()->step == 3) 1053 |
request()->step == 3, 'tab-pane']) role="tabpanel" id="step3"> 1054 |
1055 | @csrf 1056 | 1057 |
1058 |
1059 |
1060 |
1061 | 1105 |
1106 |
1107 |
1108 |
1109 |
1110 |
1111 |
1112 |
    1113 |
  • 1114 | Previous 1116 |
  • 1117 |
  • 1118 | 1122 |
  • 1123 |
1124 |
1125 |
1126 |
1127 |
1128 |
1129 | @endif 1130 | @if(request()->step == 4) 1131 |
request()->step == 4,'tab-pane']) role="tabpanel" id="summarydata"> 1132 |
1133 |
1134 |
1135 | @if($result && !$result['error']) 1136 |
1137 |

Total {{ $result['count'] }} data has been imported!  

1139 |
1140 | @endif 1141 | @if($result && $result['error']) 1142 |
1143 |
1144 |

{{ $result['error'] }}

1145 |
1146 |
1147 | @endif 1148 |
1149 |
1150 |
1151 |
1152 |
1153 |
1154 |
    1155 |
  • 1156 | Finish 1158 |
  • 1159 |
1160 |
1161 |
1162 |
1163 |
1164 | @endif 1165 |
1166 |
1167 |
1168 |
1169 | 1174 | 1175 | 1176 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | config('data-bringin.middleware'), 'prefix' => config('data-bringin.path')], function () { 7 | Route::get('/', [ImportController::class, 'index'])->name('data_bringin.index'); 8 | Route::post('/', [ImportController::class, 'store'])->name('data_bringin.store'); 9 | Route::get('/delete-record/{id}', [ImportController::class, 'deleteRecord'])->name('data_bringin.delete_record'); 10 | }); 11 | -------------------------------------------------------------------------------- /src/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | step > session('import.step') && $request->step != 4) { 23 | return to_route('data_bringin.index'); 24 | } 25 | $data = []; 26 | $table = $request->table ?? session('import.table'); 27 | $data['tables'] = $this->importService->getTables(); 28 | $data['tableColumns'] = $table ? $this->importService->getTableColumns($table) : collect(); 29 | $data['selectedTable'] = $table; 30 | $data['selectedColumns'] = collect(session('import.columns')); 31 | $data['fileColumns'] = collect(session('import.fileColumns')); 32 | $data['fileData'] = collect(session('import.data')); 33 | $data['result'] = collect(session('import.result')); 34 | 35 | return view('data-bringin::import', $data); 36 | } 37 | 38 | public function store(StoreImportRequest $request): RedirectResponse 39 | { 40 | switch ($request->step) { 41 | case 1: 42 | session()->forget('import'); 43 | $path = $request->file('file')->getRealPath(); 44 | session(['import.data' => $this->importService->csvToArray($path), 'import.step' => 2]); 45 | break; 46 | case 2: 47 | $columns = collect($request->columns)->filter(); 48 | if(!$columns->count()) { 49 | return redirect()->back(); 50 | } 51 | session([ 52 | 'import.table' => $request->table, 53 | 'import.columns' => $columns, 54 | 'import.step' => 3, 55 | ]); 56 | break; 57 | case 3: 58 | $fileData = collect(session('import.data')); 59 | $table = session('import.table'); 60 | $columns = session('import.columns'); 61 | $insertData = []; 62 | try { 63 | foreach ($fileData as $data) { 64 | $prepareData = []; 65 | foreach ($columns as $key => $column) { 66 | $prepareData[$key] = $data[$column]; 67 | } 68 | $insertData[] = $prepareData; 69 | } 70 | DB::table($table)->insert($insertData); 71 | } catch (QueryException $ex) { 72 | $errorMsg = 'There is an issue on store data in database.'; 73 | } catch (\Exception $ex) { 74 | $errorMsg = $ex->getMessage(); 75 | } 76 | $result = [ 77 | 'count' => count($insertData), 78 | 'error' => $errorMsg ?? null, 79 | ]; 80 | session()->forget('import'); 81 | session(['import.result' => $result]); 82 | break; 83 | } 84 | return to_route('data_bringin.index', ['step' => ++$request->step]); 85 | } 86 | 87 | public function deleteRecord(int $id): RedirectResponse 88 | { 89 | try { 90 | $data = collect(session('import.data'))->reject(function (array $data) use ($id) { 91 | return $data['Id'] == $id; 92 | })->values(); 93 | session(['import.data' => $data]); 94 | 95 | return redirect()->back()->withSuccess('Record Deleted Successfully.'); 96 | } catch (\Exception $exception) { 97 | return redirect()->back()->withError($exception->getMessage()); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Http/Requests/ImportRequest.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | public function rules(): array 23 | { 24 | 25 | return [ 26 | 'step' => 'integer|between:1,4|nullable', 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Http/Requests/StoreImportRequest.php: -------------------------------------------------------------------------------- 1 | 22 | */ 23 | public function rules(): array 24 | { 25 | $rules = [ 26 | 'step' => 'integer|between:1,4|nullable', 27 | ]; 28 | 29 | if ($this->step == 1) { 30 | $rules['file'] = 'required|file|mimes:csv,txt'; 31 | } 32 | 33 | if ($this->step == 2) { 34 | $rules['table'] = 'required'; 35 | } 36 | return $rules; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Providers/ImportServiceProvider.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom( 23 | __DIR__.'/../../config/data-bringin.php', 'data-bringin' 24 | ); 25 | $this->publishes([ 26 | __DIR__.'/../../config/data-bringin.php' => config_path('data-bringin.php'), 27 | ], 'data-bringin-config'); 28 | $this->loadRoutesFrom(__DIR__.'/../../routes/web.php'); 29 | $this->loadViewsFrom(__DIR__.'/../../resources/views', 'data-bringin'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Services/ImportService.php: -------------------------------------------------------------------------------- 1 | pluck('Tables_in_'.env('DB_DATABASE')); 17 | } 18 | 19 | public function getTableColumns(string $table): Collection 20 | { 21 | if (! Schema::hasTable($table)) { 22 | return collect(); 23 | } 24 | 25 | return collect(DB::select("describe `{$table}`"))->map(function ($column) { 26 | return [ 27 | 'name' => $column->Field, 28 | 'required' => $column->Null === 'NO', 29 | ]; 30 | })->reject(function ($column) { 31 | return in_array($column['name'], ['id', 'deleted_at']); 32 | }); 33 | } 34 | 35 | public function csvToArray(string $fileName): array 36 | { 37 | // open csv file 38 | if (! ($fp = fopen($fileName, 'r'))) { 39 | return []; 40 | } 41 | 42 | //read csv headers 43 | $key = fgetcsv($fp, '1024', ','); 44 | session(['import.fileColumns' => $key]); 45 | array_unshift($key, 'Id'); 46 | 47 | // parse csv rows into array 48 | $data = []; 49 | $i = 1; 50 | while ($row = fgetcsv($fp, '1024', ',')) { 51 | array_unshift($row, $i); 52 | $data[] = array_combine($key, $row); 53 | $i++; 54 | } 55 | 56 | // release file handle 57 | fclose($fp); 58 | 59 | // return data 60 | return $data; 61 | } 62 | } 63 | --------------------------------------------------------------------------------