Currently I have two tables; Users and Employees
All users are employees but not all employees are users,
I have a models Users and Employee, the personal details of a user are pulled his respective employee record.
Now I wanted to display all users and I can do it using User::all();
but also I wanted to have their personal details too.
currently I'm doing a DB:: call to join table in a function on my Users Model.
is there a better approach to this?
You can do it the Laravel way - eager load the relationship
$users = User::with('employee')->get();
This assumes that you have your relationships defined, at least on User side.
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Employee;
class User extends Authenticatable
{
// ...
public function employee()
{
return $this->hasOne(Employee::class, 'employee_no');
}
}
FYI the Laravel way doesn't necessarily mean the fastest or the best way. It's usually syntactically more expensive/terse and convenient though.
Eager loading a relationship requires an additional query. In your case two queries will be executed under the hood and then employee property will be materialized for each User model in a collection.
So your way with a join and one roundtrip to the database might be more performant at the end of the day.
You should establish a relation. In this case your users can relate to your employees as such
public function employee()
{
return $this->hasOne(Employee::class);
}
With Eloquent, you can just define methods in your User model to access the relation and be done with it.
public function role
{
return $this->employee->role;
}
However, when fetching users, you want to ensure you "eager load" your employee relation so that you're not individually fetching employees when using these methods. When you fetch your users:
User::with('employee')->all()
If you will always require the employee record you can eager load by default:
class User extends Authenticatable
{
protected $with = ['employee'];
}
Sounds like you need to use an Eloquent One to One Relationship
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function employee()
{
return $this->hasOne('App\Employee');
}
}
Related
Laravel 7.0
I am trying to set up a system where users can belong to
different models, like Courses or Realms. I call this a
'membership'.
A user who is a member in a Realm or Course always has a
Role within that Realm, like 'amdin', 'editor', or 'guest'
I have models for User, Role, Memberable and the Course/Realm stuff.
Like this:
Role ⇦1:N⇦ Memberable ⇨N:1⇨ User
⇩
poly 1:1
⇩
Realm/Course/YouNameIt
At the moment I am using a wild mix of relations to get
more or less what I want. But my approach seems rather
gross to me, or even wrong.
For example, to get a list of models that I am a member of, I write:
User::find(2)->memberships()->get()
But this gives me a Collection of Memberables, not Realms or
Courses, which kind of sucks. Can this be remedied?
To get my first Realm/Course, I have to write:
User::find(2)->memberships()->first()->memberable // YUCK!
Here are my models:
class User {
public function memberships()
{
return $this->hasMany(Memberable::class)->with('memberable');
}
public function roles()
{
return $this->belongsToMany(Role::class, 'memberables')
->withPivot(['memberable_id', 'memberable_type']);
}
}
class Memberable extends Model
{
public function role()
{
return $this->hasOne(Role::class, 'id', 'role_id');
}
public function memberable()
{
return $this->morphTo('memberable');
}
}
trait HasMembers
{
public function members()
{
return $this->morphToMany(User::class, 'memberable', 'memberables')
->withPivot('role_id')
->join('roles', 'roles.id', 'memberables.role_id')
->addSelect(['role' => Role::select('name')
->whereColumn('role_id', 'roles.id')]);
}
}
class Realm extends Model
{
use HasMembers;
}
class Course extends Model
{
use HasMembers;
}
I know that questions like "is this good" or "is this bad" are difficult to answer, so I'll ask:
Is this so wrong that I should worry?
How could I improve this design?
I'll probably never have more Models that Realms and Courses that can have members. Is it smarter to ditch the whole memberable-polymorphism in favour of two separate tables? It IS nice to keep the flexibility the polymorphic approach offers.
You could just set up more relationships
User belongsToMany Roles
Roles belongsToMany Users
User morphedByMany Realm using Memberable
User morphedByMany Courses using Memberable
User morphedByMany YouNameIt using Memberable
Realm morphToMany User using Memberable
Courses morphToMany User using Memberable
YouNameIt morphToMany User using Memberable
I'd make Memberable a morph pivot.
class Memberable extends MorphPivot { ... }
With this, accessing the relationships isn't hard.
$user->roles // Get an Eloquent Collection made up from $user's roles.
$role->users // Get an Eloquent Collection made up from users that have $role.
$user->realms // Get an Eloquent Collection made up from $user's realms.
$user->courses // Get an Eloquent Collection made up from $user's courses.
$user->youNameIt // Get an Eloquent Collection made up from $user's youNameIt.
$realm->users // Get an Eloquent Collection made up from users associated with $realm.
$course->users // Get an Eloquent Collection made up from users associated with $course.
$youNameIt->users // Get an Eloquent Collection made up from users associated with $youNameIt.
And maybe make User <---> Roles relationship use a separate pivot. If not, then make it a morph relationship as well (User morphedByMany Role using Memberable, Role morphToMany User using Memberable)
The thing is, if you use a central table to morph everything up, it will grow a lot. You're essentially making it do the job of 3-4 pivots (in this example). If your data grows a lot, it might become a problem.
Also, different relationships might need different data from the pivot table but since you're only using a single table, that would complicate things unless you opt to use a json field.
I'm pretty new to laravel and trying to create my first app.
I have three different classes: User, Activity and Lecture.
Users are capable of creating an activity and lecture.
Every activity has its technical manager, product manager and activity manager, and users are capable of enrolling the activities.
Every lecture has its lecturer and users are capable of enrolling the lecture.
I want to create the eloquent relationships necessary but I'm not sure if the users should belong to the activity or vice versa.
I have accomplished one of my goals (creating a relationship between users and activity managers) however, I'm confused with the rest of it and feel like it is not the best way to achieve my results.
In that moment, my code looks like that:
App\Activity :
class Activity extends Model
{
protected $guarded = [];
public function TechnicalManager(){
return $this->belongsTo('App\User','technical_manager');
}
public function ActivityManager(){
return $this->belongsTo('App\User','activity_manager');
}
public function ProductManager(){
return $this->belongsTo('App\User','product_manager');
}
public function Enrollers(){
return $this->belongsToMany('App\User','user_activity');
}
}
App\User :
class User extends Authenticatable
{
use Notifiable;
public function activities(){
return $this->belongsToMany('App\Activity','id');
}
}
If you plan on using Eloquent's relationships, then the idea would be:
Do I need to access users (Enrollers) from Activity and call it by accessing the relationship?
If yes, write the relationship
I see nothing wrong with writing relationships on both sides of a model, as long as you use them. If you're not going to use them, then why have them?
Image the situation:
Find a user, it's activities and who is the technical manager and the activity manager for the activities
User::with(['activities','activities.TechnicalManager','activities.ActivityManager'])->find($id)
can someone please explain how the hasManyThrough relates to the sql statement I am trying to acheive?
--offers table
id, network_id, mobile_id
--networks table
id, name
--mobiles table
id, name
I am trying to get Mobile::with('networks')
I would write this as
SELECT DISTINCT networks.name from networks, offers where offers.network_id = networks.id and offers.mobile_id in (1,2,3,4)
In relation to the above sql statement where does each arg live in the hasManyThrough method? i.e
hasManyThrough(Network::class,Offer::class,'network_id','mobile_id')
I think this is many to many relationship
--offers table
id, network_id, mobile_id
--networks table
id, name
--mobiles table
id, name
Network Model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Network extends Model
{
public function mobile(){
return $this->belongsToMany('App\Mobile', 'offers')->withPivot('mobile_id');
}
}
Mobile Model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Mobile extends Model
{
public function network(){
return $this->belongsToMany('App\Network', 'offers')->withPivot('network_id');
}
}
You may use pivot to fetch relationship
For more info visit Laravel Docs
However for such conditions you must use a pivot table, i.e mobile_network instead of offers.
I am using laravel 5.1. The scenario is as follows(this is an example. The real scenario is similar to this example)
I have 3 models
College
Student
Teacher
A college can have many students but a student can belong to only 1 college.
A college can have many teachers but a teacher can belong to only 1 college.
I want to establish relationships between these tables in laravel.
One of the methods for this is to place a college_id foreign key on the Students and Teachers table. But in my case, this foreign key will be null a lot of times. So rather than have separate columns in 3-4 tables with mostly null values, I wanted to explore the option of having a polymorphic relationship for College table.
This is what I tried:
The example given in the laravel docs(link below) depict a one-to-many relationship whereas my scenario is more of a many to one relationship.
http://laravel.com/docs/5.1/eloquent-relationships#polymorphic-relations
As given in the example, having collegeable_id and collegeable_type columns on the College table would not have fulfilled my requirement as a college can contain many students/teachers so I created a pivot table:
Schema::create('collegeables', function (Blueprint $table) {
$table->integer('college_id')->unsigned();
$table->integer('collegeable_id')->unsigned();
$table->string('collegeable_type');
});
And I have the following models
College Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class College extends Model
{
public function students()
{
return $this->morphedByMany('App\Student', 'collegeable');
}
}
Student Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Student extends Model
{
public function college()
{
return $this->morphOne('App\Colleges', 'collegeable');
}
}
With this arrangement, I am able to store students using College model instance like this
$college = \App\College::find(1);
$student = new \App\Student;
$student->name = 'John Doe';
$college->students()->save($student);
But when I try to retrieve a College model instance using a student model instance as specified below, it gives me an error:-
public function index()
{
return \App\Student::find(1)->college;
}
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'colleges.collegeable_id'
This is kind of expected as morphOne works with columns in a table I suppose.
If I change the morphOne function in Student Model to morphToMany, the code starts working and I am able to retrieve values as well. But that make this relationship a many to many which again is not what I want.
So my question is this:-
Is their a morphSomething function I can use in the student model to be able to retrieve values for the student's college while maintaining the relationship as a one-to-many?
Any help would be really appreciated. Thanks.
There's no reason to use Polymorphic relationships here. Instead, just add a foreign key to your colleges table on both your students and teachers tables. Like this:
colleges
id
name
teachers
id
name
college_id
students
id
name
college_id
Then your models can use the belongsTo() and hasMany() relations, like so:
class College extends Model {
public function students() {
return $this->hasMany(App\Student::class);
}
public function teachers() {
return $this->hasMany(App\Teacher::class);
}
}
class Teacher extends Model {
public function colleges() {
return $this->belongsTo(App\College::class);
}
}
class Student extends Model {
public function colleges() {
return $this->belongsTo(App\College::class);
}
}
Polymorphic one-to-many relations are for the opposite of this relationship where you have a model that can only be related to a single record, but that record can be many different models.
Edit: To further explain why a polymorphic relationship isn't needed here, let's take a look at where it would be needed. Say you have a simple CRM style website. There are Customers and Projects and you want to have Comments on both. In this case, you would make Comments a polymorphic relationship because Comments belong to a single Customer or a single Project, but not both.
Your relationship is the exact opposite. In your case, Students and Teachers belong to a college. If you were to follow the previous example's pattern, a college would have belonged to a single student or teacher.
I had a similar need and managed to improvise in another way, taking advantage of morph's table structure.
You will need a Collegeable class to be Pivot (https://laravel.com/docs/9.x/eloquent-relationships#defining-custom-intermediate-table-models)
And then the magic:
public function college(){
return $this->hasOneThrough(Colleges::class,
Collegeable::class,
'collegeable_id',
'id',
'id',
'college_id',
);
}
And on the Collegeable Pivot class:
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\Pivot;
class Collegeable extends Pivot
{
protected $table = 'collegeables';
}
I have three tables in my database: Users, Books, and Reading. The structure of Reading is:
id, user_id, book_id
Now, I need to access to all the books that the user is reading.
First, I would like to know which kind of relationship is, one to many, many to many, Has Many Through, etc. And what do I have to specify in each model? I mean, in the users model hasMany('Reading') or whatever.
I want to access with something like this: Auth::user()->reading()->books()->get() or something similar.
The kind of relationship where one User can be reading several books and one Book can be read by many users is Many-to-Many relationship.
So, to define such a relation in Laravel you should use belongsToMany method:
class User extends Eloquent
{
function books()
{
return $this->belongsToMany("Book", "Reading", "user_id", "book_id");
}
}
class Book extends Eloquent
{
function users()
{
return $this->belongsToMany("User", "Reading", "book_id", "user_id");
}
}
$books = Auth::user()->books;
Notice, you don't need to call method ->books() but use a property ->books, otherwise you'd have to call it like Auth::user()->books()->get().