Introdução
Vamos falar sobre o possível uso de características junto com as relações polimórficas no Laravel.
O conteúdo do artigo:
- Descrição de Domínio
- Criação de aplicativo
- Estruturas possíveis de banco de dados
- Criação de Entidades
- Uso de Traços
- Testes de escrita
Descrição de Domínio
Vamos desenvolver um sistema no qual alguns funcionários e certas equipes possam ser anexados ao projeto. A essência da área de assunto será funcionários, equipes e projetos: uma equipe é composta por funcionários, funcionários e equipes que podem ser anexados a um projeto. Entre uma equipe e um funcionário, um relacionamento muitos para muitos (digamos que um funcionário possa participar de equipes diferentes), muitos para muitos entre projetos e funcionários, muitos para muitos entre equipes e projetos. Para uma análise mais aprofundada, vamos omitir a implementação da comunicação entre a equipe e os funcionários, focar na atitude de equipes e funcionários em relação ao projeto.
Criação de aplicativo
Os aplicativos Laravel são muito fáceis de construir usando o pacote do criador de aplicativos . Após a instalação, a criação de um novo aplicativo se encaixa em um comando:
laravel new system
Estruturas possíveis de banco de dados
, : -, -, -.
, - - , (, 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
{
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();
});
}
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
{
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');
});
}
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'];
public function attachments()
{
return $this->hasMany(Attach::class);
}
public function employees()
{
return $this->morphedByMany(Employee::class, 'attachable', 'attachments');
}
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
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
{
public function attachments()
{
return $this->morphToMany(Project::class, 'attachable', 'attachments');
}
}
use.
...
use Attachable;
...
.
, Laravel PHPUnit . :
php artisan make:test AttachableTest
tests/Feature/. RefreshDatabase.
Verifique a transformação no lado do projeto e a característica por parte da equipe e equipe
<?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;
public function polymorphic_relations_scheme(): void
{
$project = factory(Project::class)->create();
$team = factory(Team::class)->create();
$employee = factory(Employee::class)->create();
$project->teams()->save($team);
$project->employees()->save($employee);
$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);
$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);
}
}
O teste passou!
As características permitem que você não duplique métodos comuns para relacionamentos polimórficos nas classes de modelo; também é possível usá-los se tiver os mesmos campos em muitas tabelas (por exemplo, o autor do registro) - aqui você também pode criar uma característica com o método de conexão.
Ficarei feliz em ouvir seus casos de uso de características no Laravel e PHP.