I many-to-many relationship, get ID of pivot table - laravel

I have the following models in a many-to-many relationship:
class Event extends Model
{
public function positions() {
return $this->belongsToMany(Position::class, 'position_events');
}
}
class Position extends Model
{
public function events() {
return $this->belongsToMany(Event::class, 'position_events');
}
}
class PositionEvent extends Model
{
public function position() {
return $this->hasOne(Position::class, 'id', 'position_id');
}
public function event() {
return $this->hasOne(Event::class, 'id', 'event_id');
}
}
The position_events table looks like:
id | event_id | position_id
If $event is an instance of Event, I can get the related positions as:
$event->positions;
This gives me something like the following for each related Position:
{"id":4,"name":"Striker","created_at":"2019-04-02 16:19:57","updated_at":"2019-04-02 16:19:57","pivot":{"event_id":27,"position_id":4}}
Notice the pivot element. It only has event_id and position_id as properties, these are columns from the position_events table. How do I get it to have the id column from that table as well?

Have you tried using withPivot(), for example:
$this->belongsToMany(Position::class, 'position_events')->withPivot('id');

Related

Laravel Eloquent HasManyThrough through 3 tables with pivot tables

I need to make a list of scopes from my positions->areas->scopes on my Booking Model.
My tables look like that:
Booking
id
...
Position
id
booking_id
...
Area
id
..
Position_areas
id
area_id
position_id
Scope
id
...
Area_Scopes
id
area_id
scope_id
And this are my relations:
class Booking extends Model
{
...
public function positions()
{
return $this->hasMany(BookingPosition::class);
}
public function areas()
{
return $this->hasManyThrough(Area::class, PositionsAreas::class, 'area_id', 'id', 'position_id', 'area_id');
}
...
}
class BookingPosition extends Model
{
...
public function booking()
{
return $this->belongsTo(Booking::class);
}
public function areas()
{
return $this->belongsToMany(Area::class, 'position_areas', 'position_id', 'area_id')
->using(PositionsAreas::class);
}
...
}
class PositionsAreas extends Pivot
{
...
protected $table = 'position_areas';
public function positions(){
return $this->belongsTo(BookingPosition::class);
}
public function areas(){
return $this->belongsTo(Area::class);
}
...
}
class Area extends Model
{
...
public function bookingPositions()
{
return $this->belongsToMany(
BookingPosition::class
)->using(PositionsAreas::class);
}
public function scopes()
{
return $this->belongsToMany(Scope::class, table: 'scope_areas');
}
...
}
class Scope extends Model
{
...
public function areas(){
return $this->belongsToMany(Area::class, table: 'scope_areas');
}
...
}
And I want to have a list of all areas on my booking model, but I don't know how to achieve that.
So that I can do something like that
...
$booking->load('scopes');
[
id
date
...
scopes => [
{...},
{...}
]
]
I tried to create pivot models for position_areas but i cant even get a list of areas on my booking model.
I couldn't figure out how to solve this with a relation like hasManyThrough but as workaround I make all scopes available in my $bookings like that.
$booking = Booking::find($booking->id);
$booking->scopes = $booking->positions
->pluck('areas')
->flatten()
->pluck('scopes')
->flatten()
->pluck('name')
->unique()
->values()
->all();

Adding and saving fields in a related belongsToMany table

