Práce s databází
Práce s databází
Section titled “Práce s databází”Projekt používá MariaDB 11 v Docker prostředí a Laravel migrations pro správu databázového schématu.
Databázová konfigurace
Section titled “Databázová konfigurace”Vývojové prostředí
Section titled “Vývojové prostředí”V .env:
DB_CONNECTION=mysqlDB_HOST=dbDB_PORT=3306DB_DATABASE=kvizDB_USERNAME=kvizDB_PASSWORD=kvizTestovací prostředí
Section titled “Testovací prostředí”V phpunit.xml:
<env name="DB_CONNECTION" value="mysql"/><env name="DB_HOST" value="db"/><env name="DB_DATABASE" value="kviz_testing"/>Migrace
Section titled “Migrace”Spuštění migrací
Section titled “Spuštění migrací”# Spustit všechny pending migracedocker compose exec fpm php artisan migrate
# S seedovánímdocker compose exec fpm php artisan migrate --seed
# Rollback poslední dávkydocker compose exec fpm php artisan migrate:rollback
# Rollback všech migracídocker compose exec fpm php artisan migrate:reset
# Reset a opětovné spuštění všech migracídocker compose exec fpm php artisan migrate:fresh
# Fresh s seedovánímdocker compose exec fpm php artisan migrate:fresh --seedVytvoření nové migrace
Section titled “Vytvoření nové migrace”# Vytvořit novou tabulkudocker compose exec fpm php artisan make:migration create_products_table
# Přidat sloupec do existující tabulkydocker compose exec fpm php artisan make:migration add_status_to_products_table
# S automatickým generováním strukturydocker compose exec fpm php artisan make:migration create_products_table --create=productsdocker compose exec fpm php artisan make:migration add_status_to_products --table=productsStruktura migrace
Section titled “Struktura migrace”<?php
use Illuminate\Database\Migrations\Migration;use Illuminate\Database\Schema\Blueprint;use Illuminate\Support\Facades\Schema;
return new class extends Migration{ public function up(): void { Schema::create('chk_products', function (Blueprint $table) { $table->id(); $table->string('name'); $table->text('description')->nullable(); $table->decimal('price', 10, 2); $table->foreignId('category_id') ->constrained('chk_categories') ->onDelete('cascade'); $table->timestamps(); }); }
public function down(): void { Schema::dropIfExists('chk_products'); }};Best Practices pro migrace
Section titled “Best Practices pro migrace”1. Vždy používejte prefix chk_
Section titled “1. Vždy používejte prefix chk_”// ✅ SprávněSchema::create('chk_products', function (Blueprint $table) { ... });
// ❌ ŠpatněSchema::create('products', function (Blueprint $table) { ... });2. Definujte foreign key constraints
Section titled “2. Definujte foreign key constraints”$table->foreignId('region_id') ->constrained('chk_regions') ->onDelete('set null') ->onUpdate('cascade');3. Používejte nullable() pro volitelná pole
Section titled “3. Používejte nullable() pro volitelná pole”$table->string('phone')->nullable();$table->text('description')->nullable();4. Indexujte časté vyhledávací sloupce
Section titled “4. Indexujte časté vyhledávací sloupce”$table->string('email')->unique();$table->index('status');$table->index(['user_id', 'created_at']);Seeders
Section titled “Seeders”Seedery slouží k naplnění databáze testovacími daty.
Struktura seederů
Section titled “Struktura seederů”database/seeders/├── DatabaseSeeder.php # Hlavní seeder├── CountrySeeder.php # Základní data - země├── RegionSeeder.php # Základní data - kraje├── CitySeeder.php # Základní data - města├── UserRoleCompanySeeder.php # Testovací uživatelé└── PubSeeder.php # Testovací pubySpuštění seederů
Section titled “Spuštění seederů”# Všechny seedery (DatabaseSeeder)docker compose exec fpm php artisan db:seed
# Konkrétní seederdocker compose exec fpm php artisan db:seed --class=CountrySeeder
# Fresh migrate + seeddocker compose exec fpm php artisan migrate:fresh --seedVytvoření nového seederu
Section titled “Vytvoření nového seederu”docker compose exec fpm php artisan make:seeder ProductSeederStruktura seederu (idempotentní)
Section titled “Struktura seederu (idempotentní)”<?php
namespace Database\Seeders;
use App\Models\Product;use Illuminate\Database\Seeder;
class ProductSeeder extends Seeder{ public function run(): void { $products = [ ['name' => 'Product 1', 'price' => 100], ['name' => 'Product 2', 'price' => 200], ];
foreach ($products as $product) { Product::updateOrCreate( ['name' => $product['name']], // Unique identifikátor $product // Data k aktualizaci ); }
$this->command?->info("✅ ProductSeeder dokončen. Vytvořeno/aktualizováno " . count($products) . " produktů."); }}Pořadí závislostí v DatabaseSeeder
Section titled “Pořadí závislostí v DatabaseSeeder”public function run(){ if (app()->environment('production')) { $this->command?->warn('⚠️ Seeding je zakázáno v produkčním prostředí.'); return; }
// Základní data v pořadí závislostí $this->call([ CountrySeeder::class, // 1. Země (bez závislostí) RegionSeeder::class, // 2. Regiony (vyžadují Country) CitySeeder::class, // 3. Města (vyžadují Region) ]);
// Testovací data $this->call([ UserRoleCompanySeeder::class, PubSeeder::class, // 4. Puby (vyžadují City) ]);}Factories
Section titled “Factories”Factories generují testovací data pro modely.
Vytvoření factory
Section titled “Vytvoření factory”docker compose exec fpm php artisan make:factory ProductFactory --model=ProductStruktura factory
Section titled “Struktura factory”<?php
namespace Database\Factories;
use App\Models\Product;use Illuminate\Database\Eloquent\Factories\Factory;
class ProductFactory extends Factory{ protected $model = Product::class;
public function definition(): array { return [ 'name' => $this->faker->words(3, true), 'description' => $this->faker->sentence(), 'price' => $this->faker->randomFloat(2, 10, 1000), 'category_id' => 1, // Nebo Category::factory() ]; }
/** * State pro drahé produkty */ public function expensive(): static { return $this->state(fn (array $attributes) => [ 'price' => $this->faker->randomFloat(2, 1000, 10000), ]); }
/** * State pro vyprodané produkty */ public function soldOut(): static { return $this->state(fn (array $attributes) => [ 'stock' => 0, ]); }}Použití factory v modelu
Section titled “Použití factory v modelu”<?php
namespace App\Models;
use Database\Factories\ProductFactory;use Illuminate\Database\Eloquent\Factories\HasFactory;use Illuminate\Database\Eloquent\Model;
class Product extends Model{ use HasFactory;
protected static function newFactory() { return ProductFactory::new(); }
// ... rest of model}Použití factory
Section titled “Použití factory”// Vytvořit jeden produkt (bez uložení)$product = Product::factory()->make();
// Vytvořit a uložit jeden produkt$product = Product::factory()->create();
// Vytvořit 10 produktů$products = Product::factory()->count(10)->create();
// S vlastními atributy$product = Product::factory()->create([ 'name' => 'Custom Product', 'price' => 99.99,]);
// Použití states$expensiveProduct = Product::factory()->expensive()->create();$soldOutProduct = Product::factory()->soldOut()->create();
// S relacemi$product = Product::factory() ->for(Category::factory()) ->create();Database Schema
Section titled “Database Schema”Export aktuálního schématu
Section titled “Export aktuálního schématu”# Export do SQL souborudocker compose exec db mysqldump -u kviz -pkviz kviz > database/schema/mysql-schema.sql
# Export pouze struktury (bez dat)docker compose exec db mysqldump -u kviz -pkviz --no-data kviz > database/schema/mysql-schema.sqlImport schématu
Section titled “Import schématu”# Import do existující databázedocker compose exec -T db mysql -u kviz -pkviz kviz < database/schema/mysql-schema.sql
# Import do testovací databázedocker compose exec -T db mysql -u kviz -pkviz kviz_testing < database/schema/mysql-schema.sqlSquash Migrations
Section titled “Squash Migrations”Pokud máte příliš mnoho migrací, můžete je “squashnout” do jednoho SQL souboru.
1. Export aktuálního schématu
Section titled “1. Export aktuálního schématu”docker compose exec db mysqldump -u kviz -pkviz --no-data kviz > database/schema/mysql-schema-YYYY-MM-DD.sql2. Archivace starých migrací
Section titled “2. Archivace starých migrací”mkdir database/migrations/archivedmv database/migrations/2024_*.php database/migrations/archived/3. Vytvoření nové base migrace
Section titled “3. Vytvoření nové base migrace”<?php
use Illuminate\Database\Migrations\Migration;use Illuminate\Support\Facades\DB;
return new class extends Migration{ public function up(): void { $sql = file_get_contents(database_path('schema/mysql-schema-2024-12-01.sql')); DB::unprepared($sql); }
public function down(): void { // Rollback není možný pro squash migraci throw new Exception('Cannot rollback squashed migrations'); }};Časté operace
Section titled “Časté operace”Resetování databáze
Section titled “Resetování databáze”# Kompletní resetdocker compose exec fpm php artisan migrate:fresh --seed
# Pouze migrace (bez seedování)docker compose exec fpm php artisan migrate:freshKontrola stavu migrací
Section titled “Kontrola stavu migrací”docker compose exec fpm php artisan migrate:statusPřímý přístup k databázi
Section titled “Přímý přístup k databázi”# MySQL CLIdocker compose exec db mysql -u kviz -pkviz kviz
# Nebo přes fpm kontejnerdocker compose exec fpm php artisan db
# Tinker (Laravel REPL)docker compose exec fpm php artisan tinkerBackup databáze
Section titled “Backup databáze”# Automatický backup script./backup-database.sh
# Manuální backupdocker compose exec db mysqldump -u kviz -pkviz kviz > backup-$(date +%Y%m%d-%H%M%S).sqlRestore databáze
Section titled “Restore databáze”docker compose exec -T db mysql -u kviz -pkviz kviz < backup-20240101-120000.sqlDatabázové konvence
Section titled “Databázové konvence”Naming conventions
Section titled “Naming conventions”-
Tabulky: Plural, snake_case s prefixem
chk_chk_users,chk_regions,chk_quiz_events
-
Sloupce: snake_case
user_id,created_at,display_name
-
Foreign keys:
{model}_idcountry_id,region_id,user_id
-
Pivot tabulky: Alphabetically ordered, singular, s prefixem
chk_pub_user,chk_quiz_team
-
Indexy:
{table}_{column}_indexusers_email_index,regions_country_id_index
Datové typy
Section titled “Datové typy”$table->id(); // BIGINT UNSIGNED AUTO_INCREMENT$table->string('name', 255); // VARCHAR(255)$table->text('description'); // TEXT$table->integer('count'); // INT$table->decimal('price', 10, 2); // DECIMAL(10,2)$table->boolean('active'); // TINYINT(1)$table->timestamp('published_at'); // TIMESTAMP$table->timestamps(); // created_at, updated_at$table->softDeletes(); // deleted_atTroubleshooting
Section titled “Troubleshooting””Table doesn’t exist” chyby
Section titled “”Table doesn’t exist” chyby”# Spusťte migracedocker compose exec fpm php artisan migrate”Access denied” chyby
Section titled “”Access denied” chyby”# Zkontrolujte credentials v .env# Zkontrolujte, že databázový kontejner běžídocker compose ps dbMigrace selhávají
Section titled “Migrace selhávají”# Zkontrolujte syntax v migraci# Zkontrolujte existenci foreign key tabulek# Rollback a zkuste znovudocker compose exec fpm php artisan migrate:rollbackdocker compose exec fpm php artisan migrate