Laravel 5.4 Relationships between 3 tables - php

I am new in laravel, I already know how to join tables using the query builder. I just like to learn how to use relationships to avoid repetition of codes and to simplify it. I can join 2 tables, but I can't get the 3rd table.
I like to display employees assigned tasks information from the Tasks table, this table only has the project id that needs to be joined to the Projects table. Other employees can join in existing projects with other employees.
Employee model:
public function tasks()
{
return $this->hasMany('\App\Task', 'project_coder', 'id');
}
Task model:
public function projects()
{
return $this->hasMany('\App\Project', 'id', 'project_id');
}
Projects model:
public function belongsToTasks()
{
return $this->belongsToMany('\App\Task', 'project_id', 'id');
}
I can only get the IDS from Task model. the ID will be use to fetch the project info from project tables. Unfortunately I cant do that part.
Employees controller:
public function show($id)
{
$data = Employees::find($id);
return view('show-employee')->withInfo($data);
}
Is it good practice to use query builder rather than relationships?
UPDATE:
Employees table
{
"id":1,
"name": "Juan"
}
Tasks table
{
"id":1, // autoincrement and will not be use for linking to other tables.
"project_id": 1, //use to connect to project table
"project_coder": 1 // use to connect to employees table
}
Projects table
{
"id":1,
"name": "First Project"
}

To deal with this is best to create pivot table like employee_task
where table will have just two columns task_id and employee_id
then you can define in Task model
public function employees()
{
return $this->belongsToMany('\App\Employee', 'employee_task');
}
and Employee model
public function tasks()
{
return $this->belongsToMany('\App\Task', 'employee_task');
}
now you can see all employee tasks and rest of you relations work just fine
$data = Employees::find($id);
$data->tasks //you get all tasks assigned to this employee
$data->tasks()->first()->projects //you get all your projects for first task
$data->tasks()->first()->employees //all employees assigned to first task with this employee
Also recommend to you to lookup pivot tables, attach(), detach() and sync() functions. you can check it here : https://laravel.com/docs/5.7/eloquent-relationships#updating-many-to-many-relationships
UPDATE:
Ok I understand now what you are trying to do. You already have pivot table. I was little confused with your Project model which is not necessary.
You can remove your Project class if you have it just for this relation
and update your model relations as I wrote above. You don't need project_id and project_coder_id in this relation. Also change the column names to more conventional names like employee_id and task_id as I mentioned or whatever your table names are.
And you can rename employee_task pivot table name to your project table or you can rename it as well.
EDIT
When you use Project model for another data, you need to create 4th table as I mentioned above.
FINAL
drop project_coder column in Tasks table - unecessary column
create pivot table employees_task with employee_id,task_id
create mentioned relations with pivot table
I assume that Project hasMany() tasks and Task only belongsTo() one project. So need to create these relations as well.
Then you can use these relations like this:
$employee = Employee::find($id);
$task = Task::find($id);
$project = Project::find($id);
$employee->tasks //all tasks assigned to employee
$task->employees //all employees assigned to task
$task->project //project info assigned to task
$employee->tasks()->first()->project //project data from first task of employee
$project->tasks()->first()->employees //all employees assigned to first project task

Related

How to make Query between two tables in laravel

Hello I want to ask for how to make query in 2 tables to get the summary of value from table payments where type_id = id from types table and this is tables structure
this is the charts code
$chartـin_contract = Charts::create('bar', 'highcharts')
->title('My nice chart')
->labels($value_type->type)
->values([5,10])
->dimensions(0,500);
in labels i get the values from database but did't work with me
and this is the direct query
$value_type = DB::select('select type, value from payments,types where payments.`type_id` = types.id');
I want view the data that came from database in chart I am using laravel chart package
Please review Eloquent Relationships in the Laravel docs - https://laravel.com/docs/5.5/eloquent-relationships
The relationship between the two tables is defined (as in a one-to-one, one-to-many or many-to-many relationship) and then you will be able to query those relationships.
For this you need to establish the Relationship in tables.
NOTE: I am assuming that your task may have multiple payments
In your tasks model its one to many relation.
Task.php (Model add the following)
public function payments(){
return $this->hasMany(Payments::class);
}
And in your payments model its many to one relation.
Payments.php (Assuming)
public function task(){
return $this->belongsTo(Task::class);
}
Think now you want to get all the payments for a task. Let me show the eg: in command line
php artisan tinker
$task = App\Task::where('id',1)->get(); //Think that you have first task
$task->payments; //You can call the relation ship established condition function
Think you are browising for payment and want a task then
php artisan tinker
$payment = App\Payment::where('id',1)->get();//find the payment with id 1, just for the sake of example
$payment->task; //This will be the task() function that you have written int the model

One to many relation in pivot table in laravel?

