Get Data through relation in laravel - laravel

I'm using this query to get data using relation
return Product::with('attributes')
->whereHas('attributes', function ($query) use ($attribute_id,$attribute_value){
$query->whereIn('attribute_id', $attribute_id);
$query->whereIn('value', $attribute_value);
})
->paginate(10);
$attribute_id and $attribute_value are arrays, i'm getting data using this relation but when $attribute_id and $attribute_value are empty then i'm not getting any result but it should return result through product table if there are no attributes.
I have changed it to something like this:
if(!empty($attribute_id))
{
$query->whereIn('attribute_id', $attribute_id);
}
if(!empty($attribute_value))
{
$query->whereIn('value', $attribute_value);
}
model relation :
public function attributes()
{
return $this->hasMany(ProductsAttribute::class, 'product_id ');
}
Table:
id | Title | Price
1 Title 1 5000
2 Product 2 7000
this is related to product_attribute table
id | product_id | attribute_id | attribute_name | value
1 1 5 Color Red
2 1 6 Size XL
3 2 5 Color Green
Is there any other way to make a check in query so that if attributes are not provided then atleast product data should return.

A cleaner way might be to use local scopes. That way, your controllers will look cleaner. It also makes the code easily testable. Here is how I might approach this.
NOTE: Code hasn't been tesed.
In your controller:
return Product::with([
'attributes' => function ($query) use ($attribute_id, $attribute_value) {
return $query->inAttributeId($attribute_id)
->inAttributeValue($attribute_value);
}
])->paginate(10);
In your ProductsAttribute model:
public function scopeInAttributeId($query, $attributeId)
{
if (empty($attributeId)) {
return $query;
}
return $query->whereIn('attribute_id', $attributeId);
}
public function scopeInAttributeValue($query, $attributeValue)
{
if (empty($attributeValue)) {
return $query;
}
return $query->whereIn('value', $attributeValue);
}
As you can see, the scopes modify the query only if there are values in the passed in array. If the passed in array is empty, it returns the original query.

Related

Retrieve specific value on eloquent query

