{{tag>laravel framework php}}

{{backlinks>.}}

====== Отношения / Relations ======

  * Отношения «один к одному»
  * Отношение «один ко многим»
  * Имеет отношение «один из многих»
  * Отношения HasOneThrough и HasManyThrough
  * Отношение «многие ко многим»
  * Полиморфные отношения
  * Полиморфный Один к одному
  * Полиморфный Один Ко Многим
  * Полиморфный Один из Многих
  * Полиморфный Многие-К-Многим

===== Ссылки =====

  * [[https://habr.com/ru/articles/494658/|Используем трейты для полиморфных связей]]

===== Отношения «один к одному» =====

{{:php:laravel:one-to-one.png?600|}}

<code bash>
$ php artisan make:model Tenant 
$ Php artisan make:model Rent
</code>

<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Tenant extends Model
{
    /**
    * Get the rent of a Tenant
    */
    public function rent() 
    {
        return $this->hasOne(Rent::class);
        //return $this- >hasOne(Rent::class, "custom_key");
        //return $this->hasOne(Rent::class, "custom_key", "other_key"); 
    } 
}

$rent = Tenant::find(10)->rent;
</code>

===== Отношение «один ко многим» =====

{{:php:laravel:one-to-many.png?600|}}

<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Tenant extends Model
{
    /**
    * Get the rents of a Tenant
    */
    public function rent() 
    {
        return $this->hasMany(Rent::class);
        //return $this->hasMany(Rent::class, "foreign_key");
        //return $this->hasMany(Rent::class, "foreign_key", "local_key");
    }
}

$rents = Tenant::find(10)->rent()->where('payment', '>', 500)->first();
</code>

<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Rent extends Model
{
    /**
    * Return the tenant for the rent
    */
    public function tenant() 
    {
        return $this->belongsTo(Tenant::class);
    }
}

$tenant = Rent::find(1)->tenant;
</code>

===== Имеет отношение «один из многих» =====


<code php>
public function latestRent() {
    return $this->hasOne(Rent::class)->latestOfMany();
}

public function oldestRent() {
    return $this->hasOne(Rent::class)->oldestOfMany();
}

return $this->hasOne(Rent::class)->ofMany('price', 'min');
</code>

===== Отношения HasOneThrough и HasManyThrough =====

{{:php:laravel:has-one-through.png?600|}}

<code>
rent
    id - integer
    name - string
    value - double

tenants
    id - integer
    name - string
    rent_id - integer

landlord
    id - integer
    name - string
    tenant_id - integer
</code>
    
<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Rent extends Model
{
    /**
    * Return the rents' landlord
    */
    public function rentLandlord() 
    {
        return $this->hasOneThrough(Landlord::class, Tenant::class);
    }
}
</code>

<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Tenant extends Model
{
    /**
    * Get the rents of a Tenant
    */
    public function rent() 
    {
        return $this->hasMany(Rent::class);
    }
}
</code>

<code php>

</code>

===== Аналогично, отношение «Has Many Through» =====

{{:php:laravel:has-many-through.png?600|}}

<code>
country
    id - integer
    name - string

user
    id - integer
    country_id - integer
    name - string

games
    id - integer
    user_id - integer
    title - string

</code>

<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Country extends Model
{
    protected $fillable = ['name'];

    public function users()
    {
        return $this->hasMany(User::class);
    }

    public function games()
    {
        return $this->hasManyThrough(Games::class, User::class);
    }
}
</code>

<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected $fillable = [article_id, 'name'];

    public function country()
    {
        return $this->belongsTo(Country::class);
    }

    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}
</code>

<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Game extends Model
{
    protected $fillable = ['user_id', 'title'];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}
</code>

<code php>
<?php

$country = Country::find(159);
            
// Retrieve all games for the country
$games = $country->games;
</code>

===== Отношение «многие ко многим» =====

{{:php:laravel:many-to-many.png?600|}}

<code>
employees
    id - integer
    name - string

roles 
    id - integer
    name - string

role_employees
    user_id - integer
    role_id - integer
</code>

<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Employee extends Model
{
    public function roles() 
    {
        return $this- >belongsToMany(Role::class);
    }
}
</code>

<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
    public function employees() 
    {
        return $this->belongsToMany(Employee::class);
        return $this->belongsToMany(Employee::class)
            ->withPivot("active", "created_at");
        return $this->belongsToMany(Employee::class)
            ->withTimestamps();
        return $this->belongsToMany(Employee::class)
            ->as('subscription')
            ->withPivot("active", "created_by");
        return $this->belongsToMany(Employee::class)
            ->wherePivot('promoted', 1);
        return $this->belongsToMany(Employee::class)
            ->wherePivotIn('level', [1, 2]);
        return $this->belongsToMany(Employee::class)
            ->wherePivotNotIn('level', [2, 3]);
        return $this->belongsToMany(Employee::class)
            ->wherePivotBetween('posted_at', ['2023-01-01 00:00:00', '2023-01-02 00:00:00']);
        return $this->belongsToMany(Employee::class)
            ->wherePivotNull('expired_at');
        return $this->belongsToMany(Employee::class)
            ->wherePivotNotNull('posted_at');
          return $this->belongsToMany(Employee::class)
            ->where('promoted', true)
            ->orderByPivot('hired_at', 'desc');
        return $this->belongsToMany(Employee::class)
                            ->using(RoleEmployees::class)
                            ->withPivot([
                                'user_id',
                                'role_id'
                            ]);
    }
}
</code>

