База даних

Concept Core використовує Illuminate Database (Capsule + Eloquent) — той самий шар, що й у Laravel Eloquent. Підключення, моделі, міграції та сидери інтегровані через DatabaseServiceProvider ядра.

HTTP і CLI працюють з однією конфігурацією (config/db.php, .env); схему оновлюють консольними командами db:* (див. Консоль). Шляхи міграцій і сидерів компонентів підключає ComponentsServiceProvider (див. Створення компонента).

Класи ядра

КласРоль
DatabaseServiceProvider Capsule, Eloquent, Migrator, реєстри міграцій/сидерів
DatabaseInterface Обгортка capsule() для query builder поза моделлю
MigrationRegistry Шляхи до каталогів міграцій (додаток + компоненти)
SeederRegistry / SeederManager Список сидерів і запуск через db:seed

Підключення

Параметри з config/db.php перекриваються змінними оточення (DB_HOSTdb.host тощо). Детальна таблиця — у Конфігурація → db.php та змінні оточення в тому ж розділі.

// config/db.php
return [
    'db' => [
        'driver'   => 'mysql',
        'host'     => '127.0.0.1',
        'port'     => '3306',
        'database' => 'concept_db',
        'username' => 'root',
        'password' => '',
        'charset'  => 'utf8mb4',
    ],
];

У DatabaseServiceProvider::boot() створюється глобальний Illuminate\Database\Capsule\Manager, викликається bootEloquent(), підключається Dispatcher для подій запитів. SQL логується за log.db_queries (QueryLoggerstorage/logs/query.log). Телеметрію TelemetryEvent::DB_QUERY_EXECUTED записують окремо за telemetry.enabled і telemetry.db_queries.

Низькорівневий доступ — Concept\Core\Services\Database\Contracts\DatabaseInterface і метод capsule() (наприклад у правилах unique / exists). Ключ db.port є в конфігу, але getConnectionOptions() ядра наразі передає в Capsule лише driver, host, database, username, password, charset.

Моделі Eloquent

Додаток наслідує Concept\App\Models\BaseModel (розширює Illuminate\Database\Eloquent\Model). Компоненти оголошують моделі у власному namespace, наприклад Concept\Components\AuthAdmin\Models\UserModel.

Рекомендовані практики:

  • константи полів FIELD_* замість «магічних» рядків у запитах і fillable;
  • BaseModel::getId(), FIELD_ID, SORT_ASC / SORT_DESC;
  • $fillable, $hidden, $casts, SoftDeletes — як у Laravel;
  • модель у конструктор контролера або сервісу — autowiring (UserModel $userModel).
use Concept\App\Models\BaseModel;
use Illuminate\Database\Eloquent\SoftDeletes;

class UserModel extends BaseModel
{
    use SoftDeletes;

    public const string FIELD_EMAIL = 'email';
    public const string FIELD_PASSWORD = 'password';
    public const string FIELD_CREATED_AT = 'created_at';

    protected $table = 'users';

    protected $fillable = [self::FIELD_EMAIL, /* ... */];
    protected $hidden = [self::FIELD_PASSWORD];
}

Запити в коді

Запити будуються через $model->newQuery() (query builder / Eloquent), не через статичні виклики на класі моделі. Це узгоджено з ін’єкцією моделі в конструктор.

public function __construct(
    private readonly UserModel $userModel,
    private readonly ConfigInterface $config,
) {}

public function index(): ResponseInterface
{
    $users = $this->userModel
        ->newQuery()
        ->orderBy(UserModel::FIELD_CREATED_AT, BaseModel::SORT_DESC)
        ->paginate($this->config->getInt('pagination.per_page', 10))
        ->withQueryString();

    return $this->viewResponse->create('@auth-admin/users/list', ['users' => $users]);
}

Створення записів після валідації — newQuery()->create([...]) або validated() з FormRequest (див. Запити та валідація). Офіційні довідники: Eloquent, Query Builder, Pagination.

Міграції

Каталоги міграцій реєструються в config/migrations.php (додаток) і через ComponentInterface::migrationPaths(). Під час ComponentsServiceProvider::boot() шляхи всіх увімкнених компонентів додаються до MigrationRegistry.

// config/migrations.php
return [
    'migrations' => [
        'table' => 'migrations',
        'paths' => ['database/migrations'],
    ],
];

// AuthAdminComponent::migrationPaths()
public function migrationPaths(): array
{
    return [
        $this->pathManager->toRelative($this->componentDir . '/Database/Migrations'),
    ];
}

Файл міграції — анонімний клас, що розширює Migration, з методами up() / down(). Приклад іменування файлів: V2026_03_23_120000_CreatePagesTable.php.

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Capsule\Manager as CapsuleManager;

return new class extends Migration
{
    public function up(): void
    {
        CapsuleManager::schema()->create('pages', function (Blueprint $table) {
            $table->increments('id');
            $table->string('slug', 255)->unique();
            $table->timestamps();
        });
    }

    public function down(): void
    {
        CapsuleManager::schema()->dropIfExists('pages');
    }
};

db:migrate створює таблицю migrations, якщо її ще немає, і застосовує всі невиконані файли з усіх зареєстрованих шляхів. Документація Laravel: Migrations.

Сидери

Класи сидерів перелічуються в config/seeders.php і в ComponentInterface::seeders(). SeederManager викликає run() лише для класів, що реалізують Concept\Core\Services\Database\Contracts\SeederInterface. Зазвичай сидер також extends Illuminate\Database\Seeder.

// config/seeders.php
use Database\Seeders\PageSeeder;

return [
    'seeders' => [
        'list' => [PageSeeder::class],
    ],
];

// database/seeders/PageSeeder.php — обов'язково SeederInterface
use Concept\Core\Services\Database\Contracts\SeederInterface;
use Illuminate\Database\Seeder;

class PageSeeder extends Seeder implements SeederInterface
{
    public function run(): void { /* ... */ }
}

db:seed без опцій запускає всі зареєстровані сидери. Щоб виконати один сидер, передайте повний FQCN класу через -c (або --class) — коротке ім’я класу не підтримується. Значення бажано взяти в лапки через зворотні слеші в namespace:

php bin/console.php db:seed -c "Concept\Components\AuthAdmin\Database\Seeders\UserSeeder"

Список доступних класів: php bin/console.php seeders:list.

Консоль

КомандаПризначення
db:migrateЗастосувати нові міграції
db:rollbackВідкат останнього batch
migration:listСписок міграцій і статус
db:seedУсі сидери; -c "Fully\Qualified\Class" — один сидер (повний FQCN)
seeders:listЗареєстровані сидери
php bin/console.php db:migrate
php bin/console.php db:seed
php bin/console.php db:seed -c "Database\Seeders\PageSeeder"
php bin/console.php db:seed -c "Concept\Components\AuthAdmin\Database\Seeders\UserSeeder"

Перед першим db:migrate переконайтесь, що БД створена і DB_* у .env відповідають вашому середовищу.

Розташування файлів

config/db.php
config/migrations.php
config/seeders.php
database/migrations/          # міграції додатку
database/seeders/             # сидери додатку (namespace Database\Seeders)
src/App/Models/BaseModel.php
src/Components/*/Models/
src/Components/*/Database/Migrations/
src/Components/*/Database/Seeders/

API запитів, відношень, scope, soft deletes і cast enum — як у Laravel Eloquent; відмінності лише в bootstrap (Capsule замість повного Laravel) та реєстрації шляхів міграцій/сидерів через конфіг і компоненти.