How to simplify this Laravel resource? - laravel

I use Laravel 7.
I build some apis in which the "GET" result depends on the request. For example
/schools?fields=name,id,school_type_id
means "give me all the schools, but only the name + id + school_type_id".
/schools?
means "give me all the schools, all the columns".
To do that I am using a resource :
class SchoolResource extends JsonResource
{
public function toArray($request)
{
$fields = $request->has('fields') ? explode(',', $request->fields) : [];
return [
'id' => $this->when(0 === \count($fields) || \in_array('id', $fields, true), $this->id),
'name' => $this->when(0 === \count($fields) || \in_array('name', $fields, true), $this->name),
.......
]
It works fine, but I think it is complicated (and also not "elegant"). Is it possible to simplify that?

use Illuminate\Support\Arr;
class SchoolResource extends JsonResource
{
public function toArray($request)
{
$fields = $request->has('fields') ? explode(',', $request->fields) : [];
return Arr::only($this->resource->toArray(), $fields);
}
}

Related

Unsupported operand types: array + App\StockOut Laravel

I wanna ask why I my query isn't work when I try in another case, I have query like this :
$getData = StockOut::select("*",
StockOut::raw('group_concat(stock_outs.id_stock_out) as id_stock_outs'),
)
->with(['stock_ins' => function ($query) {
$query->select('id_stock_in', 'stock_in_id_type')
->with(['type_of_items' => function ($query) {
$query->select('id_type_item', 'type_id_item', 'code_type_of_item', 'type_of_item');
}]);
}])
->groupBy('stock_outs.stock_out_id_stock_in')
->get()
->groupBy('stock_ins.stock_in_id_type')->map(function ($group) {
return [
'id_stock_ins' => $group->pluck('stock_ins.id_stock_in')->join(','),
'id_stock_outs' => $group->pluck('id_stock_outs')->join(',')
] + $group->first();
})->values();
I have error like this :
message: "Unsupported operand types: array + App\StockOut"
In StockOut model :
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class StockOut extends Model
{
protected $primaryKey = "id_stock_out";
protected $fillable = [
'stock_out_id_location', 'stock_out_id_stock_in', 'date_of_stock_out', 'quantity', 'description', 'created_by', 'edited_by'
];
public function locations()
{
return $this->belongsTo('App\Location', 'stock_out_id_location');
}
public function stock_ins()
{
return $this->belongsTo('App\StockIn', 'stock_out_id_stock_in');
}
}
I really don't understand about my error now, because when I try my query in another project is working and nothing error happened, I hope someone can help me to guide me solve my problem, Thank you before.
Check value on $group. It must be of type array in order for + operator to work.
Currently you might be doing
[/* ... */] + <an eloquent model>
which will give you that error

Laravel / OctoberCMS frontend filter

I am using OctoberCMS and I have created a custom component. I am trying to create a frontend filter to filter Packages by the Tour they are assigned to.
This is what I have so far. The issue is that the code is looking for a tour field within the packages table rather than using the tour relationship. Does anyone have any ideas?
<?php namespace Jakefeeley\Sghsportingevents\Components;
use Cms\Classes\ComponentBase;
use JakeFeeley\SghSportingEvents\Models\Package;
use Illuminate\Support\Facades\Input;
class FilterPackages extends ComponentBase
{
public function componentDetails()
{
return [
'name' => 'Filter Packages',
'description' => 'Displays filters for packages'
];
}
public function onRun() {
$this->packages = $this->filterPackages();
}
protected function filterPackages() {
$tour = Input::get('tour');
$query = Package::all();
if($tour){
$query = Package::where('tour', '=', $tour)->get();
}
return $query;
}
public $packages;
}
I really appreciate any help you can provide.
Try to query the relationship when the filter input is provided.
This is one way to do it;
public $packages;
protected $tourCode;
public function init()
{
$this->tourCode = trim(post('tour', '')); // or input()
$this->packages = $this->loadPackages();
}
private function loadPackages()
{
$query = PackagesModel::query();
// Run your query only when the input 'tour' is present.
// This assumes the 'tours' db table has a column named 'code'
$query->when(!empty($this->tourCode), function ($q){
return $q->whereHas('tour', function ($qq) {
$qq->whereCode($this->tourCode);
});
});
return $query->get();
}
If you need to support pagination, sorting and any additional filters you can just add their properties like above. e.g;
protected $sortOrder;
public function defineProperties(): array
{
return [
'sortOrder' => [
'title' => 'Sort by',
'type' => 'dropdown',
'default' => 'id asc',
'options' => [...], // allowed sorting options
],
];
}
public function init()
{
$filters = (array) post();
$this->tourCode = isset($filters['tour']) ? trim($filters['tour']) : '';
$this->sortOrder = isset($filters['sortOrder']) ? $filters['sortOrder'] : $this->property('sortOrder');
$this->packages = $this->loadPackages();
}
If you have a more complex situation like ajax filter forms or dynamic partials then you can organize it in a way to load the records on demand vs on every request.e.g;
public function onRun()
{
$this->packages = $this->loadPackages();
}
public function onFilter()
{
if (request()->ajax()) {
try {
return [
"#target-container" => $this->renderPartial("#packages",
[
'packages' => $this->loadPackages()
]
),
];
} catch (Exception $ex) {
throw $ex;
}
}
return false;
}
// call component-name::onFilter from your partials..
You are looking for the whereHas method. You can find about here in the docs. I am not sure what your input is getting. This will also return a collection and not singular record. Use ->first() instead of ->get() if you are only expecting one result.
$package = Package::whereHas('tour', function ($query) {
$query->where('id', $tour);
})->get();

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.

How to manipulate data before exporting in laravel 5.7 and excel 3.1

I want to customize column names, concatinate data in one column. Can put some condition on data.
Below is sample image, In which format data would show. How to make possible this-
Here you can find how to manipulate columns names:
https://laravel-excel.maatwebsite.nl/3.1/exports/mapping.html
And below its a example from my project in how to use it. Enjoy!
namespace App\Exports;
use App\Aluno;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithStrictNullComparison;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
class AlunosExport implements FromCollection, WithStrictNullComparison, WithHeadings, ShouldAutoSize
{
/**
* #return \Illuminate\Support\Collection
*/
public function collection()
{
$alunos = Aluno::all();
$dadosAluno = [];
foreach ($alunos as $aluno) {
$textoEtapas = '';
foreach ($aluno->etapas as $etapa) {
$textoEtapas .= "{$etapa->nome}";
if ($etapa->concluido) {
$textoEtapas .= ' (Concluído)';
}
$textoEtapas .= "\n";
}
$dadosAluno[] = [
'nome' => $aluno->cliente->nome,
'telefone' => formatarTelefone($aluno->cliente->telefone),
'instituicao' => $aluno->cliente->turma->unidade->instituicao->nome,
'turma' => $aluno->cliente->turma->nome,
'programa' => $aluno->programa->nome,
'etapas' => $textoEtapas,
'valor' => $aluno->valor,
'orientador' => !is_null($aluno->orientador) ? $aluno->orientador->nome : '(Excluído)',
'status' => $aluno->cliente->status
];
}
$alunoColection = collect($dadosAluno);
return $alunoColection;
}
public function headings(): array
{
return [
'Aluno',
'Telefone',
'Instituição',
'Turma',
'Programa',
'Etapas',
'Valor',
'Orientador',
'Status'
];
}
}

Laravel Dingo nested transformers

I'm trying to get one to many relationship objects with transformers. I want to get include metas but i only get just regular transform fields.
my transformer:
class AssistantTransformer extends TransformerAbstract
{
protected $availableIncludes = [
'assistantmetas'
];
public function transform(User $user)
{
return [
'id' => (int) $user->id,
'firstname' => ucfirst($user->first_name),
'lastname' => ucfirst($user->last_name),
];
}
public function includeMetas(User $user)
{
$assistantmetas = $user->userMetas;
return $this->item($assistantmetas, new AssistantsMetaTransformer);
}
}
Just use defaultIncludes not available includes, because it needs to send request via url? include=assistantmetas to get result like this.

Resources