Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[QUESTION] How to return data from implemented import method? #1980

Closed
ssyberg opened this issue Jan 3, 2019 · 13 comments
Closed

[QUESTION] How to return data from implemented import method? #1980

ssyberg opened this issue Jan 3, 2019 · 13 comments
Labels

Comments

@ssyberg
Copy link

ssyberg commented Jan 3, 2019

Prerequisites

Versions

  • PHP version: 7.2
  • Laravel version: 5.6
  • Package version: 3.1

Description

I'm just wondering if there's any way to communicate with my controller from the implemented import method. I've tried returning a data array to the controller but it's not getting through. Haven't seen any mention of this...

I know I can use toCollection and return the entire import to a collection in the controller but worried about taking a performance hit.

@patrickbrouwers
Copy link
Member

Put the imported data into a class property of your import object and make a getter for it that you can call after the import has finished iin your controller.

@ssyberg
Copy link
Author

ssyberg commented Jan 31, 2019

I must still be missing something, let me get a little more specific.

So here's my import call in my controller:
$import = Excel::import(new SalesImport, 'imports/salesdata.xlsx');

class SalesImport implements ToCollection
{
    public function collection(Collection $rows)
    {
        .... lots of other stuff ....
        $this->data = $data;
    }

It's clear to me that this data isn't making it's way back to my $import object in the controller, but I'm guessing I need to implement something other than ToCollection here?

@patrickbrouwers
Copy link
Member

class SalesImport implements ToCollection
{
    public $data;

    public function collection(Collection $rows)
    {
        .... lots of other stuff ....
        $this->data = $data;
    }
$import = new SalesImport;
Excel::import($import, 'imports/salesdata.xlsx');
dd($import->data);

@michoacano094
Copy link

class SalesImport implements ToCollection
{
    public $data;

    public function collection(Collection $rows)
    {
        .... lots of other stuff ....
        $this->data = $data;
    }
$import = new SalesImport;
Excel::import($import, 'imports/salesdata.xlsx');
dd($import->data);

Awesome!

@brunolkatz
Copy link

class SalesImport implements ToCollection
{
    public $data;

    public function collection(Collection $rows)
    {
        .... lots of other stuff ....
        $this->data = $data;
    }
$import = new SalesImport;
Excel::import($import, 'imports/salesdata.xlsx');
dd($import->data);

Can you please set that in https://docs.laravel-excel.com/3.1/imports/collection.html or another place in documentation? I lost a lot of time searching that.

@patrickbrouwers
Copy link
Member

A similar example has been in the docs for a while: https://docs.laravel-excel.com/3.1/architecture/objects.html#getters

@nrodriguezm
Copy link

Great library, this example works great for a single sheet.
Any tips on implementing with WithMultipleSheets import? How should I get the row count?

On the CRUD I am getting: Call to undefined method Maatwebsite\Excel\Excel::getRowCount()

I am using a class to call the specfic sheet importer:

class ExcelSampleSheetsImport implements WithMultipleSheets 
{    
    protected $params; 

    public function __construct($params) 
    {
        $this->params = $params;
    }

    public function sheets(): array
    {
        return [
            'Sheet to import' => new ExcelSampleImport($this->params)
        ];
    }
}

On ExcelSampleImport class I have implemented the counter as specified on the docs.

@osvcha
Copy link

osvcha commented Nov 16, 2019

How I can do this but with multiple sheets?

Import class

class CommunityImport implements WithMultipleSheets
{	
    use WithConditionalSheets;
    
    public function conditionalSheets(): array
    {
        return [
            0 => new FirstSheetCommunityImport(),
            1 => new SecondSheetCommunityImport(),
        ];
    }   
}

Class for first sheet

class FirstSheetCommunityImport implements ToCollection
{	
    public $id;
    
    public function collection(Collection $rows)
    {
	$i=0;
    	foreach ($rows as $row) 
        {
            if($i==0){
	        $this->id = $row[0];
            }
            $i++;
        }
    }    
}

Page Controller - How can I access id from FirstSheetCommunityImport class?

public function import()
     {
	$import = new CommunityImport();
	$import->onlySheets(0);
        Excel::import($import, storage_path('app/xls/').'comunidad-import.xlsx');
     } 

@junicodes
Copy link

To access that id from the FirstSheetCommunityClass was an issue for me but I used Laravel cache to store my collection for 10 minute and then access it from the controller using the Cache Facade

@lucien144
Copy link

Here is my take on getters with multiple sheets. Using cache for this is not a good idea in my opinion...

<?php
// VendorsExtraDataImportSheet.php:

use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;

class VendorsExtraDataImportSheet implements ToCollection
{
	public $count = 0;

