Laravel: query specific rows across pivot table - laravel

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

Related

Laravel: cannot insert into many to many relationship

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

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

Eloquent group by product, ordering differently based on product

I currently have the following set up:
Category, SubCategory, Business, Enhancement & Product models.
A Category has many SubCategorys
A SubCategory has many Businesss
A Business may have one Enhancement
A Enhancement must have one Product
A product could be an enhanced listing, a premium listing, or additional features.
If the business has brought either an enhanced or premium listing, it is recorded in the enhancement table.
So, product#1 = Premium Listing. Product#2 = Enhanced listing.
What I am wanting is to return all the businesses for a chosen SubCategory, grouping by the product that the enhancement is attached to. If the business has an enhancement, I'm wanting to randomise the order. If the business does not have a product, I'm wanting to order by name in ASC order.
So the result I'm expecting is to have a complete list of all businesses, with those with a Premium Listing, listed first in a random order. Then all businesses with an enhanced listing in a random order. Then all the other businesses that have no enhancement, in alphabetical order.
I currently have all the businesses listed in name order with the following code:
SubCategory::where('slug', $subCategory)->where('category_id', $category->id)
->with(['businesses' => function($query) {
$query->orderBy('name', 'ASC');
}])->firstOrFail();
Category model:
class Category extends Model
{
public function subCategories()
{
return $this->hasMany('\App\SubCategory');
}
}
SubCategory model:
class SubCategory extends Model
{
public function businesses()
{
return $this->hasMany('\App\Business');
}
public function category()
{
return $this->belongsTo('\App\Category');
}
}
Business model:
class Business extends Model
{
public function subCategory()
{
return $this->belongsTo('\App\SubCategory');
}
public function enhancements()
{
return $this->hasMany('\App\Enhancement');
}
}
Enhancement model:
class Enhancement extends Model
{
public function business()
{
return $this->belongsTo('\App\Business');
}
public function product()
{
return $this->belongsTo('\App\Product');
}
}
Product model:
class Product extends Model { }
Migrations:
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->unique();
$table->string('slug')->unique();
$table->string('featured_image');
$table->text('description');
$table->unsignedInteger('sort_order')->nullable();
$table->timestamps();
$table->softDeletes();
});
Schema::create('sub_categories', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('category_id');
$table->string('name')->unique();
$table->string('slug')->unique();
$table->string('featured_image');
$table->text('description')->nullable();
$table->unsignedInteger('sort_order')->nullable();
$table->timestamps();
$table->softDeletes();
$table->foreign('category_id')->references('id')->on('categories');
});
Schema::create('businesses', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('resort_id');
$table->unsignedInteger('sub_category_id');
$table->string('name');
$table->string('slug')->unique();
$table->string('logo')->nullable();
$table->text('description');
$table->text('content')->nullable();
$table->string('county')->nullable();
$table->string('postcode')->nullable();
$table->timestamps();
$table->foreign('resort_id')->references('id')->on('resorts');
$table->foreign('sub_category_id')->references('id')->on('sub_categories');
});
Schema::create('enhancements', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('business_id');
$table->unsignedInteger('product_id');
$table->dateTime('from_date');
$table->dateTime('to_date');
$table->timestamps();
$table->softDeletes();
$table->foreign('business_id')->references('id')->on('businesses');
$table->foreign('product_id')->references('id')->on('products');
});
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('slug')->unique();
$table->string('image');
$table->text('description');
$table->float('yearly_price');
$table->float('monthly_price');
$table->timestamps();
});
This should work for you:
SubCategory::where('slug', $subCategory)
->where('category_id', $category->id)
->with(['businesses' => function($query) {
$query->select('businesses.*')
->leftJoin('enhancements', function($join) {
$join->on('enhancements.business_id', '=', 'businesses.id')
->join('products', 'products.id', 'enhancements.product_id');
})
->orderByRaw('FIELD(products.slug, ?, ?) DESC', ['enhanced-listing', 'premium-listing'])
->orderByRaw('CASE WHEN products.slug IS NOT NULL THEN RAND() ELSE businesses.name END');
}])->firstOrFail();

Get data from 2 tables connected using a pivot table (Laravel 5.3)

How to get data from 2 tables connected using a pivot table ? for example, in my case I have users table connected to journal table using a pivot table (penulis table). Now I want to get journals data that belonged to specific user. I tried this :
$journal_list = DB::table('journal')->where('id_user', '=','id_journal')->orderBy('id', 'desc')->paginate(20);
That code above doesn't work. Below are my migrations :
Users table :
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('username')->unique();
$table->string('userslug');
$table->string('nameslug');
$table->string('email')->unique();
$table->string('phone')->nullable();
$table->string('address')->nullable();
$table->string('password');
$table->rememberToken();
$table->enum('level', ['admin', 'author']);
$table->timestamps();
});
}
Journal table :
public function up() {
Schema::create('journal', function (Blueprint $table) {
$table->increments('id');
$table->string('title', 255);
$table->text('abstract');
$table->text('file');
$table->integer('id_edition')->unsigned();
$table->string('journalslug');
$table->timestamps();
});
}
Penulis table (the pivot table)
public function up()
{
Schema::create('penulis', function (Blueprint $table) {
// Create tabel penulis
$table->integer('id_user')->unsigned()->index();
$table->integer('id_journal')->unsigned()->index();
$table->timestamps();
// Set PK
$table->primary(['id_user', 'id_journal']);
// Set FK penulis --- user
$table->foreign('id_user')
->references('id')
->on('users')
->onDelete('cascade')
->onUpdate('cascade');
// Set FK penulis --- journal
$table->foreign('id_journal')
->references('id')
->on('journal')
->onDelete('cascade')
->onUpdate('cascade');
});
}
View composer :
public function boot()
{
View::composer('user/show', function ($view) {
$journal_list = User::where('id', $user_id)->with('journal')->first();
$view->with('journal_list', $journal_list);
});
}
If you want to use Eloquent, you should setup belongsToMany() relation first:
class User extends Authenticatable
{
public function journals()
{
return $this->belongsToMany('App\Journal');
}
Then use eager loading to load the data:
User::where('id', $userId)->with('journals')->first();
If you don't want to use Eloquent and just need journals:
$journal_ids = DB::table('penulis')->where('id_user', $userId)->get(['id_journal'])->toArray();
$journal_list = DB::table('journal')->whereIn('id', $journal_ids)->paginate(20);
Or do the same by using join().
Why not make use of the Eloquent if you are using Laravel
First define the relations in your models
class User extends Model {
public function journal(){
return $this->belongsToMany('App\Journal', 'penulis', 'id_user', 'id_journal');
}
}
class Journal extends Model {
public function user(){
return $this->belongsToMany('App\User', 'penulis', 'id_journal', 'id_user');
}
}
Of course you need to define the table and fillables in your model with table name and table columns respectively.
And to get the specific data related to users you can use eloquent,
User::with('journal')->paginate(20);
This will load 20 users(paginated) with related journal data.
To know further about the eloquent relationships, take a look at this link.
Hope it solves your problem.

Laravel Eloquent Composite Primary Key Relationships

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

Resources