Laravel: cannot insert into many to many relationship - laravel

i hope you're having a good day.
so i have this ManyToMany relationship where a user can apply to multiple jobs, and a job can have multiple applicants (users).
here is the table schema
Schema::create('applicant_job', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('job_id');
$table->unsignedBigInteger('applicant_id');
$table->unique(['job_id', 'applicant_id']);
$table->foreign('job_id')
->references('id')
->on('jobs')
->onDelete('cascade');
$table->foreign('applicant_id')
->references('id')
->on('default_users')
->onDelete('cascade');
});
and here is the model code.
DefaultUser.php
class DefaultUser extends Model
{
public function user()
{
return $this->morphOne(User::class, 'userable');
}
public function applications()
{
return $this->belongsToMany(Job::class, 'applicant_job', 'job_id', 'applicant_id');
}
}
and Job.php
class Job extends Model
{
public function owner()
{
return $this->belongsTo(BusinessUser::class, 'business_user_id');
}
public function applicants()
{
return $this->belongsToMany(DefaultUser::class, 'applicant_job', 'applicant_id', 'job_id');
}
}
everything seems ok and find, however when i try to save ( a user applying to a job), i get the following error
i'm doing so inside ApplyToJobController.php
class ApplyToJobController extends Controller
{
public function store(Job $job, Request $request) {
$default_user = auth()->user()->userable;
$job->applicants()->attach($default_user->id);
return redirect("/en");
}
}
and, Thank you very much for your answers.
EDIT
i have changed the column names to this
Schema::create('applicant_job', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('job_id');
$table->unsignedBigInteger('default_user_id');
$table->unique(['job_id', 'default_user_id']);
$table->foreign('job_id')
->references('id')
->on('jobs')
->onDelete('cascade');
$table->foreign('default_user_id')
->references('id')
->on('default_users')
->onDelete('cascade');
});
it made it work, im curios any idea why?

Try to switch the order of the foreign keys in the applicants relation declared in the Job model like the example below :
public function applicants()
{
return $this->belongsToMany(DefaultUser::class, 'applicant_job', 'job_id', 'applicant_id');
}

Related

Laravel creates a one-to-many relationship instead of one-to-one

When I create a one-to-one relationship migration, laravel creates a one-to-many relationship. I tried to solve this in different ways and nothing worked.
How can I solve this?
Company:
class Company extends Model
{
public function user()
{
return $this->hasOne(User::class);
}
...
}
User:
class User extends Authenticatable
{
public function company(){
return $this->belongsTo(Company::class);
}
...
}
Migrations:
Schema::create('Company', function (Blueprint $table) {
$table->mediumIncrements('idCompany');
...
});
Schema::create('User', function (Blueprint $table) {
$table->id();
$table->increments('idUser');
$table->unsignedMediumInteger('Company_idCompany')
->unique()
->nullable();
$table->foreign('Company_idCompany')
->references('idCompany')
->on('company')
->onDelete('set null');
...
});
Laravel is creating nothing (on the migration), you always have to manually create the Model relationship (you are using hasOne and belongsTo, so that is 1-to-1) and migrations (you are creating User and Company not following the standards).
So, update your migrations to:
Schema::create('company', function (Blueprint $table) {
$table->id();
...
});
Schema::create('user', function (Blueprint $table) {
$table->id();
$table->increments('user_id');
$table->foreignId('company_id')
->unique()
->nullable();
$table->foreign('company_id')
->references('id')
->on('company')
->onDelete('set null');
...
});
See that I have moved everything to lowercase and snake case, remember to follow Laravel conventions or you are going to have a harder time working with Models...
Then, your relationships are correct:
class Company extends Model
{
public function user()
{
return $this->hasOne(User::class);
}
...
}
class User extends Authenticatable
{
public function company(){
return $this->belongsTo(Company::class);
}
...
}
So, when you do access a relationship, it will work out of the box now.
If you do Company::first()->user, that will return User or null, and if you do User::first()->company, that will return Company or null, there is no 1-to-N.

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

Fetching Relationship Model Data

I have the Below Table Structure
Users table
id- integer
name-string
Casefiles table
id- integer
user_id- foreign_key
name-string
Followups table
id- integer
date- date
casefile_id-foreign_key
I'm using the below Relationship between this models
User.php
public function casefiles()
{
if ($this->hasRole(['sales_executive'])) {
return Casefile::where('user_id', $this->id);
}
}
Casefile.php
public function user()
{
return $this->belongsTo('App\User');
}
public function followups()
{
return $this->hasMany('App\FollowUp');
}
Followup.php
public function casefile()
{
return $this->belongsTo('App\Casefile');
}
I want to fetch Users followups directly. How can i achive this ?
you need to use hasManyThrough() in your User.php you can add this,
public function followUps()
{
return $this->hasManyThrough('App\FollowUp','App\Casefile');
}
then you can normally call the followups using User::with('followUps')->find(1)->followUps
I have noticed that you are checking role in your relationship $this->hasRole(['sales_executive'] this may occur error as you are not if the statement is false. I think you take another approached and handle that as well. for more information on hasManyThrough prefer this link
This should be the case for a HasManyThrough Relationship.
In your case it should be
// Followups migration
Schema::create('followups', function (Blueprint $table) {
$table->bigIncrements('id');
$table->date('date');
$table->unsignedBigInteger('casefile_id')->nullable();
$table->timestamps();
$table->foreign('casefile_id')
->references('id')
->on('casefiles');
});
// Casefile migration
Schema::create('casefiles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->unsignedBigInteger('user_id')->nullable();
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users');
});
// User.php
public function followups() {
return $this->hasManyThrough(FollowUp::class, Casefile::class);
}
// YourController.php
$user = User::all()->first();
dd($user->followups);

