Relationship to users table without using the standard 'user_id' column name - laravel

I have 2 tables, one has different columns to record different users names based on authorisation level. but i would like to link to two together. at the moment i have tried the following:
User.php
public function approvals()
{
return $this->hasMany(Approval::class);
}
Approval.php
public function qs() {
return $this->belongsTo(User::class, 'id', 'qs');
}
index.blade.php
<td>{{ $approval->qs->name }}</td>
approvals db structure
Schema::create('approvals', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('project_id');
$table->integer('stage');
$table->unsignedBigInteger('qs')->nullable();
$table->unsignedBigInteger('pm')->nullable();
$table->unsignedBigInteger('rcm')->nullable();
$table->unsignedBigInteger('doc')->nullable();
$table->unsignedBigInteger('vpoc')->nullable();
$table->unsignedBigInteger('vpof')->nullable();
$table->timestamps();
});
users db structure
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email', 100)->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Am i going about this all wrong, the qs table column needs to be linking to the users.id?

It seems qs is the user id of the User model. So the relation to the Approval model is
public function qs()
{
return $this->belongsTo(User::class, 'qs');
}
And in User model
public function approvals()
{
return $this->hasMany(Approval::class, 'qs');
}
Now you can use
{{ $approval->qs->name }}
Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with a _ followed by the name of the primary key column. However, if the foreign key on the Model is not parent_id, you may pass a custom key name as the second argument to the belongsTo method.
Laravel Documentation

If a parent model does not use id as its primary key, or you want to join the child model to a different column, you may pass a third argument to the belongsTo method:
public function qs() {
return $this->belongsTo(User::class, 'foreign_key_here_from_child_table', 'custom_column_from_parent_table');
}

Related

How to take out subscription list in Larvel?

I'm creating project with Laravel. I want to pull out user->name from subscription table which also has user_id column in it. I want to show the current user's subscribers' name from subscription table. But it shows error:
Property [subs] does not exist on this collection instance
here is my code.
This is from IndexController
public function home() {
$data = User::all();
return view("amvs.index", [
'users' => $data,
]);
}
This is from index.blade.php
Subscriptions
#foreach ($users->subs as $sub)
<span class="ms-2">{{$subs->name}}</span>
#endforeach
This is from user model
public function sub(){
return $this->hasMany('App\Models\Subscription');
}
I didn't write anything in Subscription model. My subscription table
Schema::create('subscriptions', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->integer('user_id');
$table->timestamps();
});
My user table
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
I'm a beginner so enlighten me.
The issue is that you're trying to access a method on an Eloquent Collection which does not have any properties or methods relatated to your User or its sub relationship.
Additionally, consider using Eager Loading when accessing relationships, it is more performant and solves the N+1 query problem.
public function home() {
// access the authenticated User and load their subs relationship
$user = Auth::user()->with('subs')->first();
return view("amvs.index", [
'user' => $user
]);
}
Then to access the Users subs in your view:
#foreach ($user->subs as $sub)
{
<span class="ms-2">{{$sub->name}}</span>
}
However, you will want to change your subscriptions migration as the user_id field needs to be the same type as the id field on your users table.
Schema::create('subscriptions', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->foreignId('user_id');
$table->timestamps();
});
Further questions
don't know why I should use foreignId?
For relationships to work, the field type (string, integer etc.) of the primary and foreign key fieds must be the same. The default primary key in Laravel is the id field and it has as type of unsigned big integer. If you define a foreign key field in a related table and its type is anything other than unsignedBigInteger the relationship will fail.
foreignId is simply a helper method provided by Laravel that creates a field with the correct type and the required foreign key reference. Previously you had to do that all yourself, for example:
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
why you used first()?
The reason for using first() is that it returns a Model rather than an Eloquent Collection. You're only interested in one User (the authenticated User) so it is more efficient to use first() rather than get() as you don't then need to loop or extract the first item in the collection.
You might want to spend some free time watching the Laravel from Scratch series. It is really detailed and covers lots of common scenarios.
First of all, In your controller you should load the subs. That will be better as it will not add extra query for loading the relations. So what you can do is following
$data = User::with('subs')->all();
you should also change the relationship as hasMany follows the following convention:
public function subs(){
return $this->hasMany('App\Models\Subscription');
}
As you are pulling all the users you have to first loop through the users first, then you can iterate over subs for each users like below:
#foreach ($users as $user)
#foreach ($user->subs as $sub)
<span class="ms-2">{{$subs->name}}</span>
#endforeach
#endforeach

Laravel8 Many To Many change id for custom attribute

