Laravel Eloquent relationships and connecting multiple tables - php

I am trying to build a messaging system for a job site using Laravel 5 and using the Eloquent ORM. The basic premise is that someone posts up a job, and people can respond to that job via a message. The MySQL database is structured as so:
**users table**
id
username
password
**jobs table**
id
user_id (FK with id on Users table)
slug
title
description
**conversations table**
id
job_id (FK with id on Jobs table)
**messages table**
id
conversation_id (FK with conversations table)
user_id (FK with id on users table)
message
last_read
**conversation_user table**
conversation_id (FK with id on Conversation table)
user_id (FK with id on Users table)
When a user finds a job they like, they can send a message to the job creator which will in turn create a new conversation. The newly created conversation id is then used passed to the messages table (alongside the message text itself) and then the conversation_user pivot table is updated with the conversation id as well as the two users who are participating in the conversation (i.e. the person who posted the job and the person sending the message)
I have a model for each table and a summary of the relationships are:
**Job.php**
HasMany - Conversation model
BelongsTo - User model
**Conversation.php**
BelongsTo - Job model
HasMany - Message model
BelongsToMany - User model
**Message.php**
BelongsTo - Conversation model
BelongsTo - User model
**User.php**
HasMany - Job model
HasMany - Message model
BelongsToMany - Conversation model
I have setup a query scope in Conversation.php (my Eloquent model for the Conversations table) which accomplishes the task of displaying the conversations that the authenticated user is participating in:
public function scopeParticipatingIn($query, $id)
{
return $query->join('conversation_user', 'conversations.id', '=', 'conversation_user.conversation_id')
->where('conversation_user.user_id', $id)
->where('conversation_user.deleted_at', null)
->select('conversations.*')
->latest('updated_at');
}
and via my Conversations Repository, I pass on the results of the query scope to my view in my MessagesController like so:
public function __construct(ConversationInterface $conversation)
{
$this->middleware('auth');
$this->conversation = $conversation;
}
public function index()
{
$currentUser = Auth::id();
$usersConversations = $this->conversation->ParticipatingIn($currentUser, 10);
return view('messages.index')->with([
'usersConversations' => $usersConversations
]);
}
and for reference the ConversationInterface is bounded to my ConversationsRepo:
public $conversation;
private $message;
function __construct(Model $conversation, MessageInterface $message)
{
$this->conversation = $conversation;
$this->message = $message;
}
public function participatingIn($id, $paginate)
{
return $this->conversation->ParticipatingIn($id)->paginate($paginate);
}
My question is, given I have what I believe are the right relationships, how I can pass the title of the specific job from the job_id on the conversations table and also the first few words of the last message that was sent within the conversation?

I'm sorry if I'm stating the obvious, but:
Conversation model belongs to Job Model. As you already has the conversation object/id, just do this:
//Controller
$conversation = App\Conversation::find($id);
return view('your view', compact('conversation'));
//View
$conversation->job->title; //the conversation belongs to a job, so requesting the job will return an instance of the job model, which can be asked for the title.
You can also use this on the view to get the first chars from the message:
substr($conversation->messages->last()->message,0,desired lenght);

Related

How to get all books from another table when using many to many relationship Laravel / Eloquent / Query builder

Let me explain the scenario.
i have tables:
competitions
id title body
then
books
id name user_id
then i have a pivot table to store participants
so
participants
id competition_id user_id
Now i have set some relationships for these models.
Competition model
public function participants()
{
return $this->belongsToMany('App\User');
}
User model
public function participatedCompetitions()
{
return $this->belongsToMany('App\Competition');
}
Now i am fetching one single competition and in that same query i need to fetch a list of books of the participants of that competition.
So how can i achieve this.
Thanks.
Here is how you get all the books:
$userIds = $competition->participant()->get()->pluck('id');
// $userIds is your collection of User Ids that is participant in that compititions.
$books = Book::whereIn('user_id',$userIds)->get();

Laravel 5.5 HasManyThrough Relationship

I have the following database:
teams
-----
id
user_id
users
-----
id
pages
-----
id
user_id
team_id -> (nullable)
So a User can create a Team, and create a Page
Currently, I have the following relationships setup (replace with $this)
teams_owned() -> $user->hasMany(Team::class); // Teams a user owns
pages() -> $user->hasMany(Page::class); // Page a user created
user() -> $team->belongsTo(User::class); // User who created team
user() -> $page->belongsTo(User::class); // User who created the Page
However, a User can join a team by creating a Page for that team. In this case the pages table will fill in the team_id. Where a page is created and is not for a team, the team_id value will be null
I wanted to add a relationship for User to get the Teams joined. As explained above, you are part of Team if you have created a Page for it.
I have tried the following:
public function teams_joined()
{
return $this->hasManyThrough(Team::class, FundraisingPage::class);
}
I'm not sure if I should be using a HasManyThrough in this situation
As a backup I have the following:
public function teams_joined()
{
$uniqueTeamIds = $this->pages()->onlyForTeams()->get()->pluck('id')->unique();
return Team::whereIn('id', $uniqueTeamIds)->get();
}
where onlyForTeams() is defined on Page as
public function scopeOnlyForTeams($query) {
return $query->whereNotNull('team_id');
}
But I wanted to use a proper relationship so was wondering if I should be using HasManyThrough or something else for this situation.
Use a BelongsToMany relationship:
public function teams_joined()
{
return $this->belongsToMany(Team::class, 'pages');
}

