Laravel 5.0 ORM Relations - php

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

Related

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

Laravel foreign key relation

I've got a strange problem.
I've a users table and a company table. A User belongsTo a company and a company hasMany users.
Both primary keys of the table are id.
In the laravel documentation I read the following:
Additionally, Eloquent assumes that the foreign key should have a
value matching the id column of the parent.
I've got this in my CompanyModel:
protected $table = 'company';
public function users()
{
return $this->hasMany(UserModel::class);
}
When I try this:
$users = CompanyModel::find(1)->users;
dd($users);
It's not working. When I add a foreign key in my relation it works!?:
protected $table = 'company';
public function users()
{
return $this->hasMany(UserModel::class, 'id');
}
This is strange right? What on earth am I doing wrong.
--EDIT--
In my users table I've got a company_id column!
Firstly, I would suggest you rename your Model from CompanyModelto Company and from UserModel to User.
Then ensure you have company_id in your users table. And in your users migration file connect the users table with the companies table as such:
$table->integer('company_id')->unsigned();
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
Don't forget to refresh your database.
Then in your models, define the relationships as such:
// User model
// Laravel will automatically identify and use the `company_id` field in your reference
public function company(){
return $this->belongsTo(Company::class);
}
// Company model
public function users(){
return $this->hasMany(User::class);
}
You can then fetch your records in your controller as such:
$user = User::find(1);
$user_company = $user->company; // This might not be necessary in your controller, you can do it in your view
dd($users, $user_company);

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.

Laravel Eloquent relationships and connecting multiple tables

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

How to Call function on laravel pivot model

I was trying to get the attendance of each user in a course where the users and the courses have many to many relationship and the attendance table is based on the relationship.
But i couldn't call $user->pivot->attendance(); directly i had to call for the pivot object it self so i can call a function to it as you can see in the answer
The Following is a sample of my Database scheme
I need to run
$users=$course->users;
foreach($users as $user)
{
$user->pivot->attendance(); //error in this line
}
this line gives and error
Call to undefined method
Illuminate\Database\Query\Builder::attendance()
users
id
name
etc
courses
id
name
startDate
endDate
course_user
id
course_id
user_id
payment
regDate
status
userattendance
id
course_user_id
time
inOrOut
And here is the CourseUserPivot Class
class CourseUserPivot extends Eloquent {
protected $table ="course_user";
public function course()
{
return $this->belongsTo('Course');
}
public function user()
{
return $this->belongsTo('User');
}
public function attendance()
{
return $this->hasMany('Userattendance','course_user_id');
}
}
P.S: $user->pivot->payment works and displays the attribute but i cant call methods
You can't use $user->pivot->attendance(); as this calls attendance on the user object not on the pivot object
You will have to fetch the pivot object then call the function like so
CourseUserPivot::find($user->pivot->id)->attendance();
make user that where you used withPivot() function you include the id in the array
like in
class Course{
...
...
public function users()
{
return $this->belongsToMany('Candidate')
->withPivot('id',
'summary',
'status',
'payment'
);
}
}
I was trying to accomplish the same thing, and I was having trouble getting it to work like I wanted until I included the 'id' column of my custom pivot model in the withPivot() method.
For some context, my database structure is:
User table
id
Items Table
id
Sets table (defines a set and the items that can be in an instance of it)
id
Set_User table (Custom Pivot Model, instances of a set created by a user)
id, set_id, user_id
Items_SetUser table (items that belong to a set instance that belong to a user)
item_id, setuser_id
I do this in the controller to get all the sets that user has made an instance of, with custom pivot table data:
$user_sets = \Auth::user()->sets()->withPivot('id', 'name')->get();
And then in blade I can access the items associated with each set instance like this:
$set->pivot->set_items()->count()
Without including 'id' in the call to withPivot(), the above is not possible. Note that set_items() is a method on the custom pivot model that defines a relationship with the items table.

Categories