I created a relationship many-to-many between Faculties and Departments(im Working in a prototype timetable problem). For a petition, these tables need a validation code vcode. The problems are in the relationship of this, I don't know why the relationship recognize only the id´s tables for the eloquent query and not the vcode.
attached my migrations and model relationship.
Migration Faculties Table
public function up()
{
Schema::create('faculties', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('vcode')->index()->unique();
$table->string('code');
$table->string('name');
$table->string('website');
$table->string('email');
$table->string('phone');
$table->timestamps();
});
}
Relationshop on Faculty Model
public function departments()
{
return $this->belongsToMany(Department::class, 'faculty_departments','faculty_vcode','department_vcode');
}
Migration Departments Table
public function up()
{
Schema::create('departments', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('vcode')->index()->unique();
$table->string('code');
$table->string('name');
$table->string('phone');
$table->string('email');
$table->string('website');
$table->timestamps();
});
}
Relationshop on Department Model
public function faculties()
{
return $this->belongsToMany(Faculty::class, 'faculty_departments', 'department_vcode','faculty_vcode',);
}
Migration FacultyDepartments (Relationship)
public function up()
{
Schema::create('faculty_departments', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('faculty_vcode')->nullable()->index();
$table->foreign('faculty_vcode')
->references('vcode')
->on('faculties')
->cascadeOnUpdate()
->nullOnDelete();
$table->unsignedBigInteger('department_vcode')->nullable()->index();
$table->foreign('department_vcode')
->references('vcode')
->on('departments')
->cascadeOnUpdate()
->nullOnDelete();
$table->timestamps();
});
}
I provocate a error for get the query and tested the error (getting id´s table).
faculty::with('departments')->get() gives me:
select `departments`.*, `faculty_departments`.`faculty_vcode` as `pivot_faculty_vcode`, `faculty_departments`.`department_vcode` as `pivot_department_vcode`
from `departments`
inner join `faculty_departments` on `departments`.`id` = `faculty_departments`.`department_vcode`
where `faculty_departments`.`faculty_vcode` in (1, 2, 3, 4, 5, 6, 7)
Since you're not providing the field names for the faculties table or the departments table Laravel will assume it's the primary key (id) for those tables.
You need to update your belongsToMany method to be:
public function departments()
{
return $this->belongsToMany(
Department::class, // The related model
'faculty_departments', // The intermediate (pivot) table name
'faculty_vcode', // The pivot field relating to faculties
'department_vcode', // The pivot field relating to departments
'vcode', // The field on the faculties table
'vcode', // The field on the departments table
);
}

issue with laravel elquent relation

