【问题标题】:PHP how to map importer fields to csv first row fields?PHP如何将导入器字段映射到csv第一行字段?
【发布时间】:2021-03-02 21:04:46
【问题描述】:

我正在将 csv 文件中的轮辋导入到网上商店项目中。没什么可卖的,只是一个学习进口商如何工作的个人项目。 我正在尝试将我的 $EANColumn 变量映射到我的 csv 中的第一行字段名称。

所以目前我有一个包含以下字段的 csv:

EAN;品牌;...还有更多的来袭


1234-WB;WheelBrand...and-more-comming


5678-BW;BrandWheel...and-more-comming


目前在我的导入器中,当我映射时它可以工作:

$EANColumn     = str_replace('’', '', $importData_arr["EAN"]);

并通过数组将其插入我的数据库:

foreach($importData_arr as $importData){
           // var_dump($importData);
            $insertData = array(
                "EAN" =>$EANColumn);
            RimsUpload::insertData($insertData);

这部分的完整代码在这里:

if ($request->input('submit') != null ){

      $file = $request->file('file');

      // File Details
      $filename = $file->getClientOriginalName();
      $extension = $file->getClientOriginalExtension();
      $tempPath = $file->getRealPath();
      $fileSize = $file->getSize();
      $mimeType = $file->getMimeType();

      // Valid File Extensions
      $valid_extension = array("csv");

      // 2MB in Bytes
      $maxFileSize = 2097152;

      // Check file extension
      if(in_array(strtolower($extension),$valid_extension)){

        // Check file size
        if($fileSize <= $maxFileSize){

          // File upload location
          $location = 'uploads';

          // Upload file
          $file->move($location,$filename);

          // Import CSV to Database
          $filepath = url($location."/".$filename);

          // Reading file
          $file = fopen($filepath,"r");

          $importData_arr = array();
          $i = 0;

          while (($filedata = fgetcsv($file, 1000, ";")) !== FALSE) {
             $num = count($filedata );

             $EANColumn     = str_replace('’', '', $importData_arr["EAN"]);
             $BrandColumn   = $importData_arr["Brand"];

             // Skip first row (Remove below comment if you want to skip the first row)
             if($i == 0){
                $i++;
                continue;
             }

             for ($c=0; $c < $num; $c++) {
                $importData_arr[$i][] = $filedata [$c];
             }
             $i++;
          }
          fclose($file);

           dump($importData_arr);
          // Insert to MySQL database
          foreach($importData_arr as $importData){
           // var_dump($importData);
            $insertData = array(
                "EAN" =>$EANColumn,
               "Brand"=>$BrandColumn,
               "Name"=>$importData[2],
               "Size"=>$importData[3],
               "PCD"=>$importData[4],
               "Offset"=>$importData[5],
               "Bore"=>$importData[6],
               "Color"=>$importData[7],
               "Price"=>$importData[8],
               "Stock"=>$importData[9],
               "ImageURL"=>$importData[10]);
            RimsUpload::insertData($insertData);

          }

          Session::flash('message','Import Successful.');
        }else{
          Session::flash('message','File too large. File must be less than 2MB.');
        }

      }else{
         Session::flash('message','Invalid File Extension.');
      }

    }

    // Redirect to index
    // return redirect()->action("RimsUploadController@index", [$request]);
    return response()->redirectToAction('App\Http\Controllers\RimsUploadController@index', [$request]);
  }

但真正的问题是我不想映射我的列,如 [0]、[1]、[2]、[3]... 我想从第一行列名称中获取它们:["EAN"],["Brand"],["Name"],["Size"]... 因此,如果 EAN 是第 1 列或第 7 列,它不会有所作为,因为它会通过名称而不是行号来检测它。 因此,它将能够处理具有不同列顺序的文件。

尝试执行此操作时,我收到错误消息: Undefined index: EAN on $EANColumn = str_replace('’', '', $importData_arr["EAN"]);

重点是提供一种简单的方法,通过 csv 将供应商的数据导入 mysql。然后将其显示到网上商店网站。

【问题讨论】:

  • 在您的 input_data 中它不是数字索引键吗?你可以 var_dump 你的 $importData_arr 吗?
  • 只需创建一个 Mapper 类,您可以在其中将您的行映射到其相关名称您还可以应用一些用于您的目的所需的逻辑( myMapperClass->getValuesByBrandName(mybrandname) 或随心所欲。
  • @Jerson array(0) { }
  • @ChristianFelix 我不确定你的意思是什么,你能告诉我吗?即使做我所做的,在课堂上。它仍然会返回未定义索引的错误
  • 当你不打算应用特殊逻辑时,只使用这个: $test = ['a','b','c','d','e','f' ]; $result = array_combine($test,$row);现在您的数组有一个与您的值关联的键

标签: php data-import


【解决方案1】:

在您的 while 循环之前,从 csv 的第一行中提取字段名称:

$file = fopen($filepath,"r");
$keys = fgetcsv($file, 1000, ';');

然后,获取数据行并将$keys 数组与数据组合成一个关联数组:

$importData_arr = [];
while ($line = fgetcsv($file, 1000, ';')) {
    $data = array_combine($keys, $line);
    // Do something with the data
    $data['EAN'] = str_replace('’', '', $data['EAN']);
    $importData_arr[] = $data;
}
fclose($file);

您现在可以按名称访问所有数据字段,而与 CSV 中的顺序无关:

foreach($importData_arr as $importData){
    echo $importData['EAN'];
}

只要字段名称保持不变,您就不必在字段顺序或计数发生变化时更改导入代码。

【讨论】:

  • @Michael Aggerholm:我的初稿有一个错误,已修复!
  • 为什么我还需要定义偏移量“$importData_arr[0]”。这是一个非常好的解决方案,我添加了这个。一切似乎都很好,但我收到错误:未定义的偏移量:8。添加 10 列时。我已经仔细检查过,应该没有错,但它不会高于 7。有什么想法吗?
  • @Michael Aggerholm:我在第一个示例中跳过了 foreach,因此必须指定偏移量才能访问元素 - 请参阅我在代码中使用 foreach 循环的更新答案。
  • @Michael Aggerholm:要解决您的第二个问题,只需通过var_dump'in fgetcsv 开始逐行调试,您的CSV 文件中可能存在某种错误
【解决方案2】:

这里有一些简单的建议,如何将您的数据映射到具有给定键的数组。

while ($row = fgetcsv($fp, 100, ',')) {

      $columnName = ['a','b','c','d','e','f'];
      $myRow = array_combine($columnName,$row);
    ....
 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-24
    • 1970-01-01
    • 1970-01-01
    • 2017-02-05
    • 2017-07-22
    • 1970-01-01
    相关资源
    最近更新 更多