I'm using Laravel 5.3 and trying to return data from multiple tables using a join.
I'm using 3 models / tables, Customer, Business and Website which are related as follows:
In Customer.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Customer extends Model
{
public function businesses()
{
return $this->hasMany('App\Business');
}
}
In Business.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Business extends Model
{
public function customer()
{
return $this->belongsTo('App\Customer');
}
public function websites()
{
return $this->hasMany('App\Website');
}
}
And in Website.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Website extends Model
{
public function business() {
return $this->belongsTo('App\Business');
}
}
So a Customer
can have many Businesses
which can have many Websites
. Now I'm trying to use a join statement to return a list of the customers and their related business and website information. I'm using the following code to return this information:
$customers = \DB::table('customers')
->join('businesses', 'customers.id', '=', 'businesses.customer_id')
->join('websites', 'businesses.id', '=', 'websites.business_id')
->select('customers.x', 'businesses.y', 'websites.z')
->get();
And I'd like the data to be return in an array of associative customer arrays with the business and websites data nested in the associative array like so:
[
0 => {
$customer1Data,
$customer1BusinessData,
$customer1WebsiteData
}
1 => {
$customer2Data,
$customer2BusinessData,
$customer2WebsiteData
}
...
]
This works fine if a customer has one business which has one website but suppose $customer1
has two businesses, then the above join returns something in this format:
[
0 => {
$customer1Data,
$customer1BusinessData1,
$customer1WebsiteData
}
1 => {
$customer1Data,
$customer1BusinessData2,
$customer1WebsiteData
}
...
]
Is there a way I can modify the join statement to return that scenario in this format:
[
0 => {
$customer1Data,
businesses => {
$customer1BusinessData1,
$customer1BusinessData2
}
...
}
]
Is there a way I can achieve this with join statements? Or should I be approaching this in a different way? Any help would be greatly appreciated, many thanks.
As per the comment by @Rooshan Akthar, you can do one the following using eloquent because of the relationships you have created:
// Loading with relationships (i.e single query)
Customer::with('businesses.websites');
// Lazy loading (i.e. multiple queries)
Customer::find($id)->load('businesses.websites');
You can also just go $customer->businesses->websites;
without having called either of the above and laravel will get those relationships for you.
Before I dive into explaining eloquent model relations, read this: https://laravel.com/docs/5.4/eloquent. This will clear things up.
In a model relation you can specify what the database field names are that link those two tables together. This even works with pivot tables. For the basic documentation read this: https://laravel.com/docs/5.4/eloquent-relationships#defining-relationships.
For example in the customer model:
public function businesses()
{
return $this->hasMany(Business::class, 'id', 'customer_id');
}
public function websites()
{
//Argument order: final class, pivot class, pivot foreign key, foreign key final model, primary key start model (customer)
return $this->hasManyThrough(Website::class, Business::class, 'customer_id', 'id', id);
}
If this last part was a bit hard to understand, read the documentation: https://laravel.com/docs/5.4/eloquent-relationships#has-many-through
And for the Business model:
public function website()
{
return $this->hasMany(Website::class, 'id', 'business_id');
}
And now you can retrieve data by using eloquent.
//This will retrieve all customers with all of their website information.
Customer::with('websites')->get();
//This will retrieve all customers with their business information.
Customer::with('businesses')->get();
//This will retrieve all customers with business and website information
//Retrieves: [
// customer: [
// customerDetails: []
// businesses: [ b1, b2],
// websites: [w1, w2]
// ]
//]
Customer::with('businesses', 'websites')->get();
//This will retrieve all customers with business information and the website information for each business
//Retrieves: [
// customer: [
// customerDetails: []
// businesses: [
// b1: [ websites: [w1] ],
// b2: [ websites: [w2] ]
// ],
// ]
//]
Customer::with('businesses.websites')->get();
I hope this helps!