Vlastní blog v Laravel: Příprava databáze

Aktualizováno pro Laravel 10

V minulém dílu jsme si připravili naše vývojové prostředí a rozběhli si nový Laravel projekt. V tomto dílu si připravíme základní databázovou strukturu, kterou budeme ze začátku potřebovat. K tomu využijeme modely, migrace, seedery, model factory společně s knihovnou Faker a vysvětlíme si k čemu slouží a jak fungují.

Pro náš projekt budeme prvně potřebovat modely, respektive tabulky, pro kategorie a pro příspěvky. Pomocí příkazové řádky a artisanu si tedy vytvoříme nové modely a rovnou si k nim vytvoříme i migrace, factory a seed (-mfs), které si popíšeme v další části. Celý příkaz pak vypadá takto:

php artisan make:model Category -mfs
php artisan make:model Post -mfs

Po spuštění příkazů se nám v adresáři app vytvořily dva nové modely - Category a Post. Ty můžeme aktuálně nechat tak jak jsou, úpravy budeme dělat postupně. Jen dodám, že defaultně se předpokládá, že databázové tabulky budou v množném čísle a budou mít tedy názvy categories a posts . Pokud bychom chtěli mít model pro jinak pojmenovanou tabulku, pak stačí přidat proměnnou $table:

/**
 * Tabulka spojena s modelem
 *
 * @var string
 */
protected $table = 'my_categories';

Stejně tak se předpokládá, že primárním klíčem bude sloupec id Pokud to tak není, stačí nastavit proměnnou $primaryKey.

Migrace

Migrace najdeme v adresáři database/migrations kde jsou již předpřipravené čtyři migrace pro vytvoření tabulky users, password_reset_tokens, failed_jobs a personal_access_tokens - tyto tabulky nemusíme aktuálně nijak řešit. Další dvě migrace jsou pro vytvoření kategorií a příspěvků, které jsme si již vytvořili v předchozí části s modely.

Jako první si upravíme migraci s kategoriemi, kde přidáme název a slug:

public function up(): void
{
    Schema::create('categories', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('slug');
        $table->timestamps();
    });
}

Poté si upravíme migraci s příspěvky podle našich potřeb:

public function up(): void
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();

        $table->unsignedBigInteger('user_id')->nullable();
        $table->unsignedBigInteger('category_id')->nullable();
        $table->string('title');
        $table->string('slug')->unique();
        $table->string('content');
        $table->timestamps();

		$table->foreign('user_id')->references('id')->on('users')->nullOnDelete()->cascadeOnUpdate();
		$table->foreign('category_id')->references('id')->on('categories')->nullOnDelete()->cascadeOnUpdate();
    });
}

Není to nic složitého, jen přidáme autora a kategorii článku (zatím nullable, v dalších díle dořešíme), jeho název a slug pro url adresu (nechceme přece vidět v odkazu ID článků) a samotný obsah. Nakonec přidáme cizí klíče.

Samotné migrace spustíme pomocí následujícího příkazu, který spustí všechny migrace, vykoná jejich příkazy a v databázi vytvoří novou tabulku migrations, kde si uloží všechny vykonané migrace. Podle toho pak pozná, které migrace již byly vykonány a které ještě ne.

php artisan migrate

Factory

Továrna se nám vytvořila v database/factories. Slouží především jako generátor testovacích dat pomocí knihovny Faker, díky které můžeme definovat jaké data pro každý sloupec chceme vygenerovat. Doporučuji si projít tuto knihovnu a zjistit co všechno nabízí. Továrnu CategoryFactory si nadefinujeme takto:

use App\Models\Category;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends Factory<Category>
 */
class CategoryFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'name' => substr($this->faker->sentence(2), 0, -1),
            'slug' => $this->faker->slug(3),
        ];
    }
}

Pro vygenerování názvu využijeme metody $this->faker->sentense() a substr pro odstranění tečky na konci věty. Poté si vytvoříme továrnu PostFactory pro příspěvky:

use App\Models\Category;
use App\Models\Post;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends Factory<Post>
 */
class PostFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'title' => substr($this->faker->sentence(2), 0, -1),
            'slug' => $this->faker->slug(3),
            'content' => $this->faker->paragraph,
            'user_id' => User::factory()->create(),
            'category_id' => Category::factory()->create(),
        ];
    }
}

Všimněte si zanoření dalších továren pro vygenerování uživatele a kategorie. Pro jednoduchost bude mít každý příspěvek přiřazenou jednu kategorii a všichni uživatelé budou mít jeden článek.

Seed

Dalším krokem je seed, tedy reálné naplnění databáze testovacími (dummy) záznamy. Seedy najdeme v database/seeders, kde si jako první upravíme PostSeeder:

namespace Database\Seeders;

use App\Models\Post;
use Illuminate\Database\Seeder;

class PostSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        Post::factory()->count(10)->create();
    }
}

Dále si upravíme hlavní seeder, díky kterému můžeme spustit více seederů naráz. Upravíme si database/seeders/DatabaseSeeder:

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        $this->call([
            PostSeeder::class
        ]);
    }
}

Nyní můžeme spouštět migrace a seedy pro vytvoření dat v tabulkách automaticky. Použitím příkazu migrate:fresh můžeme smazat všechny schémata migrací, nahrát je znovu a spustit seedy. Zároveň si tím i spustíme náš jediný seeder PostSeeder, který jsme si před chvilkou vytvořili:

$ php artisan migrate:fresh --seed

  Dropping all tables .................................................... 16ms DONE

   INFO  Preparing database.

  Creating migration table ............................................... 10ms DONE

   INFO  Running migrations.

  2014_10_12_000000_create_users_table ................................... 17ms DONE
  2014_10_12_100000_create_password_reset_tokens_table ................... 14ms DONE
  2019_08_19_000000_create_failed_jobs_table ............................. 12ms DONE
  2019_12_14_000001_create_personal_access_tokens_table .................. 19ms DONE
  2023_04_09_124415_create_categories_table ............................... 3ms DONE
  2023_04_09_124415_create_posts_table ................................... 36ms DONE

   INFO  Seeding database.
  Database\Seeders\PostSeeder ............................................ RUNNING
  Database\Seeders\PostSeeder ............................................ 43.76 ms DONE 

Není vám něco jasné, nefunguje nebo mám někde chybu? Napište do komentářů!

Zdrojové kódy pro tento díl naleznete na GitHubu

Seriál

  1. 1. Úvod a instalace
  2. 2. Příprava databáze
  3. 3. Layout a zobrazení článků
  4. 4. Vytvoření článku
  5. 5. Editace článku
  6. 6. Smazání článku
  7. 7. Zobrazení článku