I have a new Laravel application that I'm hooking up to a preexisting database. The relationships in this database are pretty much all pivot tables.
Similar to this:
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->string('name');
});
Schema::create('vehicles', function (Blueprint $table) {
$table->id();
$table->string('name');
});
Schema::create('customer_vehicle', function (Blueprint $table) {
$table->id();
$table->int('customer_id');
$table->int('vehicle_id');
});
I've configured models/pivot tables and set up a Many To Many relationship for the customers and vehicles.
Similar to this:
class Customer extends Model
{
public function vehicles()
{
return $this->belongsToMany(
Vehicle::class,
CustomerVehiclePivot::class,
'customer_id',
'vehicle_id'
);
}
}
class Vehicle extends Model
{
public function customers()
{
return $this->belongsToMany(
Customer::class,
CustomerVehiclePivot::class,
'vehicle_id',
'customer_id'
);
}
}
So far this is working, but it doesn't feel quite right. $customer->vehicles()
returns the expected results, but a vehicle should only belong to one customer, and the way I'm doing that at the moment is by doing $vehicle->customers()->first()
.
The actual relationship should be a One To Many. A customer can have many vehicles, but a vehicle should only belong to one customer.
Is there a way to configure the relationship as a One To Many when using a pivot table in order to be able to fetch a vehicle's customer with $vehicle->customer
?
Based on @chuck's suggestion, I now have the following for my Vehicle customer method.
class Vehicle extends Model
{
public function customer()
{
return $this->hasOneThrough(
Customer::class,
CustomerVehiclePivot::class,
'vehicle_id',
'id',
'id',
'customer_id'
);
}
}
I can now perform the following and get the expected results.
$vehicle->customer; // Returns the vehicle's customer
$customer->vehicles; // Returns the customer's vehicles
I'm now trying to figure out how to use factories with this configuration.
I thought I could do Vehicle::factory()->for(Customer::factory())->create()
but I get the error...
Call to undefined method Illuminate\Database\Eloquent\Relations\HasOneThrough::getOwnerKeyName()
So I'm not quite sure how you can create Vehicles for users.
I was successfully able to create users with attached vehicles by using hasAttached
.
Customer::factory()
->hasAttached(
Vehicle::factory()->count(3)
)
->create()
I was able to figure out how to use factories to create vehicles for users.
Customer::factory()->create()->vehicles()->attach(Vehicle::factory()->count(3)->create());
CodePudding user response:
Yes, you can use the hasOneThrough() relationship in Laravel to set up a one-to-many relationship between customers and vehicles using a pivot table. Here is an example of how you can set this up:
class Customer extends Model
{
public function vehicles()
{
return $this->hasMany(Vehicle::class);
}
}
class Vehicle extends Model
{
public function customer()
{
return $this->hasOneThrough(
Customer::class,
CustomerVehiclePivot::class,
'vehicle_id', // Foreign key on the pivot table
'id', // Local key on the customers table
'id', // Local key on the vehicles table
'customer_id' // Foreign key on the pivot table
);
}
}