How to design result according students - database

This is my first post. I am in a trouble in my laravel project
Here is my data table.
I have student Id like 1,2,3. every students have multiple results followed by courses.
I need to arrange them like that
I tried groupby and got this result
Is there any possible way to arrange them according to students.
Thank You
code: controller:
public function notification()
{
$auth_id = Auth::user()->id;
$teacher = Teacher::where('user_id', $auth_id)->first();
$teacher_id = ($teacher->id);
$batch = Batch::where('teacher_id', $teacher_id)->first();
$courses = AssignCourses::with('course')
->where('semester_id', $batch->semester_id)
->get();
$current_semester_results = Result::with(['student', 'course'])
->where('semester_id', $batch->semester_id)
->get()
->groupBy('student.id');
$batch_students = Student::with('result')
->where('semester_id', $batch->semester_id)
->get();
return view('users.teacher.my_batch.notification', compact(['current_semester_results', 'courses', 'batch_students']));
}

Just use the $batch_students and apply any aggregations on your PHP code, it is easier to do it.
$batch_students = Student::with('result')
->where('semester_id', $batch->semester_id)
->get();
$batch_students_grouped = $batch_students->groupBy('result.student_id');
Note: I could not test since I don't have the tables, so you might need to change the student_id nest/access index in the last line of code.
you can print out your $batch_students_grouped->all() and see how you should iterate your data and show it in frontend.

Related

How to get customer_id from different table and avoid duplications with correct method in laravel?

Hi I am trying to get customer _id from different tables Purchase order ,Sale Order and Consignments
Then I am looping through these Ids . Method I am using for this purpose is working perfectly but . I am afraid if there is a lot of data this method may get failed. Here is my method .
$consignmentCustomerIds = Consignment::select('customer_id')->where('is_repeat', 0)->whereDate('created_at','>',date('2021-03-06'))->whereRaw('(is_group = "parent" or is_group is null)')->where('finalize', 0)->where('invoice_id', null)->distinct()->pluck('customer_id')->toArray();
$poCustomerIds = PurchaseOrder::select('customer_id')->whereDate('created_at','>',date('2021-03-06'))->where('invoice_id', null)->distinct()->pluck('customer_id')->toArray();
$soCustomerIds = SaleOrder::select('customer_id')->whereDate('created_at','>',date('2021-03-06'))->where('invoice_id', null)->distinct()->pluck('customer_id')->toArray();
$spCustomerIds = StoragePeriod::select('customer_id')->whereDate('created_at','>',date('2021-03-06'))->where('invoice_id', null)->distinct()->pluck('customer_id')->toArray();
$ids = array_merge($consignmentCustomerIds, $poCustomerIds, $soCustomerIds, $spCustomerIds);
$customers = Customer::whereIn('id', $ids)->get();
foreach ($customers as $customer) {
CreateInvoiceOneByOne::dispatch($customer)->onQueue('invoice');
}
Is there any better way of doing so?
The main thing is to change ->get() to ->cursor() in the iteration:
// $customers = Customer::whereIn('id', $ids)->get();
$customers = Customer::whereIn('id', $ids)->cursor();
The cursor method may be used to significantly reduce your application's memory consumption when iterating through tens of thousands of Eloquent model records.
More info: https://laravel.com/docs/8.x/eloquent#cursors
IF YOUR RELATIONS ARE SET PROPERLY
I suggest to reduce database query. You can do this by chaning whereHas and orWhereHas within the customer request.
Querying Relationship Existence
$date = date('2021-03-06');
$customers = Customer::whereHas('consignment', function($query) use($date) {
$query->where('is_repeat', 0)->whereDate('created_at','>',$date)->whereRaw('(is_group = "parent" or is_group is null)')->where('finalize', 0)->where('invoice_id', null);
})->orWhereHas('purchase_order', function($query) use($date) {
$query->whereDate('created_at','>',$date)->where('invoice_id', null);
})->orWhereHas('sale_order', function($query) use($date) {
$query->whereDate('created_at','>',$date)->where('invoice_id', null);
})->orWhereHas('storage_period', function($query) use($date) {
$query->whereDate('created_at','>',$date)->where('invoice_id', null);
})->get();
foreach ($customers as $customer) {
CreateInvoiceOneByOne::dispatch($customer)->onQueue('invoice');
}
I set the $date variable before the query, so this way you can manipulate it at one place.
P.S. I am currently assuming the name of the relations.

