I am having a problem with simplyfing following eloquent relationship. It has a kind of nested query that uses a FieldRole model which I consider a bad pattern to follow. If I would have a raw query, then it should be evaluated as a one query using a join on field roles and it's name, but here it's doing two queries that probably are not cache'able by eloquent ORM.
class Team extends Model {
// ...
public function goalkeepers() {
return $this->belongsToMany(
SoccerPlayer::class,
'team_has_players',
'id_teams',
'id_soccer_players'
)->where(
'id_field_role',
FieldRole::where(
'name',
'Goalkeeper'
)
->first()
->getKey()
);
}
}
The second query is exectured there
FieldRole::where(
'name',
'Goalkeeper'
)
->first()
->getKey()
Is there a way to make it as a one query relationship?
You can use a JOIN:
public function goalkeepers() {
return $this->belongsToMany(
SoccerPlayer::class,
'team_has_players',
'id_teams',
'id_soccer_players'
)->join('field_roles', function($join) {
$join->on('team_has_players.id_field_role', 'field_roles.id')
->where('field_roles.name', 'Goalkeeper');
});
}
Related
I am learning laravel Eloquent relationship, I successfully created a relationship between models for eq city belongsTo State and belongsTo country.
public function state(){
return $this->belongsTo(State::class,'state_id', 'sr_id');
}
public function country(){
return $this->belongsTo(Country::class,'country_id', 'sr_id');
}
this is my old search code, I want to know how we search data using model relationship method, how we call each columns from their following table.
$city = city::leftjoin('master_country','master_country.sr_id','=','master_city.country_id')
->leftjoin('master_state','master_state.sr_id','=','master_city.state_id')
->where('master_city.sr_status',0)
->where('master_city.sr_id','LIKE','%'.$query.'%')
->orWhere('master_city.sr_name','LIKE','%'.$query.'%')
->orWhere('master_city.city_tel_code','LIKE','%'.$query.'%')
->orWhere('master_country.sr_name','LIKE','%'.$query.'%')
->orWhere('master_state.sr_name','LIKE','%'.$query.'%')
->orderBy('master_city.sr_id')
->paginate(3,array('master_city.*','master_country.sr_name AS c_name','master_state.sr_name As s_name'));
so it would we like..
City::with('state','country')->where etc
You can have a look at Constraining Eager Loads
$cities = City::with(
[
'state' => function ($query) {
$query->where('state_column', 'some_value');
},
'country' => function ($query) {
$query->where('country_column', 'some_value');
}
]
)->get();
If you don't want to retrieve the relation data, you can use the whereHas() method:
City::whereHas('state', fn (Builder $builder) => $builder->where('state_column', 'some_value')));
Using arrow function is not required.
More documentation on this
I have two models with relations as defined below
Order
public function owner()
{
return $this->belongsTo(User::class, 'owner_id');
}
User
public function company(){
return $this->belongsTo(Company::class, 'company_id');
}
company table have 'title' field.
what I want is to get all the orders sorted/order by company title. I've tried different solution but nothing seems to work. Any help or hint would be appreciated.
Recent solution that I tried is
$query = OrderModel::whereHas('owner', function($q) use ($request){
// $q->orderBy('owner');
$q->whereHas('company',function ($q2) use ($request){
$q2->orderBy('title',$request->get('orderByDirection') ?? 'asc');
});
});
but I am not getting user and company relation in query results. also the result remains same for 'ASC' and 'DESC' order.
You could sort the query after adding join like:
return Order::join('users', 'users.id', '=', 'owner_id')
->join('companies', 'companies.id', '=', 'users.company_id')
->orderBy('companies.title')
->select('orders.*')
->get();
You can define new relations in User and Company models.
User
public function orders()
{
return $this->hasMany(Order::class);
}
Company
public function users()
{
return $this->hasMany(User::class);
}
Now you can fetch companies that are in asc order and with the use of relation, you can fetch users and orders. So the ORM like be,
$companies = Company::with('users.orders')->orderBy('title', 'ASC')->get();
So these are the company-wise orders. You can use this too.
I'm trying to do where clause for fortune_code inside joindraw table, comparing with the lucky_fortune_code from product table. How can i access and do the check?
Product::where('status', StatusConstant::PT_ENDED_PUBLISHED)
->where('lucky_fortune_code', '<>', '')
->with(['joindraw' => function ($query){
$query->where('fortune_code', $this->lucky_fortune_code)
->with('user');}])->desc()->get();
Product.php
class Product extends Model
{
public function joindraw(){
return $this->hasMany('App\Models\Joindraw');
}
Joindraw.php
class Joindraw extends Model
{
public function product(){
return $this->belongsTo('App\Models\Product', 'product_id');
}
What you can do is a join:
Product::where('status', StatusConstant::PT_ENDED_PUBLISHED)
->where('lucky_fortune_code', '!=', '')
->join('joindraws', 'joindraws.fortune_code', '=', 'products.lucky_fortune_code')->get();
By the way, you can also omit the second 'product_id' parameter in the belongsTo() relation, as this column name is already assumed by convention.
Also, there is no desc() method on the query builder. Use orderBy('lucky_fortune_code', 'desc') instead.
However, whenever you have to write joins in Laravel, you should think about your relationship structure, because there's probably something wrong.
this is my query
$personnel_info = \DB::table('assigns AS a')
->join('boxes AS b','b.id','=', 'a.box_id')
->join('positions AS p','p.id','=', 'b.position_id')
->select('a.id','b.id AS box_id','p.id as position_id','p.title','a.status','a.end_date')
->where('a.personnel_id','=',$personnel_id)
->get();
and this realtionship for boxes:
class Boxes extends Model
{
public function position()
{
return $this->belongsTo('Positions');
}
public function assign()
{
return $this->hasOne('Assigns', 'box_id');
}
}
how to use eloquent query(also realtionship) for replace DB facade query?
i want select some field for tables.without define fileds in boxes model
tnx
Try
$personnel_info = Assign::with('box.position')
->where('personnel_id', $personnel_id)
->get();
Then dd($personnel_info) to see everything that was returned. If you don't like the values, then add your select() clause.
I'm having two tables as 'jobs' and 'desired_skills'.
Table structure is as follows.
jobs table
jobs Table
desired_skills table
desired_skils table
where desired_skills.job_id refers to jobs.job id
In controller I have (I am getting $id as an argument from the url, and I can confirm the argument grabs the desired value)
$jobs = DB::table('jobs')->where(function ($query) use ($id) {
$query->Join('desired_skills', 'desired_skills.job_id', '=', 'jobs.job_id')
->where('jobs.employer_id', '=', $id);
->select('*')
})->get();
when I dump and die $jobs it only returns values from jobs table.
but when I run the query
SELECT * FROM jobs INNER JOIN desired_skills ON desired_skills.job_id = jobs.job_id it returns the desired value set.
What am I doing wrong? Any help will be greatly appreciated.
I think it has to do with wrapping your join inside of a where clause. I don't think it's giving you your desired query with that there.
$jobs = DB::table('jobs')
->join('desired_skills', 'desired_skills.job_id', '=', 'jobs.job_id')
->where('jobs.employer_id', '=', $id)
->get();
The query SELECT * FROM jobs INNER JOIN desired_skills ON desired_skills.job_id = jobs.job_id
is not the same has what you are trying to do in the function. In this query there is not
mention of 'employer_id' in the table 'jobs'.
An alternative would be to use eloquent relationships, as refered in a comment.
You need 3 classes in models:
Employer
Job
DesiredSkill
Between Employer and Job -> one-to-many relation (an employer can have multiple jobs).
Between DesiredSkill and Job -> one-to-one relation.
I'm not sure what you are trying to get from the join, but i think that if you implement
the methods that allow the relationships i believe you solve whatever.
class Job extends Model
{
public function employer()
{
return $this->hasOne('App\Job');
}
}
class Employer extends Model
{
public function jobs()
{
return $this->hasMany('App\Employer');
}
public function desiredSkill()
{
return $this->hasOne('App\DesiredSkill');
}
}
class DesiredSkill extends Model
{
public function job()
{
return $this->hasOne('App\DesiredSkill');
}
}
Try this:
$jobs = DB::table('jobs')
->join('desired_skills', 'desired_skills.job_id', '=', 'jobs.job_id')
->select('jobs.*', 'desired_skills.*')
->get();