How to query in laravel

I have User Model. In user Model I have three user type Admin,Trainer,Student.
I have Job Model, I am storing the the id of trainer ,student and job in pivot table such that one trainer is assigned against one job and many students. Now after storing the ids as foreign key in pivot table.
Now how i can show in a view all trainer, job and assigned students. In la-ravel 5.2
User Model
public function Job_User()
{
return $this->belongsToMany('App\HTTP\Models\Job', 'jobs_users', 'user_id', 'job_id')->with-pivot('job_id');}
public function Trainer_User()
{
return $this->belongsToMany('App\HTTP\Models\Job', 'jobs_users', 'user_id', 'trainer_id')->with-pivot('trainer_id');
}

Laravel 5.0 ORM Relations

I'm trying to select a 'Site' from a Users 'Organisation'.
I can successfuly retrieve a User's Organisation (as an Organisation object) by using
$user->organisation
but when I try to retrieve the sites belonging to the organisation using:
$user->organisation->sites
I get every site in my DB returned (as a collection).
My User Model's organisation relationship:
public function organisation()
{
return $this->belongsTo('App\Models\Organisation', 'organisation_id');
}
My Organisation Model's User and Site relationships:
public function users()
{
return $this->hasMany('App\Models\User');
}
public function sites()
{
return $this->hasMany('App\Models\Site');
}
My Site Model's Organisation relationship:
public function organisation()
{
return $this->belongsTo('App\Models\Organisation');
}
User Table
id
organisation_id
name
email
password
last_login
persist_code
reset_password_code
remember_token
created_at
updated_at
deleted_at
responsible_to
Organisations
id
name
created_at
updated_at
deleted_at
Sites
id
organisation_id
name
address
account_code
created_at
updated_at
deleted_at
I've included everything I think will be useful here but I've missed anything I will add it as requested.
I have the following workaround in place but I am still unhappy with why the above is not working as expected.
$organisation = Organisation::where('id', $user->organisation->id)->first();
$site = Site::where('organisation_id', $organisation->id)->first();
The above workaround returns the first site from my table that does genuinely have a relationship with my user model.
If I remove ->first() I get a collection of sites that are associated with my user through the organisation rather than all from the table.
Thanks

How build a ternary relationship in Laravel 5

I have three entities:
User
Profile
Status
Summarized, users has a profile foreach status.
EXAMPLE
Users table records
user
id | name
1 user1
2 user2
3 user3
Status table records (this records is previously seeded)
status
id (PK) | title (string)
1 student
2 collaborator
3 teacher
Profile table structure
PROFILE
user_status_id (PK) (FK)
institution (string)
year (timestamp)
user1 is registered as student and fill your profile based on this status. After, he change your status to collaborator and fill another profile referred to this new status.
With that, i want to know:
When user1 was student?
the user1 was already collaborator ever?
Which institution user1 had frequented when he was student?
My first problem is:
How to model this relationship?
I'm not sure but think the above situation is a ternary relatinoship case, right?
And Second problem:
How build using Laravel Eloquent Relationships?
Let's start with relationship
class User extends Eloquent{
protected $table = 'user';
public $timestamps = true;
use SoftDeletingTrait;
public function status(){
return $this->hasOne(Status::class, 'user_id', 'id');
}
public function profile(){
return $this->hasMany(Profile::class,'user_id','id');
}
}
class Status extends Eloquent{
protected $table = 'status';
public $timestamps = true;
use SoftDeletingTrait;
public function user(){
return $this->belongsTo(User::class,'user_id','id');
}
}
class Profile extends Eloquent{
protected $table = 'profile';
public $timestamps = true;
use SoftDeletingTrait;
public function user(){
return $this->belongsTo(User::class,'user_id','id');
}
}
Above relation would somehow will get you what you need but just writing this relation made me question your table structure.
Suggestion DB Change For Better Relation
User
id, username, email, ........
Status
id, status, description, ........
Institutions
id, name, address, ............
User_Status_Institution
user_id,status_id,institution_id,timestamp,.......
This structure allows us that we can have Institution details even if there is no user_profile for that institution. Previous structure you had you can only have institution (name only) detail if and only if there is user profile. Also you can change institution (Name/address/phone etc) at one place and it will update it for all users.
As much as possible try that you can make information to be independent if possible because that reflects in models, object and relations.
Hope it makes sense.

Categories