Dapper One to Many Mapping Logic

The dapper tutorial gives this example to help a user with Multi Mapping (One to Many)
While this works I am curious why they have you store the orders in the dictionary but then in the end they use a linq.Distinct() and return from the list. It seems like it would be cleaner to just return the ordersDictionary.Values as the dictionary logic ensures no duplicates.
//Tutorial
using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
Dictionary<int,Order> orderDictionary = new Dictionary<int, Order>();
List<Order> list = connection.Query<Order, OrderDetail, Order>(sql, (order, orderDetail) =>
{
if (!orderDictionary.TryGetValue(order.OrderID, out Order orderEntry))
{
orderEntry = order;
orderEntry.OrderDetails = new List<OrderDetail>();
orderDictionary.Add(orderEntry.OrderID, orderEntry);
}
orderEntry.OrderDetails.Add(orderDetail);
return orderEntry;
}, splitOn: "OrderID")
.Distinct()
.ToList();
return list;
}
//my suggestion
using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
Dictionary<int,Order> orderDictionary = new Dictionary<int, Order>();
//change 1 no need to store into list here
connection.Query<Order, OrderDetail, Order>(sql, (order, orderDetail) =>
{
if (!orderDictionary.TryGetValue(order.OrderID, out Order orderEntry))
{
orderEntry = order;
orderEntry.OrderDetails = new List<OrderDetail>();
orderDictionary.Add(orderEntry.OrderID, orderEntry);
}
orderEntry.OrderDetails.Add(orderDetail);
return orderEntry;
}, splitOn: "OrderID"); //change 2 remove .Distinct().ToList()
return orderDictionary.Values.ToList(); //change 3 return dictionaryValues
}
I'm the author of this tutorial: https://dapper-tutorial.net/query#example-query-multi-mapping-one-to-many
why they have you store the orders in the dictionary
A row is returned for every OrderDetail. So you want to make sure to add the OrderDetail to the existing Order and not create a new one for every OrderDetail. The dictionary is used for performance to check if the Order has been already created or not.
it would be cleaner to just return the ordersDictionary.Values
How will your query return dictionary values?
Of course, if you are in a method such as yours, you can do
var list = orderDictionary.Values;
return list;
But how to make this Connection.Query return dictionary values? An order is returned for every row/OrderDetail, so the order will be returned multiple times.
Outside the Query, your dictionary solution works great and is even a better solution for performance, but if you want to make your Query return the distinct list of orders without using Distinct or some similar method, it's impossible.
EDIT: Answer comment
my suggestion return orderDictionary.Values.ToList(); //change 3 return dictionaryValues
Thank you for your great feedback, it's always appreciated ;)
It would be weird in a tutorial to use what the query returns when there is no relationship but use the dictionary for one to many relationships
// no relationship
var orders = conn.Query<Order>("", ...).Distinct();
// one to many relationship
conn.Query<Order, OrderDetail>("", ...);
var orders = orderDictionary.Values.ToList();
Your solution is better for performance the way you use it, there is no doubt about this. But this is how people usually use the Query method:
var orders = conn.Query("", ...).Distinct();
var activeOrders = orders.Where(x => x.IsActive).ToList();
var inactiveOrders = orders.Where(x => !x.IsActive).ToList();
They use what the Query method returns.
But again, there is nothing wrong with the way you do it, this is even better if you can do it.

Get or fetch Latest or last create multiple rows in laravel

