Laravel-excel: [PROPUESTA] Importar elementos sin guardar directamente

Creado en 24 ene. 2019  ·  9Comentarios  ·  Fuente: Maatwebsite/Laravel-Excel

Prerrequisitos

Versiones

  • Versión de PHP: 7.1.9
  • Versión de Laravel: 5.7.19
  • Versión del paquete: 3.0+

Descripción

La importación de modelos debería ser posible sin guardarlos directamente. También debería ser posible devolver cualquier cosa que no sean modelos de una importación.

Actualmente no puedo actualizar de 2.1.30 a 3.0.0 o superior. Necesito poder importar un conjunto de modelos sin guardarlos. Yo uso esto para las pruebas. Además, tengo una prueba en la que una fila contiene información para crear dos modelos relacionados (de diferentes clases). Actualmente, solo puedo tener un modelo por fila. Aquí no es posible reestructurar el archivo CSV.

En mi opinión, 3.0.0+ está demasiado centrado en la situación ideal en la que un archivo CSV corresponde a una tabla y una fila corresponde a un modelo, y cada modelo debe guardarse instantáneamente. Este no fue el caso de 2.X, y no sé por qué se cambió.

Tenga en cuenta que no quiero quedarme en 2.1.30, porque requiere el paquete phpoffice/phpexcel abandonado.

Ejemplo

Se debe agregar un método adicional a la fachada Excel , que tiene la misma firma que import , pero devuelve modelos en lugar de guardarlos. Ejemplo:

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

Además, se debe agregar un método item a las clases de importación, que puede devolver cualquier tipo en lugar de solo modelos.

question

Comentario más útil

@WouterFlorijn puede probar este enfoque para obtener una matriz de su archivo:

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

Todos 9 comentarios

Usar ToModel es solo una forma de lidiar con las importaciones. Esta es solo una opción que facilita las inserciones de 1 modelo por fila.

Si desea manejar diferentes estructuras y de una manera que sea similar a la versión 2.1, entonces necesita usar ToCollection : https://laravel-excel.maatwebsite.nl/3.1/imports/collection.html En el método de colección obtiene una colección similar de filas que obtuvo en 2.1.

Si desea obtener los modelos solo en el controlador y no en su objeto de importación (no es realmente un enfoque recomendado), existe el método ::toCollection , que devuelve la fila sin procesar (no se realiza ninguna conversión a modelos) a su controlador .
(https://laravel-excel.maatwebsite.nl/3.1/imports/basics.html#importing-to-array-or-collection)

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

@patrickbrouwers gracias por su respuesta. Entonces, si entiendo correctamente, usar Excel::import en una importación que implementa ToCollection devolverá una colección de modelos sin guardarlos. Si es así, esto no se indica claramente en la documentación, ya que el ejemplo al final de https://laravel-excel.maatwebsite.nl/3.1/imports/collection.html es el siguiente:

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

El valor de retorno no se almacena en ningún lugar, lo que implica que la colección de modelos importada se guarda directamente (o al menos que el método tiene efectos secundarios). De lo contrario, sería inútil llamar a import sin asignar el valor de retorno a una variable, ¿verdad?

@WouterFlorijn No, ::import() nunca devolverá filas o modelos. Solo Excel::toCollection() hace.

Usar la preocupación ToCollection es algo diferente a usar Excel::toCollection() .
Al implementar ToCollection toda la importación se encapsula dentro del objeto Importar. Devolver algo en ToCollection no se devolverá al controlador.

@patrickbrouwers Solo para volver, todavía creo que nos estamos malinterpretando. Lo que simplemente estoy buscando es un método que devuelva una colección de modelos, sin guardarlos. No quiero procesar las filas en mi controlador, me gustaría hacerlo en una clase de importación. Hasta ahora no he encontrado esto.

La idea:

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.
...

También encontré dos problemas con la función toCollection :

  1. Devuelve una colección con un solo elemento, que es otra colección que contiene una colección para cada fila.
  2. Se necesita un argumento de importación, que es inútil en los casos en los que solo desea devolver las filas como Colecciones.

Lo que simplemente estoy buscando es un método que devuelva una colección de modelos, sin guardarlos. No quiero procesar las filas en mi controlador, me gustaría hacerlo en una clase de importación. Hasta ahora no he encontrado esto.

Quizás estos documentos le resulten útiles:
Manejando la persistencia por su cuenta
Conceptos de Arquitectura

@WouterFlorijn puede probar este enfoque para obtener una matriz de su archivo:

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

@WouterFlorijn puede probar este enfoque para obtener una matriz de su archivo:

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

Eso es exactamente lo que estaba buscando.

+1 para esta solicitud. No creo que los métodos model () y collection () deban guardar nada. Debería devolver los datos de un archivo Excel / CSV a una colección (o matriz) de modelos / matrices. La persistencia debe manejarse por separado, o al menos ser una opción.

Mi caso de uso: quiero obtener la fecha mínima y máxima de los registros en un CSV. Si esto se superpone con un CSV importado existente, no debe importar nada antes de que el usuario confirme que la superposición es correcta.

Editar: Ah, estoy respondiendo a un problema cerrado. ¿Cómo manejaste esto @WouterFlorijn?

Puede lograr esto fácilmente por sí mismo manteniendo el estado dentro de la clase de importación, puede envolver el método toModels dentro de un rasgo y reutilizarlo en todas sus exportaciones.

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');
¿Fue útil esta página
0 / 5 - 0 calificaciones