add custom column to laravel excel
Asked Answered
S

4

6

I am using maatwebsite/excel, I want to know if it's possible to add custom column when I export my data as CSV or not?

Explanation

I am successfully exporting my products data, but my products have other option which is not stored in my products table such as: specification.

my specifications are stored in 2 different tables named specifications where is parent like CPU and subscpecifications where child's are stored like: Core i5.

another table i am using to store child's id and products id in order to relate each product to their subspecifications.

Sounds Complecated right? :) here i provide ugly map to get the logic :)

screen 1

Now, What I try to do is:

Add extra column to my csv file and include all specifications of each product.

sample:

sample

Codes

here is my current export function

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();
    }

Questions

  1. Is that possible?
  2. If yes, Base on my function above, how do I do it?

Thanks in advance.

UPDATE 1

I have added this code to my function

$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);

and changed this line:

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

to

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

now here is what I have:

screen3

here is my full function currently:

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();
    }

UPDATE 2

Well tonight I've played with my codes a lot and FINALLY :) I got what I needed, here is how:

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

This will give me my products specifications, however there is 3 little issues:

  1. I do not have heading for my specifications in CSV file
  2. Products without specification shows [] instead of nothing
  3. products with specification also covers them with [] and ""

Here I provided screenshot for better understanding:

screen5

Sello answered 13/4, 2018 at 5:34 Comment(4)
It should be possible. So you have your specification relationships setup, what column from the specifications did you want to use in the column?Courtnay
@Courtnay title column.Sello
anyone with knowledge? :/Sello
can anyone help in answering this #50036991Evelinaeveline
W
3

You need to prepare custom column Specifications by looping through products. Here is your fix,

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();
}

Update

As per your sheet image I can assume you have only three columns Id, Title and Specifications, you can change header array according to the columns you are getting from DB.

Wynellwynn answered 20/4, 2018 at 10:43 Comment(21)
i get Undefined offset: 0 on $sheet->fromArray($products, null, 'A1', false, false);Sello
Can you please dd($products) ?Wynellwynn
i assume specifications must add to each product and not end of my collection right?Sello
I have updated the code above please run now and let me know.Wynellwynn
preg_match() expects parameter 2 to be string, array givenSello
OK, I took some screenshots for you to see what exactly happened: 1 ibb.co/daZ4KH 2 ibb.co/cwDyeHSello
still getting preg_match() expects parameter 2 to be string, array givenSello
bro are you there? any idea?Sello
can you please do echo "<pre>"; print_r($products); so that I can understand better ?Wynellwynn
in which part i add that pre ?Sello
before this line $sheet->fromArray($products, null, 'A1', false, false); add the above statements.Wynellwynn
the result become so messy! something between white page and laravel black error page, really can't get anything out of it.Sello
ok bro i just acted fast before my view broke i got copy the codes here i shared php file including what i could copy from your pre code ufile.io/oyq42Sello
Bro I got my specifications, please see my update. thanks.Sello
Updated answer please try now.Wynellwynn
hi bro, o answer your update i have to say: no, i have more than id,title,specification (i can have all my table columns) so i really can't use header part and $mergedProducts = array_merge($headers, $products); you provided, But except headers and merge part, your function works perfectly just no have heading ibb.co/i3amOcSello
what if, we use their parents as heading? currently we are getting subspecifications like core i7 what if we get specifications as heading like cpu (as heading) and core i7 (as data of it) ?Sello
Then you have to define all you db columns in header plus custom specifications column at the last.Wynellwynn
i do have all my columns as header i just have ability to filter them so i can only get id and title or all of them, but for specification matter if you see my first update (no.1) in there i have both specifications and subspecifications in header that time i did it like foreach($specs as $spec){ $data[] = $spec->specification->title; $data[] = $spec->title; } now we need the same approach but different $data_name for sub and specs to define which one goes where.Sello
Disucssing is getting long, your main issue is solved, closed it and start another one if you have other queries thanksWynellwynn
is the same query bro "need header for results i'm getting", if you no longer able to help i understand and appreciate all your helpsSello
B
0

Yes its possible. create array for row ie. data = array(); push cell data to array

you can fetch relation data using eloquent or join as well, here I am fetching inside loop.

Updated Function as below:

I tried to match with your data structure

  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();
}
Bamboozle answered 13/4, 2018 at 6:35 Comment(3)
sorry for very late answer bro, but this doesn't works. there is some issues in you code that concern me: 1 where is this coming from? $allRows = array(); . 2 my products are already looped i don't need to use this foreach($products as $product), 3 this does not provide true relation $specs = Spec::where('product_id', $product->id)->get();Sello
I have shared update in my question please check it. PS for this part i still have problem $data[] = $product->field1; as my columns coming by selection $getCustomInput[$key] = $input['customname'][$key]; i cannot use static method as you shared in your answer is there other way to achieve that? as you see my csv is empty because of that. THANK YOU.Sello
thanks bro, here is issues with your method: 1 as i said before, i cannot have my products table data statically like $data[] = product->id; why? because i'm using filter on my columns by foreach ($input['cb'] as $key => $value) { that's why i have $sheet->row(1, $getCustomInput);. 2 your recent code shows all products in row 2 except shows each product detail in one row 3 i get : between tags except , .Sello
P
0
  1. I do not have heading for my specifications in CSV file

To solve the issue, you can define header and use use array_merge(). For I.E.

$headers[] = [
                'Title',
                'Specifications',
            ];
$products= array_merge($headers, $products);
  1. Products without specification shows [] instead of nothing
  2. products with specification also covers them with [] and ""

For 2nd and 3rd point you can use implode() to get rid of []

$product['specifications'] = implode(',', $specifications);

Hope this helps

Pinard answered 26/4, 2018 at 7:31 Comment(1)
thanks for answer, those problems are solved, the only last issue is my specifications header and why your answer won't work here i explained it #49810445 please see if you can help with that.Sello
S
0

It works for me. very simple

// 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');
Sean answered 19/10, 2018 at 7:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.