Laravel Eloquent Composite Primary Key Relationships - laravel

I have the following schema:
Schema::create('companies', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->unique();
$table->timestamps();
});
Schema::create('departments', function (Blueprint $table) {
$table->increments('id');
$table->integer('company_id');
$table->string('name');
$table->timestamps();
$table->foreign('company_id')->references('id')->on('companies');
$table->unique(['company_id','name']);
});
Schema::create('employees', function (Blueprint $table) {
$table->increments('id');
$table->integer('company_id');
$table->string('name');
$table->timestamps();
$table->foreign('company_id')->references('id')->on('companies');
});
Schema::create('managed_departments', function (Blueprint $table) {
$table->integer('company_id');
$table->integer('department_id');
$table->integer('manager_id');
$table->timestamps();
$table->primary(['company_id','department_id']);
// Overlapping foreign keys guarantee that the manager
// and the department belong to the same company.
$table->foreign(['company_id','department_id'])
->references(['company_id','department_id'])
->on('departments');
$table->foreign(['company_id','manager_id'])
->references(['company_id','id'])
->on('employees');
});
Schema::create('department_staff', function (Blueprint $table) {
$table->integer('company_id');
$table->integer('department_id');
$table->integer('employee_id');
$table->timestamps();
$table->primary(['company_id','department_id', 'employee_id']);
// Overlapping foreign keys guarantees that the employee and the
// managed department belong to the same company.
$table->foreign(['company_id','department_id'])
->references(['company_id','department_id'])
->on('managed_departments');
$table->foreign(['company_id','employee_id'])
->references(['company_id','id'])
->on('employees');
});
Whats the correct model relationship between the departments, managed_departments and the department_staff tables in the
above schema - i'm a bit confused with how to define the relationship when there are composite primary keys and the following doesn't look right to me and how will eloquent know the correct foreign keys?
class Department extends Model
{
// a department is managed by an employee
public function managedDepartment
{
$this->hasOne(app\ManagedDepartment)
}
}
class ManagedDepartment extends Model
{
// a managed department belongs to department
public function Department
{
$this->belongsTo(app\Department)
}
// a managed department is managed by an employee
public function Employee
{
$this->belongsTo(app\Employee)
}
}
class DepartmentStaff extends Model
{
public function employee()
{
return $this->belongsTo('App\Employee');
}
}
class Employee extends Model
{
// an employee can managed many depts
public function managedDepartment
{
$this->hasMany(app\ManagedDepartment)
}
// an employee is asigned to one department
public function departmentStaff()
{
return $this->hasOne('App\DepartmentStaff');
}
}

Related

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

Laravel: query specific rows across pivot table

