I want to get the title, description, and price which are stored in a pivot table between users and services called userservices. I want to be able to display this information I'll get from the userservices table, inside the user profile view page.
I have 4 tables for that which include,
A User table with id, name, surname, email, phone, area_id.
A Service table with id, name, description, and category_id.
A category table with id, name, description
and I have pivot table btw users and services called service_user which stores the service_id, user_id, title, description and price
I wish to know how can I get the title, description and price for a service that belongs to a particular user, provided the information exists in the userservice table in the database using Laravel.
In my user Controller, I did something like this
public function jobberDetails($id) {
$profiledetail = User::with('area.town.region.country')
->with('userservice')
->find($id);
DB::update("UPDATE users SET visit = visit + 1 WHERE id = '$id'");
// dd($jobdetail);
return view('Users.profileDetail', compact('profiledetail'));
}
in my web file
// Route qui permet d'afficher,le profil d'un Jobbeur
Route::get('/jobber/profiledetails/{id}', 'UserController@jobberDetails')->where(array('id' => '[0-9]+'))->name('profileDetails');
In my model I did something like this
public function area(): BelongsTo
{
return $this->belongsTo(Area::class);
}
public function getTownAttribute(): Town
{
return $this->area->town;
}
public function getRegionAttribute(): Region
{
return $this->area->town->region;
}
public function getCountryAttribute(): Country
{
return $this->area->town->region->country;
}
public function userservice(): BelongsTo
{
return $this->belongsTo(UserServices::class);
}
and in my profile detail blade I did this
<div class="row">
<div class="col-lg-8">
<div class="job-single-head3">
<div class="job-single-info3">
<h3>{{ $profiledetail->name }} {{ $profiledetail->surname }}</h3>
<span><i class="la la-map-marker"></i>{{ $profiledetail->town->name}}, {{ $profiledetail->region->name}}</span>
<span class="job-is ft" id="more" onclick="$('.details').slideToggle(function(){$('#more').html($('.details').is(':visible')?'Cacher le numero':'Voir le numero');});">Voir le numero</span>
</div>
</div><!-- Job Head -->
</div>
</div>
</div>
<div class="job-wide-devider">
<div class="row">
<div class="col-lg-8 column">
<div class="extra-job-info details" style="display:none">
<p style="text-align: center; padding: 10px; font-size: 45px;"><i class="la la-phone"></i> {{ $profiledetail->phone }}</p>
</div>
<div class="job-details">
<h3>Description</h3>
<p> {{ $profiledetail->userservices->description }}.</p>
<h3>Conditions et tarifs</h3>
<ul>
<li>{{ $profiledetail->userservices->price }}</li>
</ul>
<h3>Title</h3>
<ul>
<li>{{ $profiledetail->userservices->title }}</li>
</ul>
</div>
Here's how you can do it using pivot as suggested by @DigitalDrifter
Start by adding services
relationship method to the User
model
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class User extends Authenticatable
{
use Notifiable;
//...
public function services(): BelongsToMany
{
return $this->belongsToMany(Service::class)->withPivot('title', 'description', 'price');
}
}
Add reverse relationship to the User
from within Services
model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Service extends Model
{
protected $fillable = ['category_id', 'name', 'description'];
public function country(): BelongsTo
{
return $this->belongsTo(Category::class);
}
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class);
}
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
}
Now you can use it like so
$profileDetail = User::with(['area.town.region.country', 'services'])->find($id);
foreach($profileDetail->services as $service) {
{{ $service->pivot->title }}
{{ $service->pivot->description }}
{{ $service->pivot->price }}
{{ $service->category->name }}
}
Here's the test (containing all previous code example as well)
<?php
namespace Tests\Unit;
use App\Area;
use App\Town;
use App\User;
use App\Region;
use App\Service;
use App\Country;
use App\Category;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class UserTest extends TestCase
{
use RefreshDatabase;
/**
* @test
*/
public function pulls_area_town_region_and_country()
{
$country = Country::create([
'name' => 'United Kingdom',
'description' => 'United Kingdom'
]);
$region = Region::create([
'country_id' => $country->id,
'name' => 'Somerset',
'description' => 'Somerset'
]);
$town = Town::create([
'region_id' => $region->id,
'name' => 'Bristol',
'description' => 'Bristol'
]);
$area = Area::create([
'town_id' => $town->id,
'name' => 'South',
'description' => 'South'
]);
$category = Category::create([
'name' => 'Animals',
'description' => 'Animals'
]);
$service = Service::create([
'category_id' => $category->id,
'name' => 'Service',
'description' => 'Service'
]);
$user = factory(User::class)->create([
'area_id' => $area->id
]);
$user->services()->attach($service->id, [
'title' => 'Attached service',
'description' => 'Attached service description',
'price' => 12575
]);
$user = User::with('area.town.region.country')->first();
$recentJobbers = User::with(['area.town.region.country', 'services.category'])
->limit(5)
->whereType('jobber')
->orderBy('updated_at', 'desc')
->get();
$this->assertEquals('United Kingdom', $user->area->town->region->country->name);
$this->assertEquals('Somerset', $user->area->town->region->name);
$this->assertEquals('Bristol', $user->area->town->name);
$this->assertEquals('South', $user->area->name);
$this->assertEquals('United Kingdom', $user->country->name);
$this->assertEquals('Somerset', $user->region->name);
$this->assertEquals('Bristol', $user->town->name);
$this->assertEquals('South', $user->area->name);
$this->assertEquals('Attached service', $user->services->get(0)->pivot->title);
$this->assertEquals('Attached service description', $user->services->get(0)->pivot->description);
$this->assertEquals(12575, $user->services->get(0)->pivot->price);
$this->assertEquals('Animals', $user->services->get(0)->category->name);
}
}
Use the withPivot
method to access data from the pivot table.
See the section Retrieving Intermediate Table Columns under Many-To-Many Relationships.
Your User
model would define the relationship to Service
as:
public function services()
{
return $this->belongsToMany(Service::class)
->withPivot(['description', 'price', 'title']);
}