Foreach loop not going through correctly - laravel

I have a form to mark employees' attendance that HR fill in which is looped over every current employee. I need it to show the current values where attendance is marked in the database, otherwise it should be blank.
In my controller I query the existing results:
$results = Attendance::where('Sdate', '=', date("Y-m-d", strtotime($TheDate))) ->get();
Then loop through them to get the employee details:
foreach($results as $result)
{
$contractors = DB::table('contractors') ->where('contractors.AreaPosition', '=', $department) ->where('PRN', '!=', $result->PRN) ->get(); $employees = DB::table('current_employees') ->where('current_employees.AreaPosition', '=', $department) ->where('PRN', '!=', $result->PRN) ->get(); $showEmployees = array_merge($contractors, $employees);
}
This should exclude all employees who have a record saved in attendance for that date, however it doesn't seem to be looping correctly. It will exclude some results, but not all. If I return the results variable I get the correct list of records so I know that part is working correctly.
What I'm looking to achieve in my view is something like:
#foreach($attendance as $results)
Show form where there's an existing record for this date and department
#endforeach
#foreach($employees as $employee)
Show form for all employees in this department (but should exclude results where there is a record in attendance)
#endforeach

The problem with your code is you are saving the result in a variable and not in an array.
Your solution would be to store the data in an array
foreach($results as $result)
{
$contractors[] = DB::table('contractors') ->where('contractors.AreaPosition', '=', $department) ->where('PRN', '!=', $result->PRN) ->get(); $employees = DB::table('current_employees') ->where('current_employees.AreaPosition', '=', $department) ->where('PRN', '!=', $result->PRN) ->get(); $showEmployees = array_merge($contractors, $employees);
}
Try printing contractors array and see what happens.I hope this works

This was answered for me on Laracasts.
What I needed to do was create a list of the variable to check against (employee number)
$PRNs = Attendance::where('Sdate', '=', date("Y-m-d", strtotime($TheDate)))->lists('PRN');
And then use Laravel's whereNotIn, checking against the list.
$contractors = DB::table('contractors')
->where('contractors.AreaPosition', '=', $department)
->whereNotIn('PRN', $PRNs)
->get();

Related

Is it possible to group where clauses in Laravel?

I want to group item based on ORDER NO Where sales made by login User
$sales = KotOrder::orderBy('id','DESC')
->where('prepared_by', Auth::user()->id)
->get();
return view('settups.restaurant.pos.report', \compact('sales'));
And I tried this
$sales = KotOrder::orderBy('id','DESC')
->groupBy('qrtxt')
->where('prepared_by', Auth::user()->id)
->get();
return view('settups.restaurant.pos.report', \compact('sales'));
It gives out error

How can I do the job of three foreach loop by one foreach loop?

actually I am new to Laravel. I am doing a project for making a meal management system.
my code in my controller is:
$days=DB::table('days')
->get();
foreach ($days as $day) {
$breakfast[]= DB::table('breakfast_menus')
->leftJoin('breakfast_items', 'breakfast_menus.item_id', '=', 'breakfast_items.id')
->where('breakfast_menus.day_id',$day->id)
->select('breakfast_items.item')
->get();
$lunch[]= DB::table('lunch_menus')
->leftJoin('lunch_items', 'lunch_menus.item_id', '=', 'lunch_items.id')
->where('lunch_menus.day_id',$day->id)
->select('lunch_items.item')
->get();
$dinner[]= DB::table('dinner_menus')
->leftJoin('dinner_items', 'dinner_menus.item_id', '=', 'dinner_items.id')
->where('dinner_menus.day_id',$day->id)
->select('dinner_items.item')
->get();
}
return view('admin.show_menu',compact('days','breakfast','lunch','dinner'));
I want to show the data in a table. Where there will be
<td>day</td>
<td>Breakfast </td>
<td>Lunch</td>
<td>Dinner</td>
You should really use Laravel relationships and do justice with the framework.
Create models for each table.
Define relationship like days has breakfast_manu. See this
Then you will be able to do it like this:
$days = Days::with(['breakfast_menus','lunch_items','dinner_items'])->get();
I can say the way you wrote are very very bad for performance, why don't you use another way round in sql?
$days = DB::table('days')
->leftJoin('breakfast_menus', function($q) {
$q->leftJoin('breakfast_items', 'breakfast_menus.item_id', '=', 'breakfast_items.id')
->where('breakfast_menus.day_id', $day->id);
})
->leftJoin('lunch_menus', function($q) {
$q->leftJoin('lunch_items', 'lunch_menus.item_id', '=', 'lunch_items.id')
->where('lunch_menus.day_id', $day->id);
})
->leftJoin('dinner_menus', function($q) {
$q->leftJoin('dinner_items', 'dinner_menus.item_id', '=', 'dinner_items.id')
->where('dinner_menus.day_id', $day->id);
})
->select('days.id', 'breakfast_items.item as breakfast', 'lunch_items.item as lunch', 'dinner_items.item as dinner')
->get();
I didn't try out the SQL, but you can get the idea.
Then you can foreach $days to show your data

Not Sure if Laravel Distinct() is What I Should Use

