-
-
Save harishrkpatel/de7eb03c2e47aa0fd54e1355b6e33b01 to your computer and use it in GitHub Desktop.
| <?php | |
| use Illuminate\Support\Facades\Schema; | |
| use Illuminate\Database\Schema\Blueprint; | |
| use Illuminate\Database\Migrations\Migration; | |
| class CreateCsvDataTable extends Migration | |
| { | |
| /** | |
| * Run the migrations. | |
| * | |
| * @return void | |
| */ | |
| public function up() | |
| { | |
| Schema::create('csv_data', function (Blueprint $table) { | |
| $table->bigIncrements('id'); | |
| $table->string('created_by', 100)->nullable(); | |
| $table->string('last_upd_by', 100)->nullable(); | |
| $table->softDeletes(); | |
| $table->timestamps(); | |
| // now add the actual fields. | |
| $table->string('csv_filename', 64)->default(null)->nullable(); | |
| $table->longText('csv_data')->default(null)->nullable(); | |
| }); | |
| } | |
| /** | |
| * Reverse the migrations. | |
| * | |
| * @return void | |
| */ | |
| public function down() | |
| { | |
| Schema::dropIfExists('csv_data'); | |
| } | |
| } |
| <?php | |
| namespace App\Models; | |
| use Illuminate\Database\Eloquent\Model; | |
| class CsvData extends Model | |
| { | |
| protected $table = 'csv_data'; | |
| protected $fillable = ['csv_filename', 'csv_data']; | |
| } |
| @extends('backpack::layout') | |
| @section('header') | |
| <section class="content-header"> | |
| <h1> | |
| <span class="text-capitalize">{!! $crud->getHeading() ?? $crud->entity_name_plural !!}</span> | |
| <small>{!! $crud->getSubheading() ?? 'Import '.$crud->entity_name !!}.</small> | |
| </h1> | |
| <ol class="breadcrumb"> | |
| <li> | |
| <a href="{{ url(config('backpack.base.route_prefix'), 'dashboard') }}">{{ trans('backpack::crud.admin') }}</a> | |
| </li> | |
| <li><a href="{{ url($crud->route) }}" class="text-capitalize">{{ $crud->entity_name_plural }}</a></li> | |
| <li class="active">Import</li> | |
| </ol> | |
| </section> | |
| @endsection | |
| @section('content') | |
| <div class="container"> | |
| <div class="row"> | |
| <div class="col-md-8 col-md-offset-2"> | |
| <div class="panel panel-default"> | |
| <div class="panel-heading">CSV Import</div> | |
| <div class="panel-body"> | |
| <form class="form-horizontal" method="POST" | |
| action="{{ route('admin.'.strtolower($crud->entity_name).'.importParse') }}" | |
| action="{{ route('admin.'.strtolower(str_replace(' ', '', $crud->entity_name)).'.importParse') }}" | |
| enctype="multipart/form-data"> | |
| {{ csrf_field() }} | |
| <div class="form-group{{ $errors->has('csv_file') ? ' has-error' : '' }}"> | |
| <label for="csv_file" class="col-md-4 control-label">CSV file to import: </label> | |
| <div class="col-md-6"> | |
| <input id="csv_file" type="file" class="form-control" name="csv_file" required> | |
| @if ($errors->has('csv_file')) | |
| <span class="help-block"> | |
| <strong>{{ $errors->first('csv_file') }}</strong> | |
| </span> | |
| @endif | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label for="csv_file" class="col-md-4 control-label">Instructions:</label> | |
| <div class="col-md-6"> | |
| 1. Upload a CSV in the following format: | |
| <a href="{{ route('admin.'.strtolower($crud->entity_name).'.importFormatDownload') }}">Download</a><br> | |
| <a href="{{ route('admin.'.strtolower(str_replace(' ', '', $crud->entity_name)).'.importFormatDownload') }}">Download</a><br> | |
| @foreach($instructions as $idx => $instruction) | |
| {{ $idx+2 }}. {{$instruction}}<br> | |
| @endforeach | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <div class="col-md-8 col-md-offset-4"> | |
| <button type="submit" class="btn btn-primary"> | |
| Parse CSV | |
| </button> | |
| </div> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| @endsection | |
| @extends('backpack::layout') | |
| @section('header') | |
| <section class="content-header"> | |
| <h1> | |
| <span class="text-capitalize">{!! $crud->getHeading() ?? $crud->entity_name_plural !!}</span> | |
| <small>{!! $crud->getSubheading() ?? 'Import Mapping for '.$crud->entity_name !!}.</small> | |
| </h1> | |
| <ol class="breadcrumb"> | |
| <li> | |
| <a href="{{ url(config('backpack.base.route_prefix'), 'dashboard') }}">{{ trans('backpack::crud.admin') }}</a> | |
| </li> | |
| <li><a href="{{ url($crud->route) }}" class="text-capitalize">{{ $crud->entity_name_plural }}</a></li> | |
| <li class="active">Import Mapping</li> | |
| </ol> | |
| </section> | |
| @endsection | |
| @section('content') | |
| <div class="container m-l-5 m-r-5" style="width: 100%;"> | |
| <div class="row"> | |
| <form class="form-horizontal" method="POST" action="{{ route('admin.'.strtolower(str_replace(' ', '', $crud->entity_name)).'.importProcess') }}"> | |
| {{ csrf_field() }} | |
| <input type="hidden" name="csv_data_file_id" value="{{ $csv_data_file->id }}"/> | |
| <div style="overflow: auto; width: 100%;"> | |
| <table class="box table table-striped table-hover responsive nowrap m-t-0" style="width: 100%"> | |
| @foreach ($csv_data as $row) | |
| <tr> | |
| @foreach ($row as $key => $value) | |
| <td>{{ $value }}</td> | |
| @endforeach | |
| </tr> | |
| @endforeach | |
| <tr> | |
| @foreach ($csv_data[0] as $key => $value) | |
| <td> | |
| <select name="fields[{{ $key }}]" class="form-control select2"> | |
| <option value="">Select mapping</option> | |
| @foreach ($import_fields as $key => $import_field) | |
| <option | |
| @if ($import_field['name']===$value || $import_field['label']===$value) | |
| selected | |
| @endif | |
| value="{{ $import_field['name'] }}">{{ $import_field['label'] }} | |
| </option> | |
| @endforeach | |
| </select> | |
| </td> | |
| @endforeach | |
| </tr> | |
| </table> | |
| </div> | |
| <div style="float: left;"> | |
| <a href="{{ route('admin.'.strtolower(str_replace(' ', '', $crud->entity_name)).'.import') }}" class="btn btn-primary">Back</a> | |
| </div> | |
| <div style="float: right;"> | |
| <button type="submit" class="btn btn-primary">Import Data</button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| @endsection | |
| @section('after_styles') | |
| <!-- DATA TABLES --> | |
| <link href="{{ asset('vendor/adminlte/bower_components/select2/dist/css/select2.min.css') }}" rel="stylesheet" | |
| type="text/css"/> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/select2-bootstrap-theme/0.1.0-beta.10/select2-bootstrap.min.css" | |
| rel="stylesheet" type="text/css"/> | |
| <style> | |
| .select2-container .select2-selection--single { | |
| box-sizing: border-box; | |
| cursor: pointer; | |
| display: block; | |
| height: 35px; | |
| user-select: none; | |
| -webkit-user-select: none; | |
| } | |
| .select2-container { | |
| width: auto !important; | |
| } | |
| </style> | |
| <!-- CRUD LIST CONTENT - crud_list_styles stack --> | |
| @stack('crud_fields_styles') | |
| @endsection | |
| @section('after_scripts') | |
| <script src="{{ asset('vendor/adminlte/bower_components/select2/dist/js/select2.min.js') }}"></script> | |
| <style type="text/css"> | |
| .select2-selection__clear::after { | |
| content: ' Clear'; | |
| } | |
| </style> | |
| <script> | |
| $(document).ready(function () { | |
| $('select.select2').select2(); | |
| }); | |
| </script> | |
| <!-- CRUD LIST CONTENT - crud_list_scripts stack --> | |
| @stack('crud_fields_scripts') | |
| @endsection |
| @extends('backpack::layout') | |
| @section('header') | |
| <section class="content-header"> | |
| <h1> | |
| <span class="text-capitalize">{!! $crud->getHeading() ?? $crud->entity_name_plural !!}</span> | |
| <small>{!! $crud->getSubheading() ?? 'Import Results for '.$crud->entity_name !!}.</small> | |
| </h1> | |
| <ol class="breadcrumb"> | |
| <li> | |
| <a href="{{ url(config('backpack.base.route_prefix'), 'dashboard') }}">{{ trans('backpack::crud.admin') }}</a> | |
| </li> | |
| <li><a href="{{ url($crud->route) }}" class="text-capitalize">{{ $crud->entity_name_plural }}</a></li> | |
| <li class="active">Import Result</li> | |
| </ol> | |
| </section> | |
| @endsection | |
| @section('content') | |
| <div class="container m-l-5 m-r-5" style="width: 100%;"> | |
| <div class="row"> | |
| @if (empty($errors)) | |
| <h1 style="text-align: center; margin: 150px;">Imported successfully</h1> | |
| @else | |
| <div style="overflow: auto;"> | |
| <table class="box table table-striped table-hover display responsive nowrap m-t-0 dataTable"> | |
| <tr> | |
| <td>Row Number</td> | |
| <td>Error Messages</td> | |
| </tr> | |
| @foreach ($errors as $idx_1 => $error) | |
| <tr> | |
| <td>{{ $error['row_number'] }}</td> | |
| <td> | |
| <ul style="padding-left: 15px;"> | |
| @foreach($error['errors'] as $idx_2 => $e) | |
| <li>{{ $e }}</li> | |
| @endforeach | |
| </ul> | |
| </td> | |
| </tr> | |
| @endforeach | |
| </table> | |
| </div> | |
| @endif | |
| <div style="float: left;"> | |
| <a href="{{ route('admin.'.strtolower(str_replace(' ', '', $crud->entity_name)).'.import') }}" class="btn btn-primary">Import More</a> | |
| </div> | |
| <div style="float: right;"> | |
| <a href="{{ url($crud->route) }}" class="btn btn-primary">Finished</a> | |
| </div> | |
| </div> | |
| </div> | |
| @endsection |
| <?php | |
| namespace App\Services; | |
| use Illuminate\Http\Request; | |
| use App\Models\CsvData; | |
| use Illuminate\Support\Facades\Validator; | |
| /** | |
| * | |
| * Include this trait in any CrudController and make provision for enabling configuration driven import functionality on that entity. | |
| * To enable import on any entity the following steps need to be undertaken. | |
| * | |
| * 1. use this trait in the respective entity controller. | |
| * | |
| * 2. Override the following methods. | |
| * a) importSampleFilename() | |
| * b) importInstructions() | |
| * c) importValidationRules() | |
| * d) importValidationMessages() | |
| * e) importCreate($entity) | |
| * | |
| * Instructions of how to override each of these methods is provided against each methods documentation. | |
| * | |
| * 3. Once you have imported this trait it allows you to add the following routes. | |
| * a) GET entityName/import | |
| * b) POST entityName/importParse | |
| * c) POST entityName/importProcess | |
| * d) GET entityName/importFormatDownload | |
| * | |
| * These routes get mapped to the methods with the same names which are present in this trait. | |
| * | |
| * 4. Optionally to have a more fine grained control over the import process you can override the following two methods. | |
| * a) beforeImport($entities) | |
| * b) afterImport($entities) | |
| * | |
| * Again both these methods specify the exact nature of the functionality they are exposing. | |
| * | |
| * Trait ImportAwareTrait | |
| * @package App\Services | |
| */ | |
| trait ImportAwareTrait | |
| { | |
| /** | |
| * The entity should override this method to provide a new name for the sample CSV which will be | |
| * downloaded during the first step. | |
| * | |
| * Recommended To Override | |
| * | |
| * @return string | |
| */ | |
| protected function importSampleFilename() | |
| { | |
| return 'export_sample.csv'; | |
| } | |
| /** | |
| * Optionally you can override this method to provide a completely different view for the first step of the import process. | |
| * | |
| * Optional To Override | |
| * | |
| * @return string | |
| */ | |
| protected function importView() | |
| { | |
| return 'common/import'; | |
| } | |
| /** | |
| * You will never have to override this, however left this as a convenience just incase someone wants to override this method. | |
| * | |
| * Optional To Override | |
| * | |
| * @return string | |
| */ | |
| protected function importParseView() | |
| { | |
| return 'common/import_parse'; | |
| } | |
| /** | |
| * This view represents the last step of the import process, again optionally you can override this method to customise the | |
| * last step of the import process. | |
| * | |
| * Optional To Override | |
| * | |
| * @return string | |
| */ | |
| protected function importProcessView() | |
| { | |
| return 'common/import_process'; | |
| } | |
| /** | |
| * Override this method to provide an array of instructions. These instructions are then displayed in step 1 | |
| * as a numbered list. The first instruction is always the default instruction to download the sample csv. | |
| * | |
| * Required To Override | |
| * | |
| * @return array | |
| */ | |
| protected function importInstructions() | |
| { | |
| return []; | |
| } | |
| /** | |
| * | |
| * Override this method to provide an array of validation rules. The syntax to follow is the same as the syntax we | |
| * use for defining Laravel validation rules. | |
| * return [ | |
| * 'user_id' => 'required', | |
| * 'package_id' => 'required', | |
| * 'company_id' => 'required', | |
| * ]; | |
| * | |
| * Required To Override | |
| * | |
| * @return array | |
| * | |
| */ | |
| protected function importValidationRules() | |
| { | |
| return []; | |
| } | |
| /** | |
| * Override this method to provide an array of validation rule failure messages. A sample return could be | |
| * | |
| * return [ | |
| * 'user_id.required' => 'Specifying a user is mandatory when creating an appointment, please check if you have specified a valid name, email, date of birth (yyyy-mm-dd format) & contact number of the user.', | |
| * 'package_id.required' => 'Specifying a package name is mandatory when creating an appointment, please check if you have specified a valid package name.', | |
| * 'company_id.required' => 'Specifying a company name is mandatory when creating an appointment, please check if you have specified a valid company name.', | |
| * ]; | |
| * | |
| * Required To Override | |
| * | |
| * @return array | |
| */ | |
| protected function importValidationMessages() | |
| { | |
| return []; | |
| } | |
| /** | |
| * | |
| * After all foreign keys have been resolved and validation rules have run successfully for all rows, this method | |
| * is called with an array representing the entity which is to be created. | |
| * | |
| * Required To Override | |
| * | |
| * @param array $entity | |
| * @return mixed You need to return the created entity object, generally you can return the result of calling the create method on the entity class. | |
| */ | |
| protected abstract function importCreate($entity); | |
| /** | |
| * Takes an array of entities representing all rows in the CSV as the argument. | |
| * Each entity passed to this method is actually an array object representing the fully resolved object where all validations have passed and foreign keys resolved. | |
| * You can optionally override this method to do any processing that is required to be done across all rows which are being imported. | |
| * To do pre-create activities on a per entity basis you can simply write the code when implemeting importCreate() method. | |
| * | |
| * Optional To Override | |
| * | |
| * @param array $entities | |
| */ | |
| protected function beforeImport($entities) | |
| { | |
| } | |
| /** | |
| * Takes an array of entities representing all rows in the CSV as the argument. Each entity passed to this method is actually an instance of the entity class. | |
| * You can optionally override this method to do any processing that is required to be done across all rows which are being imported. | |
| * To do post-create activities on a per entity basis you can simply write the code when implemeting importCreate() method. | |
| * | |
| * Optional To Override | |
| * | |
| * @param array $entities | |
| */ | |
| protected function afterImport($entities) | |
| { | |
| } | |
| /** | |
| * Action method linked to the GET <entityname>/import route. | |
| * Simply renders the first step which allows one to upload hte CSV file & see the import instructions. | |
| * | |
| * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View | |
| */ | |
| public function import() | |
| { | |
| return view($this->importView(), [ | |
| 'crud' => $this->crud, | |
| 'instructions' => $this->importInstructions(), | |
| ]); | |
| } | |
| /** | |
| * Action method linked to the GET <entityname>/importFormatDownload route. | |
| * Generates a CSV and streams the response to the browser. The CSV is generated based on cofiguration provided | |
| * in the setup() method of the entity controller. | |
| * | |
| * @return \Symfony\Component\HttpFoundation\StreamedResponse | |
| */ | |
| public function importFormatDownload() | |
| { | |
| // figure out the importable fields. | |
| $importFields = $this->getImportableFields(); | |
| $headers = array( | |
| "Content-type" => "text/csv", | |
| "Content-Disposition" => "attachment; filename=" . $this->importSampleFilename(), | |
| "Pragma" => "no-cache", | |
| "Cache-Control" => "must-revalidate, post-check=0, pre-check=0", | |
| "Expires" => "0" | |
| ); | |
| $columns = []; | |
| foreach ($importFields as $idx_1 => $importField) { | |
| $columns[] = $importField['label']; | |
| } | |
| $callback = function () use ($columns) { | |
| $file = fopen('php://output', 'w'); | |
| fputcsv($file, $columns); | |
| fclose($file); | |
| }; | |
| return response()->stream($callback, 200, $headers); | |
| } | |
| /** | |
| * Action method linked to the POST <entityname>/importParse route. | |
| * This method consumes the file upload, saves it to the CsvData entity which stores the uploaded file in interim storage. | |
| * This method then renders a view which allows the user to do the mapping between the csv header fields & the field names | |
| * as specified in the setup() method of the CrudController. | |
| * | |
| * @param Request $request | |
| * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View | |
| */ | |
| public function importParse(Request $request) | |
| { | |
| $path = $request->file('csv_file')->getRealPath(); | |
| $data = array_map('str_getcsv', file($path)); | |
| $csvDataFile = CsvData::create([ | |
| 'csv_filename' => $request->file('csv_file')->getClientOriginalName(), | |
| 'csv_data' => json_encode(mb_convert_encoding($data, 'UTF-8', 'auto')) | |
| ]); | |
| $csvData = array_slice($data, 0, 10); | |
| return view($this->importParseView(), [ | |
| 'import_fields' => $this->getImportableFields(), | |
| 'csv_data' => $csvData, | |
| 'csv_header' => $csvData[0], | |
| 'csv_data_file' => $csvDataFile, | |
| 'crud' => $this->crud, | |
| ]); | |
| } | |
| /** | |
| * | |
| * Action method linked to the POST <entityname>/importProcess route. | |
| * Here is where the bulk of the logic of importing the data is written. This method uses the mapping provided in the | |
| * previous step and uses the CSV data stored earlier in the CsvData entity. | |
| * It then runs all resolutions / validations as configured. | |
| * Finally the resolved entities are passed to the importCreate() method. The lifecycle methods are also invoked | |
| * while running this method. | |
| * | |
| * @param Request $request | |
| * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View | |
| */ | |
| public function importProcess(Request $request) | |
| { | |
| // figure out the importable fields. | |
| $importFields = $this->getImportableFields(); | |
| // load the data stored in the database. | |
| $requestFields = $request->fields; | |
| $data = CsvData::find($request->csv_data_file_id); | |
| $csv_data = json_decode($data->csv_data, true); | |
| $entities = []; | |
| foreach ($csv_data as $idx_1 => $row) { | |
| if ($idx_1 == 0) { | |
| continue; | |
| } | |
| $entity = []; | |
| foreach ($importFields as $idx_2 => $importField) { | |
| $t = array_search($importField['name'], $requestFields); | |
| if ($t !== false) { | |
| $entity[$importField['name']] = isset($row[$t]) ? $row[$t] : null; | |
| } | |
| } | |
| $entities[] = $entity; | |
| } | |
| // resolve all the foreign keys. | |
| foreach ($entities as $idx_1 => &$entity) { | |
| foreach ($importFields as $idx_2 => $importField) { | |
| if (isset($importField['import_resolver'])) { | |
| $importField['import_resolver']($entity); | |
| } | |
| } | |
| } | |
| // run validations. | |
| $errors = []; | |
| foreach ($entities as $idx => &$entity) { | |
| $rules = $this->importValidationRules(); | |
| $messages = $this->importValidationMessages(); | |
| $validator = Validator::make($entity, $rules, $messages); | |
| if ($validator->fails()) { | |
| $errors[] = [ | |
| 'row_number' => $idx + 1, | |
| 'errors' => $validator->errors()->all() | |
| ]; | |
| } | |
| } | |
| // create the user appointments. | |
| $entityObjects = []; | |
| $this->beforeImport($entities); | |
| if (empty($errors)) { | |
| foreach ($entities as $idx => &$entity) { | |
| $entityObjects[] = $this->importCreate($entity); | |
| } | |
| } | |
| $this->afterImport($entityObjects); | |
| return view($this->importProcessView(), [ | |
| 'crud' => $this->crud, | |
| 'errors' => $errors, | |
| ]); | |
| } | |
| /** | |
| * | |
| * Used internally to fetch a list of importable fields. This method uses the CrudPanel metadata and infers | |
| * importable fields based on the "importable => true" configuration attribute. | |
| * | |
| * @return array | |
| */ | |
| private function getImportableFields() | |
| { | |
| $createFields = $this->crud->getFields('create'); | |
| $importFields = []; | |
| foreach ($createFields as $idx_1 => $createField) { | |
| if (isset($createField['importable']) && $createField['importable']) { | |
| if (isset($createField['importable_fields'])) { | |
| foreach ($createField['importable_fields'] as $idx_2 => $nested) { | |
| $importFields[] = $nested; | |
| } | |
| } else { | |
| $importFields[] = $createField; | |
| } | |
| } | |
| } | |
| return $importFields; | |
| } | |
| } |
I have same error
@gumpon and @ckhandla94 I'm sure y'all figured this out a while ago, so this is mostly for the benefit of others who may stumble upon this page: In order to get $this->crud->getFields('create') to return the importable fields, you need to add the following to your CRUD controller:
protected function setupImportOperation()
{
$this->setupCreateOperation();
}(alternatively, you could re-define the fields here, but I don't see any reason that would be necessary...)
The other things I had to do to get this code working in backpack 4.1:
in ImportAwareTrait, add the following method:
protected function setupImportRoutes($segment, $routeName, $controller)
{
Route::get($segment . '/import', [
'as' => "admin.$routeName.import",
'uses' => "$controller@import",
'operation' => 'import',
]);
Route::get($segment . '/import/download-format', [
'as' => "admin.$routeName.importFormatDownload",
'uses' => "$controller@importFormatDownload",
'operation' => 'import',
]);
Route::post($segment . '/import/parse', [
'as' => "admin.$routeName.importParse",
'uses' => "$controller@importParse",
'operation' => 'import',
]);
Route::post($segment . '/import/process', [
'as' => "admin.$routeName.importProcess",
'uses' => "$controller@importProcess",
'operation' => 'import',
]);
}There were a number of changes I made to the blade templates to get them to look and feel like they were a part of Backpack, but the only one that was strictly necessary for this code to work was to change the Backpack template name in the @extends() directive from backpack::layout to backpack::blank.
Other than that, the documentation covers the normal things you need to do to set up the trait's integration with your CRUD controller.
Hope this helps someone in the future!
@gumpon and @ckhandla94 I'm sure y'all figured this out a while ago, so this is mostly for the benefit of others who may stumble upon this page: In order to get
$this->crud->getFields('create')to return the importable fields, you need to add the following to your CRUD controller:protected function setupImportOperation() { $this->setupCreateOperation(); }(alternatively, you could re-define the fields here, but I don't see any reason that would be necessary...)
The other things I had to do to get this code working in backpack 4.1:
in
ImportAwareTrait, add the following method:protected function setupImportRoutes($segment, $routeName, $controller) { Route::get($segment . '/import', [ 'as' => "admin.$routeName.import", 'uses' => "$controller@import", 'operation' => 'import', ]); Route::get($segment . '/import/download-format', [ 'as' => "admin.$routeName.importFormatDownload", 'uses' => "$controller@importFormatDownload", 'operation' => 'import', ]); Route::post($segment . '/import/parse', [ 'as' => "admin.$routeName.importParse", 'uses' => "$controller@importParse", 'operation' => 'import', ]); Route::post($segment . '/import/process', [ 'as' => "admin.$routeName.importProcess", 'uses' => "$controller@importProcess", 'operation' => 'import', ]); }There were a number of changes I made to the blade templates to get them to look and feel like they were a part of Backpack, but the only one that was strictly necessary for this code to work was to change the Backpack template name in the
@extends()directive frombackpack::layouttobackpack::blank.Other than that, the documentation covers the normal things you need to do to set up the trait's integration with your CRUD controller.
Hope this helps someone in the future!
I used Backpack 4.1
Thanks for this code..
But I have a problem.. I follow this code and some changes.. the result page show Imported successfully, but nothing rows imported..
Problem solved if I commented code below in importProcess method :
if ($idx_1 == 0) { continue; }
Thanks....
Can we turn this into a BackpackForLaravel package? something that can easily connect to the admin?
hello sir can you please share a folder structure for your file
I used laravel backpack 4.1
but $this->crud->getFields('create'); is null value. How to resolve.