استخدام الصفات للعلاقات متعددة الأشكال في Laravel

المقدمة


لنتحدث عن الاستخدام المحتمل للسمات جنبًا إلى جنب مع العلاقات متعددة الأشكال في Laravel.


محتوى المقالة:


  1. وصف المجال
  2. إنشاء التطبيق
  3. هياكل قاعدة البيانات الممكنة
  4. إنشاء الكيان
  5. استخدام السمات
  6. اختبارات الكتابة

وصف المجال


سنضع نظامًا يمكن فيه إلحاق بعض الموظفين وفرق معينة بالمشروع. سيكون جوهر الموضوع هو الموظفين والفرق والمشاريع: يتكون الفريق من الموظفين والموظفين والفرق ويمكن إرفاقه بالمشروع. بين فريق وموظف ، علاقة أطراف بأطراف (دعنا نقول أنه يمكن لموظف المشاركة في فرق مختلفة) ، بين أطراف وأخرى بين المشاريع والموظفين ، والعديد من بين الفرق والمشاريع. لمزيد من الدراسة ، دعنا نحذف تنفيذ التواصل بين الفريق والموظفين ، ونركز على موقف الفرق والموظفين تجاه المشروع.


إنشاء التطبيق


من السهل جدًا إنشاء تطبيقات Laravel باستخدام حزمة صانع التطبيقات . بعد تثبيته ، يتناسب إنشاء تطبيق جديد مع أمر واحد:


laravel new system

هياكل قاعدة البيانات الممكنة


, : -, -, -.


, - - , (, 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.


تحقق من الشكل على جانب المشروع والسمات من جانب الفريق والموظفين


<?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);
    }
}

لقد مر الاختبار!


تسمح لك السمات بعدم تكرار الطرق الشائعة للعلاقات متعددة الأشكال داخل فئات النموذج ، يمكنك أيضًا استخدامها إذا كان لديك نفس الحقول في العديد من الجداول (على سبيل المثال ، مؤلف السجل) - هنا يمكنك أيضًا إنشاء سمة باستخدام طريقة الاتصال.


سأكون سعيدًا لسماع حالاتك المتعلقة باستخدام السمات في Laravel و PHP.


All Articles