Working with 3 tables in a Laravel relationship? - php

I have a season, and each clan has to have a valid season entry. The stage I'm currently stuck on is how can I have a relationship for clans in my Season class?
This would help me understand which clans a season currently holds, but without a complicated query, it seems impossible with relationships. Is there a 'good practice' way of doing this?
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Season extends Model
{
public function matches() {
return $this->hasMany('App\ClanMatch', 'season_id');
}
public function tournaments() {
return $this->hasMany('App\Tournament', 'season_id');
}
}
class SeasonEntry extends Model
{
public function season() {
return $this->belongsTo('App\Season', 'season_id');
}
public function clan() {
return $this->belongsTo('App\Clan', 'clan_id');
}
}

Think if simple.
One clan can participate in many seasons.
One seasons, there are many clans.
So I guess, this is Many-to-Many relationship. To deal with it in Laravel, commonly, you need to create a pivot table that defines the co-relation.
Schema::create('season_clan', function (Blueprint $table) {
$table->increments('id');
$table->integer('season_id')->unsigned();
$table->integer('clan_id')->unsigned();
});
And both models need to address the relationship as well.
class Season extends Model
{
public function clans()
{
return $this->belongsToMany(Clan::class);
}
}
class Clan extends Model
{
public function seasons()
{
return $this->belongsToMany(Seasons::class);
}
}
That's all I guess! You can try and it should work.

Related

Is it possible to relate a table on a pivot one with eloquent ORM?

These are my tables many-to-many:
products and suppliers, however I need to relate the pivot(product_supplier) to a table called payment_supplier.
Product model
public function suppliers(){
return $this->belongsToMany('App\Supplier');
}
Supplier model
public function products(){
return $this->belongsToMany('App\Product');
}
but I need to relate pivot product_supplier to payment_supplier table just like described on the diagram
In this case, you could use a pivot model.
# Product Model
public function suppliers() {
return $this->belongsToMany(Supplier::class)->using(ProductSupplier::class);
}
# Supplier Model
public function products(){
return $this->belongsToMany(Product::class)->using(ProductSupplier::class);
}
# ProductSupplier Pivot Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class ProductSupplier extends Pivot
{
public function payment_supplier()
{
return $this->hasMany(PaymentSupplier::class);
}
}
However, doing it like this has a big problem: You CANNOT eager load a pivot's relationships. Not without an override (or a package).
The other way to go about it is using hasManyThrough
# Product Model
public function suppliers()
{
return $this->belongsToMany(Supplier::class)->using(ProductSupplier::class);
}
public function payment_suppliers()
{
return $this->hasManyThrough(PaymentSupplier::class, ProductSupplier::class);
}
# Supplier Model
public function products()
{
return $this->belongsToMany(Product::class)->using(ProductSupplier::class);
}
public function payment_suppliers()
{
return $this->hasManyThrough(PaymentSupplier::class, ProductSupplier::class);
}
This gives you every PaymentSupplier for a single Supplier/Product, so you'll need to apply some kind of filtering.

Count instances of many to many relationship : Laravel

I have a database setup where you have a lecturer having many groups and each group having many students and also a student can be in many groups. Therefore I have a one to many relationship between a lecturer and groups (respectively) and a many to many relationship between students and groups.
I want to show the lecturer how many students they have overall. For example if the lecturer has 5 groups with 5 students in each then I want to show 25. I tried this auth()->user()->userable->groups()->withCount('students') but I got this:
Call to a member function getRelationExistenceCountQuery() on null
Edited, Here are the relationships:
# user model
class User extends Authenticatable{
public function userable(){
return $this->morphTo();
}
}
# staff/lecturer model
Staff extends Model {
public function user(){
return $this->morphOne(User::class, 'userable');
}
public function groups(){
return $this->hasMany(Group::class);
}
}
#group model
class Group extends Model {
public function staff(){
return $this->belongsTo(Staff::class);
}
public function students(){
$this->belongsToMany(Student::class, 'groups_students', 'group_id');
}
}
# student model
class Student extends Model {
public function groups(){
return $this->belongsToMany(Group::class, 'groups_students', 'student_id');
}
}
What's the most efficient way to get my desired result?
Group::students() is missing the return statement:
public function students(){
return $this->belongsToMany(Student::class, 'groups_students', 'group_id');
^^^^^^
}
You can get the total of number of students like this:
$groups = auth()->user()->userable->groups()->withCount('students')->pluck('students_count');
$count = $groups->sum();

Laravel: Sorting a collection with a many to many relationship

