Importe el archivo CSV al controlador Laravel e inserte datos en dos tablas

7 minutos de lectura

Avatar de usuario de Devin Gray
devin gris

Así que soy un completo novato en Laravel y estoy intentando algo aquí. Quiero importar un archivo CSV en dos tablas, tengo una tabla llamada listas que obtendrá el nombre de la lista y un client_id.

Luego tengo una tabla llamada clientes que obtendrá el nombre, apellido, número de contacto y client_id y un list_id.

Lo que quiero lograr es importar un archivo CSV que tomará el nombre del archivo y lo almacenará en la tabla de la lista, luego creará una matriz a través del archivo CSV e importará los datos a la tabla de clientes con la lista y la identificación del cliente.

He terminado la primera parte y se inserta correctamente en la tabla de listas. ¿Cómo creo ahora una matriz a partir del CSV que se encuentra en almacenamiento/documentos y luego la inserto en la tabla de clientes?

namespace App\Http\Controllers;

use Input;
use DB;
use Illuminate\Http\Request;
use App\Http\Requests\ListsRequest;
use App\Lists;
use App\Clients;
use App\Http\Requests;
use App\Http\Controllers\Controller;

class ListsController extends Controller {

    public function index()
    {
        // $list_items = Lists::all();
        $clients = Clients::all();

        return view('lists.show', compact('clients'));
    }

    public function store(Requests\ListsRequest $request)
    {
        $input = $request->input();
        Lists::create($input);

        if (Input::hasFile('name'))
        {

            $file = Input::file('name');
            $name = time() . '-' . $file->getClientOriginalName();

            $path = storage_path('documents');

            $file->move($path, $name);

            // All works up to here
            // All I need now is to create an array
            // from the CSV and insert into the customers database
        }
    }
}

Elegí usar la respuesta que había aceptado, pero también jugué con la otra respuesta y conseguí que funcionara así.

public function store(Requests\ListsRequest $request)
{
    $input = $request->input();
    $client_id = $request->input('client_id');

    if (Input::hasFile('name'))
    {
        $file = Input::file('name');
        $name = time() . '-' . $file->getClientOriginalName();
        $path = storage_path('documents');

        Lists::create(['client_id' => $client_id, 'name' => $name]);

        $reader = Reader::createFromPath($file->getRealPath());
        // Create a customer from each row in the CSV file
        $headers = array();

        foreach ($reader as $index => $row)
        {
            if ($index === 0)
            {
                $headers = $row;
            } else
            {
                $data = array_combine($headers, $row);
                Customers::create($data);
            }
        }

        $file->move($path, $name);

        return view('clients');
    }
}

  • mire este primer stackoverflow.com/questions/21063008/… no puede simplemente insertar directamente en la base de datos como lo hace, si el enlace no proporciona ayuda, hágamelo saber

    – Maytham Fahmi

    5 de febrero de 2016 a las 9:21

  • Estoy intentando esto ahora 🙂 Gracias, te dejaré saber cómo va en unos pocos

    – Devin Grey

    5 de febrero de 2016 a las 9:23

  • De acuerdo, probé lo que se ve en la pregunta editada anterior, pero ahora solo obtengo una pantalla en blanco incluso si solo devuelvo ‘hola’ donde tengo

    – Devin Grey

    5 de febrero de 2016 a las 9:36

  • ¿Podría ayudar a explicar la lógica en el área donde agregué?

    – Devin Grey

    5 de febrero de 2016 a las 9:36

  • es importante hacer la resolución de problemas paso a paso, por lo que si no devuelve hola, esto significa que no se obtuvo el archivo o que su declaración if está regresando falsa, intente por diversión escribir dd ($ entrada) antes de la declaración if para ver si su controlador es vida y averigüe si $ entrada contiene las cosas que esperaba

    – Maytham Fahmi

    5 de febrero de 2016 a las 9:57

Avatar de usuario de Maytham Fahmi
Maytham Fahmi

Hay 3 pasos para leer el archivo CSV e importarlo en la base de datos en Laravel.

  1. Leer archivo CSV
  2. Convertirlo en matriz
  3. Finalmente crear registros en nuestra base de datos.

Antes de comenzar, he creado una muestra. test.csv archivo y ponerlo en mi carpeta pública en la carpeta de archivos:

name,email,password
user1,email1@email.com,pasxxxxxxxxxword
user2,email2@email.com,pasxxxxxxxxxword
user3,email3@email.com,pasxxxxxxxxxword

Paso 1 y 2; Creé una función auxiliar llamada csvToArraysolo lo puse en mi controlador por ahora (esta función está inspirada en este Enlace) simplemente lee el archivo CSV y lo convierte en matriz:

function csvToArray($filename="", $delimiter=",")
{
    if (!file_exists($filename) || !is_readable($filename))
        return false;

    $header = null;
    $data = array();
    if (($handle = fopen($filename, 'r')) !== false)
    {
        while (($row = fgetcsv($handle, 1000, $delimiter)) !== false)
        {
            if (!$header)
                $header = $row;
            else
                $data[] = array_combine($header, $row);
        }
        fclose($handle);
    }

    return $data;
}