I would like to get only some values on these 3 different models:
1 user can have 1 rank
1 user can have X tchatMessages
I query the model tchatMessage, passing by the model User and I access its Rank relation.
In tchatMessage I would like to get :
content
created_at
In User :
username
In Rank :
color
icon
Here is my current query which retrieves all the data from the three models:
return TchatMessage::with(['user' => function($user){
$user->with(['rank'])->get();
}])->orderBy('created_at', 'desc')->limit(2)->get();
Relations :
In User :
public function tchatMessages()
{
return $this->hasMany(TchatMessage::class);
}
In TchatMessage
public function user()
{
return $this->belongsTo('App\Models\User');
}
In User to :
public function rank()
{
return $this->belongsTo( 'App\Models\Rank' );
}
Edit 2:
This query works, I've the username only but all fields in rank, how can I select only color & icon in rank model ?
return TchatMessage::query()
->with(array('user' => function($query) {
$query->select('id','rank_id','username')
->with('rank');
}))
->orderBy('created_at', 'desc')->limit(2)->get();
Edit 3: (works)
return TchatMessage::query()
->with(array('user' => function($query) {
$query->select('id','rank_id','username')
->with('rank:id,color,icon');
}))
->select('content', 'user_id', 'created_at')
->orderBy('created_at', 'desc')->limit(2)->get();
You can try to add select filter everywhere, like this :
return TchatMessage::query()
->select('content', 'created_at')
->with([
'user' => function ($user) {
$user->select('username');
},
'user.rank' => function ($rank) {
$rank->select('color', 'icon');
}])
->orderByDesc('created_at')
->limit(2)
->get();
And you can find more ways to do it, following this link
EDIT:
About your relations, following the official documentation, you can try to do like this :
User model :
public function tchatMessages()
{
return $this->hasMany(TchatMessage::class);
}
public function rank()
{
return $this->hasOne(Rank::class);
}
Rank model :
public function user()
{
return $this->belongsTo(User::class);
}
TchatMessage model :
public function user()
{
return $this->belongsTo(User::class);
}
EDIT 2:
With your query it works, so you can try :
return TchatMessage::query()
->select('content','created_at')
->with(['user:username' => function($user){
$user->with(['rank:color,icon'])->get();
}])->orderBy('created_at', 'desc')->limit(2)->get();
You can also let your query like this and add where conditions in your relations, something like this for example for you rank relation in your User model (if you don't need this relation somewhere else) :
public function rank()
{
return $this->hasOne(Rank::class)->select(['color', 'icon']);
}

How can I access model Relation with where condition of child and parent table in laravel?

I have Games table and which has the following schema
id | status | name
status column has 2 values (Active, Pending)
And GamePlayer table which has the following schema
id | game_id | player_id | request_status
request_status column has 3 values (Pending, Confirm, Rejected)
Now I have to select all game in which the player is involved but with the following constraints:
If the game is Pending state then it will be shown to all game_players
If the game is in Active state then it will be only shown to the game_player whose request_status is Confirm.
Game(Model)
public function GamePlayer()
{
return $this->hasMany('App\Models\GamePlayer', 'game_id', 'id');
}
public function getGames($playerId)
{
$gameList = Game::with(['GamePlayer','Category:id,name'])
->whereHas('GamePlayer', function ($q) use ($playerId) {
$q->where('player_id', $playerId);
})->get();
return $gameList;
}
Controller
$this->gameObj = new Game();
$gameList = $this->gameObj->getGames($player_id);
Please help me out how can I populate data from another table based on condition(parent table as well as the child).
You can use condition in your relationship to get only confirmed game players
public function activeGamePlayers()
{
return $this->hasMany('App\Models\GamePlayer', 'game_id', 'id')
->where('request_status', 'confirm');
}
You can as well use scopes (https://laravel.com/docs/7.x/eloquent#local-scopes) to select only active games
public function scopeActive($query)
{
return $query->where('status', 'active');
// You can then use $game->active()->...
}
So your getGame would look like:
public function getGames($playerId)
{
$player = GamePlayer::find($playerId);
if ($player->status == 'active') {
$gameList = Game::with(['GamePlayer', 'Category:id,name'])
->get();
} else {
$gameList = Game::with(['GamePlayer', 'Category:id,name'])
->active()->get();
}
return $gameList;
}
NOTE:
in your specific case, I would instead get started from the GamePlayer Model to get the games, instead of coming from the Game Model - you can use scopes and conditions in relationships as well to make your code more readable.
You can use Laravel method whereHas. You should read this part of Laravel the documentation.
Note that you should have relationships declared on every model.

Laravel - Count of items through with belongs to

A company can have many delivery dates. A delivery date may have many entries. The Entry model contains
public function company()
{
return $this->belongsTo(Company::class);
}
public function delivery_date()
{
return $this->belongsTo(MgDeliveryDate::class, 'mg_delivery_date_id');
}
What I want is a count of how many entries each delivery date has for each company. For example, something like
$companies = Company->with('delivery_dates', 'delivery_dates.entries')->withCount('delivery_dates.entries')
So if my data was
Company Delivery Date Entry Number
A 1/2/2020 1
A 1/2/2020 2
A 2/2/2020 3
B 1/2/2020 4
I would get two companies, company A with two delivery dates and a count of 2 for the first date(1/2/2020) and 1 for the second date(2/2/2020) and company B with one delivery date, with an entry count of 1.
Good question. Give this a shot.
$companies = Company::with('delivery_dates.entries')->get();
$companies->map(function($company){
return $company->delivery_dates->map(function($delivery){
return $delivery->entries->count();
})->groupBy('delivery_date');
});
I have used Laravel Collection map() method.
// i am not sure what you actually want.. if you want the data like this then you can try this
[
{ company:abc , date:[{1/20} , {2/20} ...] , entry:[{1} ,{2} ...]} ,
{},
....
]
Company model
public function entry()
{
return $this->hasMany(entry::class);
}
And Then
$companies = Company::withCount(['entry', 'delivery_dates' => function ($query) {
$query->where(your condition);
}])->get();
You may write:
$companies = Compnay::with(['delivery_dates' => function ($q) {
$q->withCount('entries');
}])
->get();
You will get the following result:

How to order by column in nested level relationship in Laravel and get first order by?

I have two model.finance has many price.i want to get just one price (last record according to time) for every finance.so used function and order by and first of each orderby.but this just works for first finance and the other i get null in the with relation.
public function prices()
{
return $this->hasMany(Price::class, 'finance_id');
}
public function finances()
{
return $this->belongsTo(Finance::class, 'finance_id');
}
$finances = Finance::with(['prices' => function ($query) {
$query->orderBy('created_at', 'desc')->first();
}])->get();
Create new relationship in your Finance model to get latest price:
public function latestPrice()
{
return $this->hasOne(Price::class)->latest();
}
Change your query as below:
$finances = Finance::with('latestPrice')->get();

advanced filters in laravel

In my case, I have to filter the data by city or institute
I have two tables like below
Institutes table
id | institute_name | phoneNumber
-------------------------------------
1 infocampus 9999999999
-------------------------------------
2 jspider 2348234982
courses table
id | institute_id | course_name
------------------------------------------
1 1 java
2 1 php
Relations that I have created
Institue model
public function courses()
{
return $this->hasMany(Course::class);
}
Course model
public function institute()
{
return $this->belongsTo(Institute::class);
}
I have tried with below code
public function filter(Request $request)
{
$institute = (new Institute)->newQuery();
// Search for a user based on their institute.
if ($request->has('institute_name')) {
$institute->where('institute_name', $request->input('institute_name'));
}
// Search for a user based on their course_name.
if ($request->has('course_name')) {
$institute->whereHas('courses', function ($query) use ($request) {
$query->where('courses.course_name', $request->input('course_name'));
});
}
return response()->json($institute->get());
}
From above i able to filter the data but it show only institution table data like below
[
{
"id": 2,
"institute_name": "qspider",
"institute_contact_number": "9903456789",
"institute_email": "qspider#gmail.com",
"status": "1",
"created_at": null,
"updated_at": null
}
]
but what I need is when I do seach with course_name or instute_name I need to fetch data from institue table as well as courses table data.
Can anyone help on this, please?
Try the following it should return the institutes with the courses.
$institute->with(['courses' => function ($query) use ($request) {
$query->where('courses.course_name', $request->input('course_name'));
}])

Resources