Laravel - eager loading a method (not a relationship) of an Eloquent model - php

Like we can eager load a relationship of an Eloquent model, is there any way to eager load a method which is not a relationship method of the Eloquent model?
For example, I have an Eloquent model GradeReport and it has the following method:
public function totalScore()
{
return $scores = DB::table('grade_report_scores')->where('grade_report_id', $this->id)->sum('score');
}
Now I am getting a collection of GradeReport Eloquent models.
$gradeReports = GradeReport::where('student_id', $studentId)->get();
How can I eager load the returning values of totalScore method for all GradeReport Eloquent models in the collection?

You can add arbitrary properties to your models by adding them to $appends array and providing a getter. In your case the following should do the trick:
class GradeReport extends Model {
protected $appends = ['totalScore'];
public function getTotalScoreAttribute() {
return $scores = DB::table('grade_report_scores')->where('grade_report_id', $this->id)->sum('score');
}
}
Now all GradeReport objects returned from your controllers will have totalScore attribute set.

The table grade_report_scores would also have an eloquent model xyz on which you define a relationship, query scopes, functions, etc.
Add relationship into GradeReport model:
public function scores()
{
return $this->hasMany('xyz', 'grade_report_id', 'id');
}
Now you can rewrite your totalScore function into this:
public function totalScores()
{
return $this->with(['scores' => function ($query) {
$query->sum('score');
}])->get();
}
not tested, note the closure, there bight be a need to call $query->select('id', 'srore', 'other used values');

Related

How to make relationship between three table in laravel eloquent

I have three tables, Sections,Questions and options.
Each Section has many questions and each question has many options.
How can I fetch data from this tables related to each other?
Section model relationship with Question model
class Section extends Model
{
use HasFactory;
protected $primaryKey='sectionid';
public function questions(){
return $this->hasMany(Question::class,'sectionid')->orderBy('order');
}
}
Question model relationship with Option model:
class Question extends Model
{
use HasFactory;
protected $primaryKey='questionid';
public $timestamps = true;
public function options(){
return $this->hasMany(Option::class,'questionid');
}
}
my query:
$data=Section::with('questions')
->where('formid',$formId)
->orderBy('sectionid')
->get()
->toJson();
It returns this:
I want each questions member contains options array related to it.
You can use nested relation in with like below.So it will fetch question options also
$data=Section::with(['questions','questions.options'])
->where('formid',$formId)
->orderBy('sectionid')
->get()
->toJson();

Laravel 5 – get particular many to many relation based on model and related model ID

I've got Tag and Attendee Eloquent models, they are in many-to-many relation. Pivot table has also two more attributes – value_int and value_string. My Attendee model looks like this:
class Attendee extends Model
{
public $timestamps = false;
protected $fillable = [
'event_id'
];
public function tags() {
return $this->belongsToMany('App\Models\Tag', 'attendee_tag', 'attendee_id', 'tag_id')
->withPivot(['value_string', 'value_int']);
}
public function scoreTagValue($tag_id) {
return $this->tags->where('tag_id', '=', $tag_id)->first();
}
}
What I want is to obtain pivot values based on Attendee model and variable tag_id, so I've written scoreTagValue function, but it always returns null and I don't know why :( I'm calling it this way:
$attendee->scoreTagValue($tag_id). Thanks for your help :)
You need to access the relation, not the property:
public function scoreTagValue($tag_id) {
return $this->tags()->where('tag_id', '=', $tag_id)->first();
}
Also, according to the docs, withPivot() does not take an array, so:
->withPivot('value_string', 'value_int');

how to get a belongsToMany() query from a collection ? MySQL/Laravel

I'm using Laravel 5.4.22 (the newest one). In MySQL, I have two tables, tag_categories and tags, which form a many-to-many relationship. What I need is a query which returns all the tags for the selected categories. I know how to solve this when I have only one object, and I know how to solve this with querying and looping each of those objects, but there has to be a query or eloquent based solution for the whole thing?
I understand the code below doesn't work because I'm using ->belongsToMany on a collection rather than an object, but how to I bridge this gap the simplest way?
$resultingTags = TagCategory::whereIn('id', $chosenCategoriesIds)
->belongsToMany(Tag::Class)->get();
dd($resultingTags);
belongsToMany generally belongs in the model class, not a method called on the fly. When looking to eager load the relationship, you then call the with() method on the query builder.
https://laravel.com/docs/5.4/eloquent-relationships#many-to-many
ex:
class User extends Model
{
/**
* The roles that belong to the user.
*/
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
// Query
$users = User::with('roles')->get();
$rolesOfFirstUser = $users->first()->roles;
If you're trying to get all the tags of the given categories, then you should be querying tags, not tag_categories.
Tag::whereHas('categories', function ($query) use ($chosenCategoriesIds) {
$query->whereIn('id', $chosenCategoriesIds);
})->get();
This is One-to-many relation
Define relation at TagCategory model at app/TagCategory.php
public function tags()
{
return $this->hasMany('App\Tag');
}
And handle at your Controller
$resultingTags = TagCategory::whereIn('id', $chosenCategoriesIds)->with(['tags'])->get();
If you want define Many-To-Many relation for this case
You need to have 3 tables tags, tag_categories, tag_tag_category
Define relation at TagCategory model at app/TagCategory.php
public function tags()
{
return $this->belongsToMany('App\Tag', 'tag_tag_category', 'tagcategory_id', 'tag_id');
}
And handle at your Controller
$resultingTags = TagCategory::whereIn('id', $chosenCategoriesIds)->with(['tags'])->get();

Laravel 5.4 orderBy on morphTo relation

I am trying to order the results of a morphTo relation in Laravel 5.4. The below example does not work. Adding an orderBy method on other relations ( eg hasMany() ) does work.
class OrderLineItem extends Model
{
public function eventtable()
{
return $this->morphTo()->orderBy('date');
}
}
I have been able to order the result set after the query, by using sortBy on the collection. But would be good to order the results in the query. The date col is always available in the polymorphic related tables.
class OrderLineItem extends Model
{
public function eventtable()
{
return $this->morphTo()->orderBy('date','Desc');
//or you can use
//return $this->morphTo()->latest('date');
}
}

How to return one property of a belongsTo model with the child model in Laravel resource controller

I'm using Laravel as a REST API for a SPA. I have a relationship where families have multiple contributions. The contributions table has a foreign key reference to family's id. I can call on the contributions route with the hasMany/belongsTo set up, and every contribution gets the entire family model it belongs to. But I don't need all that data, I just need a single field from the family table (not the id, but a different field) with each contribution.
Here are my models and resource controller:
class Family extends Eloquent {
protected $table = 'families';
// relationships
public function contributions() {
return $this->hasMany('Contribution');
}
}
class Contribution extends Eloquent {
protected $table = 'contributions';
// relationships
public function family() {
return $this->belongsTo('Family');
}
public function other_field() {
return $this->belongsTo('Family')->select('other_field');
}
}
class ContributionController extends BaseController {
public function index()
{
// works - but returns the entire family with every contribution
$contributions = Contribution::with('family')->get();
// returns other_field == null with every contribution
$contributions = Contribution::with('other_field')->get();
return Response::json($contributions->toArray(),
200);
}
Where am I going wrong with selecting this single field from the belongsTo relationship?
You can use query constraints on the relationship if you use eager loading.
Family::with(['contributions', function($query)
{
$query->select('column');
}])->get();

Categories