Laravel excel add complex headers to an export - laravel-5

I need to export a sheet with a complex heading via Laravel Excel. I need a main heading and another sub-level heading after.
I'm trying like this,
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
class InvoicesExport implements FromQuery, WithHeadings
{
public function headings(): array
{
return [
'Account 1' =>[
"Account 1 id",
"Account 1 branch"
],
'Account 2' =>[
"Account 2 id",
"Account 2 branch"
],
];
}
}
But getting header columns like, [ "Account 1 id", "Account 1 branch" ]
is there a way to archive this task?

Finally, I managed to do it. Adding it since it will be useful for someone else.
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithCustomStartCell;
use Maatwebsite\Excel\Events\AfterSheet;
use Maatwebsite\Excel\Concerns\WithEvents;
use \Maatwebsite\Excel\Sheet;
class InvoicesExport implements FromCollection, WithHeadings, WithCustomStartCell, WithEvents{
public function startCell(): string
{
return 'A2';
}
public function registerEvents(): array {
return [
AfterSheet::class => function(AfterSheet $event) {
/** #var Sheet $sheet */
$sheet = $event->sheet;
$sheet->mergeCells('A1:B1');
$sheet->setCellValue('A1', "Account 1");
$sheet->mergeCells('C1:D1');
$sheet->setCellValue('C1', "Account 2");
$styleArray = [
'alignment' => [
'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
],
];
$cellRange = 'A1:D1'; // All headers
$event->sheet->getDelegate()->getStyle($cellRange)->applyFromArray($styleArray);
},
];
}
public function headings(): array
{
return [
"Account 1 id",
"Account 1 branch"
"Account 2 id",
"Account 2 branch"
];
}
}
Here I added startCell() to start from second row. registerEvents() to merge and center align first row cells with content.

Related

How to insert Custom row Laravel excel collection

I trying to export a Excel file, from a collection using laravel. The code bellow, returns me this. I need to add a 2 new rows above the start of columsn, is that possible? What Should I do?
<?php
namespace App\Traits;
namespace App\Exports;
// use Illuminate\Support\Collection;
use Illuminate\Database\Eloquent\Collection;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithColumnWidths;
use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
use Maatwebsite\Excel\Concerns\WithCustomStartCell;
class exportSafety implements FromCollection, WithHeadings, WithMapping, WithColumnWidths, WithStyles, WithColumnFormatting, WithCustomStartCell
{
protected $services;
protected $request;
public function __construct(Collection $services)
{
$this->services = $services;
}
public function startCell(): string
{
return 'A3';
}
public function columnWidths(): array
{
return [
'A' => 30,
'B' => 20,
'C' => 20,
'D' => 15,
];
}
public function columnFormats(): array
{
return [
'B' => NumberFormat::FORMAT_DATE_DDMMYYYY,
];
}
public function styles(Worksheet $sheet)
{
return [
// Style the first row as bold text.
3 => ['font' => ['bold' => true]],
];
}
public function collection()
{
$this->services->each(function ($service) {
$this->map($service);
});
return $this->services;
}
public function headings(): array
{
$columns = [
'Name' => 'Name',
'Data de Nascimento' => 'Data de Nascimento',
'CPF' => 'CPF',
'Valor do Seguro' => "Valor do Seguro"
];
return $columns;
}
public function startRow(): int
{
return 2;
}
public function map($service): array
{
$columns = [
'Name' => $service->name,
'Data de Nascimento' => $service->birthdate,
'CPF' => $service->cpf,
'Valor do Seguro' => $service->client->donation_safety
];
return $columns;
}
}
But I need something like this:
I need to put two custom row above the start of the columns, is that possible? How I to that? I am using https://docs.laravel-excel.com/3.1/imports/multiple-sheets.html
you need to use WithHeadings trait to format heading rows.
$rangeHeadings = [
'chiqaruvchi',
'chiqarilgan',
'sotilgan',
"sana",
];
public function headings(): array
{
return [
[
$this->product?->name . " product " . $this->params['from_date'] . ' - ' . $this->params['to_date'] . " report",
],
$rangeHeadings,
];
}

