I've a messaging system (1v1) on my website and I want to join some informations about my interlocutor (name, avatar, etc.).
My structure is more than common:
Threads:
Schema::create('threads', function (Blueprint $table) {
$table->increments('id');
//...
});
Participants:
Schema::create('participants', function (Blueprint $table) {
$table->increments('id');
$table->integer('thread_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->foreign('thread_id')->references('id')->on('threads')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
To get my Threads I've this query:
Thread::select(
'users.name',
'threads.id',
//...
)->join('participants', 'participants.id', '=', 'threads.id')
->join('users', 'users.id', '=', 'participants.user_id')
->where('participants.user_id', '=', $user->id)
->get();
Of course, because of my where condition, it's my name and not the name of my interlocutor. How can I join the informations of my interlocutor and "exclude" mine?
PS: Please don't give me a messaging system package. I want to code it myself.
Edit:
Relation in my model Thread :
public function users()
{
return $this->belongsToMany('App\User', 'participants', 'thread_id', 'user_id');
}
public function participants()
{
return $this->hasMany('App\Participant', 'thread_id', 'id');
}
Edit 2:
#Jonas Staudenmeir code:
$threads = Thread::select(
'threads.id',
'threads.last_sender',
'threads.is_read',
'threads.last_message',
'threads.date'
)->whereHas('users', function($query) use($user) {
$query->where('users.id', $user->id);
})->with('users')->get();
foreach($threads as $thread) {
$interlocutor = $thread->users->where('users.id', '!=', $user->id)->first();
}
Trying to get the fields I only need:
$threads = Thread::select(
'threads.id',
'threads.last_sender',
'threads.is_read',
'threads.last_message',
'threads.date'
)->whereHas('users', function($query) use($user) {
$query->select('users.id') // May be its gonna run faster
->where('users.id', $user->id);
})->with('users')->get();
foreach($threads as $thread) {
$interlocutor = $thread->users->select(
'id',
'name',
...
)->where('users.id', '!=', $user->id)->first();
}
$intercolutor give me this error : Method Illuminate\Database\Eloquent\Collection::select does not exist.
Try this:
$threads = Thread::select('id', 'last_sender', 'is_read', 'last_message', 'date')
->whereHas('users', function($query) use($user) {
$query->where('users.id', $user->id);
})
->with('users:users.id,name,avatar')
->get();
foreach($threads as $thread) {
$interlocutor = $thread->users->where('id', '!=', $user->id)->first();
}
Related
I have this query:
$result = PortingItem::whereHas('porting', function ($query) {
$query->whereIn('status', [
Porting::STATUS_REQUESTED,
Porting::STATUS_ACCEPTED,
Porting::STATUS_DELAYED,
]);
})->where(function ($query) use ($numbers) {
$query->whereBetween('phone_number_start', [$numbers[0], $numbers[1]])
->orWhereBetween('phone_number_end', [$numbers[0], $numbers[1]]);
})->orWhere([
['phone_number_start', '<=', $numbers[0]],
['phone_number_end', '>=', $numbers[1]],
])->get();
The PortingItem model still returns the query result while the porting relation is empty. I don't understand why this happens.
This is my Porting model relation
public function items()
{
return $this->hasMany(PortingItem::class);
}
This is my PortingItem model relation:
public function porting()
{
return $this->belongsTo(Porting::class);
}
You should always group orWhere calls in order to avoid unexpected behavior when global scopes are applied.
$result = PortingItem::whereHas('porting', function ($query) {
$query->whereIn('status', [
Porting::STATUS_REQUESTED,
Porting::STATUS_ACCEPTED,
Porting::STATUS_DELAYED,
]);
})->where(function ($query) use ($numbers) {
$query->where(function ($query) use ($numbers) {
$query->whereBetween('phone_number_start', [$numbers[0], $numbers[1]])
->orWhereBetween('phone_number_end', [$numbers[0], $numbers[1]]);
})->orWhere(function ($query) use ($numbers) {
$query->where('phone_number_start', '<=', $numbers[0])
->where('phone_number_end', '>=', $numbers[1]);
});
})->get();
https://laravel.com/docs/8.x/queries#logical-grouping
All the rest of the functionality works fine, follow and latest but for some reason it won't filter the likes. I think it is the count method, but if I do likes->count() I end up with too many queries, any solutions for this?
public function index(Request $request) {
$search = request()->input('title');
$posts = Post::query()->latest();
if ($search) {
$posts->where('title', 'LIKE', '%' . request()->title. '%');
} elseif ($request->has('likes')) {
$posts->withCount('likes')->orderByDesc('likes_count');
} elseif ($request->has('latest')) {
$posts->orderByDesc('created_at');
} elseif ($request->has('follow')) {
$posts->whereIn('user_id', $request->user()->following()->pluck('users.id'));
}
return view('welcome', [
'posts' => $posts->withCount(['comments', 'likes'])->paginate(12)
]);
}
Schema::create('likes', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->foreignId('post_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
This is the issue
$posts = Post::query()->latest();
"->latest()" is already sorting by date.
If you take it out, it should work just fine.
I have a problem with ordering by columns in subquery (lastname, firstname).
I already tried this code as suggested by other posts:
->with(['customer' => function ($query) {
$query->orderBy("lastname", "asc")
->orderBy("firstname", "asc");
}])
Here my full code, but it doesn't work.
return Membership::forCompany($companyId)
->whereIn('state', ['ATTIVA', 'IN ATTESA DI ESITO', 'DA INVIARE'])
->where(function ($query) {
$query->where('end_date', '>=', Carbon::now()->toDateString())
->orWhereNull('end_date');
})
->with('federation')
->with(['customer' => function ($query) {
$query->orderBy("lastname", "asc")
->orderBy("firstname", "asc");
}]);
Here the relationships:
In customer model I have:
public function memberships() {
return $this->hasMany('App\Models\Membership');
}
In Membership model I have:
public function customer() {
return $this->belongsTo("App\Models\Customer");
}
Try orderBy() with join() like:
$memberships = \DB::table("memberships")
->where("company_id", $companyId)
->where(function ($query) {
$query->where('end_date', '>=', Carbon::now()->toDateString())
->orWhereNull('end_date');
})
->join("customers", "memberships.customer_id", "customers.id")
->select("customers.*", "memberships.*")
->orderBy("customers.lastname", "asc")
->get();
dd($memberships);
Let me know if you are still having the issue. Note, code not tested! so you may need to verify by yourself once.
I'd like to find
Project::with('tasks.tags')->get();
where only projects with a particular id of tag return in the result set.
For ex. I'd like to find a project with tasks and tasks with tags with only id of 1. In other words, filter the tasks return inside of the Project - Task relationship.
I have tried various ways but have failed so far.
I have tried:
$project = Project::with('tasks.tags')->whereHas('tasks', function($query){
$query->whereHas('tags', function($query) {
$query->where('id', 1);
});
})->get();
And:
$project = Project::with('tasks.tags')->whereHas('tasks', function($query){
$query->whereHas('tags', function($query) {
$query->where('tag_id', 1);
});
})->get();
This is how the relationships are setup:
In Project.php
public function tasks()
{
return $this->hasMany(Task::class, 'project_id')->setEagerLoads([]);
}
In Task.php
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable')->setEagerLoads([]);
}
Note that relationship between Task and Tags is of morphToMany.
Any pointers?
You would need to scope the eager loading as well. Something like the following should work:
$project = Project::with(['tasks.tags' => function ($query) {
$query->where('id', 1);
}])->whereHas('tasks', function ($query) {
$query->whereHas('tags', function ($query) {
$query->where('id', 1);
});
})->get();
Found the answer over here.
Project::with(['tasks' => function($q) {
$q->whereHas('tags', function($query) {
$query->where('tag_id', 1);
});
}])->get();
I'm building a small application on laravel 5.5 where I'm retrieving models with the relationship absence, something like this:
$milestone = Milestone::where('unique_id', $request->id)
->whereDoesntHave('block')
->first();
This is working fine but when I convert milestone variable to an array I'm getting absurd results, I tried:
$milestone = Milestone::where('unique_id', $request->id)
->whereDoesntHave('block', function ($q) use($request){
foreach($request->milestone as $m)
$q->where('unique_id', $m);
})
->first();
Edit:
Following is my relationship:
Milestone Model:
public function block()
{
return $this->morphMany('App\Models\Team\Block', 'block');
}
Block Model:
public function block()
{
return $this->morphTo();
}
and my block database table:
Schema::create('blocks', function (Blueprint $table) {
$table->increments('id');
$table->string('unique_id');
$table->string('block_type');
$table->integer('block_id');
$table->integer('generic_id');
$table->string('type');
$table->integer('user_id');
$table->timestamps();
$table->softDeletes();
});
Help me out in this, Thanks
You should use whereIn rather than a foreach with multiple where clauses. I.e.
$q->whereIn('unique_id', $mArray);
If you chain the where clauses together, those are AND where clauses. As an example
App\Models\User::where('id', 1)->where('id', 2)->toSql();
"select * from `users` where `id` = ? and `id` = ?"
App\Models\User::whereIn('id', [1,2])->toSql();
"select * from `users` where `id` in (?, ?)"
the former gives no results, while the latter gives the results you might expect
Chain whereDoesntHave():
$milestone = Milestone::where('unique_id', $request->id);
foreach($request->milestone as $m) {
$milestone = $milestone->whereDoesntHave('block', function ($q) use($m) {
$q->where('unique_id', $m);
});
}
$milestone = $milestone->first();
Or use whereHas() with whereNotIn():
$milestone = Milestone::where('unique_id', $request->id)
->whereHas('block', function ($q) use($request) {
$q->whereNotIn('unique_id', $request->milestone);
})
->first();