If I have two tables individuals and contracts with a many to many relationship represented in a table contracts_individuals_map, how would make query that is equivalent to:
SELECT *
FROM individuals
WHERE individuals.id IN
(SELECT individual_id
FROM contracts_individuals_map
WHERE contract_id IN (9,11)
);
MODELS:
class Individual extends Model
{
public function contracts()
{
return $this->belongsToMany(Contract::class, 'contracts_individuals_map');
}
}
class Contract extends Model
{
public function individuals()
{
return $this->belongsToMany(Individual::class, 'contracts_individuals_map');
}
}
MIGRATION:
public function up()
{
Schema::create('contracts_individuals_map', function (Blueprint $table) {
$table->id();
$table->integer('contract_id')->unsigned();
$table->integer('individual_id')->unsigned();
});
Schema::table('contracts_individuals_map', function (Blueprint $table)
{
$table->foreign('contract_id')
->references('id')
->on('contracts')
->onUpdate('cascade')
->onDelete('cascade');
$table->foreign('individual_id')
->references('id')
->on('individuals')
->onUpdate('cascade')
->onDelete('cascade');
});
}
or more generally, if I had a variable of objects
$cts = Contract::whereIn('id', [9,11])->get()`;
How would I get get all individuals associated with all the contracts in $cts?
You can leverage whereHas with something like this:
$individuals = Individual::whereHas('contracts', function ($query) {
return $query->whereIn('contracts_individuals_map.contract_id', [9, 11]);
})

Laravel Polymorphic HasOne ,two different categories model to the same item

I'm trying to use two different Category model to the same items table.
I'v got 3 models
SystemCategory
Schema::create('system_categories', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
UserCategory
Schema::create('user_categories', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->integer('user_id');
$table->timestamps();
});
Item
Schema::create('items', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->integer('categoryable_id');
$table->string('categoryable_type');
$table->timestamps();
});
Item category could be either from system_categories or user_categories table
I saw some Polymorphic relations but its about how two different models can belongs to one category, not about how model can belongs to two different category models
Thanks.
It can be done, first thing your schema looks ok but you want to set catagoryable_id to a bigInteger to match the id columns of the 2 category tables.
Then you would set your models up
class Item extends Model
{
public function categoryable()
{
return $this->morphTo();
}
}
class SystemCategory extends Model
{
public function items()
{
return $this->morphMany('App\Item', 'categoryable');
}
}
class UserCategory extends Model
{
public function items()
{
return $this->morphMany('App\Item', 'categoryable');
}
}
Obviously this is presuming your models are in the App namespace

BadMethodCallException: Trying to list all partners with the categories laravel

I'm experiencing the following:
Goal: I would like to list all partners and the categories they belong to. Basically, it's a many to many relationship.
Below is the code:
Partner Categories Table Migration
public function up()
{
Schema::create('partcats', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('partcatnameP')->unique();
$table->unsignedBigInteger('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->timestamps();
});
}
Partners Table Migration
public function up()
{
Schema::create('partners', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('partnername');
$table->string('regnumber')->unique();
$table->unsignedBigInteger('activestatus_id')->unsigned();
$table->foreign('activestatus_id')->references('id')->on('activestatuses');
$table->unsignedBigInteger('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->timestamps();
});
}
Partner_Category Migration
public function up()
{
Schema::create('partner_partcat', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('partner_id')->unsigned();
$table->foreign('partner_id')->references('id')->on('partners')->onDelete('cascade');
$table->unsignedBigInteger('partcat_id')->unsigned();
$table->foreign('partcat_id')->references('id')->on('partcats')->onDelete('cascade');
$table->timestamps();
});
}
Models are as shown below:
Partcat Model
public function partners()
{
return $this->belongsToMany('App\Partcat','partner_partcat');
}
Partner Model
public function partcats()
{
return $this->belongsToMany('App\Partcat','partner_partcat');
}
and the Partners Controller is as shown below:
public function index()
{
//
$partners = Partner::all()->partcats();
// dd(Partner::all()->partcats());
return view('partners.index',['partners'=>$partners]);
}
This is where I'm trying to retrieve the list of partners and its related categories. However, I get a BadMethod call error.
You can use the following method
$partners = Partner::with('partcats')->get();
https://laravel.com/docs/5.6/eloquent-relationships#eager-loading
A many to many pivot table typically has the id for both tables it is relating.
The Partner_Category migration you have posted only seems to contain a partner_id. You may need to add in the category_id.
public function up()
{
Schema::create('partner_partcat', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('partner_id')->unsigned();
$table->unsignedBigInteger('partcat_id')->unsigned();
$table->timestamps();
$table->foreign('partner_id')->references('id')->on('partners')->onDelete('cascade');
$table->foreign('partcat_id')->references('id')->on('partcats')->onDelete('cascade');
});
}

Eloquent Query with Pivot Table

I have a question about how to generate a query with eloquent and I would appreciate any help from you.
I have 4 tables in my database:
1. modules
2. roles
3. module_rol (pivot table)
4. regions
Structure of the tables:
modules:
id int
name string
region int
active bool
roles
id int
name string
module_rol
rol_id int
module_id int
regions
id int
name string
I need to get all the values ​​from the modules table with some conditions for example ..
public function getUserModules($rol, $region)
{
// Return all modules to which that role is allowed to access and have that region defined
}
While waiting for some help, thank you very much in advance
EDIT 1:
Schema::create('regions', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('modules', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->integer('region')->unsigned();
$table->boolean('active')->default(true);
$table->timestamps();
$table->foreign('region')
->references('id')->on('regions')
->onDelete('cascade');
});
Schema::create('roles', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('module_rol', function (Blueprint $table) {
$table->increments('id');
$table->integer('rol_id');
$table->integer('module_id');
$table->timestamps();
$table->foreign('rol_id')
->references('id')->on('roles')
->onDelete('cascade');
$table->foreign('module_id')
->references('id')->on('modules')
->onDelete('cascade');
});
You need to define ManyToMany relationship between Module and Role using pivot table
Module Model
public function roles(){
return $this->belongsToMany(Role::class, 'module_rol');
}
public function region(){
return $this->belongsTo(Region::class, 'region');
}
Role Model
public function modules(){
return $this->belongsToMany(Module::class, 'module_rol');
}
Fetch Data
public function getUserModules($role, $region)
{
// Return all modules to which that role is allowed to access and have that region defined
$modules = Module::where('region', $region->id)
->whereHas(['roles' => function($query) use ($role) {
return $query->where('role_id', $role->id)
}])->get();
return $modules;
}
Details https://laravel.com/docs/5.6/eloquent-relationships#many-to-many

Resources