Schema Definition

Define your database structure in PHP or YAML.

Table of contents

Schema Formats

Rowcast Schema supports three formats. The parser is chosen automatically by the configured schema path:

  • directory path -> attribute parser
  • .php file -> PHP parser
  • .yaml / .yml file -> YAML parser

PHP format (default, no extra dependencies)

<?php

return [
    'tables' => [
        'users' => [
            'columns' => [
                'id' => ['type' => 'integer', 'primaryKey' => true, 'autoIncrement' => true],
                'email' => ['type' => 'string', 'length' => 255],
            ],
            'indexes' => [
                'idx_users_email' => ['columns' => ['email'], 'unique' => true],
            ],
        ],
    ],
];

YAML format (requires symfony/yaml)

tables:
  users:
    columns:
      id:
        type: integer
        primaryKey: true
        autoIncrement: true
      email:
        type: string
        length: 255
    indexes:
      idx_users_email:
        columns: [email]
        unique: true

YAML support is optional. Install it with composer require symfony/yaml. If the package is missing and you point to a .yaml file, the parser throws a clear error with installation instructions.

Attribute format (directory of PHP classes)

// rowcast-schema.php
return [
    'connection' => [
        'dsn' => 'mysql:host=localhost;dbname=app',
        'username' => 'root',
        'password' => 'secret',
    ],
    'schema' => __DIR__ . '/src/Entity',
    'migrations' => __DIR__ . '/migrations',
];
use AsceticSoft\RowcastSchema\Attribute\Column;
use AsceticSoft\RowcastSchema\Attribute\Table;

#[Table]
final class User
{
    #[Column(primaryKey: true, autoIncrement: true)]
    public int $id;

    #[Column(length: 255)]
    public string $email;
}

Supported Abstract Types

Type Description
integer INT / INTEGER
smallint SMALLINT
bigint BIGINT
string VARCHAR (default length: 255)
text TEXT
boolean BOOLEAN / TINYINT(1)
decimal DECIMAL (requires precision, scale)
float FLOAT
double DOUBLE
datetime DATETIME
date DATE
time TIME
timestamp TIMESTAMP
timestamptz TIMESTAMPTZ
uuid CHAR(36) / UUID
json JSON / TEXT
binary BLOB / BYTEA
enum ENUM (requires values)

Custom Database Types

You can pass vendor-specific database types as raw strings in type:

'columns' => [
    'embedding' => ['type' => 'vector(1536)', 'nullable' => true],
    'title_ci' => ['type' => 'citext'],
],

Unknown type strings are preserved as custom databaseType and emitted to SQL as-is. This works for extension types such as pgvector, citext, PostGIS, and other database-specific types.


Column Properties

Property Type Default Description
type string required Abstract column type
nullable bool false Allow NULL values
default mixed null Default value (or CURRENT_TIMESTAMP)
primaryKey bool false Shortcut for single-column PK
autoIncrement bool false Auto-increment column
length int 255 for string Length for string type
precision int null Precision for decimal
scale int null Scale for decimal
unsigned bool false Unsigned integer
comment string null Column comment
values list [] Enum values for enum type

Table Properties

Property Type Description
columns map Column definitions (required, non-empty)
primaryKey list Composite primary key columns
indexes map Named indexes
foreignKeys map Foreign key definitions
engine string MySQL engine (e.g. InnoDB)
charset string MySQL charset
collation string MySQL collation

Indexes

'indexes' => [
    'idx_users_email' => [
        'columns' => ['email'],
        'unique' => true,
    ],
    'idx_users_created' => [
        'columns' => ['created_at'],
    ],
],
Property Type Default Description
columns list required List of column names
unique bool false Whether index is unique

Foreign Keys

'foreignKeys' => [
    'fk_orders_user' => [
        'columns' => ['user_id'],
        'references' => [
            'table' => 'users',
            'columns' => ['id'],
        ],
        'onDelete' => 'cascade',
        'onUpdate' => 'restrict',
    ],
],
Property Type Description
columns list Local column names
references.table string Referenced table
references.columns list Referenced column names
onDelete string cascade, restrict, set null, no action
onUpdate string Same options as onDelete

Composite Primary Key

When a primary key spans multiple columns, use the table-level primaryKey property instead of per-column primaryKey: true:

'order_items' => [
    'columns' => [
        'order_id' => ['type' => 'integer'],
        'position' => ['type' => 'integer'],
        'product_id' => ['type' => 'integer'],
    ],
    'primaryKey' => ['order_id', 'position'],
],