Лаб. работа 3 "Создание моделей, миграций и сидеров"

Цель: Научиться проектировать сложные связи между моделями, использовать фабрики и сидеры для заполнения данных.
Задачи:

  • Создать несколько взаимосвязанных моделей: Post, Category, Comment, Tag.
  • Реализовать связи: один-ко-многим, многие-ко-многим.
  • Настроить каскадное удаление данных.

Методическая часть

1. Создание моделей и миграций

Выполните команды для создания моделей и миграций:

1php artisan make:model Post -m
2php artisan make:model Category -m
3php artisan make:model Comment -m
4php artisan make:model Tag -m

2. Настройка миграций

a. Таблица categories (database/migrations/xxxx_create_categories_table.php):

1Schema::create('categories', function (Blueprint $table) {
2    $table->id();
3    $table->string('name');
4    $table->string('slug')->unique();
5    $table->timestamps();
6});

b. Таблица posts (добавить внешние ключи):

1Schema::create('posts', function (Blueprint $table) {
2    $table->id();
3    $table->string('title');
4    $table->text('content');
5    $table->string('image')->nullable();
6    $table->foreignId('user_id')->constrained()->cascadeOnDelete();
7    $table->foreignId('category_id')->constrained()->cascadeOnDelete();
8    $table->timestamps();
9});

c. Таблица comments:

1Schema::create('comments', function (Blueprint $table) {
2    $table->id();
3    $table->text('text');
4    $table->foreignId('user_id')->constrained()->cascadeOnDelete();
5    $table->foreignId('post_id')->constrained()->cascadeOnDelete();
6    $table->timestamps();
7});

d. Таблица tags и связь многие-ко-многим с posts:

 1// Таблица tags
 2Schema::create('tags', function (Blueprint $table) {
 3    $table->id();
 4    $table->string('name');
 5    $table->string('slug')->unique();
 6    $table->timestamps();
 7});
 8
 9// Промежуточная таблица post_tag
10Schema::create('post_tag', function (Blueprint $table) {
11    $table->foreignId('post_id')->constrained()->cascadeOnDelete();
12    $table->foreignId('tag_id')->constrained()->cascadeOnDelete();
13    $table->primary(['post_id', 'tag_id']);
14});

3. Определение связей в моделях

a. Модель Post (app/Models/Post.php):

 1public function user() {
 2    return $this->belongsTo(User::class);
 3}
 4
 5public function category() {
 6    return $this->belongsTo(Category::class);
 7}
 8
 9public function comments() {
10    return $this->hasMany(Comment::class);
11}
12
13public function tags() {
14    return $this->belongsToMany(Tag::class);
15}

b. Модель Comment:

1public function user() {
2    return $this->belongsTo(User::class);
3}
4
5public function post() {
6    return $this->belongsTo(Post::class);
7}

c. Модель Category:

1public function posts() {
2    return $this->hasMany(Post::class);
3}

d. Модель Tag:

1public function posts() {
2    return $this->belongsToMany(Post::class);
3}

4. Создание фабрик

Создайте фабрики для всех моделей:

1php artisan make:factory PostFactory
2php artisan make:factory CategoryFactory
3php artisan make:factory CommentFactory
4php artisan make:factory TagFactory

Пример фабрики PostFactory:

1public function definition(): array {
2    return [
3        'title' => fake()->sentence(),
4        'content' => fake()->paragraphs(3, true),
5        'user_id' => User::factory(),
6        'category_id' => Category::factory(),
7        'image' => fake()->optional()->imageUrl(),
8    ];
9}

5. Заполнение сидеров

Измените database/seeders/DatabaseSeeder.php:

 1public function run(): void {
 2    // Создать 5 категорий
 3    Category::factory(5)->create();
 4
 5    // Создать 10 тегов
 6    Tag::factory(10)->create();
 7
 8    // Создать 20 постов
 9    Post::factory(20)
10        ->has(Comment::factory(3)) // 3 комментария к каждому посту
11        ->create()
12        ->each(function ($post) {
13            // Привязать случайные теги к постам
14            $tags = Tag::inRandomOrder()->take(3)->pluck('id');
15            $post->tags()->attach($tags);
16        });
17}

Индивидуальные задания

1. Добавление модели Like

  • Создайте модель Like с полями: user_id, likeable_type (полиморфная связь), likeable_id.
  • Реализуйте полиморфное отношение, чтобы лайки можно было ставить как постам, так и комментариям.

2. Мягкое удаление (Soft Delete)

  • Добавьте в модели Post и Comment поддержку мягкого удаления.
  • Измените миграции, добавив $table->softDeletes();.
  • Проверьте, что при удалении поста комментарии остаются в базе (если не использовать каскадное удаление).

3. Валидация slug

  • В модели Category добавьте валидацию slug через observer:
    1// Создайте observer
    2php artisan make:observer CategoryObserver --model=Category
    
  • В CategoryObserver:
    1public function creating(Category $category) {
    2    $category->slug = Str::slug($category->name);
    3}
    

4. Теги через строку

Модифицируйте форму создания поста:

  • Добавьте поле tags (строка с тегами через запятую).
  • В контроллере обработайте ввод:
    1$tags = explode(',', $request->tags);
    2foreach ($tags as $tagName) {
    3    $tag = Tag::firstOrCreate(['name' => trim($tagName)]);
    4    $post->tags()->attach($tag);
    5}
    

Проверка работы

  1. Выполните миграции и сидеры:
    1php artisan migrate:fresh --seed
    
  2. Проверьте связи через Tinker:
    1php artisan tinker
    2$post = Post::first();
    3$post->comments; // Должен вывести комментарии
    4$post->tags; // Должен вывести теги
    

Примечания

  • Каскадное удаление: При удалении категории все связанные посты будут удалены автоматически.
  • Полиморфные связи: Используются для гибкой привязки моделей (например, лайки к разным сущностям).
← Лаб. работа 2 "Добавление главной страницы и … Лаб. работа 4 "Создание индексных страниц и … →