The tables category, category_description and descriptions are related:
public function descriptions(): BelongsToMany
{
return $this->belongsToMany(Description::class);
}
public function categories(): BelongsTo {
return $this->belongsTo(Category::class);
}
public function descriptions(): BelongsTo {
return $this->belongsTo(Description::class);
}
public function descriptions(): BelongsToMany
{
return $this->belongsToMany(Category::class);
}
in Model respectively. When saving or updating:
public function createOrUpdate(Category $category, Request $request)
{
$category->fill($request->get('category'))->save();
$category->descriptions()->syncWithoutDetaching(
$request->input('category.descriptions', [])
);
}
An error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'description' in 'field list' (SQL: insert into `category_description` (`category_id`, `description`, `description_id`, `is_active`, `meta-description`, `meta-h1`, `meta-keyword`, `meta-title`, `name`, `slug`) values (1, 41231231, 0, 1, 23, 124, 12, 12, 12333312, 74))
Perhaps I missed something somewhere, since there is not so much experience.
UPDATE:
a category can have multiple entries, but the description has only one parent. Rewrote — One To Many (Polymorphic):
public function descriptions()
{
return $this->morphMany(Description::class, 'descriptable');
}
public function descriptable()
{
return $this->morphTo();
}
There are no problems with saving 1 record, but how to update several records at the same time?
How about?
// Category Model.
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
public function descriptions()
{
return $this->belongsToMany(Description::class)
->using(CategoryDescription::class);
}
}
// Description Model.
use Illuminate\Database\Eloquent\Model;
class Description extends Model
{
protected $fillable = [
"name",
"description",
"meta-title",
"meta-description",
"meta-keyword",
"meta-h1",
"slug",
"is_active",
];
public function categories()
{
return $this->belongsToMany(Category::class)
->using(CategoryDescription::class);
}
}
// Intermediate Model.
use Illuminate\Database\Eloquent\Relations\Pivot;
class CategoryDescription extends Pivot
{
protected $table = "category_description";
public $incrementing = true;
public function category()
{
return $this->belongsTo(Category::class, "category_id", "id");
}
public function description()
{
return $this->belongsTo(Description::class, "description_id", "id");
}
}
// createOrUpdate method.
public function createOrUpdate(Category $category, Request $request)
{
$category->fill($request->get('category'))->save();
$description = Description::create(
Arr::collapse($request->input('category.descriptions', []))
);
$category->descriptions()->syncWithoutDetaching(
$description->id
);
}
Notes:
Much as this may work for you, I personally think that you don't have a many-to-many relationship here. I believe a one-to-many relationship is sufficient.
The problem is you send data to be inserted in columns that are not found
You should send only the data that you need to insert in the table
so in your case, you should write your function as
$category->descriptions()->syncWithoutDetaching($description_id); // the id of the description you want to attach with this category
If you still don't have the description yet in the database and you are creating it with the same request you can do something like this
Description::create(['columnName'=>$request->get('columnName'),'columnName2'=>$request->get('columnName2')])->id

Laravel 8.x, 3 models and many to many relationship

I am new to laravel and trying the following:
I have these tables:
disciplines: id | name
specialties: id | name
categories: id | name
discipline_specialty (pivot table): id | discipline_id | specialties_id
Discipline model:
public function specialties()
{
return $this->belongsToMany(Specialty::class);
}
Specialty model:
public function disciplines()
{
return $this->belongsToMany(Discipline::class);
}
My question is:
how can I relate (many to many) the categories to the pivot table discipline_specialty in order to access the category name with the discipline and specialty ids?
I had thought of an additional pivot table that linked category id and discipline_specialty id but I don't know if it's the best solution and how to do it. Do you have any suggestions? Any help is appreciated.
You can introduce a junction/pivot model that will relate these 3 relations as many-to-one/belongsTo and one-to-many/hasMany from Discipline/Speciality/Category.
Discipline Speciality Category
\\ || //
\\ || //
DisciplineSpecialityCategory
This DisciplineSpecialityCategory model will have following attributes or FKs
Table: discipline_speciality_category
discipline_id
speciality_id
category_id
Now you model definitions will be like
class Discipline extends Model
{
public function disciplineSpecialityCategory()
{
return $this->hasMany(DisciplineSpecialityCategory::class, 'id', 'discipline_id');
}
}
class Speciality extends Model
{
public function disciplineSpecialityCategory()
{
return $this->hasMany(DisciplineSpecialityCategory::class, 'id', 'speciality_id');
}
}
class Category extends Model
{
public function disciplineSpecialityCategory()
{
return $this->hasMany(DisciplineSpecialityCategory::class, 'id', 'category_id');
}
}
class DisciplineSpecialityCategory extends Model
{
public function discipline()
{
return $this->belongsTo(Discipline::class, 'id', 'discipline_id');
}
public function speciality()
{
return $this->belongsTo(Speciality::class, 'id', 'speciality_id');
}
public function category()
{
return $this->belongsTo(Category::class, 'id', 'category_id');
}
}

Laravel Eloquent Relationship with 4 tables (3 model + 1 table)

