Complicated query from three tables in Laravel - php

I have a problem what I can’t solve with Laravel.
I have three table:
Users, Properties, Offers
Users haveMany Properties and Offers
Properties and Offers belongsTo a User
Properties table:
id
user_id
contract_start_date
other_date
…
created_at
updated_at
Offers table:
id
user_id
…
created_at
updated_at
I would like give a table that is like this (I use two date filter: startDate and endDate):
Users name || Properties count (They are filtered by contract_start_date) || Properties count (They are filtered by other_date) || Offers count
———
user1 || 5 || 2 || 12
user2 || 0 || 1 || 0
user3 || 0 || 0 || 0
…
I try with union, leftJoin, etc but I can’t solve this…
Thanks, if you can help

Quick and Dirty
First, get your users eager loading their properties' dates and all the offers.
$users = Users::with([
'property'=>function($query){
$query->select('contract_startdate','otherdate');
},
'offer'=>function($query){
$query->select('id');
},
);
Assuming you've properly set the $dates array in your model to include your contract_startdate and other_date. We can use carbon to filter the collection to get the properties we're interested in counting. In your view, you can:
<table>
<thead>
<tr>
<th>User</th>
<th>Property (start date)</th>
<th>Property (other date)</th>
<th>Offers</th>
</tr>
</thead>
<tbody>
#foreach($users as $user)
<tr>
<td>{{$user->name}}</td>
<td>{{$user->properties
->filter(function($item) use ($filter_start,$filter_end){
return $item->contract_startdate->between($filter_start,$filter_end);
})->count() }}</td>
<td>{{$user->properties
->filter(function($item) use ($filter_start,$filter_end){
return return $item->other_date->between($filter_start,$filter_end);
})->count() }}</td>
<td>{{$user->offers->count()}}</td>
</tr>
#endforeach
</tbody>
</table>
Cleaning that up
You should likely refactor the filter out of the view for cleanness, but doing so will add another loop over collection. But you might be able to remove a loop by doing something like this in your controller.
$users = Users::with([
'property'=>function($query){
$query->select('contract_startdate','otherdate');
},
'offer'=>function($query){
$query->select('id');
},
);
$byContractDate = collect();
$byOtherDate = collect();
foreach($users as $user){
foreach($properties as $property){
$contractCounter = 0;
$otherCounter = 0;
if($propery->contract_startdate->between($filter_start,$filter_end){
$contractCounter++;
}
if($propery->contract_startdate->between($filter_start,$filter_end){
$otherCounter++;
}
}
$byContractDate->put($user->id,$contractCounter);
$byOther->put($user->id,$otherCounter);
}
And in your view:
<table>
<thead>
<tr>
<th>User</th>
<th>Property (start date)</th>
<th>Property (other date)</th>
<th>Offers</th>
</tr>
</thead>
<tbody>
#foreach($users as $user)
<tr>
<td>{{$user->name}}</td>
<td>{{$byContract->get($user->id)}}</td>
<td>{{$byOther->get($user->id)}}</td>
<td>{{$user->offers->count()}}</td>
</tr>
#endforeach
</tbody>
</table>

Related

Laravel 6 - View the data of the comparison statement in if condition

The title might sound confusing but this what I want to achieve in displaying the data.
I have a table tbl_employee which has a supervisor_id. The structure would be
senior manager
manager
team leader
I am using this syntax
<table class="table table-bordered table-dark">
<tr>
<th>#</th>
<th>Department Name</th>
<th>Supervisor ID</th></th>
<th>Action</th>
</tr>
#foreach($getEmployee as $id => $employee)
#if(Auth::user()->id == $employee->supervisor_id)
<tr>
<td>{{++$id}}</td>
<td>{{$employee->first_name}}</td>
<td>{{$employee->supervisor_id}}</td>
</tr>
#endif
#endforeach
</table>
Controller
public function create() {
$getEmployee = EmployeeModel::all();
$getDepartment = DepartmentModel::pluck('department_name', 'id');
$getSupervisor = EmployeeModel::select
(DB::raw("CONCAT(last_name,', ',first_name,' ',middle_name,' ',COALESCE(extension_name,'')) AS full_name"),'id')
->pluck('full_name', 'id');
$getHR = EmployeeModel::select
(DB::raw("CONCAT(last_name,', ',first_name,' ',middle_name,' ',COALESCE(extension_name,'')) AS full_name"),'id')
->where('position_id', 1)
->pluck('full_name', 'id');
return view('EmployeeView.add', compact('getDepartment', 'getSupervisor', 'getHR', 'getEmployee'));
}
I logged-in a senior manager account and I was able to see managers who has a supervisor_id of the senior manager. Now I also wanted to see team leaders who has a supervisor_id of a manager under the senior manager. I am quite confused on how to do a query.

Grouping data inside foreach in blade in laravel

I am trying to group a product name in may table. I found a suggestion to put a ->groupBy in my controller but when I am doing it my relation to other model is broken. what is the bets approach to achieve my what I want?
here's my code in my view blade.
<table class="table table-striped m-b-none" data-ride="datatables" id="table">
<thead>
<tr>
<th width="">Product Code</th>
<th width="">Product Name</th>
<th width="">In</th>
<th width="">Out</th>
<th width="">Total Stocks</th>
<th width="">Note</th>
</tr>
</thead>
<tbody>
#foreach( $warehouse1stocks as $warehouse1stock )
#php
$totalStocks = $warehouse1stock->stock_in_qty - $warehouse1stock->stock_out_qty;
$stockWarning = $warehouse1stock->product->wh1_limit_warning;
#endphp
<tr>
<td>{{$warehouse1stock->orderItem->product_code}}</td>
<td>{{$warehouse1stock->orderItem->product_name}}</td>
<td>{{$warehouse1stock->stock_in_qty}}</td>
<td>{{$warehouse1stock->stock_out_qty}}</td>
#if($totalStocks <= $stockWarning||$totalStocks==$stockWarning) <td>{{$totalStocks}} <i data-toggle="tooltip" data-placement="top" title="below stock limit, {{$stockWarning}}" class="fas fa-exclamation-circle text-danger"></i></td>
#else
<td>{{$totalStocks}}</td>
#endif
<td>{{$warehouse1stock->delivery_note}}</td>
</tr>
#endforeach
</tbody>
</table>
here's the screenshot of the view table
My index function in my controller
public function index()
{
$warehouse1stocks = Warehouse1stocks::all();
// dd($warehouse1stock->companies->comp_name);
return view('warehouse1.index', compact('warehouse1stocks', $warehouse1stocks));
}
what I'm trying to achieve is to group the product code and sum its 'in'. How
can i do that? thank you so much in advance!
UPDATE
this is additional information regarding with my inquiry.
The column product name and product code from my output table is from eloquent eloquent orderItems
class Orderitems extends Model
{
protected $table = 'order_items';
protected $fillable = [
'product_id',
'order_id',
'product_name',
'product_code',
'cost',
'rate',
'quantity',
'total_cost',
];
}
Progress Update
#apokrypus, Here's the error after applying your suggestion.
here's the updated code
$warehouse1stocks = Warehouse1stocks::select(
'order_item_id',
Warehouse1stocks::raw('SUM(stock_in_qty) as stock_in_qty'),
Warehouse1stocks::raw('SUM(stock_out_qty) as stock_out_qty')
)->groupBy('order_item_id')->get();
// dd($warehouse1stocks);
return view('warehouse1.index', compact('warehouse1stocks', $warehouse1stocks));
Here's the screenshot
Assuming you want to sum both in and out then you can do:
public function index()
{
$warehouse1stocks = Warehouse1stocks::select(
'order_item_id',
\DB::raw('SUM(stock_in_qty) as stock_in_qty'),
\DB::raw('SUM(stock_out_qty) as stock_out_qty')
)->groupBy('order_item_id')
->get()
// dd($warehouse1stock->companies->comp_name);
return view('warehouse1.index', compact('warehouse1stocks', $warehouse1stocks));
}
This should (ideally) not require you to make any view changes.
However if your delivery note is different on each row you might consider not including it in the result since you won't be able to show it when grouping multiple rows.

Displaying total answer and correct answer of each user

I have a db structure like this:
Tables:
users(id, email, password, ...) //default laravel users table
examinees(id, user_id, ...)
exam_quizzes(id, title, explanation)
exam_quiz_answers(id, title, exam_quiz_id, is_correct_ans)
submitted_answers(id, user_id, exam_quiz_id, exam_quiz_answer_id)
I already have the respective models and relationship methods set up.
Models:
User, Examinee, ExamQuiz, ExamQuizAnswer, SubmittedAnswer
Relationships:
// User -> hasOne() -> Examinee
$user->examinee
// ExamQuiz -> hasMany() -> ExamQuizAnswer
$examQuiz->examQuizAnswers
// SubmittedAnswer -> hasMany() -> ExamQuiz
$submittedAnswer->examQuizzes
// SubmittedAnswer -> hasMany() -> ExamQuizAnswer
$submittedAnswer->examQuizAnswers
// User -> hasMany() -> SubmittedAnswer
$user->submittedAnswers
In my view, how can I display the Name, Total Answered and Total Correct for every user who is also an examinee, in a table like this:
<tr>
<th>Name</th>
<th>Answered</th>
<th>Correct</th>
</tr>
#foreach()
{{-- I have no idea what to do here --}}
<tr>
<td></td>
<td></td>
<td></td>
</tr>
#endforeach
In your controller, u get the users an pass it to view.
$users = User:get();
and the make a foreach loop to get the answer and correct answers:
<tr>
<th>Name</th>
<th>Answered</th>
<th>Correct</th>
</tr>
#foreach($users as $user)
<tr>
<td>{{$user->name}}</td>
<td>{{count($user->submittedAnswers()->get())}}</td>
#php
foreach($user->submittedAnswers()->get() as $answer){
foreach($answer->examQuizAnswers->get() as $quiz){
$count = $quiz->where('is_correct_answer',1)->count()
}
}
#endphp
<td>{{$count}}</td>
</tr>
#endforeach
But of course you can write a method in a model to retrieve the correct answers. and just call that method instead.
you can write a method like this in User model:
public function get_correct_answers($user_id){
$user = User::whereId($user_id)->first();
foreach($user->submittedAnswers()->get() as $answer){
foreach($answer->examQuizAnswers->get() as $quiz){
$count = $quiz->where('is_correct_answer',1)->count()
}
}
return $count;
}
And then in the view u just call that method like this:
<tr>
<th>Name</th>
<th>Answered</th>
<th>Correct</th>
</tr>
#foreach($users as $user)
<tr>
<td>{{$user->name}}</td>
<td>{{count($user->submittedAnswers()->get())}}</td>
<td>{{$user->get_correct_answers($user->id)}}</td>
</tr>
#endforeach
Loop your $users and echo the 3 fields you want. Something roughly like this:
{{ $user->name }}
{{ $user->submittedAnswers->examQuizAnswers()->where('is_correct_answer', 1)->get()->count() }}
{{ $user->submittedAnswers->examQuizAnswers->count() }}
But please don't actually query in view files for the sake of the children.
Eager load related models in your controller:
User::with(['submitted_answers', 'submitted_answers.exam_quiz_answers'])->get()

Laravel - Math computations in blades

Is it possible to add two integers from the database inside a blade?
To give a scenario, I have a controller that compacts a collection of orders table.
$solditems = DB::table('orders')
->where('status', 'served')
->orderBy('id')
->get();
return view('salesreports.sellingitems.index', compact('solditems'));
And I used those like this in my blade.
<table class="table table-hover">
<tr>
<th>ID</th>
<th>Item</th>
<th>Sales</th>
</tr>
<thead>
</thead>
<tbody>
#forelse($solditems as $solditem)
<tr>
<td>{{$solditem->id}}</td>
<td>{{$solditem->item}}</td>
<td>{{$solditem->subtotal}}</td>
</tr>
#empty
#endforelse
</tbody>
</table>
Now, what I want to do is to combine an item that has same item names or $solditem->item while adding up there subtotals.
For example;
ID #1 Apple = 50
ID #2 Apple = 80
Will become this;
ID #1 Apple = 130
I tried using groupBy on query builder so an item with same name will only show once, but I'm having problems designing an algorithm adding up the subtotal.
Try this one,
This gives you sum of cost with same item name for all items.
$solditems = DB::table('orders')
->where('status', 'served')
->select('orders.*',DB::raw('SUM() as total'))
->groupBy('orders.item')
->orderBy('id')
->get();
You could take advantage of Laravel's collection methods. You can use the GroupBy method to create grouped subarrays by product name and foreach of those group using the Sum method return the sum of the total column.

Need help to in laravel 5.3 to fetch data in a table in single view from multiple database tables

As I am developing a project in larawel 5.3. and I am using two tables in database first users ans second points you can see my points table structure in this link.
I want to get user id in laravel 5.3 controller with Auth::user()->id but it creates error their
So when a transection occurs. it is saved in points table getting assousiated with user_id so net points of a user can can be taken as using folloing query
$points = Points::select(DB::raw("sum(p_add)-sum(p_less) as Total"))->where('user_id', Auth::user()->id)->first();
now I am goin to gett all data of users in a single admin page. so I am using following code in controller
public function users_list()
{
$ptitle = "Website Users";
$pdesc = "";
$total_users = User::count();
$users = User::select('*')->orderby('created_at', 'desc')->get();
return view('admin.all-users-list',
['ptitle' => $ptitle,
'pdesc' => $pdesc,
'users' => $users,
'total_users' => $total_users,
]);
}
And folloing foreach loop to fetch users data in view page
<table class="table table-hover">
<tbody><tr>
<th>ID</th>
<th>User Name</th>
<th>Email</th>
<th>Country</th>
<th>Date</th>
<th>Points</th>
</tr>
<?php foreach ( $users as $u ){ ?>
<tr>
<td>{{ $u->id }}</td>
<td>{{ $u->user_name }}</td>
<td>{{ $u->email }}</td>
<td>{{ $u->country }}</td>
<td>{{ $u->created_at }}</td>
<td>????</td>
</tr>
<?php }?>
</tbody></table>
and result on view is as in this image
now I dont now that how can I fetch net points from points table for every user. please provide me some help to solve this issue.
you can make public function and call it every loop in foreach loop. Or create static function on the Points model class to get points for every user by using user_id as argument.
Put getUserPoints on Points model class
public static function getUserPoints($userId){
$points = self::select(DB::raw("sum(p_add)-sum(p_less) as Total"))
->where('user_id', $userId)->first();
if( $points != null ){
return $points->Total;
}
return 0;
}
}
And you can call it every loop as {{ \App\Points::getUserPoints($u->id) }}

Categories