I'm building a PM system, and I have a problem.
This is my PM table:
id, user_id, to, content
Now, in my inbox page I'm fetching all the users that sent me a message.
$pms = DB::table('pm')->select('user_id')->distinct()->where('to', Auth::id())->get();
The problem is if I add more columns to the select method, it won`t be distinct anymore..
You can easily do that using Eloquent and its whereHas() method.
First, define models and the relation in your model:
class Message extends Model {
protected $table = 'pm';
}
class User extends Model {
public function sent_messages() {
return $this->hasMany(Message::class);
}
}
Now, fetch all users that have a related Message models where to column matches your ID:
$usersThatSentMeMessages = User::whereHas('sent_messages', function($query) {
$query->where('to', Auth::id());
});
Related
I have two models which are connected each other.
class Company extends Model {
public function addresses() {
return $this->belongsToMany('\App\Address', 'address_mapping', 'uid_company', 'uid_address');
}
}
class Address extends Model {
}
In my JOIN table I have a column named active. How can I fetch all active addresses from the company? Or how can I implement a where-clause in the JOIN table?
Thank you!
The table that you call a "JOIN table", usually called a pivot table.
You can fetch all active records by using wherePivot method:
$company = Company::first();
$activeAdresses = $company->addresses()->wherePivot('active', 1);
Or you can directly define the relationship in your model:
class Company extends Model {
public function activeAddresses() {
return $this->belongsToMany('\App\Address', 'address_mapping', 'uid_company', 'uid_address')
->wherePivot('active', 1);
}
}
See section Filtering Relationships Via Intermediate Table Columns in Eloquent documentation
I have a Conversation model like this :
class Conversation extends Model
{
protected $primaryKey = 'conversation_id';
public function questions (){
return $this->hasMany('App\Question','conversation_id','conversation_id');
}
public function latestQuestion ()
{
return $this->hasOne('App\Question','conversation_id','conversation_id')
->orderBy('created_at', 'desc');
}
}
And a Question model like this :
class Question extends Model
{
protected $primaryKey = 'question_id';
public function conversation ()
{
return $this->belongsTo('App\Conversation', 'conversation_id', 'conversation_id');
}
}
As you can see each Conversation can have some Question.
Furthermore, Conversation model has a latestQuestion relationship that fetches latest Question for that Conversation.
Now I want to list all Conversations with their latest question.
For that I wrote :
$conversations =
Conversation::
with('latestQuestion')
->orderBy('created_at','desc')
->get();
above code, orders conversations by their created_at field.
But I want to make a list of Conversations that conversations with new question be on top of list. in fact I want to order Conversations based On latest Question created_at field But I do not know How can I do that?
You need to use Join Query. Because Eager Loading will just bring the base table and fetch the referenced table records later
Conversation::join('questions', 'conversations.conversation_id', '=', 'questions.conversation_id')
->orderBy('questions.created_at','Desc')
->groupBy('conversations.conversation_id')
->get();
I have the usual users, groups and group_user tables. I know the raw SQL that I want:
SELECT group_user.group_id, users.* FROM users
INNER JOIN group_user ON users.id = group_user.user_id
WHERE group_user.group_id IN
(SELECT group_id FROM group_user WHERE user_id=?)
ORDER BY group_user.group_id;
where ? is replaced current user's id.
but, I want to use Eloquent (outside of laravel) for this. I have tried using a User model with a groups method
public function groups() {
return $this->belongsToMany('\Smawt\User\Group');
}
and a Membership model with a users method
public function users($group_id) {
return $this->where('group_id', '=', $group_id)->get();
}
and then I loop through the groups and then loop through all its members. Finally, I append all the data to get one $users object at the end, to pass through to my view.
$thisMembership = new Membership;
$myGroups = $app->auth->groups;
$users = [];
foreach ($myGroups as $myGroup) {
foreach ($thisMembership->users($myGroup->id) as $myUser) {
$thisUser = $app->user->where('id', '=', $myUser->user_id)->first();
$thisUser->group_id = $myGroup->id;
array_push($users, $thisUser);
}
}
Then in my view I loop through my $users as normal. Although this method works, it will not be very efficient as I am unable to work out how to use Eager Loading with it.
Is there a simpler more 'Eloquent' way of getting an object of users who are in the same group as the current user? I don't want just want a list, or an array, as I want to use the other methods defined in my user model.
I have been able to construct the following Eloquent query, although I am not sure this is the 'best' way:
$users = User::join('group_user', 'users.id', '=', 'group_user.user_id')
->whereIn('group_user.group_id', function($query) {
$query->select('group_id')
->from('group_user')
->where('group_user.user_id', '=', $_SESSION['user_id']);
})->orderBy('group_id', 'asc')
->get();
The Eloquent way for the relationship and use of it:
Tables: users, groups
Models: User Group
Pivot Table: group_user (id, user_id, group_id)
In User Model:
public function groups()
{
// pivot table name and related field
// names are optional here in this case
return $this->belongsToMany('Group');
}
In Group Model:
public function users()
{
// pivot table name and related field
// names are optional here in this case
return $this->belongsToMany('User');
}
Use Case (Example):
$usersWithGroup = User::with('groups')->find(1); // or get()
$groupWithUsers = Group::with('users')->find(1); // or get()
For more information check Eloquent section on documentation.
Update:
If user belongsto any group
$usersWithGroup = User::has('groups')->with('groups')->find(1);
Also using if a user belongs to specific group:
$someGroup = 'general';
$usersWithGroup = User::whereHas('groups', function($q) use($someGroup) {
$q->where('group_name', $someGroup);
})
->with('groups')->find(1);
A Venue has many Subscriptions.
A Subscription has many Subscribers (User).
Theres a pivot table, containing the relation between user_id and subscription_id.
How can I get all Subscribers from a Venue?
I have tried with:
class Venue {
/**
* Members
*/
public function members() {
return $this->hasManyThrough('App\User', 'App\Subscription');
}
}
But it fails with MySQL error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'users.subscription_id' in 'on clause' (SQL: select `users`.*, `sub
scriptions`.`venue_id` from `users` inner join `subscriptions` on `subscriptions`.`id` = `users`.`subscription_id` where `
users`.`deleted_at` is null and `subscriptions`.`venue_id` = 1)
How my Subscription model look:
`Subscription`
class Subscription extends Model {
protected $table = 'subscriptions';
/**
* Subscripers
*/
public function subscribers() {
return $this->belongsToMany('App\User');
}
/**
* Venue
*/
public function venue() {
return $this->belongsTo('Venue');
}
}
Simple question: Why are you using a third model for Subscriptions? It sounds like a normal n:m relation between User and Venue, as already written in the comments above.
class User {
public function venues() {
return $this->belongsToMany('App\Venue');
}
}
class Venue {
public function users() {
return $this->belongsToMany('App\User');
}
}
This constellation actually needs three tables, which are (i gave each model a column name):
users
- id
- name
venues
- id
- name
user_venue
- user_id
- venue_id
But to access the relations, you can simply use the Eloquent magic:
// List of all venues (as Venue models) that are in relation with User with id $id
$venues = User::find($id)->venues()->get();
// Returns the alphabetically first user that has a relation with Venue with id $id
$user = Venue::find($id)->users()->orderBy('name', 'asc')->first();
If you need to store additional information in the pivot table (e.g. when the relation has been established), you can use additional pivot fields:
user_venue
- user_id
- venue_id
- created_at
class User {
public function venues() {
return $this->belongsToMany('App\Venue')->withPivot('created_at');
}
}
class Venue {
public function users() {
return $this->belongsToMany('App\User')->withPivot('created_at');
}
}
// Returns the date of the relations establishment for the alphabetically
// first Venue the User with id $id has a relation to
$created_at = User::find($id)->venues()->orderBy('name', 'asc')->first()->pivot->created_at;
I've never tried to do whatever you are trying to do there, because it seems (with the current information) conceptually wrong. I also don't know if it is possible to set up an own model for a pivot table, but I think it should work if the pivot table has an own primary id column. It could probably be helpful if you've a third model that needs to be connected with a connection of two others, but normally that doesn't happen. So try it with pivot tables, like shown above, first.
Alright, I still don't see a good use case for this, but I can provide you a query that works. Unfortunately I wasn't able to get an Eloquent query working, but the solution should be still fine though.
class Venue {
public function members($distinct = true) {
$query = User::select('users.*')
->join('subscription_user', 'subscription_user.user_id', '=', 'users.id')
->join('subscriptions', 'subscriptions.id', '=', 'subscription_user.subscription_id')
->where('subscriptions.venue_id', '=', $this->id);
if($distinct === true) {
$query->distinct();
}
return $query;
}
}
The relation can be queried just as normal:
Venue::find($id)->members()->get()
// or with duplicate members
Venue::find($id)->members(false)->get()
I have the following tables:
Users
Games
Characters
A user will have one active game at a time, and from that game, will have one active character.
I want to perform the following joi on my authentication table:
SELECT * FROM users
LEFT OUTER JOIN games ON games.ID = users.active_gameid
LEFT OUTER JOIN characters ON characters.ID = games.active_charid
Try to ignore the SELECT * part.
I'd like to perform these joins on my Auth table as soon as the page loads, so I have been using my User model to do the following:
class User extends Eloquent implements UserInterface, RemindableInterface {
public function game() {
return $this->hasOne('game', 'ID', 'active_gameid');
}
}
class game extends Eloquent {
protected $table = "games";
public function character() {
return $this->hasOne('character', 'ID', 'active_charid');
}
}
class character extends Eloquent {
protected $table = "characters";
}
The above doesn't work as outputting the following just returns a NULL value:
var_dump(Auth::user()->game->character);
I have tried to do the obvious checks such as making sure the data is in the table and such and that all seems fine.
Does anyone have any help on where I'm going wrong?
Thank you!
Your relations are wrong:
// User model
public function game()
{
return $this->belongsTo('Game', 'active_gameid', 'ID');
}
// Game model
public function character()
{
return $this->belongsTo('Character', 'active_charid', 'ID');
}
and obviously it won't call your query, but 2 separate queries:
Auth::user()
->game // SELECT * FROM games WHERE ID = ?
->character; // SELECT * FROM characters WHERE ID = ?