I just want to make the row of datas will rendered after headings
This's the result that i want
this what i want
But i only get this result
this i get
I already using startRow and set to 7, but nothing change
I have 6 row of heading, so how to render/display the data after headings, and i already return another collection with another model, but the result is same there's nothing change, the data keep displayed from first row
<?php
namespace App\Exports;
Importing Models...
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithColumnWidths;
use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\AfterSheet;
use Maatwebsite\Excel\Concerns\WithEvents;
class TahapSeleksiExport implements FromCollection, WithHeadings, WithColumnWidths, WithStyles, WithEvents
{
use RegistersEventListeners;
protected $id;
function __construct($id) {
$this->id = $id;
}
/**
* #return \Illuminate\Support\Collection
*/
public function collection()
{
$tahap = Tahap::where('id_tahap', $this->id)->first();
if ($tahap->status == '0') {
if ($tahap->tahap_ke == '1') {
return Pelamar::select('pelamar.id_pelamar', 'alm.nama', 'jur.akronim', 'ang.angkatan', 'pelamar.tanggal_kirim')
->where('lowongankerja_id', $tahap->lowongankerja_id)
->join('alumni_mendaftar_pelamar as almPel', 'almPel.pelamar_id', '=','pelamar.id_pelamar')
->join('alumni as alm', 'almPel.alumni_id', '=','alm.id_alumni')
->join('jurusan as jur', 'alm.jurusan_id', '=','jur.id_jurusan')
->join('angkatan as ang', 'alm.angkatan_id', '=','ang.id_angkatan')
->orderBy('pelamar.tanggal_kirim')
->orderBy('jur.akronim')
->orderBy('ang.angkatan', 'DESC')
->get();
}else{
return SeleksiPelamar::select('pelamar.id_pelamar', 'alm.nama', 'jur.akronim', 'ang.angkatan', 'pelamar.tanggal_kirim')
->where('lowongankerja_id', $tahap->lowongankerja_id)
->join('pelamar', 'pelamar.id_pelamar', '=','seleksi_pelamar.pelamar_id')
->join('alumni_mendaftar_pelamar as almPel', 'almPel.pelamar_id', '=','pelamar.id_pelamar')
->join('alumni as alm', 'almPel.alumni_id', '=','alm.id_alumni')
->join('jurusan as jur', 'alm.jurusan_id', '=','jur.id_jurusan')
->join('angkatan as ang', 'alm.angkatan_id', '=','ang.id_angkatan')
->orderBy('pelamar.tanggal_kirim')
->orderBy('jur.akronim')
->orderBy('ang.angkatan', 'DESC')
->where('keterangan', '1')->whereHas('tahap', function ($tahaps) use ($tahap) {
$tahaps->where('lowongankerja_id', $tahap->lowongankerja_id)->where('tahap_ke', $tahap->tahap_ke - 1);
})->get();
}
}
}
public function columnWidths(): array
{
return [
'A' => 15,
'B' => 40,
'C' => 15,
'D' => 15,
'E' => 25,
'F' => 12,
];
}
public function styles(Worksheet $sheet)
{
$sheet->getStyle(2)->getFont()->setBold(true);
$sheet->mergeCells('A2:G2');
$sheet->mergeCells('A3:G3');
$sheet->mergeCells('A4:G4');
}
public static function afterSheet(AfterSheet $event)
{
$sheet = $event->sheet->getDelegate();
$sheet->getStyle(2)->getFont()->setSize(16);
$sheet->getStyle(3)->getFont()->setSize(14);
$sheet->getStyle(4)->getFont()->setSize(14);
$sheet->getStyle('A6:G6')->getFont()
->setBold(true)
->getColor()->setRGB('ffffff');
$sheet->getStyle('A6:G6')->getFill()
->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
->getStartColor()->setARGB('2041BB');
}
public function headings():array
{
$tahap = Tahap::where('id_tahap', $this->id)->first();
return [ // PER ROW HEADINGNYA
[], [$tahap->nama], ['Seleksi Alumni'], ['BKK SMKN 1 Kota Bekasi'],[],[
'ID Pelamar',
'Nama',
'Jurusan',
'Angkatan',
'Tanggal Submit',
'Nilai',
'Lulus',
]
];
}
}
The easy solution is to add an empty array of data to the collection. The solution is not idle but I think it can works. Try this:
public function collection()
{
$tahap = Tahap::where('id_tahap', $this->id)->first();
$PelamarData = new Collection();
if ($tahap->status == '0') {
if ($tahap->tahap_ke == '1') {
$PelamarData = Pelamar::select('pelamar.id_pelamar', 'alm.nama', 'jur.akronim', 'ang.angkatan', 'pelamar.tanggal_kirim')
->where('lowongankerja_id', $tahap->lowongankerja_id)
->join('alumni_mendaftar_pelamar as almPel', 'almPel.pelamar_id', '=','pelamar.id_pelamar')
->join('alumni as alm', 'almPel.alumni_id', '=','alm.id_alumni')
->join('jurusan as jur', 'alm.jurusan_id', '=','jur.id_jurusan')
->join('angkatan as ang', 'alm.angkatan_id', '=','ang.id_angkatan')
->orderBy('pelamar.tanggal_kirim')
->orderBy('jur.akronim')
->orderBy('ang.angkatan', 'DESC')
->get();
}else{
$PelamarData = SeleksiPelamar::select('pelamar.id_pelamar', 'alm.nama', 'jur.akronim', 'ang.angkatan', 'pelamar.tanggal_kirim')
->where('lowongankerja_id', $tahap->lowongankerja_id)
->join('pelamar', 'pelamar.id_pelamar', '=','seleksi_pelamar.pelamar_id')
->join('alumni_mendaftar_pelamar as almPel', 'almPel.pelamar_id', '=','pelamar.id_pelamar')
->join('alumni as alm', 'almPel.alumni_id', '=','alm.id_alumni')
->join('jurusan as jur', 'alm.jurusan_id', '=','jur.id_jurusan')
->join('angkatan as ang', 'alm.angkatan_id', '=','ang.id_angkatan')
->orderBy('pelamar.tanggal_kirim')
->orderBy('jur.akronim')
->orderBy('ang.angkatan', 'DESC')
->where('keterangan', '1')->whereHas('tahap', function ($tahaps) use ($tahap) {
$tahaps->where('lowongankerja_id', $tahap->lowongankerja_id)->where('tahap_ke', $tahap->tahap_ke - 1);
})->get();
}
//Add empty array data to skip the first 7 rows
foreach (range(1, 7) as $item)
{
$PelamarData->prepend([]);
}
return $PelamarData;
}
}
So I am making a Businesses web app with the filters feature. There are two filters that I have problem with: Order By and Attributes(Has following attributes) features. Which looks like this:
Order By
Highest Rated (radio button)
Most reviews (radio button)
Attributes
Accepts Credit Cards (checkbox)
Accepts Events (checkbox)
Alcohol (checkbox)
Delivery (checkbox)
Smoking (checkbox)
So when Order By option is clicked this function is executed. Where $term is value of order_by get request parameter.
BusinessFilter.php
public function orderby($term)
{
if ($term == 'reviews_count') {
return $this->builder
->leftJoin('reviews', 'businesses.id', '=', 'reviews.business_id')
->groupBy('businesses.id')
->selectRaw('businesses.*, COUNT(reviews.id) as reviews_count')
->orderByDesc('reviews_count');
} else if ($term == 'rating') {
return $this->builder
->leftJoin('reviews', 'businesses.id', '=', 'reviews.business_id')
->groupBy('businesses.id')
->selectRaw('businesses.*, AVG(reviews.rating) AS average')
->orderByDesc('average');
} else {
return $this->builder;
}
}
It works ok and the result is correct.
Now when Attribute have some check boxes this function is executed where $term is an array with set of ids.
BusinessFilter.php
public function attributes($term)
{
$attributes= json_decode($term);
if (count($attributes) == 0) {
return $this->builder;
}
return $this->builder
->select('businesses.*')
->join('business_attribute_value', 'businesses.id', '=', 'business_attribute_value.business_id')
->join('values', 'business_attribute_value.attribute_value_id', '=', 'values.id')
->whereIn('values.id', $attributes)
->groupBy('businesses.id')
->havingRaw('COUNT(*) = ?', [count($attributes)]);
}
the result is correct here too.
Now the problem is when both filters have values it executes both queries together and It doesn't return the correct result. I assume it has something to do with joins. Am I doing something wrong? Please help. And if you need more info or code please let me know. Thank you, you are the best guys!
This is how I execute filters
public function getSearch(BusinessFilter $filters)
{
$businesses = Business::filter($filters)->paginate(30);
return $businesses;
}
This is QueryFilter class. Basically what it does is that it goes through each request parameter and executes its function that was mentioned above.
class QueryFilters{
protected $request;
protected $builder;
public function __construct( Request $request )
{
$this->request = $request;
}
public function apply(Builder $builder)
{
$this->builder = $builder;
foreach( $this->filters() as $name => $value ){
if( !method_exists($this, $name ) ){
continue;
}
if(strlen($value)){
$this->$name($value);
} else {
$this->$name();
}
}
return $this->builder;
}
public function filters()
{
return $this->request->all();
}
}
I've got a pre-existing function in my controller that will run a simple query and return the model_name and id then return the result as json.
public function getModel($id)
{
$models = DB::table('model')->where('man_id',$id)->pluck('model_name','id');
return json_encode($models);
}
New requirement is that I include an additional column named model_num with the query. Plan is to concatenate the model_name and model_num columns.
Tried the following, but it doesn't return any values and I get a 404 response for the json:
public function getModel($id)
{
$models = DB::table("model")->select("id","CONCAT(model_name, '-', model_num) as model")->where("man_id",$id)->pluck('model','id');
return json_encode($models);
}
Am I missing something obvious?
You are using SQL functions within a select these will probably not work. You can use selectRaw instead:
public function getModel($id)
{
$models = DB::table("model")
->selectRaw("id, CONCAT(model_name, '-', model_num) as model")
->where("man_id",$id)
->pluck('model','id');
return response()->json($models); // response()->json() is preferable
}
alternatively you can do the concatenating in the PHP side:
public function getModel($id)
{
$models = DB::table("model")
->select("id", "model_name" "model_num")
->where("man_id",$id)
->get()
->mapWithKeys(function ($model) {
return [ $model->id => $model->model_name.'-'.$model->model_num ];
})
return response()->json($models);
}
public function getModel($id)
{
$models = DB::table('model')->where('man_id',$id)->first() ;
$models->model = $models->model_name. '-'. $models->model_num;
return json_encode($models->pluck('model', 'id');
}
I have a given table :
tools toolparts parts part_details
----- --------- ----- ------------
id* id* id* id*
name tool_id name part_id
part_id total (int)
----- --------- ----- ------------
the relation between Tools and Parts is ManyToMany. and the relation between parts and part_details is one to many.
with Laravel model, how can I get tool with part that has the biggest part_details.total ??
//tool model
public function parts()
{
return $this->belongsToMany('App\Part', 'tool_part');
}
//part model
public function tools()
{
return $this->belongsToMany('App\Tool', 'tool_part')
}
public function details(){
return $this->hasMany('App\Part_detail');
}
//partDetail model
public function part(){
return $this->belongsTo('App\Part');
}
Controller
public function index()
{
$tools = Tool::with('parts', 'parts.details')->has('parts')->get();
return $tools;
}
what I expected is something like :
Controller
public function index()
{
$tool = Tool::with('SinglePartThatHasHigestTotalInPartDetail');
}
Any Idea ??
You can use Laravel aggregates for querying to get the desired result,
In your code use max() function,
public function index()
{
$tool = Tool::with(['parts.part_details' => function ($query) {
$max = $query->max('total');
$query->where('total',$max);
})->first();
}
I haven't tested this but you can do like this.
Comment if you will get any errors.
I Manage my problem with "hacky" ways. if someone have a better and more elegant solution, please tell me.
//tool model
public function partWithHighestTotalDelivery($trans_date = null){
if (is_null($trans_date)) {
$trans_date = date('Y-m-d');
}
$parts = $this->parts;
$highest_total_delivery = 0;
foreach ($parts as $key => $part) {
$part->detail;
$total_delivery = $part->first_value;
if (isset( $part->detail->total_delivery )) {
$total_delivery += $part->detail->total_delivery;
}
if ($highest_total_delivery < $total_delivery ) {
$highest_total_delivery = $total_delivery;
$part->total_delivery = $highest_total_delivery;
$result = $part;
}
}
if (!isset($result)) {
$result = null;
}
$this->part = $result;
}
In controller i have :
public function index(Request $request){
$tools = Tool::has('parts')
->get();
$tools->each(function($tool){
$tool->partWithHighestTotalDelivery();
});
return $tools;
}
with this, I need to run tool->partWithHighestTotalDelivery() tools.count times. which is take noticeable process if the tools is many.
and also, the code I post and the question I ask has a slightly difference.that's for a simplicity sake's
Use the the hasManyThrough Relationship to get the all part details related to tool and then you can check the one by one record and get the highest total of the tool part.
// Tool Model
public function partsdetails()
{
return $this->hasManyThrough('App\PartDetail', 'App\Part','tool_id','part_id');
}
In Your controller
$data = Tool::all();
$array = [];
if(isset($data) && !empty($data)) {
foreach ($data as $key => $value) {
$array[$value->id] = Tool::find($value->id)->partsdetails()->max('total');
}
}
if(is_array($array) && !empty($array)) {
$maxs = array_keys($array, max($array));
print_r($maxs);// This array return the max total of the tool related parts
}
else{
echo "No Data Available";
}
You can start with the part detail and get the tool(s) from there:
$maxPartDetail = Part_detail::orderByDesc('total')->first();
$tools = $maxPartDetail->part->tools;
I have a function named siblings which fetches all siblings of a user.
select siblings(id) as `siblings` from users where id = 1
I can access the function in Eloquent as
User::where('id', 1)->first([DB::raw(siblings(id) as `siblings`)]->siblings;
I want to make the siblings available via custom attribute.
I added siblings to $appends array
I also created getSiblingsAttribute method in my User model as
public function getSiblingsAttribute()
{
if (!$this->exists()) {
return [];
}
$siblings = User::where('idd', $this->id)
->first([DB::raw('siblings(id) AS `siblings`')])
->siblings;
return explode(',', $siblings);
}
But this is not working as $this->id returns null
My table schema is users(id, username,...), so clearly id is present.
Is there a way by which I can bind the siblings function while querying db and then returning something like $this->siblings from getSiblingsAttribute. If I can bind siblings(id) as siblings with query select globally as we do for scopes using global scope.
That way my code can be simply
public function getSiblingsAttribute()
{
return $this->siblings;
}
The simplest way is to create a view in your database and use that as a table:
protected $table = 'user_view';
Otherwise I need more information about your id == null problem.
If you can fix this by your own in the next step it is important that you use an other column name by selecting as in your accessor otherwise you run in an infinite loop.
public function getSiblingsAttribute()
{
if (!$this->exists()) {
return [];
}
$siblings = User::where('id', $this->id)
->first([DB::raw('siblings(id) AS `siblings_value`')])
->siblings_value;
return explode(',', $siblings);
}
EDIT
Sadly there is no simple way to archieve this.
But after a little bit tinkering I have found a (not very nice) solution.
Give it a try.
You have to add the following class and trait to your app.
app/Classes/AdditionalColumnsTrait.php (additional column trait)
namespace App\Classes;
trait AdditionalColumnsTrait {
public function newEloquentBuilder($query) {
$builder = new EloquentBuilder($query);
$builder->additionalColumns = $this->getAdditionalColumns();
return $builder;
}
protected function getAdditionalColumns() {
return [];
}
}
app/Classes/EloquentBuilder.php (extended EloquentBuilder)
namespace App\Classes;
use Illuminate\Database\Eloquent\Builder;
class EloquentBuilder extends Builder {
public $additionalColumns = [];
public function getModels($columns = ['*']) {
$oldColumns = is_null($this->query->columns) ? [] : $this->query->columns;
$withTablePrefix = $this->getModel()->getTable() . '.*';
if (in_array('*', $columns) && !in_array($withTablePrefix, $oldColumns)) {
$this->query->addSelect(array_merge($columns, array_values($this->additionalColumns)));
} elseif (in_array($withTablePrefix, $oldColumns)) {
$this->query->addSelect(array_values($this->additionalColumns));
} else {
foreach ($this->additionalColumns as $name => $additionalColumn) {
if (!is_string($name)) {
$name = $additionalColumn;
}
if (in_array($name, $columns)) {
if (($key = array_search($name, $columns)) !== false) {
unset($columns[$key]);
}
$this->query->addSelect($additionalColumn);
}
}
if (is_null($oldColumns)) {
$this->query->addSelect($columns);
}
}
return parent::getModels($columns);
}
}
after that you can edit your model like this:
class User extends Model {
...
use App\Classes\AdditionalColumnsTrait;
protected function getAdditionalColumns() {
return [
'siblings' => DB::raw(siblings(id) as siblings)),
];
}
...
}
now your siblings column will be selected by default.
Also you have the option to select only specific columns.
If you don't want to select the additional columns you can use: User::find(['users.*']).
Perhaps it is a solution for you.