Database brick

Коли форма вже валідується, наступний біль — куди зберігати дані і як еволюціонувати схему без ручного SQL у проді. addDatabase() на ConceptStack підключає Illuminate/Eloquent через extension-database-eloquent: connection, міграції, seeders, опційно query log і events. Повертає DatabaseBuilder. Рецепт з MySQL — База даних.

Stack не читає .env — масив connection передає Bootstrap (literal + getenv()).

Методи DatabaseBuilder:

Метод Параметри Опис Залежність
setConnection() array<string, mixed> $connection Illuminate connection (driver, host, database, username, password, …) —
setMigrations() list<string> $paths Абсолютні шляхи до каталогів з migration files —
setMigrationsTable() string $table Таблиця обліку виконаних міграцій —
setSeeders() list<class-string> $seeders Seeder classes для SeederManager —
withQueryLogging() string $logFilePath, int $maxFiles = 7 Opt-in rotating SQL query log —
withMasking() — Маскування чутливих полів у query log addMasking()
withEmitQueryEvents() — Emit DatabaseQueryExecuted events addEvents()

setConnection()

$stack->addDatabase()
    ->setConnection([
        'driver' => 'mysql',
        'host' => getenv('MYSQL_HOST') ?: '127.0.0.1',
        'port' => (int) (getenv('MYSQL_PORT') ?: 3306),
        'database' => getenv('MYSQL_DATABASE') ?: 'concept_recipes',
        'username' => getenv('MYSQL_USER') ?: 'root',
        'password' => getenv('MYSQL_PASSWORD') ?: 'root',
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',
    ]);

Без connection немає Capsule — інжект DatabaseInterface у controller не має куди йти. Масив іде в extension-database-eloquent зі стандартними ключами Illuminate. Glue збирає значення сам (env Docker vs local), Stack їх не шукає у файлах — той самий принцип «explicit arguments», що й у інших bricks.

setMigrations()

$stack->addDatabase()
    ->setMigrations([$rootPath . 'database/migrations']);

Абсолютні шляхи до PHP-migration files потрапляють у MigrationRegistry — Migrator знає, де шукати файли. Кілька каталогів — коли міграції розкидані по пакетах/компонентах, а не лише в одному app-корені.

setMigrationsTable()

$stack->addDatabase()
    ->setMigrationsTable('migrations');

Таблиця обліку виконаних міграцій (Illuminate DatabaseMigrationRepository). Default — migrations. Задавай явно, якщо кілька додатків ділять одну БД і потрібні різні таблиці обліку — інакше міграції одного додатку «бачать» історію іншого.

setSeeders()

$stack->addDatabase()
    ->setSeeders([
        ContactSubmissionsSeeder::class,
    ]);

Демо-дані / фікстури: class-string список seeder-ів (SeederInterface) потрапляє в SeederManager. Список класів — на Database brick, не в CLI-командах.

withQueryLogging()

$stack->addDatabase()
    ->setConnection([ /* … */ ])
    ->withQueryLogging($rootPath . 'storage/logs/query.log', 7);

Opt-in, коли треба побачити реальний SQL під час розробки (N+1, зайві запити). RotatingFileHandler усередині DatabaseEloquentServiceProvider. Без виклику запити в файл не пишуться — на проді зазвичай не вмикають постійно. Це окремий sink від app Monolog.

withMasking()

$stack->addMasking()
    ->setPatterns([ /* … */ ]);

$stack->addDatabase()
    ->setConnection([ /* … */ ])
    ->withQueryLogging($rootPath . 'storage/logs/query.log')
    ->withMasking();

Query log легко просочує паролі й токени в bindings. Opt-in маскування викликає require(DATABASE, MASKING): без addMasking() Stack не збереться. Має сенс лише разом із withQueryLogging() — інакше маскувати нічого.

withEmitQueryEvents()

$stack->addEvents();

$stack->addDatabase()
    ->setConnection([ /* … */ ])
    ->withEmitQueryEvents();

Коли потрібна телеметрія або кастомне логування без файлового query log: після SQL емітиться DatabaseQueryExecuted (listeners через Events brick). require(DATABASE, EVENTS) — потрібен addEvents().

Що реєструє brick

  • DatabaseEloquentServiceProvider → DatabaseInterface (Capsule)
  • MigrationRegistry — шляхи з setMigrations()
  • Migrator + repository (таблиця з setMigrationsTable())
  • SeederManager — класи з setSeeders()
  • PaginationConfiguratorServiceProvider — pagination defaults

Controllers/services інжектять DatabaseInterface, не Capsule напряму — легше підміняти в тестах. Eloquent Model — опційно в додатку; brick його не вимагає.

Мінімальний фрагмент

$stack->addDatabase()
    ->setConnection([ /* driver, host, … */ ])
    ->setMigrations([$rootPath . 'database/migrations'])
    ->setMigrationsTable('migrations')
    ->setSeeders([ContactSubmissionsSeeder::class]);

Рецепт — 6. База даних. Каталог bricks — Bricks і addX(). Extension — Database.