how to call model method in the model relationship method in laravel - laravel

I have four tables namely: users, games, activities. The users and activities tables have Many to Many relationship. And, games and activities have One to Many relationship respectively. Of course I've that fourth pivot table for the Many to Many relationship above, namely, activity_user.
Inside the Game model, I have this relationship method to call all activities owned by that game, like so:
/**
* Get game activities
*
* #return hasMany
*/
public function activitiesFilter()
{
$user_id = auth('api')->id();
return $this->hasMany(Activity::class)->where('status_id', 2)->multiplayer()->whereDoesntHave('users', function($q) use ($user_id){
$q->where('user_id', $user_id);
});//select only this game approved(status_id===2) activities whose multiplayer count have not been reached and which this user have not joined/created
}
To select activities whose multiplayer count have not been reached, I've a scope function inside the Activity model, like so:
/**
* Scope a query to only include activity whose multiplayer count have not been reached.
*note that the activities table have an int field for multiplayer.
* #return \Illuminate\Database\Eloquent\Builder
*/
public function scopeMultiplayer($query)
{
return $query->where('multiplayer','>', $this->users()->count());
}
However, this doesn't seem to work as $this->users()->count() seems to always return 0.
Your solution will be highly appreciated.

Related

Laravel getting data from a deep relationship

I have 3 tables:
Users
Baskets
Items
id
id
id
user_id
basket_id
price
I'm trying setup a relationship in eloquent by which I can get all the all the Items and the corresponding Baskets where the price of items is X. I want it so that I can simply use $user->items(x) and get the results.
I'm unsure if this can be done using Relationships alone or will I have to resort to writing custom queries.
Any, and all, help and guidance will be appreciated!
The relationship you are looking for is hasManyThrough
https://laravel.com/docs/7.x/eloquent-relationships#has-many-through
User Modal
public function items()
{
return $this->hasManyThrough(Item::class, Bucket::class);
}
The way you want to use is not possible to achieve I think.
Possible Usage
$user->items()->where('price', x);
of if you define custom scopes
Item Modal
public function scopeWherePrice($query, $value)
{
return $query->where('price', $value);
}
Usage
$user->items()->wherePrice(x);
EDIT
If you really want to write a code like $user->items(x) you can define a method on the User Modal.
Note that this is not a relationship, just another method which fetch the result.
User Modal
public function items($price)
{
return this->items()->where('price', $price)->get();
}
Using hasManyThrough Define the relationship in your models:
User Model
/**
* Get all of the items & baskets for the user.
*/
public function items($price)
{
return $this->hasManyThrough('App\Items', 'App\Baskets')
->with('basket')
->where('price',$price);
}
Basket Model
/**
* Get the Items's Basket.
*/
public function basket()
{
return $this->belongsTo('App\Basket','basket_id');
}
And then call it like this:
$user->items(x);
This will return all user items with their corresponding baskets in a specific price.

Using whereHasMorph inside a local scope for MophByMany relationships

