Manipulating data within an object - php

Hi I am new to Laravel and php. In my database each student has three marks on each subject and I need to retrieve them and send to the view the average mark for each student.
I tried doing it like below, but the returned value is an object (e.g. [5,4,3]) and it doesn't let me count the average. Please advise how I can operate with data within the object.
$students = Student::all();
foreach ($students as $student) {
$mathPoints = Point:: where('subject_id', 1)
->where('student_id', $student->id)
->pluck('points');
}
I tried turning it into an array by (array) method, but I couldn't calculate the sum of values with array_sum after.
Update: my Point model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Point extends Model
{
//Get the student the credit points are related to
public function student()
{
return $this->belongsTo('App/Models/Student');
}
//Get the subject the credit points are related to
public function subject()
{
return $this->belongsTo('App/Models/Subject');
}
}

use Model::avg('columnName') to calculate average .
read more here : https://laravel.com/docs/5.4/queries#aggregates
$students = Student::all();
foreach ($students as $student){
$mathPoints = Point::where(['subject_id'=>1,'student_id'=>$student->id])->avg('points');
$student->avgPoint=$mathPoints;
}
inside your blade :
{{ $student->avgPoint}}

Point::where('student_id', $student->id)->get()
When you use all() with Eloquent, it makes the query for you. If you use where(), you have to ‘get’ it using get() before you can use it as a collection.
$mathPoints = Point::where('student_id', $student->id)
->get()
->pluck('points');
However, I’d probably look at using more complicated queries to fetch this data, as you could easily end up making hundreds of queries per page, rather than just 1.

Related

How to retrieve data from one table based on the calculation of another two table?

Suppose I have Three model named as Customer ,Invoice and Payment.
Invoice and Payment model looks like
id , customer_id, amount
I want to get only those customer whose
Invoice.sum(amount)>Payment.sum(amount) with these amount difference
I am currently retrieve like
$customers=Customer::get();
foreach($customers as $customer)
{
$pay=Payment::where('customer_id',$customer->id)->sum('amount');
$due=Invoice::where('customer_id',$customer->id)->sum('amount');
if($due>$pay){
// showing this customers
}
}
Is there any better way with eloquent join?
How Can I get In laravel eloquent ?
Have you set any relationship in the Model? A better eloquent query will look like this. You might need to adjust a bit
Customer::join('payment','customer.id','=','payment.customer_id')
->join('invoice','customer.id','=','invoice.customer_id')
->select(array('customer.*'),DB::raw("SUM(payment.amount) as payment_sum,SUM(invoice.amount) as invoice_sum"))
//->where('customer_id',$customer->id)
->groupBy('customer.id') //replace with anything that make sense for you.
->havingRaw('invoice_sum > payment_sum')
->get();
Try this
First, define the relationship in your Customer Model
public function payments()
{
return $this->hasMany(Payment::class); //based on your logic or structure
}
public function invoices()
{
return $this->hasMany(Invoice::class); //based on your logic or structure
}
Customer::with(['payments' => function($query) {
$query->sum('amount');
}])
->get();
or
$customers=Customer::with('payments','invoices')->get();
foreach($customers as $customer)
{
$pay = $customer->payments()->sum('amount');
$due = $customer->invoices()->sum('amount');
//other logic
}

Foreach with eloquent in laravel

I'm trying to loop through the items using eloquent in laravel but I'm getting 0. Please see my code below.
Model
Class Store{
public function products(){
return $this->hasMany('App\Product');
}
}
Controller
$products_count = 0;
foreach($store->products() as $product)
{
if($product->status == 1)
{
$products_count++;
}
}
dd($products_count);
Note: I have data in my database.
You can also use withCount method something like that
Controller
$stores = Store::withCount('products')->get();
or
$store = Store::where('id', 1)->withCount('products')->first();
WithCount on the particular status
$stores = Store::withCount(['products' => function ($query) {
$query->where('status', 1);
}
])
->get();
ref: withcount on relationship
That's because $store->products() returns an eloquent collection which doesn't contain the data from the database yet. You need to do $store->products instead.
If you need to get the count from the database then use
$store->products()->where('status', 1)->count()
With the function-annotation (i.e. products()) you are retrieving the \Illuminate\Database\Eloquent\Builder-instance, not the actual Eloquent-collection.
Instead, you would have to use $store->products – then you will get retrieve the related collection.
In Laravel $store->products() makes you access the QueryBuilder instance, instead there is the Laravel way of doing $store->products, which loads the QueryBuilder and retrieves the collection automatically and down the line is easy to optimise.

Laravel: Count number of rows in a relationship