accessing nested relationship in laravel 5

i have 3 models like below :
Date
Property
PropertyDetail
and here is my migration for tables i write in order
Date :
public function up()
{
Schema::create('dates', function (Blueprint $table) {
$table->bigIncrements('id');
$table->dateTime('date');
$table->timestamps();
});
}
Property :
public function up()
{
Schema::create('properties', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('type');
$table->text('title');
$table->integer('base_capacity');
$table->timestamps();
});
and PropertyDetail :
public function up()
{
Schema::create('property_details', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('property_id');
$table->string('state');
$table->string('city');
$table->timestamps();
});
}
i tried to remove unnecessarily fields from migration so to keep it clean so here is my 2 relations bettwen date and proeprties
Datemodel :
public function properties() {
return $this->belongsToMany(Property::class);
}
and propery model :
public function dates(){
return $this->belongsToMany(Date::class);
}
public function features(){
return $this->hasMany(Feature::class);
}
ok now finally in my controller i want to do this :
$search = Date::with('properties')
->where('date',$someday)->get()
->and some how here i want to select the city from the property detail table
;
so here is my problem , now i can easily access properties and show thier name but from this relation how can i access features relation and select the city from there should i use joins or some thing there i hope i was clear enough that what i want to do
You can do this:
Property model:
public function details(){
return $this->belongsToMany(Details::class,'property_details','id','property_id');
}
and in Date model:
public function properties() {
return $this->belongsToMany(Property::class);
}
public function propertiesDetails() {
return $this->properties()->with('details');
}
and in your controller you can get detail of properties by use:
$search = Date::with('propertiesDetails')
->where('date',$someday)->get();
now you can access to details of properties.
Hope it helps.

One to Many not working on Laravel Eloquent

I have three models that are related. First I have User that belongs to a Role. On the other hand, Role has many roles. Role belongs to many permissions and Permissions belongs to many Role. I am using the AuthServiceProvider as suggested by jeffrey way of laracast. But the problem now, when I want to fetch all the permissions of a User I am having error which is, "Call to a member function getKey() on boolean". Can someone please help me on this. Please refer to the codes below.
User.php
public function role()
{
return $this->belongsTo('App\Role');
}
public function assignRole($role)
{
return $this->roles()->save(
Role::whereName($role)->firstOrFail()
);
}
public function hasRole($role)
{
if(is_string($role)){
return $this->role->contains('name', $role);
}
return !! $role->intersect($this->role)->count();
}
Role.php
class Role extends Model
{
public function users()
{
return $this->hasMany('App\User');
}
public function permissions()
{
return $this->belongsToMany('App\Permission');
}
public function givePermissions(Permission $permission)
{
return $this->permissions()->save($permission);
}
}
Permission.php
class Permission extends Model
{
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
AuthServiceProvider
public function boot(GateContract $gate)
{
$this->registerPolicies($gate);
//get all permissions
foreach ($this->getPermissionTo() as $permission ) {
$gate->define($permission->name, function($user) use ($permission){
return $user->hasRole($permission->roles);
});
}
}
public function getPermissionTo()
{
return Permission::with('roles')->get();
}
and lastly, heres the user table that has a foreign key of role_id
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->integer('role_id')->unsigned();
$table->string('id_no')->unique()->index();
$table->string('u_first_name');
$table->string('u_middle_name');
$table->string('u_last_name');
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
roles table
Schema::create('roles', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('label')->nullable();
$table->timestamps();
});
permissions table
Schema::create('permissions', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('label')->nullable();
$table->timestamps();
});
permission_role table
Schema::create('permission_role', function (Blueprint $table) {
$table->integer('permission_id')->unsigned();
$table->integer('role_id')->unsigned();
$table->foreign('permission_id')
->references('id')
->on('permissions')
->onDelete('cascade');
$table->foreign('role_id')
->references('id')
->on('roles')
->onDelete('cascade');
$table->primary(['permission_id', 'role_id']);
});
In the line: return !! $role->intersect($this->role)->count();, the part that says $this->role is probably not returning a collection, which is why you're getting this error. In Collection.php there's a method that iterates through all the items in a collection you send through the intersection method that gets the primary key of it. Because you're not sending a collection to the intersect() method, it tries to use the method getKey() in a boolean. Try:
return !! $role->intersect($this->role->get())->count();

Resources