I am needing to find out the current players on a given team. I have created a scope for this. The requirements are that it checks a pivot table to see if the left_at field is null or not. If it is Null that means they are still on the team (current player). The relationship is a polymorphic many to many relationship. The reason why it's polymorphic because a team can also have players come and go as well as coaches for the team.
Team.php
/**
* Scope a query to only include current players.
*
* #param \Illuminate\Database\Eloquent\Builder $query
*/
public function scopeCurrentPlayers($query)
{
return $query->whereHasMorph('players', Player::class, function ($query) {
$query->whereNull('left_at');
});
}
**
* Get all players that have been members of the stable.
*
* #return \Illuminate\Database\Eloquent\Relations\MorphByMany
*/
public function players()
{
return $this->morphedByMany(Player::class, 'member')->using(Member::class)->withPivot(['joined_at', 'left_at']);
}
Controller
$currentTeamPlayers = $team->currentPlayers()->get()->pluck('id');
I am expecting to get a collection of current players on the team however I am receiving the following error.
+exception: Symfony\Component\Debug\Exception\FatalThrowableError^ {#5387
-originalClassName: "TypeError"
#message: "Argument 1 passed to Illuminate\Database\Eloquent\Builder::getBelongsToRelation() must be an instance of Illuminate\Database\Eloquent\Relations\MorphTo, instance of Illuminate\Database\Eloquent\Relations\MorphToMany given, called in /Users/jeffreydavidson/Projects/Ringside/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php on line 215"`
whereHasMorph function only works for morphTo associations. Reference: https://laravel.com/docs/8.x/eloquent-relationships#querying-morph-to-relationships
For morphMany associations, you can simply use whereHas. Reference: https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence
So in your case,
public function scopeCurrentPlayers($query)
{
return $query->whereHas('players', Player::class, function ($query) {
$query->whereNull('left_at');
});
}

Custom hasMany relationship query with select()

Each company on my app can store its own events.
A company and its events are related though the following hasMany relationship:
/**
* The events that belong to the company.
*/
public function events()
{
return $this->hasMany('App\Event');
}
To list a company's events, I use:
Auth::user()->company->events
Since each event stores, a lot of data that I don't need when I query the hasMany, I would like to customize the relationship to only select the id and name columns instead of the whole row.
My hasMany relationship query would be something like
DB::table('events')->where('company_id', Auth::id())->select('id', 'name')->get();
How do I take the collection returned from this result and use it as the query for my hasMany relationship, which will then correctly return a collection of event instances?
Add the filter inside your events method like :
public function events()
{
return $this->hasMany('App\Event')->select('id', 'company_id', 'name');
}
Then call it like:
Auth::user()->company->events
Important update: 'company_id' is necessary for company->events link, otherwise 'events' relationship always returns empty array
How about
Auth::user()->company()->with('events:id,name')->get();
https://laravel.com/docs/5.8/eloquent-relationships#eager-loading
Go to Eager Loading Specific Columns

Combine two eloquent relationships in a single Model and combine their data

I have multiple eloquent relationships set up through the backend in a laravel application. I need to sort of combine a few of them in a return and I'm not sure how to go about it. I'm considering a hasManyThrough relationship but I feel like since I get the data I need through other relational calls there is probably some way to combine the two. Anyways here are my call in my Quote model.
/**
* The items that belong to the quote.
*/
public function items()
{
return $this->belongsToMany('App\Item')->withPivot('waste', 'subtotal', 'required');
}
/**
* The categories that have been added to a quote.
*/
public function categories()
{
return $this->belongsToMany('App\Category')->withPivot('priority', 'expanded')->with('items');
}
What I'd like to do is somehow combine these two relationships so that categories() returns everythign that it does but it attaches the pivot table from the items method to the eager load items. I don't quite konw if I've explained it properly but I hope so.

LARAVEL: One-to-one relationship on a pivot table?

I can't think of how to handle this in Eloquent. I have a many-to-many relationship that needs a one-to-one relationship assigned to it.
Here is the basic database structure I designed in its simplest form:
ACCOUNTS: id
AGENTS: id
FEES: id
ACCOUNT_AGENT: account_id, agent_id, fee_id
Each Account belongsToMany Agents.
Each Agent belongsToMany Accounts.
Each "Account_Agent" (the many-to-many pivot table) belongsTo Fee.
How do I define that third relationship in an Eloquent model?
I want to be able to access the "account_agent" fee like this (or similar):
$account = Account::first();
foreach ($account->agents as $agent) {
echo $agent->fee;
}
Thanks, hopefully my question is clear.
See here:
https://laravel.com/docs/5.4/eloquent-relationships#many-to-many
Scroll down to Defining Custom Intermediate Table Models
Basically what you have to do is to define a class like this:
class AccountAgent extends Illuminate\Database\Eloquent\Relations\Pivot
{
/**
* Many:1 relationship with Fee model
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function fee()
{
return $this->belongsTo(Fee::class);
}
}
Then you define your many:many relationship in your Account class like this:
/**
* The agents that belong to the account.
*/
public function agents()
{
return $this->belongsToMany(Agent::class)->using(AccountAgent::class);
}
Then in your code, instead of this:
foreach ($account->agents as $agent) {
echo $agent->fee;
}
... do this:
foreach ($account->agents as $agent) {
/** #var Fee $fee_object */
$fee_object = $agent->pivot->fee;
}
In that loop $fee_object is of class Fee (the model class that covers the fees table) so you could echo $fee_object->fee_amount or whatever other columns you need to use.

Resources