I have a column name creator in the table storing the user id. When fetching records, I am using belongs to relation. I receive data, but I am not able to display it.
Note: This thread doesn't solve my issue
Category table scheme
Schema::create('categories', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->unique();
$table->string('slug')->unique();
$table->string('banner')->nullable();
$table->boolean('status')->default(false);
$table->bigInteger('creator');
$table->bigInteger('moderator');
$table->timestamps();
});
user table scheme
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Category Model:
public function creator(){
return $this->hasOne(User::class, 'id', 'creator')->select('id', 'name');
}
Category Controller code:
$records = Category::with(['creator'])->paginate(env('REC_LIMIT'));
data I get it:
"data":[{"id":1,"name":"Uncategorized","slug":"uncategorized","banner":null,"status":1,"creator":{"id":1,"name":"demon slayer"},"moderator":1,"created_at":"2019-11-03 12:08:33","updated_at":"2019-11-04 11:11:01"},
note if with clause is removed in the query, I get:
"data":[{"id":1,"name":"Uncategorized","slug":"uncategorized","banner":null,"status":1,"creator":1,"moderator":1,"created_at":"2019-11-03 12:08:33","updated_at":"2019-11-04 11:11:01"},
in blade file, I what am doing is below code to print creator user name instead of their record id.
$record->creator->name
//or
$record->creator[0]->name
currently i get this:
Facade\Ignition\Exceptions\ViewException
Trying to get property 'name' of non-object (View: /Users/dragonar/Dev/pdp/resources/views/backend/category/index.blade.php)
Have you tried instead of
public function creator(){
return $this->hasOne(User::class, 'id', 'creator')->select('id', 'name');
}
This:
public function creator(){
return $this->hasOne(User::class, 'user_id')->select('id', 'name');
}
Or change the name of the function from creator() to user().
And then in your blade $record->user->name.
This what I found on the laravel docs:
Eloquent determines the foreign key of the relationship based on the model name. In this case, the Phone model is automatically assumed to have a user_id foreign key. If you wish to override this convention, you may pass a second argument to the hasOne method: return $this->hasOne('App\Phone', 'foreign_key');
Source
I ended up renaming creator to creator_id and in model, function is creator. like this now i can access desired data $record->creator->name or $record->creator->id.
what i wanted was instead of creator returing me id from original code, i could have been able to do $record->creator->name or $record->creator->id, directly.

laravel eloquent relation one to one

I have a Laravel migration like this
usergroups:
Schema::create('usergroups', function (Blueprint $table) {
$table->integer('id')->primary();
$table->string('name');
$table->string('slug');
});
users:
Schema::create('users', function (Blueprint $table) {
$table->integer('nik')->primary();
$table->string('name');
$table->string('username');
$table->string('password');
$table->string('telp', 15);
$table->integer('usergroup_id');
$table->rememberToken();
$table->timestamps();
});
Schema::table('users', function ($table) {
$table->foreign('usergroup_id')->references('id')->on('usergroups')->onDelete('cascade');
});
User model
public function group()
{
return $this->belongsTo(Usergroup::class, 'id');
}
Usergroup model
public function user()
{
return $this->hasMany(User::class, 'usergroup_id');
}
I get blank data with this
$petugas = User::find(1);
return $petugas->group;
anyone help me, please...
This is not a One to One relationship i.e (user has one phone and one phone belongs to one user)
A group has many users in this case, One to Many relationship
You're migrating the users table twice, move the foreign key to the migration
Schema::create('users', function (Blueprint $table) {
$table->integer('nik')->primary();
$table->string('name');
$table->string('username');
$table->string('password');
$table->string('telp',15);
$table->integer('usergroup_id');
$table->foreign('usergroup_id')->references('id')->on('usergroups')->onDelete('cascade');
$table->rememberToken();
$table->timestamps();
});
Hope this helps
First of all, this is not a One to One relationship. This is a One to Many relationship. The relation you have build in wrong way according to migration files.
The relation code block should look like this.
public function group()
{
return $this->hasMany(Usergroup::class);
}
public function users()
{
return $this->belongsTo(User::class);
}
Some more info:
In your scenario there might be two possible fact.
A user has many groups, but a group is belongs to only one
user.
A group has many users but a user is belongs to only one
group.
Fact 1: In this case the foreign key column should place in groups table. To follow the convention make the foreign column name user_id in groups table. And the code should look like this
public function groups()
{
return $this->belongsTo(Usergroup::class);
}
public function user()
{
return $this->hasMany(User::class);
}
Fact 2: In this case the foreign key column should place in users table. To follow the convention make the make the foreign column name group_id in users table And the relation code should look like this
public function group()
{
return $this->hasMany(Usergroup::class);
}
public function users()
{
return $this->belongsTo(User::class);
}
i got it...
this on user model
public function group()
{
return $this->belongsTo(Usergroup::class,'usergroup_id');
}
and this on usergroup model
public function user()
{
return $this->hasMany(User::class,'usergroup_id');
}

Laravel hasOne (one to one relationship)

I am trying to learn Laravel-> one to one relationship.
In given code link(join) should be dependent on name(user2s table) and title(post2s table) but the link(join) is dependent on my_id(user2s table) and title(post2s table)
My full codes
Migrations:-
user2s table
Schema::create('user2s', function (Blueprint $table) {
$table->increments('my_id');
$table->string('name');
$table->string('email');
$table->string('password');
$table->string('remember_token');
$table->timestamps();
});
post2u table:
Schema::create('post2s', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->string('title');
$table->text('content');
$table->timestamps();
$table->tinyInteger('is_admin');
});
Model User2
protected $primaryKey = 'my_id';
public function postx(){
return $this->hasOne(Post2::class, 'title', 'name');
}
My Route Code
Route::get('user/{id}/post', function($id){
return User2::find($id)->postx;
});
http://localhost:8000/user/abc/post
error: Trying to get property of non-object
user2s table
post2s table
Let me explain what is your issue.
error: Trying to get property of non-object, it means it can't find the result. The result object is null, so when you looking for null->postx, it can't get them anything.
You search for User2::find($id), when you use find(), it is looking for primary key. And you User2 Model primary key is my_id, and you are looking for Post2->title. It not able to find it.
More infor about find()
https://laravel.com/docs/5.5/eloquent#retrieving-single-models
Since you are looking for the Post2 title. And you are referencing from User2. It is not correct.
What you should do is
In your route.php
Route::get('user/{title}/post', function($title){
//return Post2::all();
$post = Post2::with('userx')->where('title', $title)->first();
dump($post);
dump($post->userx)//<- you can get user info via
});
In Post2 Model.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post2 extends Model
{
public function userx(){
return $this->belongsTo(User2::class, 'user_id');
}
}

Resources