为Laravel Excel添加自定义列

6
我正在使用maatwebsite/excel,我想知道在导出CSV时是否可以添加自定义列?

说明

我已成功导出我的产品数据,但我的产品有其他选项,这些选项未存储在我的产品表中,例如:规格

我的规格存储在两个不同的表中,名为规格,其中父级如CPU,而子规格则存储了像Core i5这样的子级。

我正在使用另一个表来存储子级ID和产品ID,以便将每个产品与其子规格相关联。

听起来很复杂吧? :) 这里提供了一个难看的地图来获取逻辑 :)

screen 1

现在,我要做的是:

向我的csv文件添加额外的列,并包括每个产品的所有规格。

示例:

sample

代码

这是我的当前导出函数

public function export(Request $request) {
      $input = $request->except('_token');
      foreach ($input['cb'] as $key => $value) {
        if ($value== 'on') {
          $getRealInput[$key] = $input['defaultname'][$key];
        }
      }

      $products = Product::select($getRealInput)->get();


      Excel::create('products', function($excel) use($products, $request) {
        $excel->sheet('sheet 1', function($sheet) use($products, $request){

          $input = $request->except('_token');
          foreach ($input['cb'] as $key => $value) {
            if ($value== 'on') {
              $getCustomInput[$key] = $input['customname'][$key];
            }
          }

          $sheet->fromArray($products, null, 'A1', false, false);
          $sheet->row(1, $getCustomInput);
        });
      })->export('csv');
      return redirect()->back();
    }

问题

  1. 这是否可能?
  2. 如果是的话,基于我上面的函数,我该如何做?

提前感谢。

更新 1

我已经将此代码添加到我的函数中。

$allRows = array();
  $data = array();
  foreach($products as $product){
  $specs = $product->subspecifications;
  foreach($specs as $spec){
    $data[] = $spec->specification->title;
    $data[] = $spec->title;
  }
}
array_push($allRows , $data);

并修改了这行代码:

$sheet->fromArray($products, null, 'A1', false, false);

to

$sheet->fromArray($allRows, null, 'A1', false, false);

现在我有这个:

screen3

这是我目前的完整函数:

public function export(Request $request) {
      $input = $request->except('_token');
      foreach ($input['cb'] as $key => $value) {
        if ($value== 'on') {
          $getRealInput[$key] = $input['defaultname'][$key];
        }
      }

      $products = Product::select($getRealInput)->get();


      Excel::create('products', function($excel) use($products, $request) {
        $excel->sheet('sheet 1', function($sheet) use($products, $request){

          $input = $request->except('_token');
          foreach ($input['cb'] as $key => $value) {
            if ($value== 'on') {
              $getCustomInput[$key] = $input['customname'][$key];
            }
          }


          // test code of adding subspacifications
          $allRows = array();
          $data = array();
          foreach($products as $product){
              $specs = $product->subspecifications;
              foreach($specs as $spec){
                    $data[] = $spec->specification->title;
                    $data[] = $spec->title;
              }
          }
          array_push($allRows , $data);
          $sheet->fromArray($allRows, null, 'A1', false, false);
          //
          // $sheet->fromArray($products, null, 'A1', false, false);
          $sheet->row(1, $getCustomInput);
        });
      })->export('csv');
      return redirect()->back();
    }

更新 2

今晚我经过多次尝试,终于成功了 :) 我得到了所需的结果,以下是过程:

//codes...

// Here is you custom columnn logic goes
          foreach($products as $product){
            $specifications = DB::table('products')
            ->where('products.id', $product->id)
            ->join('product_subspecification', 'product_subspecification.product_id', '=', 'products.id')
            ->join('subspecifications', 'subspecifications.id', '=', 'product_subspecification.subspecification_id')
            ->select('subspecifications.title')
            ->pluck('title');

            $product['specifications'] = rtrim($specifications,',');
          }
          //


          $sheet->fromArray($products, null, 'A1', false, false);
          $sheet->row(1, $getCustomInput);

//... rest of the codes
这将给出我的产品规格,但有三个小问题:
  1. 我没有CSV文件中的规格标题
  2. 没有规格的产品显示为[]而不是无
  3. 带规格的产品也被包含在[]""
这里提供了截图以更好地理解:

screen5


应该是可以的。所以你已经设置好了规范关系,你想在哪一列中使用规范中的列? - CUGreen
@CUGreen 标题列。 - mafortis
有人了解吗?:/ - mafortis
有人能帮忙回答这个问题吗?https://stackoverflow.com/questions/50036491/impossible-4-columns-permutation-with-limit-of-11-in-vba-excel - G. Nicky
4个回答

3

您需要通过循环产品来准备自定义列规格。以下是您的解决方案,