	public function collection(Collection $rows)
	{
			$this->count++;
	}
}
<?php
// VendorsExtraDataImport.php

use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithConditionalSheets;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class VendorsExtraDataImport implements ToCollection, WithMultipleSheets
{
	use WithConditionalSheets;

	public const SHEET_TO_IMPORT = 'Example data input';

	public $sheet;

	public function collection(Collection $rows)
	{
	}


	public function conditionalSheets(): array
	{
		if (!$this->sheet) {
			$this->sheet = new VendorsExtraDataImportSheet;
		}

		return [
			self::SHEET_TO_IMPORT => $this->sheet,
		];
	}
}
<?php
	// ...
	// PageController.php
	public function import()
	{
		$import = new VendorsExtraDataImport();
		$import->onlySheets(VendorsExtraDataImport::SHEET_TO_IMPORT);
		Excel::import($import, resource_path('data/vendors.xlsx'));
		dd($import->sheet->count);
	} 
	// ...

@fernando-moreno
Copy link

I'm unable to make it work with ToModel method... any other options?

@adnane-ka
Copy link

I'm unable to make it work with ToModel method... any other options?

I myself solved that problem by creating an array property in the imported class and each time a new item is inserted i push it the result array. example:

public $inserted = [];
    /**
     * @param array $row
     *
     * @return YourModel|null
     */
    public function model(array $row)
    {
        $inserted = new YourModel([
           ..
        ]);

        array_push($this->inserted ,$inserted);

        return $inserted;
    }

and then, read that property as bellow:

$instance = new YourImportClass;
$imported = Excel::import($instance , $items);

return $instance->inserted;

@FareedR
Copy link

FareedR commented Jun 23, 2022

I'm unable to make it if I implement WithProgressBar class

reference https://docs.laravel-excel.com/3.1/imports/progress-bar.html

class DatasImport implements ToCollection, WithChunkReading, WithLimit, WithHeadingRow, WithStartRow, WithProgressBar
{
    use Importable;

    private $datas = [];
    private $headers = [];
    private $index;
    private $count = 0;
    private $column = [];

    public function __construct($headingRow = 0, $startRow = 1, $isSync = false)
    {
        $this->headingRow = $headingRow;
        $this->startRow = $startRow;
        $this->diffRow = $startRow - $headingRow;
        $this->isSync = $isSync;
    }

    public function chunkSize(): int
    {
        return $this->headingRow + 5;
    }

    public function limit(): int
    {
        if($this->isSync) {
            return 1000000;
        }

        return $this->startRow + 5;
    }

    public function headingRow(): int
    {
        return $this->headingRow;
    }

    public function startRow(): int
    {
        return $this->startRow - $this->diffRow;
    }

    public function collection(Collection $rows)
    {
        // get headers
        if (!$this->headers) {
            $this->headers = $rows->toArray()[0];
            $rows = $rows->slice($this->diffRow);
        }
        $this->count += count($rows->toArray());
        
        if(!$this->isSync) {
            $rows = $rows->slice(0, $this->startRow + 5);
        }

        foreach ($rows as $lineRow => $row){
            foreach ($row as $idx => $data) {
                if(!($data == null || $data == '')) {
                    if (!isset($this->column[$idx])) $this->column[$idx] = $data;
                    if (!empty($row[$idx])) $this->column[$idx] = $data;
                } else {
                    $this->column[$idx] = null;
                }
            }
            array_push($this->datas,$this->column);
        }
        // end get data
    }

    public function getDatas() : array
    {
        return $this->datas;
    }

    public function getHeaders() : array
    {
        return $this->headers;
    }

    public function getIndex() : int
    {
        return $this->index;
    }
}
// in my command class

// current approach is NOT OK
$this->output->title("Start import file {$integration->label} ");
(new DatasImport($integration->header_row,$integration->start_row,true))
    ->withOutput($this->output)
    ->import($integration_checker->integration_file_location->file_location, 'public');

// what should i implement here to get implemented import method??

// previous approach is OK
// $import = new DatasImport($integration->header_row,$integration->start_row,true);
// Excel::import($import, $integration_checker->integration_file_location->file_location, 'public');
// $keys = $import->getHeaders();
//$datas = $import->getDatas();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests