Calling 2 joined functions in one Model - laravel

I want to know how to chain two scopes from my Match model, here are the two scopes:
public function scopeMainMatches($query){
return $query->where('matches.type','main');
}
public function scopeDotaMatches($query,$type){
return $query
->join('leagues','leagues.id','=','matches.id')
->select('matches.*')
->where('leagues.type',$type);
}
here is my Controller which returns the ID league of the table leagues:
public function showDotaMatches($ptr){
$_matches = \App\Match::mainMatches()
->whereNotIn('status',['ongoing','open'])
->get()
->load('league','teamA', 'teamB')
->where('league_id','1')
->sortByDesc('schedule')
->slice($ptr, 10);
what I want to happen is this:
public function showDotaMatches($ptr,$request){
$_matches = \App\Match::mainMatches()
->dotaMatches($request-type)
->where('leagues.type','dota2') // instead of ('league_id','1')
to make the code clean. but when I did chain the two scopes, it says SQL constraint violation since both matches table and leagues table has status and type in it. anyone who can help me with this?

I think you're after a whereHas query:
// Retrieve all matches with at least one league with the type 'dota2'
$matches = App\Match::whereHas('leagues', function ($query) {
$query->where('type', 'dota2');
})->get();
You then wouldn't need your join in scopeDotaMatches.

Related

Get only one column from relation

I have found this: Get Specific Columns Using “With()” Function in Laravel Eloquent
but nothing from there did not help.
I have users table, columns: id , name , supplier_id. Table suppliers with columns: id, name.
When I call relation from Model or use eager constraints, relation is empty. When I comment(remove) constraint select(['id']) - results are present, but with all users fields.
$query = Supplier::with(['test_staff_id_only' => function ($query) {
//$query->where('id',8); // works only for testing https://laravel.com/docs/6.x/eloquent-relationships#constraining-eager-loads
// option 1
$query->select(['id']); // not working , no results in // "test_staff_id_only": []
// option 2
//$query->raw('select id from users'); // results with all fields from users table
}])->first();
return $query;
In Supplier model:
public function test_staff_id_only(){
return $this->hasMany(User::class,'supplier_id','id')
//option 3 - if enabled, no results in this relation
->select(['id']);// also tried: ->selectRaw('users.id as uid from users') and ->select('users.id')
}
How can I select only id from users?
in you relation remove select(['id'])
public function test_staff_id_only(){
return $this->hasMany(User::class,'supplier_id','id');
}
now in your code:
$query = Supplier::with(['test_staff_id_only:id,supplier_id'])->first();
There's a pretty simple answer actually. Define your relationship as:
public function users(){
return $this->hasMany(User::class, 'supplier_id', 'id');
}
Now, if you call Supplier::with('users')->get(), you'll get a list of all suppliers with their users, which is close, but a bit bloated. To limit the columns returned in the relationship, use the : modifier:
$suppliersWithUserIds = Supplier::with('users:id')->get();
Now, you will have a list of Supplier models, and each $supplier->users value will only contain the ID.

Eloquent Removing Columns

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);
}

Eloquent query all the latest records for each id

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.

How to add condition in connection tables?

I have two tables: Users and Images.
So, a user can have some images.
For this relationship I have additional function in model User:
public function images()
{
return $this->hasMany('App\Images', 'idElement', 'id');
}
And in controller I have:
$users = Users::where('id', $id)->with("images")->get();
How can I add additional condition in controller for images table that will be "where images.type = 1"?
Now this tables are connected only by primary keys, but I need to set a new condition yet.
You can filter your images with callback function, try this:
$users = Users::where('id', $id)->with(["images" => function ($query){
$query->where('type', 1);
}])->get();
For something like this, where you want to scope down a subset of images based on their type, you can add another method called something like public function scopedImages() and define it as such:
public function scopedImages() {
return $this->hasMany('App\Images', 'idElement', 'id')->where("images.type", "=", 1);
}
In your controller, you would access this function the same as you would the images() function on User:
$users = Users::where('id', $id)->with(["scopedImages"])->get();
Keep the function images() as well, so if you need to find all images attached to a User, but adding additional functions like this gives you flexibility on what you want to return and when.

Laravel / Eloquent: Search for rows by value in polymorphed table

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.

Resources