LEMONADE Documentation

Documentation.

Fifteen chapters covering installation, project structure, application development, CLI and production deployment.

Chapter 9 of 15

Database and migrations.

Use the container-managed connection, parameterized queries, and explicit one-way migrations.

The database service

Configure a driver in Database.yaml and inject Database. Both select() and statement() accept bindings; never interpolate values into SQL.

Database service
<?php

use Lemonade\Framework\Database\Database;

final readonly class UserRepository
{
    public function __construct(private Database $database) {}

    public function find(int $id): ?array
    {
        $rows = $this->database->select(
            'SELECT id, email FROM users WHERE id = :id',
            ['id' => $id],
        );

        return $rows[0] ?? null;
    }
}

A query builder is available for more involved queries. Database::transaction() uses the same container-managed connection stack.

One-way migrations

A migration implements MigrationInterface, has a stable identifier, and defines up(Schema $schema). Register it with MigrationRegistry from a bootable provider.

CreateUsersTable.php
<?php

use Lemonade\Framework\Database\Migration\MigrationInterface;
use Lemonade\Framework\Database\Schema\Schema;

final class CreateUsersTable implements MigrationInterface
{
    public static function identifier(): string
    {
        return '20261023090000_create_users';
    }

    public function up(Schema $schema): void
    {
        $schema->create('users', static function ($table): void {
            $table->id();
            $table->string('email', 191)->unique();
        });
    }
}

Run vendor/bin/lemonade database:migrate and inspect status with database:migrate:status. Automatic rollback is not supported.

Detailed technical documentation on GitHub