Hi I have this 4 tables
Employee:
EmployeeID,
EmployeeName,
EmployeeEmail,
EmployeePassword
Department:
DepartmentID,
DepartmentName
Position:
PositionID,
PositionType
employee_deployment:
EmployeeDeploymentID,
EmployeeID,
DepartmentID,
PositionID
I created a migration for a Pivot table employee_deployment
public function up()
{
// Set schema to create field of table
Schema::create('employee_deployment', function (Blueprint $table) {
$table->bigIncrements('EmployeeDeploymentID');
$table->bigInteger('EmployeeID')->unsigned();
$table->bigInteger('DepartmentID')->unsigned();
$table->bigInteger('PositionID')->unsigned();
});
Schema::table('employee_deployment', function ($table) {
$table->foreign('EmployeeID')->references('EmployeeID')->on('tbl_employees')->onDelete('cascade');
$table->foreign('DepartmentID')->references('DepartmentID')->on('tbl_departments')->onDelete('cascade');
$table->foreign('PositionID')->references('PositionID')->on('positions')->onDelete('cascade');
});
}
Can someone help me to create a relationship for each model? And save the data into pivot table (employee_deployment table).
A pivot table cannot be used in this way to define 2 relationships at once, instead I would recommend having a Deployment model which has a one to one relationship with the other three models.
class Deployment extends Model
{
public function employee()
{
return $this->hasOne('App\Employee');
}
public function department()
{
return $this->hasOne('App\Department');
}
public function position()
{
return $this->hasOne('App\Position');
}
}
class Employee extends Model
{
public function deployment()
{
return $this->belongsTo('App\Deployment');
}
}
class Position extends Model
{
public function deployment()
{
return $this->belongsTo('App\Deployment');
}
}
class Department extends Model
{
public function deployment()
{
return $this->belongsTo('App\Deployment');
}
}
If you want to be able to access the relationships between Employee and Position or Position and Department or Employee and Department directly you can also add hasOneThrough relationships to the other 3 models
public function employee()
{
return $this->hasOneThrough('App\Employee', 'App\Deployment');
}
public function department()
{
return $this->hasOneThrough('App\Department', 'App\Deployment');
}
public function position()
{
return $this->hasOneThrough('App\Position', 'App\Deployment');
}
I think this should get you the relationships you're looking for
If any of these relationships aren't 1 to 1 then you'll need pivot tables between Deployment and the other 3 models but you should be able to just switch hasOneThrough to hasManyThrough to keep the direct relationships
For your migrations, if you don't use regular id columns on the employee, department, and position models you'll have to add a custom foreign key definition to the relationships. As an example the one for Deployment->Employee would be
public function employee()
{
return $this->hasOne('App\Employee', 'EmployeeID', 'EmployeeID');
}

Eloquent/Laravel5 linking distant relations ("hasOneThrough")

The question in short:
"pages" and "tasks" have a many-to-many relationship linked by the pivot table "page_tasks". The table "responses" is linked to that pivot table by the foreign key "page_task_id".
Now I want to be able to access the page and the task a response belongs to directly with Eloquent. However the hasManyThrough function does not work, as it exspects the foreign_keys at different places:
public function task(){
return $this->hasManyThrough('PageTask', 'Task', 'page_task_id', 'task_id');
}
Unknown column 'tasks.page_task_id' in 'field list'
This means that eloquent exspects the task table having a foreign key page_task_id pointing to page_tasks. But in my model the page_tasks table has a foreign key task_id pointing to tasks. How do I tell eloquent that fact?
An other approach I tried was to use existing relations that were previously defined:
public function task(){
return $this->page_task->task();
}
This however tells me that there is no methoid called "task".
What would the recommended way be to achieve this? What am I doing wrong?
Here are some more details if needed:
"pages" and "tasks" have a many-to-many relationship with pivot table page_tasks linking it.
Page-Model:
class Page extends Model {
public function tasks(){
return $this->belongsToMany('Task', 'page_tasks');
}
}
Task-Model:
class Task extends Model {
public function pages()
{
return $this->belongsToMany('Page', 'page_tasks');
}
}
This works fine.
Response-Model looks like this
class Response extends Model {
protected $fillable = [
'page_task_id',
];
public function page_task(){
return $this->belongsTo('App\PageTask', 'page_tasks');
}
public function task(){
??????
}
}
PageTask-Model looks like this:
class PageTask extends Model {
protected $fillable = [
'page_id',
'task_id',
];
public function page(){
return $this->belongsTo('Page');
}
public function task(){
return $this->belongsTo('Task');
}
public function responses(){
return $this->hasMany('Response');
}
}

Resources