Straight forward question. How does one get the total number of rows in a spreadsheet with laravel-excel?
I now have a working counter of how many rows have been processed (in the CompanyImport file), but I need the total number of rows before I start adding the rows to the database.
The sheet I'm importing is almost 1M rows, so I am trying to create a progress bar.
My import:
public function model(array $row)
{
# Counter
++$this->currentRow;
# Dont create or validate on empty rows
# Bad workaround
# TODO: better solution
if (!array_filter($row)) {
return null;
}
# Create company
$company = new Company;
$company->crn = $row['crn'];
$company->name = $row['name'];
$company->email = $row['email'];
$company->phone = $row['phone'];
$company->website = (!empty($row['website'])) ? Helper::addScheme($row['website']) : '';
$company->save();
# Everything empty.. delete address
if (!empty($row['country']) || !empty($row['state']) || !empty($row['postal']) || !empty($row['address']) || !empty($row['zip'])) {
# Create address
$address = new CompanyAddress;
$address->company_id = $company->id;
$address->country = $row['country'];
$address->state = $row['state'];
$address->postal = $row['postal'];
$address->address = $row['address'];
$address->zip = $row['zip'];
$address->save();
# Attach
$company->addresses()->save($address);
}
# Update session counter
Session::put('importCurrentRow', $this->currentRow);
return $company;
}
My controller:
public function postImport(Import $request)
{
# Import
$import = new CompaniesImport;
# Todo
# Total number of rows in the sheet to session
Session::put('importTotalRows');
#
Excel::import($import, $request->file('file')->getPathname());
return response()->json([
'success' => true
]);
}
In Laravel Excel 3.1 you can get the total rows by implementing WithEvents and listening to beforeImport event.
<?php
namespace App\Imports;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeImport;
class UserImport extends ToModel, WithEvents {
[...]
public function registerEvents(): array
{
return [
BeforeImport::class => function (BeforeImport $event) {
$totalRows = $event->getReader()->getTotalRows();
if (!empty($totalRows)) {
echo $totalRows['Worksheet'];
}
}
];
}
[...]
}
You can use below code to calculate number of rows
Excel::import($import, 'users.xlsx');
dd('Row count: ' . $import->getRowCount());
You can check the Docs
Update
The above method was for calculating the rows which have been imported so far.
In order to get number of rows which are in the sheet, you need to use getHighestRow
Excel::load($file, function($reader) {
$lastrow = $reader->getActiveSheet()->getHighestRow();
dd($lastrow);
});
This has been referenced here by author of the Plugin.
1.- Make file for import
php artisan make:import ImportableImport
2.- Your File Import
<?php
namespace App\Imports;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\Importable;
class ImportablesImport implements ToCollection
{
use Importable;
/**
* #param Collection $collection
*/
public function collection(Collection $collection)
{
//
}
}
3.- Your controller
$array = (new ImportablesImport)->toArray($file);
dd(count($array[0]));
This doc: https://docs.laravel-excel.com/3.1/imports/importables.html
You can use below code to get number of rows before import
$fileExtension = pathinfo($file, PATHINFO_EXTENSION);
$temporaryFileFactory=new \Maatwebsite\Excel\Files\TemporaryFileFactory(
config('excel.temporary_files.local_path',
config('excel.exports.temp_path',
storage_path('framework/laravel-excel'))
),
config('excel.temporary_files.remote_disk')
);
$temporaryFile = $temporaryFileFactory->make($fileExtension);
$currentFile = $temporaryFile->copyFrom($file,null);
$reader = \Maatwebsite\Excel\Factories\ReaderFactory::make(null,$currentFile);
$info = $reader->listWorksheetInfo($currentFile->getLocalPath());
$totalRows = 0;
foreach ($info as $sheet) {
$totalRows+= $sheet['totalRows'];
}
$currentFile->delete();
The code taken from Laravel Excel libary
Check Below Example:
$sheet->getActiveSheet()->getStyle('A2:A' . $sheet->getHighestRow())->getFont()->setBold(true);
by using getHighestRow() method you can fetch the total number of rows. In the above code sample I've applied font as BOLD to the second cell of first column till the maximum row count of that same first column.
Detailed Code Snippet of another example:
$excel->sheet('Employee Details', function ($sheet) use ($AllData) {
$sheet->fromArray($AllData);
$sheet->setAutoSize(true);
$sheet->getStyle('A2:A' . $sheet->getHighestRow())->applyFromArray(array('alignment' => array('horizontal' => \PHPExcel_Style_Alignment::HORIZONTAL_LEFT)));
});
Related
After searching documentation about 2 hours and not finding a answer (https://charts.erik.cat/), maybe someone will help me with this... I'm using Laravel Charts chart.js library. How to make that on top of my column would be displayed data labels? like in this picture on DC coulmn:
This is my code:
<?php
namespace App\Http\Controllers;
use App\Content;
use App\Charts\UserLineChart;
use Charts;
use Illuminate\Http\Request;
class ChartController extends Controller
{
public function index(Request $request)
{
$content = Content::where('vei_sn', '23333')->get();
if ($request->has('date_from') && $request->input('date_from') != '' && $request->has('date_to') && $request->input('date_to') != '') {
$datefrom = $request->input('date_from');
$dateto = $request->input('date_to');
$content = $content->whereBetween('op_date', [$datefrom, $dateto]);
}
$OBD = $content->where('con_type', 'OBD')->count();
$DC = $content->where('con_type', 'DC')->count();
$BSL = $content->where('con_type', 'BSL')->count();
$content = $content->pluck('con_type', 'con_type');
$pChart = new UserLineChart;
$bChart = new UserLineChart;
$pChart->labels($content->values())->minimalist($display = true);
$bChart->labels($content->values());
$pChart->dataset('Connections', 'pie', [$OBD, $DC, $BSL]);
$bChart->dataset('Connections', 'bar', [$OBD, $DC, $BSL])->options([
'fill' => false,
]);
return view('chart.index', compact('pChart', 'bChart'));
}
}
I'm using Laravel Excel by https://laravel-excel.com/. I have a CSV file that has data like:
I want to import some CSV and validate the existed data and not inserting it into database.
But, I want to insert data that not existed in database and I don't know how to validate it.
I just want to insert the new data together and denying the old one for the purpose of preventing some duplicate data after importing CSV into a database and reducing human error.
I have example code like this:
<?php
namespace App\Imports\Points;
use App\Models\PointRegular;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\Importable;
class PointsRegularImport implements ToCollection, WithHeadingRow
{
use Importable;
public function collection(Collection $rows)
{
foreach($rows as $row) {
// Check existing data in database
$pointRegulars = PointRegular::orderBy('created_at', 'desc')
->where('product_id', $row['product_id'])
->where('channel_id', $row['channel_id'])
->where('transaction_type_id', $row['transaction_type_id'])
->where('payment_method_id', $row['payment_method_id'])
->get();
foreach($pointRegulars as $pointRegular) {
// Check for update data with id
if($row->has('id')) {
if($pointRegular->id == $row['id']) {
$point = PointRegular::findOrFail($row['id']);
$point->product_id = $row['product_id'];
$point->channel_id = $row['channel_id'];
$point->transaction_type_id = $row['transaction_type_id'];
$point->payment_method_id = $row['payment_method_id'];
}
} else {
// Create new data
// Check for data existed in database
// If exist, deny existed data and insert new data
if($pointRegular) {
return "Existed and not insert";
} else {
return "You Inserting new data without creating the old one";
}
}
}
}
}
}
Using updateOrCreate with Eloquent reference here
function updateOrCreate(array $attributes, array $values = []){}
$eanStyle = new \PHPExcel_Style();
$eanStyle->getNumberFormat()->applyFromArray([
'code' => '0000000000000'
]);
/* apply styles */
$mainSheet->duplicateStyle($eanStyle, 'A2:A10000');
Code above generates .xlsx template file, user enters data (7 rows) and upload file and then:
$mainSheet->getHighestRow('A'); // retruns 10000 instead of 8 (7 rows + header)
Thanks in advance for help.
I would advise you create a read filter to read only specific rows and columns. This would prevent the other empty rows being included:
$inputFileType = 'Xls';
$inputFileName = './sampleData/example1.xls';
$sheetname = 'Data Sheet #3';
/** Define a Read Filter class implementing \PhpOffice\PhpSpreadsheet\Reader\IReadFilter */
class MyReadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter {
public function readCell($column, $row, $worksheetName = '') {
// Read rows 1 to 7 and columns A to E only
if ($row >= 1 && $row <= 7) {
if (in_array($column,range('A','E'))) {
return true;
}
}
return false;
}
}
/** Create an Instance of our Read Filter **/
$filterSubset = new MyReadFilter();
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Tell the Reader that we want to use the Read Filter **/
$reader->setReadFilter($filterSubset);
/** Load only the rows and columns that match our filter to Spreadsheet **/
$spreadsheet = $reader->load($inputFileName);
i convert an excel file to HTML Table with PHPExcel
(PHPspreadsheet) with Symfony 2.5
I'm trying to set a filter to only load the range ('A','N') , the first 13 columns. not working..
I'm also trying to set the Width of the 'N' Column. not working..
when i dump the column's width value is correct..
I can increase the columns width but not decrease them..
it looks like the text inside the cell is defining the cell's width automatically..
Here is my controller :
public function showClientAction($client)
{
$excel = glob(''.path.'\\'.path.'\\filename_' .$client.'.{xlsx,xls,xlsm,xlsm.ink}', GLOB_BRACE);
$filterSubset = new \PHPExcel_Reader_DefaultReadFilter(1,1000,range('A','N'));
$objReader = \PHPExcel_IOFactory::createReaderForFile($excel[0]);
$objReader->setReadFilter($filterSubset);
/** Read the list of worksheet names and select the one that we want to load **/
$worksheetList = $objReader->listWorksheetNames($excel[0]);
$sheetname = $worksheetList[0];
/** Advise the Reader of which WorkSheets we want to load **/
$objReader->setLoadSheetsOnly($sheetname);
$objPHPExcel = $objReader->load($excel[0]);
$objPHPExcel->getActiveSheet()->getColumnDimensionByColumn('13')->setAutoSize(false);
$objPHPExcel->getActiveSheet()->getColumnDimensionByColumn('13')->setWidth(2.5);
// OUTPUT is : int (13) applied correctly
var_dump($objPHPExcel->getActiveSheet()->getColumnDimensionByColumn('13'));
$writer = \PHPExcel_IOFactory::createWriter($objPHPExcel, "HTML");
$writer->generateSheetData();
$writer->generateStyles();
return $this->render('SocPerfclientBundle:Default:testexcel.html.twig', array(
'excelHtml'=>$writer,
'stylesExcel'=>$writer,
'client'=>$nom_client
));
}
My filter :
class PHPExcel_Reader_DefaultReadFilter implements PHPExcel_Reader_IReadFilter
{
public $_startRow = 0;
public $_endRow = 0;
public $_columns = array();
/** Get the list of rows and columns to read */
public function __construct($startRow, $endRow, $columns) {
$this->_startRow = $startRow;
$this->_endRow = $endRow;
$this->_columns = $columns;
}
public function readCell($column, $row, $worksheetName = '') {
// Only read the rows and columns that were configured
if ($row >= $this->_startRow && $row <= $this->_endRow) {
if (in_array($column,$this->_columns)) {
return true;
}
}
return false;
}
}
my view :
{{ excelHtml.generateSheetData | raw }}
{{ stylesExcel.generateStyles | raw }}
Here a screenshot html view :
We can see the "RCA" column still having the initial width.. my setWidth isnt applied..
if i change the link by a shorter word like : yes.docx , the column decreases.
I want to keep track of users download on my web application so I decide to create a tables called downloads. I already assign the relation in my model.
Download.php
<?php
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;
class Download extends Eloquent {
protected $table = 'downloads';
// Relations
public function user(){return $this->belongsTo('User','user_id');}
public function catalog_downloads(){return $this->hasMany('CatalogDownload'); }
public function marketing_materials(){return $this->hasMany('Download'); }
}
Here is my download function in one of my controller
public function file_download($id)
{
$catalog_download = CatalogDownload::findOrFail($id);
$distributor = Auth::user()->distributor()->first();
$export_type = $distributor->export_type()->first();
$product_export = $catalog_download->product_exports()->first();
$destinationPath = base_path().'/app/files/product_export/'. $catalog_download->id.'/'. $export_type->id.'/';
$file_name = $product_export->file_path;
$pathToFile = $destinationPath .$file_name;
if(Response::download()){
$download = new Download;
$download->title = $catalog_download->title;
$download->count = $download->count + 1;
$download->user_id = Auth::user()->id ;
$download->save();
}
return Response::download($pathToFile);
}
I have downloads table already.
For some reasons, no data has been save to the database. :(
Can someone help me take a look into this ?
I just added this block of code.
if(Response::download()){
$download = new Download;
$download->title = $catalog_download->title;
$download->count = $download->count + 1;
$download->user_id = Auth::user()->id ;
$download->save();
}
The rest is all correct.
you have a return statement before your code, it is unreachable, you cannot do anything after a return...