I have the following relationship:
A venue has many offers
A offer has many orders
I have the following Eloquent model to represent this:
class Venue {
public function orders()
{
return $this->hasManyThrough(Order::class, Offer::class);
}
}
I want to determine the total number of orders for venues with location_id = 5 using Laravel's Eloquent model.
The only way I managed to do this is as follows:
$venues = Venue::where('location_id', 5)->with('orders')->get();
$numberOfOrders = 0;
foreach($venues as $venue) {
$numberOfOrders += $venue->orders->count();
}
dump($numberOfOrders); // Output a single number (e.g. 512)
However, this is obviously not very efficient as I am calculating the count using PHP instead of SQL.
How can I do this using Eloquent model alone.
You can use Eloquent. As of Laravel 5.3 there is withCount().
In your case you will have
$venues = Venue::where('location_id', 5)->with('orders')->withCount('orders')->get();
Then access it this way
foreach ($venues as $venue) {
echo $venue->orders_count;
}
Can find reference here: https://laravel.com/docs/5.3/eloquent-relationships#querying-relations
$venues = Venue::with([
'orders' => function ($q) {
$q->withCount('orders');
}
])->get();
then use it this way for getting single record
$venues->first()->orders->orders_count();
Alternatively, you can use this way too for collections
foreach($venues as $venue)
{
echo $venue->order_count;
}
If you are using Laravel 5.3 or above you can use withCount.
If you want to count the number of results from a relationship without
actually loading them you may use the withCount method, which will
place a {relation}_count column on your resulting models. For example:
$venues = Venue::withCount(['orders'])->get;
foreach ($venues as $venue) {
echo $venue->orders_count;
}
You can read more about withCount in the Laravel Documentation.
If you are using lower than 5.3, you can make a custom relation on your Venue model:
public function ordersCount()
{
return $this->belongsToMany('App\Models\Order')
->selectRaw('venue_id, count(*) as aggregate_orders')
->groupBy('venue_id');
}
public function getOrderCount()
{
// if relation is not loaded already, let's do it first
if (!array_key_exists('ordersCount', $this->relations)) {
$this->load('ordersCount');
}
$related = $this->getRelation('ordersCount')->first();
// then return the count directly
return ($related) ? (int) $related->aggregate_orders : 0;
}
which can then be used as: Venue::with('ordersCount');. The benefit of this custom relation is you only are querying the count rather than the querying all of those relations when they are not necessary.

How to perform a calculation on a row basis and SUM on laravel

I have a situtaion where I have data in two columns in a table, which need to be multiplied on a row basis. Then each value from the multiplication has to be added to provide a net result
I tried this but it does not work
public function getCampaignStats($item)
{
$query = CampaignStats::where('item',$item);
foreach($query as $q) {
$q->p_c;
$q->caa;
dd($q->p_c);
}
return $query;
}
I get this exception when i try to do this
Object of class Illuminate\Database\Eloquent\Builder could not be converted to string
Is there a better way to do this foreach loop in laravel
You can use raw queries for such a case and do the math within your query. Have a look at the docs:
https://laravel.com/docs/5.4/queries#raw-expressions
https://laravel.com/docs/5.4/queries#where-exists-clauses

Eloquent and Pivot Tables in Laravel 4

I have a Poll table, a Students table, and a pivot table between them that includes a token and their three votes.
public function students()
{
return $this->belongsToMany('Student', 'polls_students')->withPivot('token','first','second','third');
}
While working out saving the poll results, I came across some odd behavior that I don't quite understand. I'm hoping somebody can explain what it is I'm missing:
$poll = Poll::find(Input::get('poll_id'));
foreach($poll->students()->where('students.id', '=', Input::get('student_id'))->get() as $student){
var_dump($student->pivot->token);
}
$student = $poll->students()->where('students.id', '=', Input::get('student_id'))->get();
var_dump($student->pivot->token);
In the above code, the foreach loop will successfully display the token, where the second one throws the exception Undefined property: Illuminate\Database\Eloquent\Collection::$pivot
What am I missing? Are these two calls not logically creating the same object? How is 'pivot' working on the first and not the latter?
You first example:
$poll = Poll::find(Input::get('poll_id'));
foreach($poll->students()->where('students.id', '=', Input::get('student_id'))->get() as $student){
var_dump($student->pivot->token);
}
Here $poll->students() retrieves a collection and because of foreach loop you get a single object in your $student variable and you can use $student->pivot->token
You second example:
$student = $poll->students()->where('students.id', '=', Input::get('student_id'))->get();
var_dump($student->pivot->token);
Here you are doing same thing, using $poll->students() you are getting a collection but this time you are not using a loop and trying to do same thing using $student->pivot->token but it's not working because you didn't define any index from which you want to get the pivot->token, if you try something like this
$student->first()->pivot->token
Or maybe
$student->get(1)->pivot->token
Or maybe you can use first() instead of get() like this
$student = $poll->students()->where('students.id', '=', Input::get('student_id'))->first();
Then you can use
$student->pivot->token
Remember that, get() returns a collection even if there is only one record/model.
$poll = Poll::find(Input::get('poll_id'));
foreach($poll->students as $student){
var_dump($student->pivot->where('student_id',$student->id)->where('poll_id',$poll->id)->first()->token);
}

Categories