How to access to user data through intermediate table (hasOneThrough / hasManyThrough) - laravel

For a job posting application, I have three tables, which shortly are defined as:
applications:
id as primary key
job_offer_uuid as external key
job_offers:
uuid as primary key
user_id as external key
users:
Just laravel normal users table with id as primary key
Because I need to notify job_offer owner (a member of User model) any time that an application is registered, I'm trying to create a hasOneThrough or hasManyThrough relationship from applications to users, but without success for the moment.
For clarification:
User model only hosts users that publish job offers, and any user can publish many job offers. There is not applicants in users table
Based on my understanding of eloquent documentation (https://laravel.com/docs/8.x/eloquent-relationships#has-one-through), my actual code in Application model is:
public function publisher()
{
return $this->hasOneThrough(User::class, JobOffer::class, 'job_offer_uuid', 'user_id');
}
But it fires an SQL error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'job_offers.job_offer_uuid' in 'field list' (SQL: select `users`.*, `job_offers`.`job_offer_uuid` as `laravel_through_key` from `users` inner join `job_offers` on `job_offers`.`id` = `users`.`user_id` where `job_offers`.`job_offer_uuid` in (1)
using hasManyThrough instead, I got an identical error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'job_offers.job_offer_uuid' in 'field list' (SQL: select `users`.*, `job_offers`.`job_offer_uuid` as `laravel_through_key` from `users` inner join `job_offers` on `job_offers`.`id` = `users`.`user_id` where `job_offers`.`job_offer_uuid` in (1))
I can get accurate results using pure SQL with a sentence like this:
select applications.id, applications.job_offer_uuid, job_offers.uuid, job_offers.user_id, users.id, users.name, users.email from `applications` inner join job_offers on `applications`.`job_offer_uuid` = `job_offers`.`uuid` join users on job_offers.user_id = users.id where `applications`.id = 1
Any video or tutorial that I found related to this point are using the final table with a foreign key to the intermediate table, and thats means my User model should have a foreign job_offer_id key, but that make no sense to me.
Any clarification should be truly appreciate. Regards!

You are doing it wrong. You have to define relationship in User Model as follow:
public function publisher()
{
return $this->hasOneThrough(
Application::class,
JobOffer::class,
'user_id', // Foreign key on job_offers table
'job_offer_uuid', // Foreign key on applications table
'id', // Local key on user table
'uuid' // Local key on job_offer table
);
}

Related

Eloquent Intermediate Tabel with None Standard ID Column

While creating my database according to the eloquent standard, I ran into the problem that my table_name and id column name combined would be longer as 64 characters.
very_long_table_name.very_long_column_name_id
So I used a shorter column name as the foreign key in my Intermediate Table.
Migration file:
$table->unsignedBigInteger('short_id');
$table->foreign('short_id')->references('id')->on('very_long_table_name');
That worked fine, yet now I would like to insert a connection
Seeder.php:
$x->very_long_table_name()->attach($other_table_name->id);
I get the error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'very_long_column_name_id' in 'field list' (SQL: insert into very_long_table_name (just_an_id, very_long_column_name_id) values (1, 1))
What I would want is that it would use the column short_id instead of very_long_column_name_id to insert this, is there any cool way to fix this? or do I need to insert and query the connection manually if I keep the long names?
Like #Tim points out in the comments this needs to be done in the Model VeryLongTableName.php where you define the relationship:
public function very_long_table_name() {
return $this->belongsToMany(Model::class, 'very_long_table_name', 'local_id', 'short_id');
}

Pivot table but not using table id

Is it possible to make a Pivot Table without using table id?
users
id
biometric_id
first_name
last_name
attendances
id
biometric_id
date
emp_in
emp_out
user_attendances
user_id
attendances_biometrics_id
I wanted to ask if this is available to link it like this? Because I need to show the attendance of the user that has his biometrics.
If it is possible, how?
If attendances.biometric_id has a unique constraint on it then there should be no reason why you cannot use it as a foreign key constraint.
Assuming your tables have been setup properly with foreign key constraints, your user model would probably have something like this:
public function attendances() {
return $this->belongsToMany('App\Attendances', 'user_attendances', 'user_id', 'attendances_biometrics_id');
}

sql 42S22 error in Laravel (choosing a column I didn't mention)

I am doing a basic project in Laravel, when trying to delete an entry, it generates this error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'id' in 'where clause' (SQL: select * from `employees` where `id` = 6 limit 1)
and it is true I don't have a column named 'id', instead I have employee_id, but why is it choosing id instead of employee_id?
Please explain from where did it bring this id column?
In your Employee model (Employee.php), add
protected $primaryKey = 'employee_id';
This will tell Laravel to use employee_id as the primary key for Empolyee objects.

Laravel / Eloquent -- Lookup Table Issue

I have 3 tables that I am trying to work through and am having a hard time connecting them via Eloquent joins.
Character Table
profileID (PK)
Character Gear Table
profileId (PK)
qualityId (FK)
Quality Lookup Table
id (PK)
name
I am able to access the Character Gear Lookup with the following in my Character Model:
public function gear()
{
return $this->hasMany('App\Models\CharacterGear', 'profileId')->where('gearSet', '=', '0');
}
How do I get the lookup to work so that I can get the quality name from the Quality Lookup table to tie in to the gear() shown above?
Please let me know if you need any further information!
Figured it out. Eloquent has Nested Relationships and I didn't know that.

Soft delete on a intermediate table for many-to-many relationship

How do I set soft delete on an intermediate table which is connecting two different types of entities? I've added deleted_at column, but the docs say that I need to put this into the model:
protected $softDelete = true;
Of course, I don't have a model for an intermediate table.
Any idea?
You can put a constraint on the Eager Load:
public function groups()
{
return $this
->belongsToMany('Group')
->whereNull('group_user.deleted_at') // Table `group_user` has column `deleted_at`
->withTimestamps(); // Table `group_user` has columns: `created_at`, `updated_at`
}
Instead of HARD deleting the relationship using:
User::find(1)->groups()->detach();
You should use something like this to SOFT delete instead:
DB::table('group_user')
->where('user_id', $user_id)
->where('group_id', $group_id)
->update(array('deleted_at' => DB::raw('NOW()')));
You could also use Laravel's Eloquent BelongsToMany method updateExistingPivot.
$model->relation->updateExistingPivot($relatedId, ['deleted_at' => Carbon\Carbon::now()]);
So to use #RonaldHulshof examples you have a User model with a groups relationship which is a belongsToMany relationship.
public function groups() {
return $this->belongsToMany(Group::class)->whereNull('groups_users.deleted_at')->withTimestamps();
}
Then in order to soft delete the pivot table entry you would do the following.
$user->groups()->updateExistingPivot($groupId, ['deleted_at' => Carbon\Carbon::now()]);
As far as I understand it; an intermediate table is simply a length of string attaching one tables record to a record in another table and as such it does not require a soft delete method.
To explain, imagine you have a Users table and a Groups table, each user can have more than one Group and each Group can belong to more than one User. Your pivot table may be User_Group or something like that and it simply contains two columns user_id and group_id.
Your User table and Group table should have a deleted_at column for soft deletes, so when you "delete" say a Group, that group association will not appear in $User->Groups() while the pivot table row has remained unaffected. If you then restore that deleted Group, it will once again appear in $User->Groups().
The pivot table row should only be affected if that group record is hard deleted, in which case the pivot rows should also be hard deleted.
Now I have explained why I do not believe you need to add soft delete to a pivot table; is there still a reason why you need this behavior?

Resources