<code php>
class RoleEmployees 
{

}
</code>

<code php>
$employee = Employee::find(1);
$employee->roles->forEach(function($role) { // });
$employee = Employee::find(1)->roles()->orderBy('name')->where('name', 'admin')->get();
</code>

===== Полиморфный Один к одному =====

{{:php:laravel:one-to-one-polymorphic.png?600|}}

<code>
tenants
    id – integer
    name – string

landlords
    id – integer
    name – string

waterbills
    id – integer
    amount – double
    waterbillable_id
    waterbillable_type
</code>
    
<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class WaterBill extends Model
{
    public function billable()
    {
        return $this->morphTo();
    }
}

class Tenant extends Model
{
    public function waterBill()    
    {
        return $this->morphOne(WaterBill::class, 'billable');
    }
}

class Landlord extends Model
{
    public function waterBill()    
    {
        return $this->morphOne(WaterBill::class, 'billable');
    }
}
</code>

<code php>
<?php

$tenant = Tenant::find(1)->waterBill;
$landlord = Landlord::find(1)->waterBill;
</code>

===== Полиморфный Один Ко Многим =====

{{:php:laravel:one-to-many-polymorphic.png?600|}}

<code>
posts 
    id – integer
    title – string
    body – text

videos
    id – integer
    title – string
    url – string

polls
    id – integer
    title – string

comments 
    id – integer
    body – text
    commentable_id – integer
    commentable_type – string
</code>
    
<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Comment extends Model 
{
    public function commentable()
    {
        return $this->morphTo();
    }
}

class Poll extends Model
{
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

class Live extends Model
{
    public function comments()
    {
        return $this->morphMany(Comments::class, 'commentable');
    }
}
</code>

<code php>
<?php

use App\Models\Live;
use App\Models\Comment;

$live = Live::find(1);

foreach ($live->comments as $comment) { }

// OR

Live::find(1)->comments()->each(function($comment) { // });
Live::find(1)->comments()->map(function($comment) { // });
Live::find(1)->comments()->filter(function($comment) { // });

$comment = Comment::find(10);
$commentable = $comment->commentable;
</code>

===== Полиморфный Один из Многих =====



===== Полиморфный Многие-К-Многим =====

{{:php:laravel:many-to-many-polymorphic.png?600|}}

<code>
videos
    id – integer
    description – string

stories 
    id – integer
    description – string

taggables 
    tag_id – integer
    taggable_id – integer
    taggable_type – string
</code>

<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Video extends Model
{
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}
</code>

<code php>
<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Tag extends Model
{
    public function stories()
    {
        return $this->morphedByMany(Story::class, 'taggable');
    }

    public function videos()
    {
        return $this->morphedByMany(Video::class, 'taggable');
    } 
}
</code>

<code php>
<?php
use App\Model\Tag;

$tag = Tag::find(10);
$posts = $tag->stories;
$videos = $tag->stories;
</code>