Laravel-excel: [PROPOSTA] Importar itens sem salvar diretamente

Criado em 24 jan. 2019  ·  9Comentários  ·  Fonte: Maatwebsite/Laravel-Excel

Pré-requisitos

Versões

  • Versão PHP: 7.1.9
  • Versão do Laravel: 5.7.19
  • Versão do pacote: 3.0+

Descrição

A importação de modelos deve ser possível sem salvá-los diretamente. Também deve ser possível retornar qualquer coisa diferente de modelos de uma importação.

No momento, não consigo atualizar do 2.1.30 para o 3.0.0 ou superior. Preciso ser capaz de importar um conjunto de modelos sem salvá-los. Eu uso isso para testes. Além disso, tenho um teste em que uma linha contém informações para criar dois modelos relacionados (de classes diferentes). Atualmente, só posso ter um modelo por linha. A reestruturação do arquivo CSV não é possível aqui.

IMO, 3.0.0+ é muito focado na situação ideal onde um arquivo CSV corresponde a uma tabela e uma linha corresponde a um modelo, e cada modelo deve ser salvo instantaneamente. Não foi o caso do 2.X, e não sei por que foi alterado.

Observe que não quero ficar no 2.1.30, porque requer o pacote phpoffice/phpexcel abandonado.

Exemplo

Um método adicional deve ser adicionado à fachada Excel , que tem a mesma assinatura de import , mas retorna modelos em vez de salvá-los. Exemplo:

$users = Excel::load(new UsersImport, 'users.xlsx');

Além disso, um método item deve ser adicionado às classes de importação, que podem retornar qualquer tipo em vez de apenas modelos.

question

Comentários muito úteis

@WouterFlorijn, você pode tentar esta abordagem para obter um array de seu arquivo:

$array = Excel::toArray([], 'file.xlsx');

Todos 9 comentários

Usar ToModel é apenas uma maneira de lidar com as importações. Esta é apenas a opção que torna mais fácil inserir 1 modelo por linha.

Se você quiser lidar com estruturas diferentes e de uma forma que seja semelhante à versão 2.1, você precisa usar ToCollection : https://laravel-excel.maatwebsite.nl/3.1/imports/collection.html Em o método de coleta, você obtém uma coleção semelhante de linhas que obteve no 2.1.

Se você quiser obter os modelos apenas no controlador e não em seu objeto de importação (não é realmente uma abordagem recomendada), então há o método ::toCollection , que retorna a linha bruta (nenhuma conversão para modelos é feita) para seu controlador .
(https://laravel-excel.maatwebsite.nl/3.1/imports/basics.html#importing-to-array-or-collection)

$users = Excel::toCollection(new UsersImport, 'users.xlsx');

@patrickbrouwers obrigado pela sua resposta. Portanto, se bem entendi, usar Excel::import em uma importação que implementa ToCollection retornará uma coleção de modelos sem salvá-los? Nesse caso, isso não está claramente declarado na documentação, pois o exemplo na parte inferior de https://laravel-excel.maatwebsite.nl/3.1/imports/collection.html é o seguinte:

public function import() 
{
    Excel::import(new UsersImport, 'users.xlsx');
}

O valor de retorno não é armazenado em nenhum lugar, o que significa que a coleção importada de modelos é salva diretamente (ou pelo menos que o método tem efeitos colaterais). Caso contrário, seria inútil chamar import sem atribuir o valor de retorno a uma variável, certo?

@WouterFlorijn Não, ::import() nunca retornará nenhuma linha ou modelo. Apenas Excel::toCollection() faz.

Usar a preocupação ToCollection é diferente de usar Excel::toCollection() .
Ao implementar ToCollection toda a importação é encapsulada no objeto Import. Retornar algo em ToCollection não será devolvido ao controlador.

@patrickbrouwers Só para voltar, ainda acho que estamos nos entendendo mal. O que estou simplesmente procurando é um método que retorne uma Coleção de Modelos, sem salvá-los. Não quero processar as linhas em meu controlador, gostaria de fazer isso em uma classe de importação. Até agora não encontrei isso.

A ideia:

TransactionsImport.php:

<?php

namespace App\Imports;

use App\Banks\Transaction;
use Carbon\Carbon;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class TransactionsImport implements ToModel, WithHeadingRow
{
    public function model(array $row)
    {
        $transaction = new Transaction;
        $transaction->amount = $row['amount'];
        $transaction->currency = $row['currency'];

        return $transaction;
    }
}

TransactionsController.php:

...
$transactions = Excel::someFunction(new TransactionsImport, 'path/to/file.csv');
// $transactions is a Collection of Transaction models that are not saved to the database yet.
...

Também encontrei dois problemas com a função toCollection :

  1. Ele retorna uma coleção com um único item, que é outra coleção que contém uma coleção para cada linha.
  2. É necessário um argumento de importação, que é inútil nos casos em que você deseja apenas retornar as linhas como coleções.

O que estou simplesmente procurando é um método que retorne uma Coleção de Modelos, sem salvá-los. Não quero processar as linhas em meu controlador, gostaria de fazer isso em uma classe de importação. Até agora não encontrei isso.

Talvez estes documentos sejam úteis para você:
Lidando com persistência por conta própria
Conceitos de Arquitetura

@WouterFlorijn, você pode tentar esta abordagem para obter um array de seu arquivo:

$array = Excel::toArray([], 'file.xlsx');

@WouterFlorijn, você pode tentar esta abordagem para obter um array de seu arquivo:

$array = Excel::toArray([], 'file.xlsx');

Isso é exatamente o que eu estava procurando.

1 para este pedido. Não acho que os métodos model () e collection () devam salvar alguma coisa. Ele deve retornar os dados de um arquivo Excel / CSV para uma coleção (ou matriz) de modelos / matrizes. A persistência deve ser tratada separadamente ou pelo menos ser uma escolha.

Meu caso de uso: quero obter as datas mínimas e máximas de registros em um CSV. Se isso se sobrepõe a um CSV importado existente, não deve importar nada antes que o usuário confirme que a sobreposição está correta.

Edit: Ah, estou respondendo a um problema encerrado. Como você lidou com isso @WouterFlorijn?

Você pode facilmente conseguir isso mantendo o estado dentro da classe de importação, você pode envolver o método toModels dentro de uma característica e reutilizá-lo em todas as suas exportações.

new UsersImport implements ToModel, WithHeadingRow
{
    use Importable;

    protected array $models;

    public function model(array $row)
    {
         $this->models[] = new User($row);
    }

    public toModels(string $filename): array
    {
       $this->import($filename);

        return $this->models;
    }
}
$nonPersistedUsers = (new UsersImport)->toModels('users.xlsx');
Esta página foi útil?
0 / 5 - 0 avaliações