I'm currently working on a Laravel project using the Laravel-Excel package.
It is working fine, except for a use case i'm trying to solve I'm trying to solve for a few hours now.
Each CSV files I'm reading begins with the Heading Rows, and that's particularly practical, but some of my CSV Files begin with annotations like #CSV DD V2.4.3 at row 1 followed by the Heading Rows at row 2.
So, I need to find out how to determine the real line where the heading rows are located to avoid that unwanted line. I especially need to make it work in the headingRow() method implemented by the WithHeadingRow interface. is there a way t grab lines from the csv file to determine the correct heading row line ?
Hope you'll find out , thanks in advance
I would consider doing this in two steps. This is a very general example, so you will need to add in the appropriate Laravel Excel import concern and other dependencies, perform any checks to make sure the file exists, and so on.
Check the first line of the file before starting the import to determine the correct heading row.
// get the first line of the file
$line = fgets(fopen('path/to/file.csv', 'r'));
// set the heading row based on the line contents
// add terms to search array if desired ['#CSV','...']
$heading_row = Str::startsWith(trim($line), ['#CSV']) ? 2 : 1;
Dynamically inject the heading row value using the WithHeadingRow concern and associated method.
class SampleImport implements WithHeadingRow
{
private $heading_row;
// inject the desired heading row or default to first row
public function __construct($heading_row = 1)
{
$this->heading_row = $heading_row;
}
// set the heading row
public function headingRow(): int
{
return $this->heading_row;
}
}
Now you can pass a custom heading row when running the import.
Excel::import(new SampleImport($heading_row), 'path/to/file.csv');
Related
I have a collection of "Tickets", using the random collection utility method I select one from the list. The "Tickets" collection should now remove (or forget) that randomly selected ticket so I can further process that collection. Using the forget method doesn't appear to do what is described in the documentation or (more likely I'm missing something).
Can someone spot whats wrong in my code?
$tickets = Tickets::all();
$total_winners = 5;
$selected_tickets = $tickets->random($total_winners);
$jackpot_winner = $selected_tickets->random();
$selected_tickets->forget($jackpot_winner->id); // this line should remove the $jackpot_winner
When I print the contents of $selected_tickets on lines 3 and lines 5, they have the exact same items, including the $jackpot_winner.
Forget function uses the collection key not the id from the model. To achieve what you want you may use this method:
$selected_tickets = $selected_tickets->except($jackpot_winner->id);
https://laravel.com/docs/8.x/collections#method-except
I have gone through the docs and also Googled. I see little mention of returning multiple queries on the same sheet from Maat's Laravel Excel. I presume therefore it is 1 query for 1 downloaded spreadsheet. I also presume that if you do have multiple queries that you will need to place each query on an additional sheet.
Have got this right ?
Many thanks
In a perfect world, every query would get its own sheet. But in reality, it will export whatever you give it so long as it receives a single array or collection for the output, depending on your configuration. It would be up to you to determine how to combine your queries into a format that could be interpreted as rows and columns.
Basic example with two queries:
class ExportSample implements FromCollection
{
// ...
public function collection()
{
// query 1
$a = User::where('id',2)->get();
// query 2
$b = User::where('id',4)->get();
// merge collections
return $a->merge($b);
}
}
Of course, if your queries result in different column structures, there may be additional obstacles.
I'm using django-import-export to upload csv files through django admin. I have the ability to override the before_import function to add functionality before the import. I have a csv file with no headers, and the actual data starts on line one. I need to add a header, or insert a row before my csv file is uploaded, so that it can be read properly.
class UpdateResource(resources.ModelResource):
def before_import(self, dataset, using_transactions, dry_run, **kwargs):
dataset.header = ['sku', 'quantity']
class Meta:
model = Upload
import_id_fields = ('sku',)
This code changes the value of the first row of my csv file to sku,quantity, but I need to insert one above that value, not replace it. Alternatively, if there is an option to ignore headers and just map the values to my model from left to right or something, that would be great too.
My fix was to store the first row as a variable, create the desired header and append the first row to end of file.
class UpdateResource(resources.ModelResource):
def before_import(self, dataset, using_transactions, dry_run, **kwargs):
first_row = dataset.header
dataset.header = ['sku', 'quantity']
dataset.append(first_row)
I'm using Maatwebsite's Laravel-Excel to import an Excel file with two sheets. This file is generated by another system; I can't change the way it is produced.
On the first sheet, the first row is the column headings. This works fine.
...but the second sheet has two rows of unwanted text, and then the headers in the third row.
I can set config(['excel.import.startRow' => 3]) to start importing at the third row, but that means I miss the first two rows of useful data in the first sheet.
config(['excel.import.startRow' => 3]);
$sheets = $import->all();
Is there any way I can leave excel.import.startRow set to 1 for the first sheet, but set excel.import.startRow to 3 for the other sheet?
You can use:
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithStartRow;
In class:
class nameClass implements ToModel, WithHeadingRow, WithStartRow
add the functions:
public function headingRow(): int
{
return 3;
}
/**
* #return int
*/
public function startRow(): int
{
return 4;
}
So I've come up with an answer. It's not a great solution, but I guess it will do.
I will just import the whole document, and process the People tab and ignore the Finance tab.
Then I will set excel.import.startRow to 3 and import the whole document a second time, and this time I'll ignore the People tab and process the Finance tab.
Like I say this is not an elegant solution so if anyone comes up with a better way to do it I'd love to hear from you. But for now it will do.
On my grid, after a user enters text on the bottom row, I am adding another row so they can fill out another row if needed. The grid will grow as needed by the user. This is working fine, however after a page reload and populating from db, the addrowdata() function does not honor existing row ids and creates duplicates, starting from 1 again, e.g. jqg1. It should look at existing row ids and create new unique ids. So if I have 5 rows already, it might start at jqg6. Here is the relevant code inside onCellSelect:
var records = jQuery("#table-1").jqGrid('getGridParam', 'records');
var lastRowId = jQuery("#table-1").jqGrid('getDataIDs')[records - 1];
if (lastRowId == id)
{
jQuery('#table-1').addRowData(undefined, {}, 'last');
}
I have also tried $.jgrid.randId() instead of undefined, same results as expected.
Thanks
Ryan
I think that the error is in the part where you fill grid with the data from the database. The data saved in the database has unique ids. The ids are not in the form jqg1, jqg2, ... So if should be no conflicts. You should just fill the id fields of the JSON with the ids from the database.
One more possibility is that you just specify the rowid parameter (the first parameter) of addRowData yourself. In the case you will have full control on the new ids of the rows added in the grid.
The code of $.jgrid.randId function is very easy. There are $.jgrid.uidPref initialized as 'jqg' and $.jgrid.guid initialized to 1. The $.jgrid.randId function do the following
$.jgrid.randId = function (prefix) {
return (prefix? prefix: $.jgrid.uidPref) + ($.jgrid.guid++);
}
If it is really required you can increase (but not decrease) the $.jgrid.guid value without any negative side effects.