Skip to content

marko/database-mysql

MySQL and MariaDB driver for the Marko framework database layer. Provides a MySQL-specific connection, query builder, SQL generator, and schema introspector --- all wired automatically when you install the package.

Implements ConnectionInterface, QueryBuilderInterface, SqlGeneratorInterface, and IntrospectorInterface from marko/database.

Terminal window
composer require marko/database-mysql

This automatically installs marko/database (the interface package) as a dependency.

Create a configuration file at config/database.php:

config/database.php
<?php
declare(strict_types=1);
return [
'driver' => 'mysql',
'host' => $_ENV['DB_HOST'] ?? 'localhost',
'port' => (int) ($_ENV['DB_PORT'] ?? 3306),
'database' => $_ENV['DB_DATABASE'] ?? 'marko',
'username' => $_ENV['DB_USERNAME'] ?? 'root',
'password' => $_ENV['DB_PASSWORD'] ?? '',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
];

Set these in your .env file:

DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=your_database
DB_USERNAME=your_username
DB_PASSWORD=your_password

This driver supports both MySQL 8.0+ and MariaDB 10.5+. Both are tested and fully supported.

The default charset is utf8mb4 which supports the full Unicode range including emojis. This is the recommended setting for new applications.

Marko enables MySQL strict mode by default. This ensures data integrity by rejecting invalid data rather than silently truncating or coercing values.

MySQL’s native JSON type is fully supported. Use type: 'json' on any array or ?array property:

use Marko\Database\Attributes\Column;
#[Column(type: 'json')]
public array $metadata = [];
#[Column(type: 'json')]
public ?array $settings = null;

Values are serialized and deserialized automatically. The root value must be an array --- top-level JSON scalars are not supported. See marko/database for JSON query operators (whereJsonContains, arrow-path syntax, etc.) and indexing guidance.

Once configured, the MySQL driver is automatically used when you interact with the database. See marko/database for entity definition and repository usage.

use Marko\Database\Connection\ConnectionInterface;
class MyService
{
public function __construct(
private ConnectionInterface $connection,
) {}
public function doSomething(): void
{
// Connection is automatically MySQL
$result = $this->connection->query('SELECT * FROM users');
}
}

MySqlConnection implements ConnectionInterface and TransactionInterface. It wraps PDO with lazy connection --- the database connection is not established until the first query.

MethodDescription
query(string $sql, array $bindings = []): arrayExecute a query and return all rows as associative arrays
execute(string $sql, array $bindings = []): intExecute a statement and return the affected row count
prepare(string $sql): StatementInterfacePrepare a statement for repeated execution
lastInsertId(): intGet the last auto-increment ID
connect(): voidExplicitly open the database connection
disconnect(): voidClose the connection
isConnected(): boolCheck whether the connection is open

MySqlConnection also implements TransactionInterface:

MethodDescription
beginTransaction(): voidStart a transaction (throws on nested transactions)
commit(): voidCommit the current transaction
rollback(): voidRoll back the current transaction
inTransaction(): boolCheck whether a transaction is active
transaction(callable $callback): mixedExecute a callback inside a transaction --- auto-commits on success, rolls back on exception

MySqlQueryBuilder implements QueryBuilderInterface with a fluent API:

MethodDescription
table(string $table): staticSet the target table
select(string ...$columns): staticChoose columns to return
where(string $column, string $operator, mixed $value): staticAdd a WHERE condition
orWhere(string $column, string $operator, mixed $value): staticAdd an OR WHERE condition
whereIn(string $column, array $values): staticAdd a WHERE IN condition
whereNull(string $column): staticAdd a WHERE IS NULL condition
whereNotNull(string $column): staticAdd a WHERE IS NOT NULL condition
join(string $table, string $first, string $operator, string $second): staticInner join
leftJoin(string $table, string $first, string $operator, string $second): staticLeft join
rightJoin(string $table, string $first, string $operator, string $second): staticRight join
orderBy(string $column, string $direction = 'ASC'): staticOrder results
limit(int $limit): staticLimit result count
offset(int $offset): staticSkip rows
get(): arrayExecute and return all matching rows
first(): ?arrayExecute and return the first row, or null
insert(array $data): intInsert a row and return the last insert ID
update(array $data): intUpdate matching rows and return the affected count
delete(): intDelete matching rows and return the affected count
count(?string $column = null): intReturn the count of matching rows (COUNT(*) or COUNT(column))
sum(string $column): int|floatReturn the sum of a column
avg(string $column): int|floatReturn the average of a column
min(string $column): int|floatReturn the minimum value of a column
max(string $column): int|floatReturn the maximum value of a column
distinct(): staticAdd DISTINCT to the SELECT clause
groupBy(string ...$columns): staticAdd GROUP BY columns
having(string $expression, array $bindings = []): staticAdd a HAVING condition
union(QueryBuilderInterface $query): staticAppend a UNION (deduplicates rows)
unionAll(QueryBuilderInterface $query): staticAppend a UNION ALL (keeps duplicates)
whereJsonContains(string $column, mixed $value): staticWHERE JSON array contains value
whereJsonExists(string $path): staticWHERE JSON key/path exists
whereJsonMissing(string $path): staticWHERE JSON key/path does not exist
raw(string $sql, array $bindings = []): arrayExecute raw SQL

MySqlGenerator implements SqlGeneratorInterface --- produces MySQL-specific DDL from schema diffs (used by the migration system).

Abstract TypeMySQL Type
integer / intINT
bigintBIGINT
smallintSMALLINT
tinyintTINYINT
stringVARCHAR(n) (default 255)
textTEXT
boolean / boolTINYINT(1)
datetimeDATETIME
dateDATE
timeTIME
timestampTIMESTAMP
decimalDECIMAL(10,2)
floatFLOAT
doubleDOUBLE
blob / binaryBLOB
jsonJSON

MySqlIntrospector implements IntrospectorInterface --- reads the live database schema via information_schema for use by the migration diff calculator.

MethodDescription
getTables(): arrayList all table names in the database
getTable(string $name): ?TableGet a full Table schema object (columns, indexes, foreign keys)
tableExists(string $name): boolCheck whether a table exists
getColumns(string $table): arrayGet column definitions for a table
getIndexes(string $table): arrayGet index definitions for a table
getForeignKeys(string $table): arrayGet foreign key definitions for a table
getPrimaryKey(string $table): arrayGet primary key column names for a table