array must be compatible with Maatwebsite\Excel\Concerns\WithMapping::map($row) in - Laravel

I am using Laravel-5.8 and Maatwebsite-3.1 to export to excel.
<?php
namespace App\Exports;
use App\User;
use Auth;
class StudentExport implements FromCollection, ShouldAutoSize, WithHeadings, WithMappings, WithCustomStartCell
{
private $headings = [
'Student ID',
'Name',
'Class',
'Status',
'Teacher'
];
public function collection()
{
$current_terms = DB::table('appraisal_identity')->select('term_name')->where('company_id', $userCompany)->where('is_current', 1)->first()->term_name;
$publishedgoals = AppraisalGoal::select('employee_code')->where('is_published', 1)->where('company_id', $userCompany)->groupBy('employee_code')->get();
$published_goals = DB::table('hr_students AS e')
->join('hr_employees AS em','em.id','=','e.teacher_id')
->select(
'e.student_id',
DB::raw('CONCAT(e.first_name, " ", e.last_name) AS full_name'),
'e.student_class,
DB::raw('(CASE WHEN e.is_status = 3 THEN "Excellent" WHEN e.is_status = 2 THEN "Good" WHEN e.is_status = 1 THEN "Average" ELSE "Pass" END) AS student_status')
DB::raw('CONCAT(em.first_name, " ", em.last_name) AS teacher_name')
)
->whereIn('e.student_id', $publishedgoals)
->distinct()
->get();
$published_goals = $published_goals->unique('student_id');
return collect($published_goals, $current_terms);
}
public function map($published_goals, $current_terms): array
{
return [
$published_goals->student_id,
$published_goals->full_name,
$published_goals->student_class,
$published_goals->student_status,
$published_goals->teacher_name,
$current_terms->term_name,
];
}
public function startCell(): string
{
return 'A4';
}
public function headings() : array
{
return $this->headings;
}
public function registerEvents() : array
{
return [
AfterSheet::class => function(AfterSheet $event) {
$event->sheet->setCellValue('A2', 'Current Term:');
$event->sheet->getDelegate()->setCellValue('B2', $current_terms);
$cellRange = 'A4:E4'; // All headers
$event->sheet->getDelegate()->getStyle($cellRange)->getFont()->setSize(14);
$event->sheet->getDelegate()->getStyle($cellRange)->getFont()->getColor()
->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_WHITE);
$event->sheet->getDelegate()->getStyle($cellRange)->getFill()
->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
->getStartColor()->setARGB('FF17a2b8');
$event->sheet->setAutoFilter($cellRange);
},
];
}
}
This is my expected output:
I have written the code above to get this result:
I want to make B2 to have the output of this variable: $current_terms
I got this error:
ERROR: Declaration of App\Exports\HrEmployeeGoalExport::map($published_goals, $current_terms): array must be compatible with Maatwebsite\Excel\Concerns\WithMapping::map($row)
How do I resolve this?
Thank you
Check the install docs for Laravel excel: https://docs.laravel-excel.com/3.1/getting-started/installation.html#installation
You probably need to run…
composer require psr/simple-cache:2.0 maatwebsite/excel
Enjoy !
You are implementing a number of the contracts from the Maatwebsite\Excel package, one of those contracts specifies that you must implement a map method that takes a $row as the argument; Maatwebsite\Excel\Concerns\WithMapping::map($row).
In your class you have HrEmployeeGoalExport::map($published_goals, $current_terms): array
To get this to work, you must change your map function to be HrEmployeeGoalExport::map($row) and then use $row to do any mapping.'
As such, you need to change the arguments you are receiving and remove the return type that you have specified.

laravel - change value in array for API Resources

