how can i do that with function in model?
Select * from friends where (user_id = 22 or content_id = 22) and type=2 and situation = 1;
i try that, but it gives error;
public function friends() {
return $this->hasMany('Friends',function ($query) {
$query->where('content_id', $this->attributes['id']);
$query->orWhere('user_id',$this->attributes['id']);
})->where('type',2)->where('situation',1)->orderBy('id','DESC');
}
First, is your model name 'Friends' or just 'Friend'? Assuming you're following convention and using the singular tense for your model names, this should work:
return $this->hasMany('Friend')->where(function($query) {
$query->where('content_id', $this->attributes['id']);
$query->orWhere('user_id',$this->attributes['id']);
})->where('type',2)->where('situation',1)->orderBy('id','DESC');
in other words, add your additional query parameters following the hasMany() relationship, not as a closure for the second argument.
Related
i have made indirect relation from one model to another in couple of my models.
this is my Work Model:
public function GeoEntities()
{
return $this->hasMany(\App\GeoEntity::class);
}
public function geoLand()
{
$builder = $this->GeoEntities()->where("entity_type", 0);
$relation = new HasOne($builder->getQuery(), $this, 'work_id', 'id');
return $relation;
}
public function geoLandPoints()
{
return $this->geoLand->geoPoints();
}
this return $this->intermediateModel->FinalModel(); would work, if intermediate relation is belongsTo() and returns a relation instance.
but in this case, when geoLand is Empty it produce error:
Call to a member function geoPoints() on null
like below line:
$points = $work->geoLandPoints;
The Intermediate Relation is a hasMany
i want to have this like relation call geoLandPoints and not geoLandPoints() but,
when intermidate models are null, i want an empty relation.
but i can not figure it out, how to achieve this.
with Fico7489\Laravel\EloquentJoin\Traits\EloquentJoin
using Fico7489\Laravel\EloquentJoin\Traits\EloquentJoin package, i have tried to refactor relation like below:
public function geoLandPoints()
{
$builder = $this
->select("works.*")
->join("geo_entities", "works.id", "geo_entities.work_id")
->join("geo_points", "geo_entities.id", "geo_points.geo_entity_id")
->where("entity_type", 0)
->where("works.id", $this->id);
return new HasMany($builder->getQuery(), $this, "work_id", "id");
}
but it couldn't convert Database Query Builder to Eloquent Query Builder.
Argument 1 passed to
Illuminate\Database\Eloquent\Relations\HasOneOrMany::__construct()
must be an instance of Illuminate\Database\Eloquent\Builder, instance
of Illuminate\Database\Query\Builder given
Why don't you use the hasOne() method instead of trying to return your own HasOne class? Also, you can use withDefault() so the relationship returns an empty GeoEntity instead of null.
public function geoLand()
{
return $this->hasOne(\App\GeoEntity::class)->where("entity_type", 0)->withDefault();
}
You could even pass an array of default values. withDefault(['column' => 'value', 'column2' => 'value2', ...])
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.
Is it possible to make Laravel relation through belongsToMany relations?
I have 4 tables:
1)Restaurants (id , name) - uses hasManyRelation with Workers table
2)Directors (id , name)
3)Directors_Restaurants (id, director_id, restaurant_id) - pivot table for connecting belongsToMany Restaurants with Directors
3)Workers (id, name, restaurant_id)
With this function in Directors model i can get all connected restaurants
public function restaurants()
{
return $this->belongsToMany('App\Restaurant','director_restaurant');
}
With this function in my code i can get all workers of all restaurants of one director
$director = Director::find(1);
$director->load('restaurants.workers');
$workers = $director->restaurants->pluck('workers')->collapse();
So my question is : can i declare similar relation in my Director model to get all its workers of all its restaurants?
Of course you can have hasMany relationship method on Director model with Eager Loading
just like below
public function restaurants()
{
return $this->hasMany(Restaurant::class)->with('restaurants.workers');
}
i can suggest a solution like this:
Director Model OPTION 1
public function getAllRestaurants(){
return $this->hasMany(Restaurant::class)->with('restaurants.workers');
}
Director Model OPTION 2
public function getAllRestaurants(){
$this->load('restaurants.workers');
return $this->restaurants->pluck('workers')->collapse();
}
You can get all restaurants anywhere
$all_restaurants = Director::find(1)->getAllRestaurants();
You can define a direct relationship by "skipping" the restaurants table:
class Director extends Model
{
public function workers()
{
return $this->belongsToMany(
Worker::class,
'director_restaurant',
'director_id', 'restaurant_id', null, 'restaurant_id'
);
}
}
You can define an accessor method in your model to hide some of the logic
# App/Director.php
// You'll need this line if you want this attribute to appear when you call toArray() or toJson()
// If not, you can comment it
protected $appends = ['workers'];
public function getWorkersAttribute()
{
return $this->restaurants->pluck('workers')->collapse();
}
# Somewhere else
$director = Director::with('restaurants.workers')->find(1);
$workers = $director->workers;
But ultimately, you still have to load the nested relationship 'restaurants.workers' for it to work.
Given your table attributes you could also define a custom HasMany relationship that looks like this
# App/DirectorRestaurant.php
public function workers()
{
return $this->hasMany(Worker::class, 'restaurant_id', 'restaurant_id');
}
# Somewhere else
$director = Director::find(1);
$workers = DirectorRestaurant::where('director_id', $director->id)->get()->each(function($q) { $q->load('workers'); });
But I don't recommend it because it's not very readable.
Lastly, there's the staudenmeir/eloquent-has-many-deep package where you can define that sort of nested relationship.
https://github.com/staudenmeir/eloquent-has-many-deep
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.
On my User model I have the following:
public function isOnline()
{
return $this->hasMany('App\Accounting', 'userid')->select('rtype')->latest('ts');
}
The accounting table has activity records and I'd like this to return the latest value for field 'rtype' for a userid when used.
In my controller I am doing the following:
$builder = App\User::query()
->select(...fields I want...)
->with('isOnline')
->ofType($realm);
return $datatables->eloquent($builder)
->addColumn('info', function ($user) {
return $user->isOnline;
}
})
However I don't get the value of 'rtype' for the users in the table and no errors.
It looks like you're not defining your relationship correctly. Your isOnline method creates a HasMany relation but runs the select method and then the latest method on it, which will end up returning a Builder object.
The correct approach is to only return the HasMany object from your method and it will be treated as a relation.
public function accounts()
{
return $this->hasMany('App\Accounting', 'userid');
}
Then if you want an isOnline helper method in your App\User class you can add one like this:
public function isOnline()
{
// This gives you a collection of \App\Accounting objects
$usersAccounts = $this->accounts;
// Do something with the user's accounts, e.g. grab the last "account"
$lastAccount = $usersAccounts->last();
if ($lastAccount) {
// If we found an account, return the rtype column
return $lastAccount->rtype;
}
// Return something else
return false;
}
Then in your controller you can eager load the relationship:
$users = User::with('accounts')->get(['field_one', 'field_two]);
Then you can do whatever you want with each App\User object, such as calling the isOnline method.
Edit
After some further digging, it seems to be the select on your relationship that is causing the problem. I did a similar thing in one of my own projects and found that no results were returned for my relation. Adding latest seemed to work alright though.
So you should remove the select part at very least in your relation definition. When you only want to retrieve certain fields when eager loading your relation you should be able to specify them when using with like this:
// Should bring back Accounting instances ONLY with rtype field present
User::with('accounts:rtype');
This is the case for Laravel 5.5 at least, I am not sure about previous versions. See here for more information, under the heading labelled Eager Loading Specific Columns
Thanks Jonathon
USER MODEL
public function accounting()
{
return $this->hasMany('App\Accounting', 'userid', 'userid');
}
public function isOnline()
{
$rtype = $this->accounting()
->latest('ts')
->limit(1)
->pluck('rtype')
->first();
if ($rtype == 'Alive') {
return true;
}
return false;
}
CONTROLLER
$builder = App\User::with('accounting:rtype')->ofType($filterRealm);
return $datatables->eloquent($builder)
->addColumn('info', function (App\User $user) {
/*
THIS HAS BEEN SUCCINCTLY TRIMMED TO BE AS RELEVANT AS POSSIBLE.
ARRAY IS USED AS OTHER VALUES ARE ADDED, JUST NOT SHOWN HERE
*/
$info[];
if ($user->isOnline()) {
$info[] = 'Online';
} else {
$info[] = 'Offline';
}
return implode(' ', $info);
})->make();