Paso 3; Y aquí está mi paso final, lea la matriz e insértela en nuestra base de datos:

public function importCsv()
{
    $file = public_path('file/test.csv');

    $customerArr = $this->csvToArray($file);

    for ($i = 0; $i < count($customerArr); $i ++)
    {
        User::firstOrCreate($customerArr[$i]);
    }

    return 'Jobi done or what ever';    
}

Nota: esta solución supone que tiene un modelo en su proyecto Laravel y tiene la tabla adecuada en su base de datos.

si utiliza dd($customerArr) obtendrás esto
ingrese la descripción de la imagen aquí

  • Creo que este es un buen enfoque. Pero, ¿qué pasa con un CSV grande como 100 000 filas? La matriz tendrá un tamaño grande y podría tener problemas con la memoria ram.

    – Rolly

    18 de agosto de 2017 a las 16:36

  • El encabezado en este caso depende de su modelo de datos como se menciona en la nota. En mi caso, es el modelo de usuario y contiene el nombre, la contraseña del correo electrónico. hazlo tú mismo y pruébalo. si te he entendido mal por favor házmelo saber.

    – Maytham Fahmi

    28 de mayo de 2018 a las 17:28


  • @ maytham-ɯɐɥʇʎɐɯ ¿Puedes decirme cómo se cifra la contraseña después de cargar el archivo csv?

    – ToxifiedHashkey

    26 de abril de 2021 a las 19:51

  • @ToxifiedHashkey Dejé de trabajar con laravel hace algunos años. pero la función bcrypt puede buscarla en Google y encontrar una función para cifrar la contraseña. pero $clienteArr[$i] es cada objeto que importa, conceptualmente puede hacer algo como sin probarlo y validarlo. $clienteArr[$i]->contraseña = bcryptFunction($clienteArr[$i]->contraseña) Esto sobrescribirá la contraseña de texto con la contraseña cifrada.

    – Maytham Fahmi

    27 de abril de 2021 a las 14:57


  • @maytham-ɯɐɥʇʎɐɯ Muchas gracias por ese consejo: D

    – ToxifiedHashkey

    27 abr 2021 a las 15:07

En tus store() método, cree el registro en su lists y luego iterar sobre el contenido del archivo CSV e insertar los datos en el customers mesa. Deberías crear un relación entre clientes y listas para este propósito. También sería mejor usar algo como el Paquete CSV de PHP League para leer tales archivos:

public function store(AddCustomersRequest $request)
{
    // Get uploaded CSV file
    $file = $request->file('csv');

    // Create list name
    $name = time().'-'.$file->getClientOriginalName();

    // Create a list record in the database
    $list = List::create(['name' => $name]);

    // Create a CSV reader instance
    $reader = Reader::createFromFileObject($file->openFile());

    // Create a customer from each row in the CSV file
    foreach ($reader as $index => $row) {
        $list->customers()->create($row);
    }

    // Redirect back to where you need with a success message
}

  • Usé la función de @maytham-ɯɐɥıλɐɯ para hacer esto, pero también jugué con tu respuesta para ver cómo hacer esto, estoy editando mi pregunta para que la veas.

    – Devin Grey

    5 de febrero de 2016 a las 13:03

Avatar de usuario de Koushik Das
Koushik Das

@maytham La solución de Maytham funcionará bien. Sin embargo, tendrá un gran problema si está tratando de hacerlo con grandes datos. Incluso si hace 1000 filas, creará un problema, ya que hará 1000 declaraciones de inserción por separado. Solo editaré el tercer método por él y agregaré mi propia entrada.

public function importCsv()
{
    $file = public_path('file/test.csv');

    $customerArr = $this->csvToArray($file);
    $data = [];
    for ($i = 0; $i < count($customerArr); $i ++)
    {
        $data[] = [
            'column_name1' => 'value',
            'column_name2' => 'value2',
            .. so..on..and..on
        ];
        //User::firstOrCreate($customerArr[$i]);
    }
    DB::table('table_name')->insert($data);
    return 'Jobi done or what ever';    
}

Esto llamará a la base de datos una vez para insertar tantas filas como desee. Ya sea 1000, 100000 o lo que sea.
Sin embargo, si tiene un csv enorme, esto también será un problema, ya que deberá insertarlo en fragmentos. Al igual que en PostgreSQL, me di cuenta de que puede insertar hasta 65000 filas en una declaración. Tal vez me equivoque con el número, pero hay un límite en cada base de datos y debe buscarlo.

  • Sí, ese es un muy buen punto. Si tiene un archivo CSV grande, es muy probable que no pueda almacenarlo todo en una matriz en la memoria antes de comenzar a insertar los datos en la base de datos, por lo que debe insertar los datos en fragmentos a medida que los lee desde el archivo CSV. . Gracias.

    – Hartley San

    24 de septiembre de 2018 a las 12:43

  • Correcto. También vi que hay una limitación en el número de filas en una inserción.

    – Koushik Das

    24/09/2018 a las 15:55

¿Ha sido útil esta solución?