I have pivot table and it has one to many relationship with another table, So I am confused with database design and relationship in Laravel Elequent.
Is this right way to design databse or should I create id as primary key for award_entries and use it is foreign key in entry_files. ?
If I am following existing design (first one), how will I write relation in Laravel eloquent?
Here how your relation will look like. You may need to change model or columns name.
In award_entry model:
public function entry_file() {
return $this->belongsTo('App\Models\entry_file','award_entries_award_id');
}
And in Entry_file model:
public function award_entries(){
return $this->hasMany('App\Models\award_entries','award_entries_award_id');
}

Laravel-Many-to-one Polymorphic relationship

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

Can I use php artisan db:seed to seed related tables?

Is it possible to seed related tables using the following in Laravel 5?
php artisan db:seed
I have two tables
users
id
first name
projects
id
name
and a pivot table
project_user
project_id
user_id
I would like to create a number of users, a number of projects and then relate the users and their respective projects.
Seeding the users and projects isn't a problem but I am not sure how to handle the pivot table.
Is it possible?
Of course you can. If you are using Eloquent, you can simply work with normal relations (maybe the easiest way). Or if you use the SQL builder directly, you can feed the table just as normal, but you need to stick to your foreign key rules.
Just give in a try and you'll see. But make sure you import classes you use.
Adding a relation between two models is easy, but there are some differences between the common relation types (and he perspective): one-to-many, many-to-one and many-to-many.
One-to-Many and Many-to-One
Assumed that each of your project has a creator, an owner so-to-say, you could have a 1:n relation between User and Project.
public class User {
public function ownedProjects() {
return $this->hasMany('App\Project');
}
}
public class Project {
public function owner() {
return $this->belongsTo('App\User');
}
}
In this relation, you can either attach a Project to a User or tell the Project who his owner is.
// Attach a project to an user
$project = Project::create([]);
User::find($id)->ownedProjects()->save($project);
// There is also a function saveMany() for an array of projects
// Tell the project who his owner is
$project = Project::create([]);
$project->owner()->associate(User::find($id));
Many-to-Many
In your case, we need a Many-to-Many relation between Users and Projects. The syntax is a bit different, but the outcome quite straight forward. First we need a relation between the both models:
public class User {
public function projects() {
return $this->belongsToMany('App\Project');
}
}
public class Project {
public function users() {
return $this->belongsToMany('App\User');
}
}
Then we can query the relation just like that:
$project = Project::create([]);
User::find($id)->projects()->attach($project->id);
You can also attach a whole bunch of projects, do the same things from the other side, detach models or synchronize them, if you want to make sure that an exact amount (and only this amount) is in relation:
// Adds a relation for the user to projects with ids 1, 2, 4 and 6
User::find($id)->projects()->attach([1, 2, 4, 6]);
// Adds the users with ids 19 and 173 to this project
Project::find($id)->users()->attach([19, 173]);
// Removes the user 19 from the projects relations
Project::find($id)->users()->detach(19);
// Removes all relations between this user and projects that are
// not listed in the synchronization array and adds a relation
// to all projects where none exists yet
User::find($id)->projects()->sync([4, 7, 19, 6, 38]);
This is the normal syntax for Many-to-Many relations, but you can also attach models just like in a One-to-Many relation:
// Creation of project could also be done before and saved to a variable
User::find($id)->projects()->save(Project::create([]));

Laravel 4 eloquent pivot table

I have three tables: users, items and user_items. A user has many items and a item belongs to many users.
The tables:
Users
id
username
password
Items
id
name
equipable
User_items
id
user_id
item_id
equipped
The models:
class User extends Eloquent {
public function items()
{
return $this->belongsToMany('Item', 'user_items')
->withPivot('equipped');
}
}
class Item extends Eloquent {
public function users()
{
return $this->belongsToMany('User', 'user_items');
}
}
In the pivot (user_items) table I've a very important column named "equipped".
I've a form where users can equip, unequip and throw items. This form has a hidden field with the pivot (user_items) table row id. So, when a user tries to equip an item, the system checks if the item is equipable.
So, I want a object with the pivot data and the item data, based on item_id from the pivot table, I can send to the handler (where all logic is handled).
So what I've to do is to first access the pivot table and then access the item table.
Something like this (does not work):
$item = User::find(1)->items->pivot->find(1);
Is this possible to do?
You first have to include 'equipable' on your pivot call:
return $this->belongsToMany('User', 'user_items')
->withPivot('equipable');
Then you can ask Eloquent if your item is equipable or not:
$item = User::with('items')->get()->find(1)->items->find(2)->pivot->equipable;
Keep two things in mind:
Eloquent uses 'items' as a key internally, so that might interfere.
Whatever method you put before "get()" is part of the db query. Everything after "get()" is handled by PHP on the Object. The latter will be slower in most cases.

Categories