How to add information to a pivot table in laravel? - laravel

I have a many:many relation between student and course.
Here are my models and my pivot table:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Student extends Model
{
use HasFactory;
protected $fillable = [
'name',
'surname',
'age',
'tdah',
'description',
'hobbies',
];
/* public function course(){
return $this->belongsTo(Course::class);
} */
public function data(){
return $this->hasMany(Datum::class, 'student_id', 'id');
}
public function configurations(){
return $this->hasMany(Configuration::class, 'student_id', 'id');
}
public function courses(){
return $this->belongsToMany(Course::class, 'course_student', 'student_id', 'course_id');
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Course extends Model
{
use HasFactory;
protected $fillable = [
'name',
'academic_course_id',
'user_id',
];
public function user()
{
return $this->belongsTo(User::class);
}
public function academicCourse()
{
return $this->belongsTo(AcademicCourse::class);
}
public function planification(){
return $this->hasOne(Planification::class, 'course_id', 'id');
}
public function subjects(){
return $this->hasMany(Subject::class, 'course_id', 'id');
}
/* public function students(){
return $this->hasMany(Student::class, 'course_id', 'id');
} */
public function students(){
return $this->belongsToMany(Student::class, 'course_student', 'course_id', 'student_id');
}
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('course_student', function (Blueprint $table) {
$table->id();
$table->foreignId('course_id')->constrained()->onDelete('cascade');
$table->foreignId('student_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('course_student');
}
};
I'd like to create a student that belongs to a group. I know how to create a student and a group, but I'd like to create a register for that student in my course_student pivot table. My StudentController method store is:
public function store(Request $request)
{
Student::create($request->all());
$courses = Course::all();
$academicCourses = AcademicCourse::all();
return view('course.index', compact('courses', 'academicCourses'));
}
It creates a new student but I don`t know how to create a new register for the pivot table.
I thought about doing something like:
course_student::create(request)
in my store method but I think it isn`t that way.

In Laravel you can do it by using attach function, Attach() function has two parameters :
1- the another foreign key in you case attach(course_id).
2-(this is optional) array for any another columns inside pivot table for example :
attach(course_id,['users_id'=>$usersId])
In your case you will create the records inside the pivot table (course_student) via the object from student model .
$student->courses()->attach($course_id);
note :
there is another method which does the opposite detach() but you need to use it carefully if you write it without any parameter it will remove all the records inside (course_student) that belong to the student object so specify the course that you want to remove it by that way :
$student->courses()->detach($course_id);
I hope that will help you ...

$student->courses()->attach($courseId);
https://laravel.com/docs/9.x/eloquent-relationships#updating-many-to-many-relationships
Edit :
You can use attach() method on the relationship. In your code it would look like this :
public function store(Request $request, Course $course) //add parameter course to know which course needs to be attached
{
$newStudent = Student::create($request->all()); // create() returns instance of created Student
$newStudent->courses()->attach($course->id);
$courses = Course::all();
$academicCourses = AcademicCourse::all();
return view('course.index', compact('courses', 'academicCourses'));
}

Related

How to correctly use relationships with() in Laravel?

I just wanted to clarify using the relationship in tables. Right now, I wanted to fetch records of designation names from designation_id in employees table.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\{
Designations,
Positions
};
class Employees extends Model
{
use HasFactory;
protected $table = 'employees';
protected $primaryKey = 'id';
public $timestamps = true;
protected $casts = [
'designation_id' => 'array',
'position_id' => 'array',
'basic_pay' => 'decimal:2',
];
protected $dates = ['created_at', 'updated_at'];
protected $fillable = [
'first_name',
'last_name',
'designation_id',
'position_id',
'basic_pay',
];
public function designations()
{
return $this->hasMany(Designations::class, 'id', 'designation_id');
}
public function positions()
{
return $this->hasMany(Positions::class, 'id', 'position_id');
}
}
Here's my designation model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\Employees;
class Designations extends Model
{
use HasFactory;
protected $table = 'designations';
protected $primaryKey = 'id';
public $timestamps = true;
protected $dates = ['created_at', 'updated_at'];
protected $fillable = [
'name',
'description'
];
public function employees()
{
return $this->belongsTo(Employees::class, 'designation_id');
}
}
Here's my EmployeeController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\{
Employees,
Designations
};
class EmployeesController extends Controller
{
public function index()
{
$employees = Employees::with('designations', 'positions')->get();
return array_reverse($employees);
}
}
I checked my api url, http://localhost:8000/api/employees and got this error:
SQLSTATE[HY093]: Invalid parameter number (SQL: select * from designationswheredesignations.id in (52))
I would recommend you to install phpstorm, it gives you hints of function parameters and you won't have this kind of issues anymore.
correct format is:
return $this->hasMany('App\Comment', 'foreign_key', 'local_key');
in your designations model:
public function DesignationNames()
{
return $this->hasMany(\App\Models\Employees::class, 'designation_id', 'id');
}
When you retrieve them in your controller you need to use the with() method as:
Designations::with('DesignationNames')->get();
And then to access properties in the related employee collection you would need to:
$designation->DesignationNames->DesignationProperty
Your relationships parameters are wrong. It's
hasMany(class, foreignKey, relatedPrimaryKey)
# Employee
public function designations()
{
return $this->hasMany(Designations::class, 'employee_id', 'id');
}
public function positions()
{
return $this->hasMany(Positions::class, 'employee_id', 'id');
}
If you're eager loading more than 1 relationship, use array notation.
Also, $employees will be an instance of a Collection, so you can't use it as an argument to array_reverse.
You can either use collection methods to achieve the same result, or use $employees->all() to get the underlying array.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Employees;
class EmployeesController extends Controller
{
public function index()
{
$employees = Employees::with(['designations', 'positions'])->get();
return $employees->reverse()->values()->all();
// OR
return array_reverse($employees->all());
}
}
This is assuming your tables have a structure like this:
Schema::create('employees', function (Blueprint $table) {
$table->id();
...
});
Schema::create('designations', function (Blueprint $table) {
$table->id();
$table->foreignId('employee_id')->constained('employees');
...
});
Schema::create('positions', function (Blueprint $table){
$table->id();
$table->foreignId('employee_id')->constained('employees');
...
});
Since you're using increments instead of id(), the code has to be a little different.
Schema::create('employees', function (Blueprint $table) {
$table->increments('id')->unique();
...
});
Schema::create('designations', function (Blueprint $table) {
$table->increments('id')->unique();
$table->unsignedInteger('employee_id');
$table->foreign('employee_id')->references('id')->on('employees');
...
});
Schema::create('positions', function (Blueprint $table){
$table->increments('id')->unique();
$table->unsignedInteger('employee_id');
$table->foreign('employee_id')->references('id')->on('employees');
...
});

insert data to table pivot use form and show it index.blade.php in laravel 5.7

I have form create team.blade.php below this
Form Team index.blade.php
display the name of the one-team user with that user, and display the project that is being done by the user, and display the user as what (role).
the relationship of one user has many teams. and one team has many users. therefore, I choose many to many relations. but when I create team, I want to insert user_id and team_id in the pivot user_teams table as the relation table between user and team.
but when I tried to create team failed, he did not save data to the user_teams table.
and in the team index, he does not display the name of a team user with that user, and displays the project that is being done by the user, and displays the user as what.
my user models
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Presence;
use App\Models\Project;
use App\Productivity;
use App\Sick_leave;
use App\Annual_leave;
use App\Models\Team;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password', 'role_id',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function role()
{
return $this->belongsTo(Role::class, 'role_id');
}
public function teams()
{
return $this->belongsToMany(Team::class, 'user_teams');
}
public function projects()
{
return $this->belongsToMany(Project::Class, 'user_projects');
}
}
Team Models
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\User;
use App\Role;
use Auth;
class Team extends Model
{
use SoftDeletes;
protected $table = 'teams';
protected $fillable = [
'id',
'project_id',
];
public function users()
{
return $this->belongsToMany(User::class, 'user_teams');
}
public function project()
{
return $this->belongsTo(Project::class);
}
public function role()
{
return $this->belongsTo(Role::class);
}
}
Project Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Project extends Model
{
use SoftDeletes;
protected $table = 'projects';
protected $fillable = [
'project_id',
'project_name',
'start_date',
'end_date',
'project_category',
];
public function users()
{
return $this->belongsToMany(User::class, 'user_projects');
}
public function team()
{
return $this->hasOne(Team::class);
}
}
UserTeam model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class UserTeam extends Model
{
use SoftDeletes;
protected $table = "user_teams";
public function team()
{
return $this->belongsTo(Team::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
Team Controller
public function index()
{
$users = auth()->user()->name;
$users = User::all();
return view ('teams.index', compact ('teams', 'users', 'projects'));
}
public function create()
{
$users = User::all();
$projects = Project::pluck('project_name', 'id');
return view ('teams.form', compact('projects', 'users'));
}
public function store(Request $request)
{
$team = Team::create($request->all());
$userIds = User::find(2);
$team->users()->attach($userIds);
return redirect()->route('team.create');
}
In user_teams has fields user_id and team_id. how do i overcome this??
You have to create the team and then attach the users that belong to it.
Example from the docs:
Attaching
Eloquent also provides a few additional helper methods to make working
with related models more convenient. For example, let's imagine a user
can have many roles and a role can have many users. To attach a role
to a user by inserting a record in the intermediate table that joins
the models, use the attach method:
$user = App\User::find(1);
$user->roles()->attach($roleId);
In your case:
Team Controller
public function store(Request $request)
{
$team = Team::create($request->except('user_id'));
$team->users()->attach($request->get('user_id', []));
return redirect()->route('team.create');
}

Laravel scout check if relation is not empty?

namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravel\Scout\Searchable;
class Event extends Model
{
protected $table = 'events';
public $timestamps = true;
use Searchable;
use SoftDeletes;
protected $dates = ['deleted_at'];
public function entities()
{
return $this->belongsTo('App\Entity', 'entity_id');
}
public function users()
{
return $this->belongsTo('App\User', 'id');
}
public function events()
{
return $this->belongsTo('App\DirtyEvent', 'id');
}
public function toSearchableArray()
{
$data = $this->toArray();
$data['entities'] = $this->entities->toArray();
return $data;
}
}
This is my model for Event, as you can see I am using toSearchableArray which is Laravel scout function to import 'relations' to algolia. However the problem is that sometimes it is empty. So for example
event id 1 has entity_id 1
but in another example
event id 2 has entity_id = null
How can I modify this function to check if the entities() relation is not empty before putting it into array?
if i understand u correctly this should help. if the relationship does not exist return an empty array and scout won't update the index
public function toSearchableArray()
{
if(is_null($this->entities)){
return [];
}
$this->entities
return $this->toArray();
}
please update foreign_key in relation as this
user_id as foreign_key instead of id
event_id as foreign_key instead of id
public function users()
{
return $this->belongsTo('App\User', 'user_id');
}
public function events()
{
return $this->belongsTo('App\DirtyEvent', 'event_id');
}
I think if load the relation before the toArray().
public function toSearchableArray()
{
$this->entities;
return $this->toArray();
}

can't attach topic_id in the comment table

I am making a forum where users can create topics and leave a reply just like this forum.
I made a relationship just like below.However, when I save an article the topic_id does not get attached.I think the saveReply method is wrong.
Also,in this case how do you pass comments on the particular post to the view in the show method??
I am a noob,so if my question is vague I am sorry,but any help will be appreciated!!
Route
Route::group(['middleware' => 'web'], function () {
Route::get('forums','ForumsController#index');
Route::get('forums/create','ForumsController#create');
Route::post('forums', 'ForumsController#store');
Route::get('forums/{category_id}/{title}','ForumsController#show');
Route::post('forums/{category_id}/{title}', 'ForumsController#saveReply');
});
forumcontroller
class ForumsController extends Controller
{
public function index()
{
$categories = Category::all();
$topics = Topic::latest()->get();
return view('forums.index',compact('categories','topics'));
}
public function create()
{
$categories = Category::lists('title', 'id');
return view('forums.create', compact('categories'));
}
public function store(Request $request)
{
Auth::user()->topics()->save(new Topic($request->all()));
flash()->success('投稿しました','success');
return redirect('forums');
}
public function show($category_id, $title)
{
Topic::where(compact('category_id','title'))->first();
return view('forums.post', compact('topic'));
}
public function saveReply (Request $request)
{
Auth::user()->comments()->save(new Comment($category_id,$request->all()));
flash()->success('投稿しました','success');
return redirect()->back();
}
}
topic model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class topic extends Model
{
protected $fillable = [
'title',
'body',
'category_id'
];
public function category()
{
return $this->belongsTo('App\category');
}
public function user()
{
return $this->belongsTo('App\User');
}
public function comments()
{
return $this->hasMany('App\Comment');
}
}
user model
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function articles()
{
return $this->hasMany('App\Article');
}
public function topics()
{
return $this->hasMany('App\Topic');
}
public function comments()
{
return $this->hasMany('App\Comment');
}
}
comment model
class Comment extends Model
{
protected $fillable = [
'reply',
'user_id',
'topic_id'
];
public function topic()
{
return $this->belongsTo('App\Topic');
}
public function user()
{
return $this->belongsTo('App\User');
}
}
comment table
class CreateCommentsTable extends Migration
{
public function up()
{
Schema::create('comments', function (Blueprint $table) {
$table->increments('id');
$table->text('reply');
$table->integer('user_id')->unsigned();
$table->integer('topic_id')->unsigned();
$table->timestamps();
});
}
public function down()
{
Schema::drop('comments');
}
}
The Request::all returns an array of all inputs so when you are doing:
new Comment($category_id,$request->all())
You'll get something like this:
1['some' => 'thing', 'other'=> 'values']
Which could be the problem so try this instead:
new Comment(array_merge(['category_id' => $category_id ], $request->all())
When on development/local environment, set the debug true so you'll get meaningful error messages so you can findout the exect problem easily.

How to make user, and roles relationship in Laravel 5

I have two tables :
User ->
id :
name :
role_id : ->references('id')->on('roles');
Roles ->
id :
role_name :
access :
I am trying to access roles details from user.
My User model has:
public function role()
{
return $this->belongsTo('App\Role');
}
My Role model has:
public function user()
{
return $this->hasMany('App\User');
}
When I try to do following :
$user = User::find(1);
$details = [
'name' => $user->first_name,
'role' => $user->role->role_name
];
I get error :
Trying to get property of non-object
My roles table contains access columns containing array of permissions to different routes. So my user will have only one role. While a role can have multiple users.
How to do that?
In my recent project, I handled these requirement in that way..
First of All Database Table Structure/Migration
User Table
class CreateUserTable extends Migration {
public function up() {
Schema::create('user', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password', 60);
$table->boolean('status')->default(0);
$table->boolean('is_admin')->default(0);
$table->boolean('notify')->default(0);
$table->rememberToken();
$table->timestamps();
});
}
public function down() {
Schema::drop('user');
}
}
Role Table
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateRoleTable extends Migration {
public function up()
{
Schema::create('role', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->unique();
$table->string('display_name')->nullable();
$table->string('description')->nullable();
$table->boolean('status')->default(0);
$table->timestamps();
});
}
public function down()
{
Schema::drop('role');
}
}
Role And User Relation Table
class CreateRoleUserTable extends Migration {
public function up() {
// Create table for associating roles to users (Many-to-Many)
Schema::create('role_user', function (Blueprint $table) {
$table->integer('user_id')->unsigned();
$table->integer('role_id')->unsigned();
$table->foreign('user_id')->references('id')->on('user')
->onUpdate('cascade')->onDelete('cascade');
$table->foreign('role_id')->references('id')->on('role')
->onUpdate('cascade')->onDelete('cascade');
$table->primary(['user_id', 'role_id']);
});
}
public function down() {
Schema::drop('role_user');
}
}
After these table you have to handle permission by assigning to specific Role.
Permission
class Permission extends Migration {
public function up() {
Schema::create('permission', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->unique();
$table->string('pattern');
$table->string('target');
$table->string('module');
$table->string('display_name')->nullable();
$table->boolean('status')->default(0);
$table->timestamps();
});
}
public function down() {
Schema::drop('permission');
}
}
Permission and Role Table Relation
class PermissionRole extends Migration {
public function up() {
// Create table for associating roles to permission (Many-to-Many)
Schema::create('permission_role', function (Blueprint $table) {
$table->integer('permission_id')->unsigned();
$table->integer('role_id')->unsigned();
$table->foreign('permission_id')->references('id')->on('permission')
->onUpdate('cascade')->onDelete('cascade');
$table->foreign('role_id')->references('id')->on('role')
->onUpdate('cascade')->onDelete('cascade');
$table->primary(['permission_id', 'role_id']);
});
}
public function down() {
Schema::drop('permission_role');
}
}
And Finally our model would look alike:
User Model
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
use Authenticatable, CanResetPassword;
protected $table = 'user';
protected $fillable = ['name', 'email', 'password', 'is_admin'];
protected $hidden = ['password', 'remember_token'];
public function scopeActive($query) {
return $query->whereStatus('1');
}
public function scopeAdmin($query) {
return $query->whereIsAdmin('1');
}
public function scopeNotify($query) {
return $query->whereNotify('1');
}
public function roles() {
return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');
}
public function attachRole($role) {
if (is_object($role)) {
$role = $role->getKey();
}
if (is_array($role)) {
$role = $role['id'];
}
$this->roles()->attach($role);
}
public function detachRole($role) {
if (is_object($role)) {
$role = $role->getKey();
}
if (is_array($role)) {
$role = $role['id'];
}
$this->roles()->detach($role);
}
public function attachRoles($roles) {
foreach ($roles as $role) {
$this->attachRole($role);
}
}
public function detachRoles($roles) {
foreach ($roles as $role) {
$this->detachRole($role);
}
}
public function isSuperUser() {
return (bool)$this->is_admin;
}
public function hasAccess($permissions, $all = true) {
if ($this->isSuperUser()) {
return true;
}
return $this->hasPermission($permissions, $all);
}
public function hasPermission($permissions) {
$mergedPermissions = $this->getMergedPermissions();
//dd($mergedPermissions);
if (!is_array($permissions)) {
$permissions = (array)$permissions;
}
foreach ($permissions as $permission) {
$matched = false;
// We will set a flag now for whether this permission was
// matched at all.
$founded_perms = find_in($mergedPermissions, "name", $permission);
if (!empty($founded_perms)) {
$matched = true;
}
}
if ($matched === false) {
return false;
}
return true;
}
public function getMergedPermissions() {
$permissions = array();
foreach ($this->getRoles() as $group) {
$permissions = array_merge($permissions, $group->permissions()->get()->toArray());
}
return $permissions;
}
public function getRoles() {
$roles = [];
if ($this->roles()) {
$roles = $this->roles()->get();
}
return $roles;
}
}
Role Model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'role';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name', 'display_name', 'description'];
public function scopeActive($query) {
return $query->whereStatus('1');
}
/**
* Many-to-Many relations with User.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function users() {
return $this->belongsToMany('App\User');
}
public function permissions() {
return $this->belongsToMany("App\Permission");
}
}
Permission Model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Permission extends Model {
protected $table = 'permission';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name', 'pattern', 'target', 'module', 'display_name', 'status'];
public static function displayable() {
$prepared_array = [];
$temp = self::orderBy('module')->get()->toArray();
foreach ($temp as $sin) {
$prepared_array[$sin['module']][] = $sin;
}
return $prepared_array;
}
public function scopeActive($query) {
return $query->whereStatus('1');
}
public function roles() {
return $this->belongsToMany("App\Role");
}
}
Well, thats the basic structure helped to implement basic ACL and Auth with laravel 5.
Let me know if you have any further related question. Or If you need complete implementation I'll provide it to you.
For a one-to-many relationship you don't need a pivot table, so you can delete the user_roles table. Then add a role_id column to your users table, that will reference the id column in for your roles table. Next define the relations as follows for each of your models:
// User.php
public function role()
{
return $this->belongsTo('App\Role');
}
and
// Role.php
public function users()
{
return $this->hasMany('App\User');
}
Now you can access your role via the relation like this:
$user->role->name;
I got the problem, i was having a role column in user table, so when i was doing
$user->role->role_name
it was fetching role column instead of relationship.
i noticed you are not using the laravel default table naming conventions,
you are using user_roles whereass laravel naming conventions state you should use:
role_user (alphabetical and singular)
you could override the belongsToMany by stating your custom table name ofcource.
public function users() {
return $this->belongsToMany('App\User', 'user_roles');
}
on the second node there are also some good libraries to handle these kind of things, take a look at : https://github.com/romanbican/roles

Resources