{
"data": {
"username": "candy",
"certificates": [
{
"id": 11,
"category_id": 1,
"certname": "cert name test",
"created_at": "2018-08-18 00:58:12",
"updated_at": "2018-08-18 00:58:12"
}
]
}
}
Above is a response by using Eloquent: API Resources.
I would like to put category name instead of category_id.
Below is resource class
public function toArray($request)
{
return [
'nickname' => $this->nickname,
'certificates' => $this->certificates,
];
}
certificates are in array (hasMany relationship)
certificates belongsTo category
In this case, in the resource class you can fetch category name for each certificate and attach it.
public function toArray($request)
{
$certificateList = $this->certificates;
foreach($certificateList as $ceritificate) {
// fetch only the category name from the database.
// attach to the certificate.
$categoryName = Category::where('id', $certificate->category_id)->pluck('name')->first();
$certificate->setAttribute('category_name, $categoryName);
}
// then as usual
return [
'nick_name' => $this->nick_name,
'certificates' => $certificateList
];
}
This Might Help,
Run a foreach loop
$category = "Your SELECT Query";
foreach ($category as $value) {
$categoryId = json_decode($value->category_id);
$x = Category::select('certname')->whereIn('id', $categoryId)->get();
foreach ($x as $as) {
$y[] = $as->certname;
}
$value->certname = $y;
you can just do it like this
in controler
return CertificateResource::collection(Certificate::with('category')->get());
in CertificateResource
return [
'nickname' => $this->nickname,
'certificates' => $this->certificates,
'category_name'=>$this->whenLoaded('category', function () {
return $this->category->category_name;
}),
];

laravel resource collection has blank output

I am trying to get a json output of a collection but all I am getting is a data [].
I have 2 tables.
TABLE:Player ||
id |
name
and
TABLE:FlightTime || id | vehicle | totaltime | player_id (foreign key)
I am trying to get all the flighttime entry for a particular player as a collection.
My FlightTime resource:
class FlightTime extends JsonResource
{
public function toArray($request)
{
return [
'vehicle' => $this->vehicle,
'total-time' => $this->totaltime,
];
}
}
And my FlightTimeCollection:
class FlightTimeCollection extends ResourceCollection
{
public function toArray($request)
{
return [
'data' => $this->collection,
'test' => 'did this work',
];
}
}
My api route is set as
Route::get('/v1/player/{name}/flights', 'PlayerController#showFlightbyName');
And I have this in my controller:
public function showFlightbyName($name)
{
$pid = Player::select('id')->where('name', $name)->first();
return new FlightTimeCollection(FlightTime::where('player_id', $pid)->get());
}
Now when I visit localhost/api/v1/player/Angel/flights, No error is thrown. But all I am getting is this.
{
"data": [],
"test": "did this work"
}
I just can't figure out what's going on here and what I did wrong.
You should treat the toArray() method in your FliightTimeCollection the same way you treat it in FlightTimeResource. The collection will be automatically wrapped in data => [stuff]'.
So, like this:
class FlightTimeCollection extends ResourceCollection
{
public function toArray($request)
{
return [
'vehicle' => $this->vehicle,
'another_field' => $this->field2,
// ...
];
}
}
Result of that would be
{
"data": [
{"vehicle": "some value", "another_field": "some value"},
// ...
],
}
I got it working. $pid is an obj and I needed to get the value out of $pid->id
public function showFlightbyName($name)
{
$pid = Player::select('id')->where('name', $name)->first();
return new FlightTimeCollection(FlightTime::where('player_id', $pid->id)->get());
}

Yii2- get from related table name to add to Sluggable

Yii2. How can i get data from the related table and add it to Sluggable behavior.
In the example below, I want for every book add slug-title like "Book House, author Greenberg".
class Books extends \yii\db\ActiveRecord
{
public function behaviors()
{
return [
[
'class' => SluggableBehavior::className(),
'attribute' => "Book" . $this->name . ", author " . $this->getAuthor->name,
//'slugAttribute' => 'slug',
],
];
}
public function getAuthor()
{
return $this->hasOne(Author::className(), ['id' => 'author_id']);
}
}
Simply use a callback for the sluggable behavior like so:
public function behaviors()
{
return [
[
'class'=>SluggableBehavior::className(),
'value'=>function ($event) {
$parts = ['Book', $this->name, 'author', $this->author->name];
return Inflector::slug(implode('-', $parts));
},
],
];
}
My example will output a slug like this: book-house-author-greenberg which is more best practice for slugs than your version. Anyway...if you still prefer the way you described above, simply change the return value.
The doc for the feature used in my example is here.

Resources