public function export(Request $request) {

  $headers[] = [
                'Id',
                'Title',
                'Specifications',
            ];


  $input = $request->except('_token');
  foreach ($input['cb'] as $key => $value) {
    if ($value== 'on') {
      $getRealInput[$key] = $input['defaultname'][$key];
    }
  }

  $products = Product::select($getRealInput)->with('subspecifications')->get()->toArray();

  Excel::create('products', function($excel) use($headers,$products, $request) {
    $excel->sheet('sheet 1', function($sheet) use($headers,$products, $request){

      $input = $request->except('_token');
      foreach ($input['cb'] as $key => $value) {
        if ($value== 'on') {
          $getCustomInput[$key] = $input['customname'][$key];
        }
      }
      // Here is you custom columnn logic goes
          foreach($products as $product){
            $specs = "";
            $specifications = DB::table('products')
            ->where('products.id', $product->id)
            ->join('product_subspecification', 'product_subspecification.product_id', '=', 'products.id')
            ->join('subspecifications', 'subspecifications.id', '=', 'product_subspecification.subspecification_id')
            ->select('subspecifications.title')
            ->pluck('title');
            foreach($specifications as $spec){
              $specs = $specs .','.$spec;
            }
            $product['specifications'] = ltrim($specs,',');
          }
          //
      $mergedProducts = array_merge($headers, $products);
      $sheet->fromArray($mergedProducts, null, 'A1', false, false);
      $sheet->row(1, $getCustomInput);
    });
  })->export('csv');
  return redirect()->back();
}

更新

根据您提供的表格图像,我可以推断出您只有三列:Id、Title和Specifications。您可以根据从数据库中获取的列更改标题数组。


我在 $sheet->fromArray($products, null, 'A1', false, false); 上遇到了 Undefined offset: 0 的错误。 - mafortis
您能请执行 dd($products) 吗? - Faraz Irfan
我认为“规格说明”应该添加到每个产品而不是我的集合末尾,对吗? - mafortis
preg_match() expects parameter 2 to be string, array given - mafortis
1
兄弟,你在吗?有什么想法吗? - mafortis
显示剩余16条评论

0
  1. 我的CSV文件规范中没有标题

为了解决这个问题,您可以定义标题并使用array_merge()。例如:

$headers[] = [
                'Title',
                'Specifications',
            ];
$products= array_merge($headers, $products);
  1. 没有规格的产品显示 [] 而不是空白
  2. 有规格的产品也用 [] 和 "" 包含它们

对于第二和第三点,您可以使用 implode() 来去掉 []

$product['specifications'] = implode(',', $specifications);
希望这能有所帮助。

谢谢您的回答,那些问题已经解决了,唯一的最后一个问题是我的规范头文件以及为什么您的答案在这里不起作用,我在这里解释了 https://dev59.com/F6rka4cB1Zd3GeqPf5Zs#B74ioYgBc1ULPQZFR9cA 请看看您是否能够帮助解决。 - mafortis

0

是的,这是可能的。 为行创建数组,例如: data = array(); 将单元格数据推入数组

您也可以使用 Eloquent 或 Join 提取关联数据,在此我在循环内提取。

以下是更新的函数:

我尝试与您的数据结构匹配。

  public function export(Request $request) {
  $input = $request->except('_token');
  foreach ($input['cb'] as $key => $value) {
    if ($value== 'on') {
      $getRealInput[$key] = $input['defaultname'][$key];
    }
  }

  $products = Product::select($getRealInput)->get();


  Excel::create('products', function($excel) use($products, $request) {
    $excel->sheet('sheet 1', function($sheet) use($products, $request){


      // test code of adding subspacifications
      $allRows = array();
      array_push($allRows , ['id', 'title', 'specifications']); // Added title row
      $data = array();
      foreach($products as $product){
          $data[] = $product->id;    // Added product fields 
          $data[] = $product->title;
          $specs = $product->subspecifications;
          $spec_details = "";
          foreach($specs as $spec){                    
                $spec_details .= $spec->specification->title.':'. $spec->title. ' '; // appended specification:subspecification 
          }
          $data[] = $spec_details;
      }
      array_push($allRows , $data);
      $sheet->fromArray($allRows, null, 'A1', false, false);
      //
      // $sheet->fromArray($products, null, 'A1', false, false);
      //$sheet->row(1, $getCustomInput);   // commented
    });
  })->export('csv');
  return redirect()->back();
}

抱歉回复晚了,但这个不起作用。你的代码有一些问题让我担心:1 这是从哪里来的? $allRows = array();2 我的产品已经循环了,我不需要使用这个 foreach($products as $product)3 这并没有提供真正的关系 $specs = Spec::where('product_id', $product->id)->get(); - mafortis
我在我的问题中分享了更新,请检查一下。对于这部分,我仍然有问题$data[] = $product->field1;,因为我的列是通过选择来的$getCustomInput[$key] = $input['customname'][$key];,我不能像你在答案中分享的那样使用静态方法,有其他方法可以实现吗?正如您所看到的,我的CSV文件是空的,因为这个问题。谢谢。 - mafortis
谢谢兄弟,你的方法有问题:1正如我之前所说,我不能像$data[] = product->id;那样静态地获取我的产品表数据,为什么?因为我正在使用foreach ($input['cb'] as $key => $value) {对我的列进行过滤,这就是为什么我有$sheet->row(1, $getCustomInput);2你最近的代码在第二行显示所有产品,除了在一行中显示每个产品的详细信息3我在标签之间得到:而不是, - mafortis

0

对我来说很有效。非常简单

// Headings//
$headers[] = ['Id', 'Name'];

// 2 Rows //
$data[0] = ['1', 'John'];
$data[1] = ['2', 'Roger'];

Excel::create('report', function($excel) use($headers, $data) {

    $excel->sheet('sheet 1', function($sheet) use($headers, $data){
        $merged_records = array_merge($headers, $data);
        $sheet->fromArray($merged_records, null, 'A1', false, false);
    });
})->export('csv');

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,