This might be simple but I cant seem to figure it out. Customers have many machines. I need to return just the customer name once for a list. What I'm getting is an array of all machines.
public function machine_past_due(){
$today = date('Y-m-d');
$machines_past =Machine::distinct()
->whereDate('cert_date', '<', $today)
->with('customer')
->get();
return response()->json($machines_past);
}
I may be misunderstanding, and I know you already have an accepted solution, but if you want customers who have machines, it seems to me answers here are coming at it from the wrong direction - you don't want machines with customers, you want customers.
As a first step:
Customers::has('machines')->get();
will give you a list of customers who have at least 1 machine.
To incorporate your date restriction, you can use whereHas() to do something like:
Customers::whereHas('machines', function (Builder $query) {
$query->whereDate('cert_date', '<', date('Y-m-d'));
})->get();
This will give you all customers who have at least one machine matching the date condition. Note it does not include the machines - just a customer list.
If you want to include a customer's machines in the results, you have to then use with(), while constraining it with the same date condition:
Customers::whereHas('machines', function (Builder $query) {
$query->whereDate('cert_date', '<', date('Y-m-d'));
})->with(['machines' => function($query) {
$query->whereDate('cert_date', '<', date('Y-m-d'));
}])->get();
This will give you a list of all customers who have at least one machine matching the date condition, and list each customers' machines as a property of the customer, accessible as $customer->machines. You can then iterate over customers and do things like (in a blade view say):
#foreach ($customers as $customer)
{{ $customer->name }}, {{ $customer->machines->count() }} machines:
#foreach ($customer->machines as $machine)
{{ $machine->cert_date }}
// ... some other $machine stuff :-)
#endforeach
#endforeach
Here is the solution to achieve your goal:
public function machine_past_due(){
$today = date('Y-m-d');
$machines_past =Machine::distinct()
->whereDate('cert_date', '<', $today)
->with('customer')
->get();
$machines_past = $machines_past->pluck('customer.property_name')->unique(); //added this line
return response()->json($machines_past);
}
force the query to only return distinct results.
This is what distinct do, here is the source code,
so when you use distinct, it will check all the columns you selected which is duplicated.
You can use groupBy instead:
$machines_past =Machine::groupBy('customer_id')
->whereDate('cert_date', '<', $today)
->with('customer')
->get();
And if you are using mysql 5.7+ and you are using strict mode in laravel, you need to disable ONLY_FULL_GROUP_BY in laravel.
If what you are trying to return is an array of distinct customer names from your machine collection then laravel collection have a couple of methods that can help you. Assuming your customer is a "toOne" relationship and has a name attribute then:
public function machine_past_due(){
$today = date('Y-m-d');
$machines_past = Machine::whereDate('cert_date', '<', $today)
->with('customer')
->get();
$customer_names = $machines_past
->pluck('customer.name')
->unique()
->all();
return response()->json($customer_names);
}
The code will pluck the customer name from each of the machine returned from your query and removes all duplicate before finally converting it to an array.

SQL query similar to the concept of set (complement or except)

I need your help. I just want to display the name of all users (from table users) whose are not in table documents but in today's date
I've tried but I failed
Here is my code
public function activeUser(){
$documents = DB::table('users')
->leftJoin('documents', 'users.id', '=', 'documents.user_id')
->select('users.fname','users.mname','users.sname','documents.created_at')
->where('documents.user_id',null)
->where('documents.created_at',null)
->get();
return view('activity.activity')->with('documents', $documents);
}
I don't know to add current date in the where clause.
The above code gave me the all users who are note in table documents but if user exist in documents once will always considered as is in that documents table.
You can use "whereBetween" (https://laravel.com/docs/6.x/queries#where-clauses).
public function activeUser(){
$yesterday = Carbon::yesterday();
$today = Carbon::today();
$documents = DB::table('users')
->leftJoin('documents', 'users.id', '=', 'documents.user_id')
->select('users.fname','users.mname','users.sname','documents.created_at')
->where('documents.user_id',null)
->whereBetween('documents.created_at', [$yesterday, $today])
->get();
return view('activity.activity')->with('documents', $documents);
}
Remember, you can also use "whereNotInBetween" if that better matches your business logic case.

Ordering by updated_at per group

I have the following simple query to attempt to get the last updated row per module:
$distincts = SerialNumber::where('company_id', Auth::user()->active_company_id)
->groupBy('module')
->orderBy('updated_at', 'desc')
->get();
This doesn't work the way I want it to. Each row in the module group will not be ordered by updated_at (which is a datetime stamp).
How can I use orderBy for each row in a group? Thanks for reading!
The following works, but is a very bad solution:
$distincts = array();
$modules = SerialNumber::select('module')
->where('company_id', Auth::user()->active_company_id)
->groupBy('module')
->pluck('module');
foreach ($modules as $mod) {
$se = SerialNumber::where('company_id', Auth::user()->active_company_id)
->where('module', $mod)
->orderBy('updated_at', 'desc')
->first();
$distincts[] = $se;
}
What you need is a subquery:
$query = SerialNumber::orderBy('updated_at', 'desc')->getQuery();
$distincts = DB::table(DB::raw("(". $query->toSql() . ") as subQuery"))
->where('company_id', Auth::user()->active_company_id)
->groupBy('module')
->get();
This makes that you get only the latest records in group.

Resources