Utilisation de traits pour les relations polymorphes dans Laravel

introduction


Parlons de l'utilisation possible des traits ainsi que des relations polymorphes dans Laravel.


Le contenu de l'article:


  1. Description du domaine
  2. Création d'application
  3. Structures de base de données possibles
  4. Création d'entité
  5. Utilisation des traits
  6. Tests d'écriture

Description du domaine


Nous développerons un système dans lequel certains employés et certaines équipes pourront être rattachés au projet. L'essence du sujet sera les employés, les équipes et les projets: une équipe composée d'employés, d'employés et d'équipes peut être attachée à un projet. Entre une équipe et un employé, une relation plusieurs à plusieurs (disons qu'un employé peut participer à différentes équipes), plusieurs à plusieurs entre projets et employés, plusieurs à plusieurs entre équipes et projets. Pour un examen plus approfondi, omettons la mise en œuvre de la communication entre l'équipe et les employés, concentrons-nous sur l'attitude des équipes et des employés envers le projet.


Création d'application


Les applications Laravel sont très faciles à construire à l' aide du package du créateur d'application . Après l'avoir installé, la création d'une nouvelle application tient dans une seule commande:


laravel new system

Structures de base de données possibles


, : -, -, -.


, - - , (, 1 — , 2 — ).


- , — , .



, , , . :


php artisan make:model Employee -f //    
php artisan make:model Team -f //    
php artisan make:model Project -f //    
php artisan make:migration CreateEntitiesTables //     
php artisan make:model Attach -m //    

App/, database/migrations/ database/factories/.


. , : , . — .



<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateEntitesTables extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('employees', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });

        Schema::create('teams', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });

        Schema::create('projects', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('employees');
        Schema::dropIfExists('teams');
        Schema::dropIfExists('projects');
    }
}


<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateAttachesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('attachments', function (Blueprint $table) {
            $table->id();
            $table->morphs('attachable');
            $table->unsignedInteger('project_id');
            $table->timestamps();

            $table->foreign('project_id')->references('id')->on('projects')
                ->onDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('attachments');
    }
}

, morphs().



:


<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

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

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

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


<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphToMany;

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

    /**
     * Relation for project attachments
     * @return HasMany
     */
    public function attachments()
    {
        return $this->hasMany(Attach::class);
    }

    /**
     * Relation for project employees
     * @return MorphToMany
     */
    public function employees()
    {
        return $this->morphedByMany(Employee::class, 'attachable', 'attachments');
    }

    /**
     * Relation for project teams
     * @return MorphToMany
     */
    public function teams()
    {
        return $this->morphedByMany(Team::class, 'attachable', 'attachments');
    }    
}


<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Attach extends Model
{
    protected $table = 'attachments';
    protected $fillable = ['attachable_id', 'attachable_type', 'project_id'];
}


<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use Faker\Generator as Faker;

$factory->define(/* (//) */, function (Faker $faker) {
    return [
        'name' => $faker->colorName
    ];
});

, .



Laravel — morphedByMany(), — morphToMany(). , .


app/Traits : Attachable.php


<?php

namespace App\Traits;

use App\Project;
use Illuminate\Database\Eloquent\Relations\MorphToMany;

trait Attachable
{
    /**
     * Relation for entity attachments
     * @return MorphToMany
     */
    public function attachments()
    {
        return $this->morphToMany(Project::class, 'attachable', 'attachments');
    }
}

use.


...
    use Attachable;
...

.



, Laravel PHPUnit . :


php artisan make:test AttachableTest

tests/Feature/. RefreshDatabase.


Vérifiez la morphologie du côté du projet et le trait de la part de l'équipe et du personnel


<?php

namespace Tests\Feature;

use App\Team;
use App\Employee;
use App\Project;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class OrderTest extends TestCase
{
    use RefreshDatabase;

    /** @test */
    public function polymorphic_relations_scheme(): void
    {
        // Given project
        $project = factory(Project::class)->create();
        // Given team
        $team = factory(Team::class)->create();
        // Given employee
        $employee = factory(Employee::class)->create();

        // When we add team and employee to project
        $project->teams()->save($team);
        $project->employees()->save($employee);

        // Then project should have two attachments
        $this->assertCount(2, $project->attachments);
        $this->assertCount(1, $project->teams);
        $this->assertCount(1, $project->employees);
        $this->assertEquals($team->id, $project->teams->first()->id);
        $this->assertEquals($employee->id, $project->employees->first()->id);
        // Team and employee should have attachment to project
        $this->assertCount(1, $team->attachments);
        $this->assertCount(1, $employee->attachments);
        $this->assertEquals($project->id, $team->attachments->first()->id);
        $this->assertEquals($project->id, $employee->attachments->first()->id);
    }
}

Le test est réussi!


Les traits vous permettent de ne pas dupliquer les méthodes courantes pour les relations polymorphes au sein des classes de modèle, vous pouvez également les utiliser si vous avez les mêmes champs dans de nombreuses tables (par exemple, l'auteur de l'enregistrement) - ici, vous pouvez également faire un trait avec la méthode de connexion.


Je serai heureux d'entendre vos cas d'utilisation de traits dans Laravel et PHP.


All Articles