I have two tables: assessments and benchmarks. benchmarks has a field called content. There is a many to many relationship between them: assessment_benchmark. I want to sort a collection of records from the assessment_benchmark table by the content attribute of the corresponding benchmark. I have tried:
$sorted = AssessmentBenchmark::all()->sortBy(function($assessmentBenchmark){
return $assessmentBenchmark->benchmark->content;
});
But this just does not work (it just returns the original order). However, when I return $assessmentBenchmark->comment for example, it does work (comment is a field in assessment_benchmark).
The models look like this:
class AssessmentBenchmark extends Model
{
public function benchmark()
{
return $this->belongsTo(Benchmark::class);
}
public function assessment()
{
return $this->belongsTo(Assessment::class);
}
}
class Benchmark extends Model
{
public function assessments()
{
return $this->belongsToMany(Assessment::class);
}
}
class Assessment extends Model
{
public function benchmarks()
{
return $this->belongsToMany(Benchmark::class);
}
}
Well, you can use below query for sorting, I'm gonna use Assessment model, because, I'm never use pivot modal before. Actually, I never had pivot model..
$assessments = Assessment::with(["benchmarks"=>function($query){
$query->orderBy("content","DESC");
}])
With method aşso provide you eagerloading, so when you put $assessments in iteration , you won't make new query for each relation
From chat discussion, it found that you have pivot field and for that you can change your belongsToMany relationship like this
class Benchmark extends Model
{
public function assessments()
{
return $this->belongsToMany(Assessment::class)->withPivot('comment','score')->withTimestamps();
}
}
class Assessment extends Model
{
public function benchmarks()
{
return $this->belongsToMany(Benchmark::class)->withPivot('comment','score')->withTimestamps();
}
}
Now fetch data
$assessment = Assessment::with(['benchmarks' => function($query){
$query->orderBy('content', 'desc');
}])->find($assessmentId);
In view you can render it like this
#foreach($assessment->benchmarks as $benchmark)
<tr>
<td>{{$benchmark->id}}</td>
<td>{{$benchmark->name}}</td>
<td>{{$benchmark->pivot->score}}</td>
<td>{{$benchmark->pivot->comment}}</td>
</tr>
#endforeach
For update you can use updateExistingPivot
For details check ManyToMany relationship https://laravel.com/docs/5.6/eloquent-relationships#many-to-many

Laravel Pivot Table and indirect relationship

I'm writing a survey with Laravel 4 and need the ability for users to be able to take the same survey multiple times (and have their answers saved as different instances.)
I currently have a pivot table called survey_user that links a user to an invited survey. A potentially positive side effect of the pivot table is that its primary key could be used to have unique survey instances.
My problem is figuring out how to get answers, specifically through the user model. Answers table would contain a foreign key to the primary of the pivot table.
My User model:
class User extends Eloquent {
public function surveys() {
return $this->belongsToMany('Survey', 'survey_user')
->withPivot('id', 'completed_at');
}
public function answers() {
// This should return all of the user's answers, irrespective of
// survey id's.
}
}
Tables:
surveys: id
users: id
survey_user: id, survey_id, user_id, completed_at
answers: survey_user_id, answer_text, ...
How might I accomplish this psuedo-relationship or perhaps a better way to structure?
Use relationships! Here's how I would do it:
class User extends Eloquent {
public function surveys() {
return $this->belongsToMany('Survey');
}
public function answers() {
return $this->hasMany('Answer');
}
}
class Survey extends Eloquent {
public function surveys() {
return $this->belongsToMany('User');
}
public function answers() {
return $this->hasMany('Answer');
}
}
class Answer extends Eloquent {
public function survey() {
return $this->belongsTo('Survey');
}
public function user() {
return $this->belongsTo('User');
}
}

Retrieving relationships of relationships using Eloquent in Laravel

I have a database with the following tables and relationships:
Advert 1-1 Car m-1 Model m-1 Brand
If I want to retrieve an Advert, I can simply use:
Advert::find(1);
If I want the details of the car, I could use:
Advert::find(1)->with('Car');
However, if I also want the detail of the Model (following the relationship with Car), what would the syntax be, the following doesn't work:
Advert::find(1)->with('Car')->with('Model');
Many thanks
It's in the official documentation under "Eager Loading"
Multiple relationships:
$books = Book::with('author', 'publisher')->get();
Nested relationships:
$books = Book::with('author.contacts')->get();
So for you:
Advert::with('Car.Model')->find(1);
First you need to create your relations,
<?php
class Advert extends Eloquent {
public function car()
{
return $this->belongsTo('Car');
}
}
class Car extends Eloquent {
public function model()
{
return $this->belongsTo('Model');
}
}
class Model extends Eloquent {
public function brand()
{
return $this->belongsTo('Brand');
}
public function cars()
{
return $this->hasMany('Car');
}
}
class Brand extends Eloquent {
public function models()
{
return $this->hasMany('Model');
}
}
Then you just have to access this way:
echo Advert::find(1)->car->model->brand->name;
But your table fields shoud be, because Laravel guess them that way:
id (for all tables)
car_id
model_id
brand_id
Or you'll have to specify them in the relationship.
Suppose you have 3 models region,city,hotels and to get all hotels with city and region then
Define relationship in them as follows:-
Hotel.php
class Hotel extends Model {
public function cities(){
return $this->hasMany(City::class);
}
public function city(){
return $this->belongsTo('App\City','city_id');
}
}
City.php
class City extends Model {
public function hotels(){
return $this->hasMany(Hotel::class);
}
public function regions(){
return $this->belongsTo('App\Region','region_id');
}
}
Region.php
class Region extends Model
{
public function cities(){
return $this->hasMany('App\City');
}
public function country(){
return $this->belongsTo('App\Country','country_id');
}
}
HotelController.php
public function getAllHotels(){
// get all hotes with city and region
$hotels = Hotel::with('city.regions')->get()->toArray();
}
will adding the relation function just ask for the relation needed
public function Car()
{
return $this->belongsTo(Car::class, 'car_id')->with('Model');
}
but if you want a nested relation just use the period in the with
Advert::with('Car.Model')->find(1);
but for multi-relation use the array
Advert::with('Car','Model')->find(1);

Categories