I am in need of desperate help. I am newbie to laravel and programming.
I have a sales controller which fetch multiple records from form using jquery and select.
Sales Store controller looks like:
for ($i=0; $i < count($request['product_id']); ++$i)
{
$sales= new Sale;
$sales->product_id = $request['product_id'][$i];
$sales->qty= $request['qty'][$i];
$sales->user_id = Auth::user()->id;
$sales->save();
$product = new Product;
$product->where('id', '=', $request['product_id'][$i])->decrement('stock', $request['qty'][$i]);
}
this code is working perfectly fine.
Now the scenario is that I want to fetch these last created specific records to send it somehow to other page or as an invoice. Any help will be greatly appreciated on how to achieve this? Thanks.
Make a new array to hold the sales and product data and redirect to your desired url with that data.
$data = array();
for ($i=0; $i < count($request['product_id']); ++$i)
{
$sales= new Sale;
$sales->product_id = $request['product_id'][$i];
$sales->qty= $request['qty'][$i];
$sales->user_id = Auth::user()->id;
$sales->save();
$product = new Product;
$product->where('id', '=', $request['product_id'][$i])->decrement('stock', $request['qty'][$i]);
$data[]['sales'] = $sales;
$data[]['product'] = $product;
}
return redirect("/your desired url")->with('data', $data);
For your second question in the comment, In your controller function of your desired url do this -
$data = [];
if ($request->session()->has('data')) {
$data = $request->session()->get('data');
}
return view('your view', compact('data'));
And then in your view -
#foreach($data as $d)
{{$d['sales']}} //here $d['sales'] is your sales object
{{$d['product']}} //here $d['product'] is your product object
#endforeach
You can do
$sales = Sale::latest()->take(count($request['product_id']))->get();
latest() will just order all the sales by the date of creation in descending order.
if count($request['product_id']) is 5, take() will fetch the first 5 sales.

cakephp - using create() not working as expected

I have a product controller and when I'm saving a new product I want to save some records to another related controller to make a record of what categories the product is associated with.
My code I'm using is:
$this->Product->create();
if ($this->Product->save($this->request->data)) {
$newProductId = $this->Product->getInsertID();
//associate products with categories
foreach($categoriesToSave as $key=>$value) {
$saveArray['CategoriesProduct'] = array('category_id'=>$value, 'product_id'=>$newProductId);
$this->Product->CategoriesProduct->create();
$this->Product->CategoriesProduct->save($saveArray);
$this->Product->CategoriesProduct->clear();
}
}
For some reason though, even if $categoriesToSave has 10 items in it, only the very last one is being saved. So it's obviuosly creating only the one new CategoriesProduct item and saving each record over the top of the last instead of create()-ing a new one.
Can anyone explain what I'm doing wrong and how I can make this work?
The way I would do it would be like this:
//Add a counter
$c = 0
foreach($categoriesToSave as $key=>$value) {
$saveArray[$c]['CategoriesProduct']['category_id'] = $value;
$saveArray[$c]['CategoriesProduct']['product_id'] = $newProductId;
$c++;
}
$this->Product->CategoriesProduct->saveMany($saveArray);
I don't think that is the only way to do it but that should work just fine.
Good luck!

how to retrieve data from model cakephp

I have a controller function named updateoos(), a model for that function Outofserviceday and a table named outofservicedays. The table has 3 fields - id, userid, outofservicedays.
I want to get the out of service days from today to the last day of month
how to write a function in Outofserviceday model with two arguments today and monthedDday like.
function ($today $monthedDday) { }
In my controller I get the two dates
$today = date("Ymd");
$monthend=date("ymd", strtotime($today));
I edited all my mistakes
Just convert your times to unix timestamp and check the values against your target dates.
Example:
$no_service_days = $this-> Outofserviceday->find('all');
$nsd_array = array();
$end_date = strtotime($monthend); // or strtotime('31-01-12');
foreach ($no_service_days as $key => $day) :
$record_u_time = strtotime($day['Outofserviceday']['outofservicedays']);
if($record_u_time < $end_date){
$nsd_array[] = $day;
}
endforeach;
pr($nsd_array);
This is a loose approach to the technique you should use since your code and naming conventions are honestly pretty confusing.
I don't see a date field in your table so I assume it's outofservicedays and your $monthend=date("ymd", strtotime($today)); doesn't appear to be a date in the future or past.

Resources