I'm having a really strange issue with my eloquent query. I have a table called Calls which I am joining to Contacts and Companies. I am trying to reference the column calls.id but it has been replaced with the id for Companies.
Here is my query:
$calls=DB::table('calls')
->leftJoin('contacts','calls.contact_id','=','contacts.id')
->leftJoin('companies','calls.company_id','=','companies.id')
->where('completed','=',false)
->orderBy('call_on','asc')
->get();
return $calls;
I have seen on Github that this seems to be a known bug but no-one has put forward a workaround.
Can anyone point me in the right direction?
The most direction solution to your immediate question is to add a select to your Eloquent query:
$calls=DB::select('calls.* from calls')
->leftJoin('contacts','calls.contact_id','=','contacts.id')
->leftJoin('companies','calls.company_id','=','companies.id')
->where('completed','=',false)
->orderBy('call_on','asc')
->get();
return $calls;
Instead of the default select *, explicitly dictate what is returned. However, this can be done a lot more cleanly with Eloquent using models:
Calls::whereHas('companies', function (Builder $query) {
$query->where('completed', false);
})->orderBy('call_on', 'asc')->get();
In order for this to work you need to setup the relationship on the model level:
// App\Calls model:
public function companies() {
return $this->belongsTo(App\Companies::class);
}
// App\Companies model:
public function calls() {
return $this->hasMany(App\Calls::class);
}
Related
I have an issue where a profile can have many campaigns and also many locations.
The campaigns are linked via a pivot table but my goal is just to return all of the location ids.
Profile:
public function campaigns() {
return $this->hasMany('App\Models\Campaign', 'profile_id', 'id');
}
Campaign:
public function locations() {
return $this->belongsToMany('App\Models\Location')->withPivot('campaign_id', 'location_id');
}
Currently I am solving this by doing
$campaigns = $profile->campaigns;
[Doing a nested foreach loop and placing each ID into the array]
How would I get this via a query?
I've tried
$campaigns = $profile->campaigns()
->with('locations')
->get()
->pluck('location.id');
Well, your goal is to get information from the location, so I'd start your query with that. You can condition your query based on the relationships using the whereHas() method.
This assumes your Location has the campaigns relationship defined, and your Campaign has the profile relationship defined.
$ids = Location::whereHas('campaigns.profile', function ($query) use ($profile) {
return $query->where('id', $profile->id);
})->pluck('id');
You can read more about querying by relationships in the documentation here.
I'm looking to do something like this, but with Eloquent: get latest record for each ID
Personally, I have three tables: Game, Assignments, Users.
Games get assigned to Users through the Assignments table. However, when a game needs to be assigned to a new user, I just make a new Assignment, and go off of the latest assignment for each game.
My end goal is to be able to grab a collection of games that any given User has assigned to them. However, to do that, I first need to be able to query Assignments and filter out any assignment that isn't the most recent for that given Game id.
Any thoughts? I've been trying some things (see below) but not getting anywhere.
Game function (works):
public function latestAssignment() {
return $this->hasOne('App\Models\Game_Assignment', 'game_id')->latest();
}
Game_Assignment function:
public function isLatestAssignment() {
if($this->game->latestAssignment()->id == $this->id) {
return true;
} else {
return false;
}
}
User function (throws error):
public function current_game_assignments() {
return $this->hasMany('App\Models\Game_Assignment', 'statistician_id')->where('isLatestAssignment', true);
}
Let me know what y'all think I can do!
What you can do is select your games with the id of the latest assigned user in a subquery. You can then use a special relation that utilizes this subquery column to join to the users table:
class Game extends Model
{
public function latestUser()
{
return $this->hasOne(User::class, 'id', 'latest_user_id');
}
}
$games = Game::query()
->select('*') // necessary to avoid overrides by selectSub()
->selectSub(
Assignment::query()
->whereColumn('game_assignments.game_id', 'games.id') // table prevents ambiguity
->latest()
->select('game_assignments.user_id')
->take(1),
'latest_user_id'
)
->with('latestUser')
->get();
After re-reading your question, I come to a different solution. If you want all the games for a specific user of which the user is the latest assigned user, you can use the following query. It uses a little hack with the wrapping, but without this it doesn't allow to filter on the subquery:
// only for demonstration purposes
$user = User::find(1);
$games = Game::query()
->fromSub(
Game::query()
->select('*') // necessary to avoid overrides by selectSub()
->selectSub(
Assignment::query()
->whereColumn('game_assignments.game_id', 'games.id')
->latest()
->select('game_assignments.user_id')
->take(1),
'latest_user_id'
),
'games'
)
->where('latest_user_id', $user->id)
->get();
Please note that the subquery alias (second argument) must be the table name of your games.
I have several relationships, one specifically that I would like to use for ordering a list, but I can't seem to find the right way to do it.
Below are my relationships:
public function date(){
return $this->hasOne(agent_billings_dates::class,'id','dateID');
}
public function carrier(){
return $this->hasOne(customer::class,'id','carrierID');
}
As well as two attributes which I have added as appends:
public function getItemCountAttribute(){
return $this->items->count();
}
public function getItemMissingAttribute(){
return $this->itemIssues->count();
}
public function getBatchSumAttribute(){
return $this->items->sum('amount');
These show up all fine when I have the following in my function:
$batches = agent_billings_batches::with(['date','carrier','carrier.carrierDetails'])
->where('status',$request->status)
->get();
But the attributes and the with's fall off when I do this (however the date is sorted appropriately):
$batches = agent_billings_batches::with(['carrier','carrier.carrierDetails'])
->join('agent_billings_dates', 'agent_billings_dates.id', '=', 'agent_billings_batches.dateID')
->orderBy('agent_billings_dates.date','desc')
->where('status',$request->status)
->get();
Am I doing something wrong? I'd appreciate any help anyone could give.
Thanks!
Eloquent does not use Joins when loading relationships. It loads them in a separate query, therefore you cannot order the main result using a relationship at query time, you need to do it after the data is collected:
$batches = agent_billings_batches::with(['date','carrier','carrier.carrierDetails'])
->where('status',$request->status)
->get()
->sortBy(function ($batch) {
return $batch->date->date;
});
I have a model Partner_deal which has lots of fields but the only one you really need to know about is called quantity which is an integer that specifies how many times the deal can be redeemed.
I then have another model Partner_deal_redemption to keep track of the redemptions. This has a partner_deal_id column and a user_id column to record which users have redeemed which deal.
I want to create a scope in my Partner_deal model so that it will only return deals where the number of redemptions is less than the quantity field.
I know how to do this in MySql by doing a subquery that counts how many redemptions each deal has had and uses a HAVING clause to filter out the ones where the number of redemptions = quantity.
I have no idea where to begin doing this in eloquent, this is my best attempt:
function scopeNotRunOut($query)
{
return $query->having('quantity', '>', function($q)
{
$q->from('partner_deal_redemptions')
->selectRaw('count(*)')
->where('partner_deal_id', '=', 'id');
});
}
You can probably use the has() function of Eloquent:
http://laravel.com/docs/5.0/eloquent#querying-relations
function scopeNotRunOut($query)
{
return $query->has('redemptions', '<', DB::raw('quantity'));
}
To use this function you need to define the redemptions function in your Partner_deal model, which will represent the relation between the Partner_deal and the Partner_deal_redemption models.
MrShibby was correct but then I realised I needed to check if quantity was null as well so I modified his solution slightly to the following:
function scopeNotRunOut($query)
{
return $query->where(function($q) {
$q->orHas('redemptions', '<', DB::raw('quantity'))
->orWhere('quantity', '=', null);
});
}
I'm stuck at the moment and hope someone can give me a hand. I'm using a polymorphic relation and want to search my database for rows that fulfill conditions in the "parent" and the "child" table.
To get concrete, one small example. Given the following structure I e.g. want to look for a property with price "600" and rooms "3". Is there a way to do that with eloquent?
Tables
Table properties (parent)
id
price
details_type [can be "Apartment" or "Parcel"]
details_id
Table apartments (child)
id
rooms
Table parcels (child)
id
... (does not have a "rooms" column)
Relationships
Class Property
public function details() {
return $this->morphTo();
}
Classes Apartment + Parcel
public function property() {
return $this->morphMany('Property', 'details')
}
What I tried
A lot, really. But somehow I'm always doing something wrong or missing something. The solutions that, in my opinion should work are either:
Property::with(array('details' => function($query) {
$query->where('rooms', 3);
}));
or
Property::with('details')
->whereHas('details', function($query) {
$query->where('rooms', '=', '3');
});
But in both cases I get the following FatalError.:
Class name must be a valid object or a string
Has anyone of you already had a similar problem? Thank you very much for any kind of hint.
Let's start with your naming convention:
public function detail() // It relates to a single object
{
return $this->morphTo();
}
And
public function properties() // It relates to several objects
{
return $this->morphMany('Property', 'details')
}
Then you would be able to do this:
$properties = Property::whereHas('details', function($q)
{
$q->where('rooms', '=', '3');
})
->where('price', '=', 600)
->get();
Please note that this will never return a Parcel, since there isn't a parcel with a room.