Download the PHP package glivers/roline without Composer
On this page you can find all versions of the php package glivers/roline. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download glivers/roline
More information about glivers/roline
Files in glivers/roline
Package roline
Short Description This is the entry point into the Rachie console commands
License MIT
Informations about the package roline
Roline CLI Toolkit
Command-line interface for Rachie Framework - Generate code, manage databases, scaffold resources.
Quick Start
Roline is already installed with Rachie. Start using it immediately:
Create a model with database columns:
This creates application/models/ProductModel.php:
What just happened?
Roline generated a complete model file with your database schema defined in annotations. Your model IS your schema - no separate migration files.
What is Roline?
Roline is the CLI toolkit bundled with Rachie Framework. It helps you:
- Generate models, controllers, and views with working code
- Define database schemas using
@columnannotations in your models - Create and update database tables automatically from your model annotations
- Scaffold complete resources in seconds
Your database schema lives in your model properties. Need to add a column? Add a property with @column. Need to change a column? Update the annotation. Roline reads your annotations and handles the SQL.
Add more columns to your model:
Interactive prompts guide you through adding properties with proper annotations.
Generate the database table:
Roline reads your @column annotations and creates the products table with all columns, indexes, and constraints.
That's it. Your model is your schema. No separate migration files.
What You'll Learn
Part 1: Getting Started
- Installation & Setup
- Your First Model
- Command Overview
Part 2: Model Commands
- model:create
- model:delete
- model:append
- model:table-create
- model:table-update
- model:table-drop
- model:table-rename
- model:table-schema
- model:table-empty
- model:table-reset
- model:table-export
Part 3: Controller Commands
- controller:create
- controller:append
- controller:delete
- controller:complete
Part 4: View Commands
- view:create
- view:add
- view:delete
Part 5: Table Commands
- table:create
- table:copy
- table:delete
- table:rename
- table:schema
- table:empty
- table:reset
- table:export
- table:partition
- table:unpartition
Part 6: Migration Commands
- migration:make
- migration:run
- migration:rollback
- migration:status
Part 7: Database Commands
- db:list
- db:tables
- db:create
- db:drop
- db:table-drops
- db:reset
- db:schema
- db:seed
- db:export
- db:import
Part 8: Cache Commands
- cleanup:cache
- cleanup:views
- cleanup:logs
- cleanup:sessions
- cleanup:all
Part 9: Utility Commands
- list
- help
- version
Part 10: Reference
- Model Annotations
- Advanced Features
- Troubleshooting
Installation & Setup
Roline is bundled with Rachie. When you install Rachie, you get Roline automatically.
Install Rachie:
Or clone from GitHub:
Verify Roline is installed:
You'll see the Roline command list. You're ready to go.
Update Roline (updates all packages):
This updates Rachie, Rackage, and Roline together.
Important: Configure Your Project Settings
Before generating code, update config/settings.php with your details. Roline uses these when scaffolding controllers and models:
Generated files will include these in their docblocks. Update this immediately after installation to avoid generic placeholders in your code.
Working Directory
All Roline commands must be run from your project root - the directory containing the roline file, application/, public/, config/, and vendor/.
If you get "Command not found" or path errors, check you're in the project root directory.
Your First Model
Let's build a complete User model with authentication fields, step by step.
Create the model:
Edit the generated file (application/models/UserModel.php):
Generate the database table:
Output:
Use your model in a controller:
That's your first model. Schema defined in annotations, table created automatically, ready to use.
Command Overview
List all available commands:
Output shows commands grouped by category:
Best Practices & Command Selection
Before diving into commands, let's make sure you're using the right ones. This will save you from debugging headaches later.
⚠️ The Golden Rule: Use the Right Command Family
If your table has a model, ALWAYS use model: commands. Never mix model: and table: commands on the same table.
Here's why this matters:
model:commands read your model annotations and keep everything in synctable:commands work directly on the database, completely bypassing your model- Mixing them causes schema drift - your model thinks one thing, the database has another
- Migrations won't capture changes you made with
table:commands - You'll get confusing "column not found" errors when your model expects columns that don't exist
Use model: commands for: (This is 99% of your tables)
Use table: commands ONLY for:
- Legacy tables you haven't created models for yet
- Temporary tables you're experimenting with
- Simple lookup/reference tables that don't need model logic
- One-off operations on tables without models
Use db: commands for:
- Database-level operations affecting all tables at once
- Creating or dropping entire databases
- Full database exports, imports, or resets
Model Name Format
When you run model: commands, use your model name without the "Model" suffix:
Note: While UserModel works (Roline strips the suffix automatically), we recommend using just User for consistency and brevity.
Naming Conventions: Models vs Tables
Critical to understand: Roline follows standard conventions for model and table names.
Model Names - Singular, PascalCase:
Table Names - Plural, snake_case (auto-generated):
What happens automatically:
- Model names stay singular (User → UserModel.php)
- Table names get pluralized (User → 'users')
- Compound names get snake_cased (OrderItem → 'order_items', then pluralized)
Custom Table Names - When you need specific naming:
Want to use a specific table name instead of the auto-generated one? You have two options:
Both approaches work. Use Option A when you know the table name upfront. Use Option B when you decide to change it later.
Important: The second argument to model:create is the TABLE name (lowercase), not another model name.
Database Command Defaults
The db: commands work on the database specified in your config/database.php file by default. You can override this by providing a database name:
This is super helpful when managing multiple environments (development, staging, testing).
The Correct Migration Workflow
This trips up a lot of people: Always update your database BEFORE creating migrations.
Why? The migration:make command compares your current database state with the previous migration's snapshot. If you haven't applied your model changes to the database yet, there's nothing to diff - the migration will be empty or won't capture your changes.
Think of it this way: migrations are recordings of changes you already made, not instructions for future changes.
Common Mistakes to Avoid
Let's look at some pitfalls you'll want to steer clear of:
Quick Decision Guide
Not sure which command to use? Ask yourself:
"Does this table have a model file in application/models/?"
- YES → Use
model:commands (model:table-create, model:table-update, etc.) - NO → Use
table:commands (table:create, table:schema, etc.)
"Am I working with the entire database or just one table?"
- Entire database → Use
db:commands (db:export, db:reset, etc.) - One table → See question above
When in doubt, use model: commands. They're safer because they read from your model's source of truth.
Model Commands
Model commands help you create and manage your data models and database tables. In Rachie, your model file IS your database schema - you define columns using @column annotations in model properties, and Roline reads these annotations to create or update your tables automatically. This eliminates the need for separate migration files and keeps your schema definition close to your model code.
These commands handle the complete lifecycle: creating model files, adding properties interactively, generating tables from annotations, updating existing tables when you change your model, and managing table data (viewing structure, exporting, emptying, or dropping tables).
Note: Generated models are starting templates with properly structured schema definitions. You'll need to add your business logic methods, relationships, validation, and custom query methods specific to your application.
model:create
Generates your model file with the table name and basic structure ready. Use this when starting a new resource in your application. The command can add properties interactively right after creation, or you can add them later with model:append or by editing the file directly. Your model properties with @column annotations become your database schema.
Syntax:
Standard usage (auto-generates table name):
Output:
Specify your own table name (optional):
Output:
Use a custom table name when you have specific naming requirements or preferences. Otherwise, Roline generates one automatically.
Alternative approach: Create with auto-generated table name, then use model:table-rename later if needed (see below).
Interactive property creation: After creating the model, you'll be prompted to add properties interactively. This quickly scaffolds basic properties with name and type - you'll still need to edit the model file to add descriptions, additional annotations (@unique, @nullable, etc.), and refine data types.
model:append
Adds new properties with @column annotations to your existing model through interactive prompts. Use this when extending your data model with additional fields. Each property you add here can later become a database column with model:table-update. Saves you from manually writing annotations.
Add properties to existing model interactively:
Interactive prompts:
Inserts properties with @column annotations before the MODEL METHODS section.
model:table-create
Reads your model's @column annotations and creates the database table. Warning: This DROPS the existing table first, so all data is permanently lost. Use this only for new tables or when you're certain you want to recreate from scratch. For existing tables with data, use model:table-update instead.
Creates database table from model annotations:
Output:
Important: This DROPS existing tables. Use model:table-update for safe updates.
model:table-update
The safe way to sync your database with model changes. Compares your model's @column annotations with the actual database table and generates ALTER TABLE statements to add new columns, change data types (like @varchar(255) to @text), or modify constraints. Your data stays intact. Use special annotations like @drop and @rename to explicitly handle column deletions and renames. This is what you'll use most often after initial table creation.
Safely update existing table from model changes:
Output:
Use special annotations:
@drop- Mark column for deletion@rename old_name- Rename column
If dropping or renaming columns, you'll see:
model:table-schema
Displays your database table structure using your model name. Use this to verify what's actually in the database, check if your model:table-update changes were applied correctly, or debug schema mismatches. Shows columns, data types, indexes, and keys. Same output as table:schema but you pass your model name instead of the table name.
View table structure:
Output:
model:delete
Removes the model class file from your filesystem. Use this when you've deleted a feature or resource from your application. This only deletes the PHP file - your database table remains untouched. Use model:table-drop if you need to remove the table as well.
Delete a model file:
Output:
Note: This only deletes the model file, not the database table. Use model:table-drop to delete the table.
model:rename
Renames a model file and updates the class name inside the file. Use this when you need to rename a model to better reflect its purpose or fix naming conventions. The command handles the file renaming and class name update automatically.
Note: This command only renames the model file and class name. You'll need to manually update any references to the old model name in controllers, views, or other files.
Rename a model:
Output:
The command updates both the filename and the class name inside the file. You can provide names with or without the "Model" suffix.
model:table-drop
Completely destroys your database table and all its data forever. Use this when removing obsolete features or cleaning up development databases. The command requires double confirmation because this cannot be undone. Your model file remains - this only affects the database. Similar to table:delete but works with your model name.
Permanently drop a database table:
Output:
Important: This permanently deletes the table and ALL data. Cannot be undone.
model:table-rename
Renames your database table AND automatically updates your model's $table property to match. Use this when refactoring table names or fixing incorrect auto-pluralization. This is a one-command operation that keeps everything in sync.
Why use this instead of manual rename:
- Updates BOTH database table name AND model's
$tableproperty - No data loss - all table data is preserved during rename
- Prevents sync issues - manually renaming requires changing two places (database + model file)
- If you forget to update either one, queries break with "table not found" errors
Rename database table and update model:
Output:
What changes:
- Database table name:
products→items - Model
$tableproperty:'products'→'items' - All existing data preserved
What stays the same:
- Model file name:
ProductModel.php(unchanged) - Model class name:
ProductModel(unchanged)
Note: Second argument is the new TABLE name (lowercase, e.g., 'items' not 'Item').
model:table-empty
Wipes all data from your table while keeping the table structure intact. Use this for clearing test data, resetting development databases, or removing all records before a fresh import. Uses DELETE (not TRUNCATE) so foreign keys are respected and auto-increment counters stay as-is.
If you want to reset auto-increment use php roline model:table-reset ModelName
Delete all rows from table:
Output:
Uses DELETE (not TRUNCATE) - respects foreign keys, preserves auto-increment counter.
model:table-reset
Resets your table by truncating all data AND resetting the auto-increment counter back to 1. Use this when you need a completely fresh start with IDs starting from 1 again. Unlike model:table-empty which preserves the auto-increment counter, this gives you a clean slate. Much faster than DELETE for large tables but temporarily disables foreign key checks.
Reset table and auto-increment:
Output:
Difference from model:table-empty:
model:table-empty- Uses DELETE (slow, safe, preserves auto-increment)model:table-reset- Uses TRUNCATE (fast, resets auto-increment to 1)
Uses TRUNCATE - faster but resets auto-increment. May fail if table has foreign key references.
model:table-export
Dumps your table's data to a file for backups, data migration, or sharing. Automatically detects format from file extension (.sql for SQL INSERT statements, .csv for spreadsheets). Use this before risky operations, when moving data between environments, or creating test fixtures. Same as table:export but works with model names.
Export table data to SQL or CSV:
Auto-generates filename with timestamp:
Export to specific file:
Format detected from file extension (.sql or .csv). Files saved to application/storage/exports/.
Controller Commands
Controller commands help you create and manage HTTP request handlers in your application. Controllers coordinate between your models and views - they receive requests, fetch data from models, and pass it to views for rendering. Rachie uses method prefixes (get, post, put, delete) to automatically route HTTP verbs to the right controller methods.
These commands generate controllers with RESTful CRUD methods already scaffolded, let you add custom methods interactively, and provide the complete MVC scaffold (controller + model + views) in one command for rapid prototyping.
Note: Generated controllers are scaffolds with empty methods and commented examples showing common patterns. You'll need to implement the actual logic: data validation, model operations, error handling, authorization checks, and business rules specific to your application.
controller:create
Generates your controller file with RESTful CRUD methods already scaffolded as starting templates. Use this when starting a new feature or resource - it saves you from manually creating the file and typing boilerplate structure. The command can add custom methods interactively, or you can add them later with controller:append or by editing directly.
Note: The generated controller uses TodoModel as a placeholder in all methods. You'll want to replace TodoModel with your actual model class name (e.g., PostModel, UserModel).
Create a new controller:
Output:
If you answer y, it prompts for method names interactively. If n:
Generated controller includes RESTful CRUD methods: getIndex(), getNew(), postNew(), getShow($id), getEdit($id), postEdit($id), getDelete($id). Each method demonstrates common patterns using TodoModel as a placeholder.
controller:append
Adds a new method template to your existing controller. Use this when extending your controller with additional actions beyond the standard CRUD operations (like getPublished, getArchive, getExport). Auto-generates the method skeleton with GET prefix and proper view path - you still need to implement the actual functionality inside the method.
Add a method to existing controller:
Output:
Generates:
Method inserted before closing brace with GET prefix.
controller:delete
Removes the controller class file from your filesystem. Use this when removing features from your application. This only deletes the PHP file - routes in your routing configuration and related view files remain. You'll need to clean those up manually if needed.
Delete a controller file:
Output:
Note: This only deletes the controller file, not routes or views.
controller:rename
Renames a controller file and updates the class name inside the file. Use this when you need to rename a controller to better match your resources or fix naming conventions. The command handles the file renaming and class name update automatically.
Note: This command only renames the controller file and class name. You'll need to manually update any routes, view paths, redirects, or other references to the old controller name.
Rename a controller:
Output:
The command updates both the filename and the class name inside the file. You can provide names with or without the "Controller" suffix.
controller:complete
Creates a complete MVC scaffold in one command - controller, model, and views all together as starting templates. Use this for rapid prototyping or when starting a brand new resource from scratch. Generates the file structure and boilerplate you need to start building: controller with empty CRUD methods, model with basic structure, view templates (layout, index, show, create), and CSS file. You'll still need to add your properties to the model, implement controller logic, and customize the views for your specific application. If any step fails, it rolls back automatically.
Create controller, model, and views together:
Output:
Creates complete MVC resource in one command. If any step fails, rolls back created files.
View Commands
View commands help you create and organize your HTML templates. Views render the user interface by displaying data passed from controllers using Rachie's template engine with features like layout inheritance (@extends), sections (@section/@yield), loops (@loopelse), and conditionals (@if).
These commands generate complete view structures with layout files, individual templates (index, show, create), and accompanying CSS files, following a consistent organization pattern that makes your views easy to maintain and extend.
Note: Generated views are template starting points with example markup demonstrating Rachie's template syntax and common patterns. You'll need to customize the HTML, add your actual content, style the CSS, handle your specific data fields, and build the UI/UX appropriate for your application.
view:create
Generates a complete view directory structure with template files demonstrating Rachie's template engine syntax (layout with @extends/@section/@yield, index with @loopelse, show, create with CSRF forms) and a CSS file. Use this when starting a new feature - it saves you from manually creating files and typing HTML boilerplate. The templates include example markup showing common patterns like flash messages, form handling, and empty states. You'll need to customize the HTML for your actual data fields, style the CSS, and build the UI/UX specific to your application.
Create complete view structure:
Output:
Creates directory with layout, index, show, create, and edit templates, plus CSS file with responsive styling.
view:add
Adds a single view file to an existing view directory with basic HTML5 boilerplate. Use this when you need additional templates beyond the standard set (like edit.php, profile.php, or custom action views). The generated file is a simple starting point - just the HTML structure with a heading and comment placeholder. You'll need to add your actual content, template syntax, and styling.
Add view file to existing directory:
Output:
Generates basic HTML5 template:
view:delete
Permanently removes an entire view directory and all template files inside. Use this when removing features from your application or cleaning up unused views. This is destructive and cannot be undone. After deleting the view directory, you'll be prompted to optionally delete the associated CSS file in public/css/.
Delete entire view directory:
Output:
Warning: Permanently deletes directory and all files inside. Cannot be undone. CSS deletion is optional.
view:rename
Renames a view directory and its associated CSS file. Use this when you need to rename views to better match your resources or fix naming conventions. The command handles both the directory and CSS file renaming automatically.
Note: This command only renames the view directory and CSS file. You'll need to manually update any View::render() calls in controllers or routes that reference the old view name.
Rename a view directory:
Output:
The command renames both the view directory and the associated CSS file in public/css/. All view files inside the directory remain unchanged.
Table Commands
Table commands work directly with database tables without requiring model files. Use these for quick table operations, prototyping, lookup tables, or managing tables that don't need models. Unlike model commands that read @column annotations, these commands interact with the database schema directly.
⚠️ Important: Only use table: commands on tables that don't have models. If your table has a model in application/models/, always use model: commands instead. Mixing table: and model: commands on the same table causes schema drift and breaks your migrations. See Best Practices for details.
These commands handle creating tables interactively or from SQL files, copying table structures, viewing schemas, exporting data, and managing table partitioning for large datasets.
table:create
Creates database tables directly without requiring a model file. Use this when you need quick tables for lookups, reference data, or prototyping, or when working with legacy databases that don't follow your model conventions. Unlike model:table-create which reads @column annotations from your model, this command builds tables interactively or from SQL files.
Create table directly (no model):
Interactive prompts:
Or from SQL file:
table:copy
Duplicates a table within the same database, copying both structure and data. Use this for creating backups before risky operations, generating test tables from production data, or creating table variants for experiments. Faster than export/import since data never leaves MySQL. Alternative to model:table-export + table:create when you need quick copies.
Copy table structure and data:
Output:
Copy structure only (no data):
table:delete
Permanently drops a database table by name, without needing a model file. Use this for removing temporary tables, cleaning up test databases, or deleting obsolete tables that were never associated with models. Similar to model:table-drop but works directly with table names. Destructive operation - all data permanently lost.
Drop table by name:
Output:
table:rename
Renames a database table using RENAME TABLE statement. Use this for tables without models or when you only need to change the database table name without updating model files. If you have a model, use model:table-rename instead, which renames the table AND updates the model's $table property automatically.
Rename database table:
Output:
Note: Does NOT update model files. Use model:table-rename if you have a model.
table:schema
Displays database table structure directly by table name, without requiring a model file. Use this to inspect tables created by other tools, legacy databases, or tables without models. Shows columns, data types, indexes, and keys. Identical functionality to model:table-schema but works with table names instead of model names.
Display table structure:
Output:
table:empty
Deletes all rows from a table while preserving the table structure and auto-increment counter. Works directly with table names (no model required). Use this for clearing data from tables without models, or when you need to respect foreign key constraints. Unlike TRUNCATE, this uses DELETE so it's safer but slower.
Delete all rows from table:
Output:
Uses DELETE - respects foreign keys, preserves auto-increment. Same as model:table-empty but for tables without models.
table:reset
Resets a table by truncating all data and resetting the auto-increment counter to 1. Works directly with table names (no model required). Use this when you need a completely fresh start with IDs beginning at 1. Much faster than DELETE for large tables. Temporarily disables foreign key checks.
Reset table and auto-increment:
Output:
Difference from table:empty:
table:empty- Uses DELETE (slow, safe, preserves auto-increment)table:reset- Uses TRUNCATE (fast, resets auto-increment to 1)
Uses TRUNCATE - faster than DELETE but resets auto-increment. Same as model:table-reset but for tables without models.
table:export
Exports table data to SQL or CSV format by table name, without requiring a model. Use this for backing up tables that don't have models, exporting legacy data, or creating SQL dumps for tables created with table:create. Identical functionality to model:table-export but accepts table names instead of model names.
Export table to SQL or CSV:
Auto-generates filename:
Export with specific filename:
Format detected from extension. Same functionality as model:table-export.
table:partition
Adds MySQL partitioning to existing tables for improved query performance on massive datasets (100M+ rows). Uses safe copy-swap method that keeps original table live during the process, minimizing downtime. Use this when queries on large tables are slow even with proper indexes, or when you need to manage data by ranges/hash buckets for archival. Partition column must be part of the primary key.
Add partitioning to large table:
Output:
Uses copy-swap method - safe for production with minimal lock time. Partition column must be part of PRIMARY KEY.
table:unpartition
Removes MySQL partitioning from tables, converting them back to standard non-partitioned tables. Use this when partitioning is no longer needed (data size reduced, schema changed) or when you need to modify the partition scheme (unpartition first, then re-partition differently). Uses same safe copy-swap method as table:partition, keeping original table live during conversion.
Remove partitioning from table:
Output:
Part 6: Migration Commands
Migration commands manage database schema changes across environments through version-controlled migration files. When you create or modify tables using model or table commands, Roline captures those changes as migrations - PHP files with up() and down() methods containing SQL to apply and revert changes. This lets you version control your schema changes alongside code, deploy confidently to production, and roll back problematic changes when needed.
Migrations work by comparing your current database schema with snapshots saved from previous migrations. When you run migration:make, Roline detects what changed (new tables, added columns, modified indexes) and generates the SQL automatically. Run migration:run to apply pending migrations in other environments. Use migration:status to see what's been run and what's pending. Use migration:rollback if you need to undo the last batch. Each migration is tracked in a database table to prevent double-execution and enable rollback functionality.
migration:make
Captures current database changes as a versioned migration file by comparing your database schema with the last migration snapshot. Use this after creating or modifying tables with model or table commands to record those changes for deployment to other environments. Generates both the migration file (with up() and down() SQL) and a schema snapshot for the next comparison. The migration name should describe what changed (like "add_email_to_users" or "create_products_table").
⚠️ Critical Workflow: Always run model:table-update (or model:table-create) BEFORE running migration:make. The migration captures changes that already exist in your database, not pending model changes. If you create a migration before updating your database, the migration will be empty or incomplete. See Migration Workflow for details.
Create migration after making database changes:
Output:
Generated migration file structure:
Timestamp prefix prevents filename conflicts. Requires database changes to exist before running - errors if no changes detected since last migration. Use table:create, table:update, or model:table-create/model:table-update first to make schema changes, then capture them with migration:make.
migration:run
Executes all pending migrations that haven't been run yet, applying their up() SQL to update the database schema. Use this after pulling code with new migration files, or when deploying to staging/production to sync the database with your codebase. Migrations run sequentially in timestamp order (oldest first), and each is tracked in a database table to prevent double-execution. Stops immediately if any migration fails.
Run all pending migrations:
Output:
If no pending migrations:
Each successfully-run migration is recorded in the migrations tracking table with a batch number. If a migration fails, the command stops and shows the error - you'll need to fix the migration file and run again (already-successful migrations are skipped). Use migration:status before running to see which migrations will execute.
migration:rollback
Reverts previously executed migrations by running their down() methods in reverse chronological order (newest first). Use this to undo problematic migrations in development, roll back failed deployments, or temporarily revert schema changes. By default rolls back the last batch (all migrations from the most recent migration:run). Optional steps parameter lets you roll back multiple batches.
Roll back last batch of migrations:
php roline migration:rollback
Output:
Rolling back 2 migration(s)...
→ 2025_01_15_143022_add_status_to_posts.php
✓ 2025_01_15_143022_add_status_to_posts.php
→ 2025_01_15_130000_add_email_verification.php
✓ 2025_01_15_130000_add_email_verification.php
Rolled back 2 migration(s) successfully!
Roll back multiple batches:
php roline migration:rollback 3
Output:
Rolling back 5 migration(s)...
→ 2025_01_15_143022_add_status_to_posts.php
✓ 2025_01_15_143022_add_status_to_posts.php
→ 2025_01_15_130000_add_email_verification.php
✓ 2025_01_15_130000_add_email_verification.php
→ 2025_01_15_120000_create_users.php
✓ 2025_01_15_120000_create_users.php
(continues for all migrations in last 3 batches...)
Rolled back 5 migration(s) successfully!
If no migrations to rollback:
No migrations to rollback.
Successfully rolled-back migrations are removed from the tracking table and can be run again. Rollback only reverts schema changes - it does NOT restore deleted data. The down() method must properly reverse the up() method changes. Stops immediately if any rollback fails. Test rollbacks on development database first and backup before rolling back on production.
migration:status
Shows comprehensive overview of all migrations - which have been executed and which are pending. Use this before running migrations to see what will execute, after deployment to verify all migrations ran, or when debugging to understand database migration state. Read-only command that makes no changes.
Check migration status:
php roline migration:status
Output (mixed state):
=================================================
MIGRATION STATUS
=================================================
Ran Migrations (3):
✓ 2025_01_15_120000_create_users.php
✓ 2025_01_15_130000_add_email_verification.php
✓ 2025_01_15_135000_create_posts.php
Pending Migrations (2):
⏳ 2025_01_15_140000_add_status_to_posts.php
⏳ 2025_01_15_145000_create_comments.php
=================================================
Output (up to date):
=================================================
MIGRATION STATUS
=================================================
Ran Migrations (5):
✓ 2025_01_15_120000_create_users.php
✓ 2025_01_15_130000_add_email_verification.php
✓ 2025_01_15_135000_create_posts.php
✓ 2025_01_15_140000_add_status_to_posts.php
✓ 2025_01_15_145000_create_comments.php
Pending Migrations (0):
Database is up to date!
=================================================
Safe to run anytime without side effects. Queries the migrations tracking table for executed migrations and scans the migrations directory for all files to determine pending migrations. Use before migration:run to preview what will execute, or after to confirm all migrations applied successfully.
Part 7: Database Commands
Database commands operate at the database level rather than individual tables - managing entire databases, listing database information, bulk operations across all tables, and data import/export. These commands work directly with MySQL without requiring model files.
Database Configuration: Most db: commands work on the database specified in your config/database.php file by default. You can override this by providing a database name as an argument (e.g., db:tables staging_db or db:create test_db). See Database Command Defaults for examples.
Use these for database-wide operations. Most require careful handling and include confirmation prompts for destructive actions like dropping databases or truncating all tables.
db:list
Shows all databases on your MySQL server with table counts and table names. Use this to see available databases and quickly assess their size. Shows first few table names for each database, then truncates with '+N more' for databases with many tables. Current database from config marked with asterisk.
List all databases:
php roline db:list
Output:
Databases on localhost:
rachie *
8 tables: users, posts, comments, categories, +4 more
testdb
3 tables: products, orders, customers
myapp_staging
(empty)
* = current database from config
Excludes system databases (information_schema, mysql, performance_schema, sys). Current database from config marked with asterisk.
db:tables
Lists all tables in a database with row counts. Use this to see what tables exist and their approximate sizes. Can query specific database or use config default. Shows formatted output with aligned columns and total row count summary.
List tables in current database:
php roline db:tables
List tables in specific database:
php roline db:tables myapp_staging
Output:
Database: rachie
users 1,245 rows
posts 8,932 rows
comments 15,673 rows
categories 12 rows
tags 45 rows
5 tables, ~25,907 total rows
Row counts are estimates from MySQL's information_schema. Actual counts may vary slightly for InnoDB tables.
db:create
Creates a new database with UTF8MB4 charset and collation. Use this for initial project setup or creating test/staging databases. Supports --if-not-exists flag to skip if already exists. Can specify database name as argument or uses config. Shows next steps (migration:run, db:seed) after creation.
Create database from config:
php roline db:create
Create specific database:
php roline db:create myapp_test
Output:
Creating database: myapp_test
Charset: utf8mb4
Collation: utf8mb4_unicode_ci
Database 'myapp_test' created successfully!
Next steps:
php roline migration:run # Run migrations
php roline db:seed # Seed data
Errors if database already exists unless --if-not-exists flag provided. Database must not exist or command fails.
db:drop
Drops entire database permanently with triple confirmation system. Use with extreme caution - this deletes everything. Shows table count before confirmation. Three separate confirmation steps: yes/no, type exact database name, final yes/no. Lists everything that will be deleted (tables, views, procedures, functions).
Drop database:
php roline db:drop
Output:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
WARNING: This will DROP THE ENTIRE DATABASE!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Database: rachie
Tables: 8
This will PERMANENTLY DELETE:
- The database itself
- ALL tables and their data
- ALL views, procedures, functions
- ALL stored routines
This action CANNOT be undone!
You will need to recreate the database manually!
Are you ABSOLUTELY sure you want to DROP database 'rachie'? (y/n): y
To confirm, please type the database name: rachie
Database name: rachie
FINAL WARNING: Drop the entire database now? (y/n): y
Dropping database...
Database 'rachie' has been dropped!
Recreate with: php roline db:create rachie
Triple confirmation: yes/no, type database name, final yes/no. NEVER use on production without backup.
db:table-drops
Drops all tables in database but keeps the database itself. Use for resetting to clean state before migrations. Lists all tables before confirmation. Disables foreign key checks during operation for safe deletion. Continues through errors to drop as many tables as possible, shows success count.
Drop all tables:
php roline db:table-drops
Output:
WARNING: This will DROP ALL tables in the database!
Database: rachie
Tables to drop: 8
→ users
→ posts
→ comments
→ categories
→ tags
→ sessions
→ migrations
→ cache
This action CANNOT be undone!
Are you ABSOLUTELY sure you want to drop ALL rachie tables? (y/n): y
To confirm, please type the database name: rachie
Database name: rachie
Final confirmation. Drop all tables now? (y/n): y
Dropping tables...
→ Dropping users...
→ Dropping posts...
→ Dropping comments...
→ Dropping categories...
→ Dropping tags...
→ Dropping sessions...
→ Dropping migrations...
→ Dropping cache...
Successfully dropped 8 tables!
Database 'rachie' is now empty.
Triple confirmation like db:drop. Disables foreign key checks during operation for safe deletion.
db:reset
Empties all tables using TRUNCATE while preserving structures. Faster than DELETE and resets auto-increment counters. Disables foreign key checks during operation. Continues through errors, shows count of successfully truncated tables. Single confirmation (not triple like drop commands).
Empty all tables:
php roline db:reset
Output:
WARNING: This will TRUNCATE ALL tables (delete all data)!
Database: rachie
Tables to truncate: 8
→ users
→ posts
→ comments
→ categories
→ tags
→ sessions
→ migrations
→ cache
This action CANNOT be undone!
Note: Table structures preserved, auto-increment counters reset
Are you sure you want to TRUNCATE ALL tables in rachie? (y/n): y
Truncating tables...
→ Truncating users...
→ Truncating posts...
→ Truncating comments...
→ Truncating categories...
→ Truncating tags...
→ Truncating sessions...
→ Truncating migrations...
→ Truncating cache...
Successfully truncated 8 tables!
All data deleted from 'rachie'. Auto-increment counters reset.
TRUNCATE is faster than DELETE for clearing large tables. Cannot be rolled back even in transactions.
db:schema
Shows complete database schema including all tables, columns, types, keys, and indexes. Use for documentation or schema review. Read-only command, safe to run anytime. Shows foreign keys with ON DELETE/UPDATE actions, check constraints, and partitioning if configured. Formatted output with borders and indentation for readability.
View entire database schema:
php roline db:schema
Output:
Reading database schema...
=================================================
DATABASE SCHEMA
=================================================
Total Tables: 3
TABLE: users
--------------------------------------------------
id INT(11) NOT NULL AUTO_INCREMENT
username VARCHAR(50) NOT NULL
email VARCHAR(100) NOT NULL
password VARCHAR(255) NOT NULL
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
PRIMARY KEY: id
INDEXES:
idx_username: username UNIQUE
idx_email: email UNIQUE
TABLE: posts
--------------------------------------------------
id INT(11) NOT NULL AUTO_INCREMENT
user_id INT(11) NOT NULL
title VARCHAR(200) NOT NULL
body TEXT
status VARCHAR(20) NOT NULL DEFAULT 'draft'
published_at TIMESTAMP
PRIMARY KEY: id
INDEXES:
idx_user_id: user_id
idx_status: status
FOREIGN KEYS:
fk_posts_user_id: user_id → users(id) [ON DELETE CASCADE]
TABLE: comments
--------------------------------------------------
id INT(11) NOT NULL AUTO_INCREMENT
post_id INT(11) NOT NULL
user_id INT(11) NOT NULL
body TEXT NOT NULL
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
PRIMARY KEY: id
INDEXES:
idx_post_id: post_id
idx_user_id: user_id
=================================================
Read-only command that makes no changes. Shows full schema for all tables in database.
db:seed
Runs database seeder classes to populate tables with test/sample data. Use after fresh migrations to add development data. Can run all seeders or specify one by name. DatabaseSeeder always runs first when running all (master seeder convention). Continues through errors, shows success/fail count at end. Seeders must be in application/database/seeders/ directory.
Run all seeders:
php roline db:seed
Run specific seeder:
php roline db:seed Users
Output (all seeders):
Running all seeders...
Running seeder: DatabaseSeeder...
✓ DatabaseSeeder completed
Running seeder: UsersSeeder...
✓ UsersSeeder completed
Running seeder: PostsSeeder...
✓ PostsSeeder completed
All seeders completed successfully! (3 seeders)
Output (specific seeder):
Running seeder: UsersSeeder...
✓ UsersSeeder completed
Seeders must be in application/database/seeders/ directory. DatabaseSeeder runs first when running all seeders.
db:export
Exports entire database to SQL file with streaming (no memory limit - handles any size). Shows live progress with row counts as tables export. Auto-generates timestamped filename if not provided. Batches INSERT statements (1000 rows per statement) for fast import. Can run while other applications access the database. Saves to application/storage/exports/ directory.
Export with auto-generated filename:
php roline db:export
Export with custom filename:
php roline db:export mybackup.sql
Output:
Exporting database: rachie
Tables to export: 8
→ Exporting users... (1,245 rows)
→ Exporting posts... (8,932 rows)
→ Exporting comments... (15,673 rows)
→ Exporting categories... (12 rows)
→ Exporting tags... (45 rows)
→ Exporting sessions... (0 rows)
→ Exporting migrations... (15 rows)
→ Exporting cache... (2,341 rows)
Database exported successfully!
Location: /path/to/application/storage/exports/rachie_backup_2025-01-15_143022.sql
Exports include DROP TABLE, CREATE TABLE, and INSERT statements. Prompts before overwriting existing files.
db:import
Imports SQL dump by streaming file line by line (no memory limit - handles any size). Shows live progress updating every 100 statements. Shows duration timing when complete. Smart path resolution checks multiple locations (exact path, current directory, exports folder). Stops on first error with statement and line number. Database must exist before importing.
Import SQL file:
php roline db:import backup.sql
Import with full path:
php roline db:import /path/to/database_dump.sql
Output:
Importing database: rachie
Source file: /path/to/backup.sql
File size: 145.3 MB
→ Importing... (100 statements)
→ Importing... (200 statements)
→ Importing... (15,847 statements)
Database imported successfully!
Executed: 15,847 statements
Duration: 2 minutes 34 seconds
Compatible with mysqldump, db:export, and standard SQL dumps. Shows file size before starting (KB/MB/GB).
Part 8: Cache Commands
Cache commands clean up temporary files, cached data, compiled views, log files, and sessions. These commands help you reclaim disk space, troubleshoot caching issues, and maintain your application. Most operate on the vault directory structure where Rachie stores temporary data.
Use these during development when debugging caching issues, after deployments to force cache refresh, or during maintenance to clear old files. Some commands like cleanup:sessions log out all users, so run those during maintenance windows.
cleanup:cache
Clears application cache based on your configured driver (file, memcached, redis). Use this when you need to force cache refresh after code changes or when debugging cache-related issues. Shows your current cache configuration before clearing. For file driver, clears vault/cache/ directory. For memcached/redis, provides connection commands to flush manually. Requires confirmation before clearing.
Clear application cache:
php roline cleanup:cache
Output:
Current Cache Configuration:
Status: Enabled
Driver: file
Path: vault/cache
What will be cleared:
- All files in: vault/cache/
Note: This only clears cache. Use 'cleanup:views' to clear compiled views.
Are you sure you want to clear the cache? (y/n): y
Clearing cache...
Cleared: Application Cache
Cache cleared successfully!
For memcached or redis drivers, shows manual flush commands instead of clearing directly. Skips non-existent directories without error.
cleanup:views
Clears orphaned compiled view templates from vault/tmp/ directory. Use this after debugging view errors or when you notice many old compiled files accumulating. Rachie compiles templates to temporary files during rendering and normally deletes them afterward, but errors can leave orphaned files. Your source views in application/views/ are never touched - only temporary compiled files are removed. Safe to run anytime without data loss.
Clear compiled view templates:
php roline cleanup:views
Output:
What will be cleared:
- vault/tmp/ (Compiled view templates)
Note: This only clears compiled views, not your source views.
Are you sure you want to clear compiled views? (y/n): y
Clearing compiled views...
Cleared: Compiled view templates
Compiled views cleared successfully!
Views will automatically recompile on next request. Source files in application/views/ remain untouched.
cleanup:logs
Truncates error log files to zero bytes without deleting them. Use this when your log files have grown large and are slowing down debugging or consuming excessive disk space. Shows current log file sizes before clearing to help you decide if clearing is needed. Logs are truncated (emptied), not deleted, so logging continues to work normally after clearing. Consider backing up important logs before running if you need historical error data.
Clear error logs:
php roline cleanup:logs
Output:
What will be cleared:
- vault/logs/error.log (Application error log) - 245.67 MB
Are you sure you want to clear log files? (y/n): y
Clearing log files...
Cleared: Application error log
Log files cleared successfully!
Truncation is permanent - log content cannot be recovered. Log files continue to work and accept new entries after clearing.
cleanup:sessions
Clears all PHP session files from vault/sessions/ directory. Use this during scheduled maintenance windows or after security incidents requiring session invalidation. This is destructive - ALL users will be logged out immediately and lose shopping carts, form data, and session state. Never run during active business hours. Shows warning about logging out all users and requires explicit confirmation before executing.
Clear all session files:
php roline cleanup:sessions
Output:
What will be cleared:
- vault/sessions/ (Session files)
WARNING: This will log out ALL active users!
Are you sure you want to clear all sessions? (y/n): y
Clearing sessions...
Cleared: Session files
Sessions cleared successfully!
All users have been logged out.
Users must log in again to continue using the application. Use when session storage is consuming excessive disk space or during maintenance.
cleanup:all
Runs all cleanup operations in sequence: cache, compiled views, logs, and sessions. Use this for comprehensive cleanup during scheduled maintenance windows or after major deployments. Shows complete list of what will be cleared across all categories before execution. ALL users will be logged out when sessions are cleared. Shows log file sizes before truncation. Reports progress for each cleanup step and provides summary of successes/failures at the end.
Run all cleanup operations:
php roline cleanup:all
Output:
Cleanup All - Complete System Cleanup
The following will be cleared:
Cache:
- vault/cache/ (Application cache)
Compiled Views:
- vault/tmp/ (Compiled view templates)
Log Files:
- vault/logs/error.log (Application error log) - 245.67 MB
Sessions:
- vault/sessions/ (Session files)
WARNING: This will log out ALL active users!
Are you sure you want to run ALL cleanup operations? (y/n): y
Running all cleanup operations...
1. Clearing cache...
Cleared: Application cache
2. Clearing compiled views...
Cleared: Compiled view templates
3. Clearing log files...
Cleared: Application error log
4. Clearing sessions...
Cleared: Session files
All cleanup operations completed successfully!
Total items cleared: 4
All users have been logged out.
Useful for fresh starts, troubleshooting caching issues, or reclaiming disk space. Never run during active business hours.
Part 9: Utility Commands
Utility commands provide information about Roline itself - listing available commands, showing help, and displaying version information. These are reference commands you'll use when learning Roline or when you need quick reminders about command syntax.
Use these when you're getting started with Roline, when you forget command names, or when you need version information for bug reports or compatibility checking.
list
Lists all available Roline commands organized by category with usage syntax and descriptions. Use this when you want to see what commands are available or when you forget a command name. This is the default command - running php roline without arguments shows the list. Commands are grouped into categories (Controller, Model, View, Table, Migration, Database, Cache, Utility) with color-coded usage syntax showing required and optional arguments. Shows usage examples at the bottom.
List all commands:
php roline list
Or simply:
php roline
Output:
Roline - Rachie Command Line Interface
Controller Commands:
controller:create <name|required> Create a new controller
controller:append <name|required> Add method to controller
controller:delete <name|required> Delete controller file
controller:complete <name|required> Create controller, model, and views together
Model Commands:
model:create <name|required> Create a new model
model:append <name|required> Add properties to model
model:delete <name|required> Delete model file
model:table-create <name|required> Create database table from model
model:table-update <name|required> Update table from model changes
model:table-drop <name|required> Drop table associated with model
model:table-rename <name|required> <new> Rename model's table
model:table-schema <name|required> Show model's table structure
model:table-empty <name|required> Delete all rows (preserves auto-increment)
model:table-reset <name|required> Reset table (TRUNCATE, resets auto-increment)
model:table-export <name|required> Export table to SQL file
View Commands:
view:create <view|required> Create a complete view structure with templates
view:add <view|required> <name|required> Add single view file to existing view
view:delete <view|required> Delete entire view directory
Table Commands:
table:create <name|required> Create database table directly
table:copy <source> <destination> Copy table structure and data
table:delete <name|required> Drop database table
table:rename <old> <new> Rename database table
table:schema <name|required> Show table structure
table:empty <name|required> Delete all rows (preserves auto-increment)
table:reset <name|required> Reset table (TRUNCATE, resets auto-increment)
table:export <name|required> Export table to SQL
table:partition <table> <type> <count> Add partitioning to table
table:unpartition <table> Remove table partitioning
Migration Commands:
migration:make <name|required> Create a new migration file
migration:run Run pending migrations
migration:rollback <steps|optional> Rollback last migration batch
migration:status Show migration status (ran and pending)
Database Commands:
db:list List all databases with table counts
db:tables [database] List all tables with row counts
db:create [database] [--if-not-exists] Create the database
db:drop [database] Drop the entire database
db:table-drops Drop all database tables (keeps database)
db:reset Empty all tables (TRUNCATE, resets auto-increment)
db:schema Show full database schema
db:seed <seeder|optional> Run database seeders
db:export <file|optional> Export entire database
db:import <file|required> Import SQL dump file into database
Cache Commands:
cleanup:cache Clear application cache
cleanup:views Clear compiled view temporary files
cleanup:logs Clear error log files
cleanup:sessions Clear old session files
cleanup:all Run all cleanup operations (cache, views, logs, sessions)
Utility Commands:
list List all available commands
help Show help information
version Show version information
Usage:
php roline <command> [arguments]
php roline <command> --help
Examples:
php roline controller:create Posts
php roline model:create Post
php roline table:create posts
Arguments in angle brackets with color coding indicate required (<name|required>) or optional ([database]) parameters. Run any command with --help flag for detailed help.
Example using --help flag:
php roline model:create --help
Output:
Roline - Rachie Command Line Interface
model:create <name|required>
Create a new model
Creates a new model class file in application/models/ with schema definition
using @column annotations. Models extend Rackage\Model and include static
methods for database operations.
Arguments:
<name|required> Model name (singular, PascalCase, e.g., Post, User)
Examples:
php roline model:create Post
php roline model:create User
Creates:
application/models/PostModel.php
application/models/UserModel.php
Generated Model:
- Namespace: Models\
- Extends: Rackage\Model
- Property: protected static $table (auto-pluralized)
- Property: protected static $columns = [] (for schema)
- Property examples with @column annotations
- Docblock with metadata
Documentation: https://rachie.dev/docs/models
Note: Models are starting templates - add your business logic methods,
relationships, validation, and custom queries specific to your application.
help
Shows quick help information with usage syntax and common examples. Use this when you need a brief reminder of how to use Roline commands without seeing the full command list. Points you to php roline list for the complete list of available commands. This is a lightweight alternative to the list command when you just need basic usage information.
Show help:
php roline help
Output:
Roline - Rachie Command Line Interface
Usage:
php roline <command> [arguments]
Examples:
php roline controller:create Posts
php roline model:create Post
php roline table:create Posts
php roline cache:clear
Run "php roline list" to see all available commands.
For detailed help on specific commands, use php roline <command> --help.
version
Displays version information for Roline CLI and Rachie Framework. Use this when reporting bugs, checking compatibility, or verifying your installation. Helpful for support requests and ensuring you're running the expected versions. Shows both Roline CLI version and Rachie Framework version on separate lines.
Show version:
php roline version
Output:
Roline CLI v1.0.0
Rachie Framework v2.0
Include this information when reporting issues or asking for help with Roline commands.
Part 10: Model Annotations Reference
Model annotations define your database schema using docblock comments on model properties. Each property with @column becomes a database column. Annotations control data types, constraints, indexes, and relationships. The ModelParser reads these annotations and generates SQL statements for table creation and updates.
Critical Rule: Column properties must be non-static instance properties. Static properties (like $table, $timestamps) are skipped because they're class-level configuration, not record data.
Formatting Rule: One Annotation Per Line
Always write each annotation on its own line within the docblock. Never compress multiple annotations onto a single line.
Why this matters:
- Easier to scan and understand at a glance
- Simpler to add/remove/modify individual annotations
- Better for code reviews and diffs
- Standard PHP docblock convention
- Maintains visual consistency across your models
This formatting applies to ALL annotations including constraints (@nullable, @unsigned), indexes (@index, @fulltext), relationships (@foreign, @ondelete), and modifiers (@rename, @drop).
Documentation Rule: Always Include a Description
Every property docblock must start with a human-readable description before the annotations. This explains what the column represents in business terms.
Why this matters:
- Property names can be ambiguous (
$status- status of what? order? payment? user?) - Provides business context that annotations alone cannot convey
- Shows in IDE tooltips when hovering over the property
- Standard PHPDoc convention - description comes before tags
- Helps other developers (and AI tools) understand intent
- Makes code self-documenting without needing external wiki/docs
Quick Reference
| Numeric | String | Date/Time | Special | Binary |
| @tinyint | @char | @date | @boolean | @blob |
| @smallint | @varchar | @time | @enum | @mediumblob |
| @mediumint | @text | @year | @set | @longblob |
| @int | @mediumtext | @datetime | @json | Spatial |
| @bigint | @longtext | @timestamp | @autonumber | @point |
| @decimal | Modifiers | Constraints | @uuid | @linestring |
| @float | @comment | @primary | Indexes | @polygon |
| @double | @tablecomment | @unique | @index | @geometry |
| @after | @nullable | @fulltext | Relationships | |
| @first | @unsigned | @composite | @foreign | |
| @drop | @default | @compositeUnique | @ondelete | |
| @rename | @check | @partition | @onupdate |
Numeric Types
@tinyint
Syntax: @tinyint or @tinyint length
Example:
Resulting SQL: age TINYINT(4) UNSIGNED NOT NULL
When to use: Small whole numbers, flags, status codes, small counters. Range: -128 to 127 (or 0 to 255 if unsigned). Perfect for boolean-like values, single-digit numbers, percentages.
Notes:
- Default length is 4 if not specified
- Only 1 byte of storage (smallest integer type)
- For true boolean flags, use
@booleanannotation instead (which internally uses TINYINT(1))
@smallint
Syntax: @smallint or @smallint length
Example:
Resulting SQL: stock_quantity SMALLINT(6) UNSIGNED NOT NULL DEFAULT 0
When to use: Medium-range whole numbers. Range: -32,768 to 32,767 (or 0 to 65,535 if unsigned). Good for inventory counts, port numbers, moderate counters.
Notes:
- Default length is 6 if not specified
- Takes 2 bytes of storage
- Sweet spot between TINYINT (too small) and INT (unnecessary overhead)
@mediumint
Syntax: @mediumint or @mediumint length
Example:
Resulting SQL: daily_views MEDIUMINT(9) UNSIGNED NOT NULL DEFAULT 0
When to use: Large counters that don't need full INT range. Range: -8,388,608 to 8,388,607 (or 0 to 16,777,215 if unsigned). Good for high-volume counters, moderately large datasets.
Notes:
- Default length is 9 if not specified
- Takes 3 bytes of storage (vs 4 bytes for INT)
- Saves 25% storage compared to INT when you don't need the full range
@int
Syntax: @int or @int length
Example:
Resulting SQL: quantity INT(11) UNSIGNED NOT NULL DEFAULT 0
When to use: Whole numbers like counts, quantities, IDs, ages, years. Range: -2,147,483,648 to 2,147,483,647 (or 0 to 4,294,967,295 if unsigned). Most common integer type.
Notes:
- Default length is 11 if not specified
- Takes 4 bytes of storage
- Use
@unsignedfor positive-only values (doubles the upper range) - For auto-incrementing IDs, use
@autonumberinstead (automatically sets type to INT, adds UNSIGNED, AUTO_INCREMENT, and PRIMARY KEY)
@bigint
Syntax: @bigint or @bigint length
Example:
Resulting SQL: total_views BIGINT(20) UNSIGNED NOT NULL DEFAULT 0
When to use: Very large whole numbers that exceed INT range. Common for counters, timestamps as integers, large IDs. Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 (or 0 to 18,446,744,073,709,551,615 if unsigned).
Notes:
- Default length is 20 if not specified
- Takes 8 bytes of storage (vs 4 bytes for INT)
- Use when you expect values to exceed 4 billion (unsigned INT limit)
@decimal
Syntax: @decimal precision,scale
Example:
Resulting SQL: price DECIMAL(10,2) UNSIGNED NOT NULL DEFAULT 0.00
When to use: Exact decimal values where precision matters - prices, monetary amounts, percentages, coordinates. Never use FLOAT/DOUBLE for money due to rounding errors.
Notes:
- Precision (first number): Total digits (before + after decimal point)
- Scale (second number): Digits after decimal point
- Example: DECIMAL(10,2) stores up to 99999999.99
- Default is DECIMAL(10,2) if not specified
- REQUIRED format:
@decimal 10,2(with comma, no spaces in some parsers) - Always use DECIMAL for money, never FLOAT or DOUBLE
@float
Syntax: @float
Example:
Resulting SQL: temperature FLOAT NOT NULL
When to use: Approximate decimal numbers where slight precision loss is acceptable - scientific measurements, coordinates (when high precision not critical), calculated values. Faster than DECIMAL for math operations.
Notes:
- Takes 4 bytes of storage
- Approximate values (can have rounding errors)
- Precision: ~7 decimal digits
- Never use for money - use @decimal instead
- Good for large datasets where storage/speed matters more than exact precision
@double
Syntax: @double
Example:
Resulting SQL: latitude DOUBLE NOT NULL
When to use: High-precision approximate decimal numbers - geographic coordinates, scientific calculations, statistical data. More precise than FLOAT when you need 15+ decimal digits.
Notes:
- Takes 8 bytes of storage (double the size of FLOAT)
- Approximate values (can have rounding errors but less than FLOAT)
- Precision: ~15 decimal digits
- Never use for money - use @decimal instead
- Use when FLOAT precision isn't enough but DECIMAL's exactness isn't required
String Types
@char
Syntax: @char or @char length
Example:
Resulting SQL: country_code CHAR(2) NOT NULL DEFAULT 'US'
When to use: Fixed-length strings where every value has exactly the same number of characters - country codes, state abbreviations, fixed codes, checksums. CHAR pads shorter values with spaces to reach the defined length.
Notes:
- Default length is 255 if not specified
- Takes exactly N bytes of storage (where N is the length)
- Faster than VARCHAR for fixed-length data because MySQL doesn't need to store the length
- Maximum length: 255 characters
- Avoid for variable-length data - wastes space with padding
@varchar
Syntax: @varchar length
Example:
Resulting SQL: email VARCHAR(255) NOT NULL UNIQUE
When to use: Variable-length strings up to 255 characters - names, emails, titles, URLs, usernames. Most common string type for short to medium text. Only uses the storage needed for the actual content plus 1-2 bytes for length.
Notes:
- Default length is 255 if not specified
- Takes actual string length + 1 byte (if length ≤ 255) or + 2 bytes (if length > 255) for storage
- Maximum length: 65,535 characters (but use TEXT types for content over 255)
- More efficient than CHAR for variable-length data
- Can be indexed and searched efficiently
@text
Syntax: @text
Example:
Resulting SQL: description TEXT NULL
When to use: Long text content that exceeds VARCHAR's practical limit - articles, descriptions, comments, formatted content. Ideal for content between 256 and 65,535 characters (64 KB).
Notes:
- No length parameter needed (fixed at 64 KB maximum)
- Takes actual string length + 2 bytes for storage
- Cannot have a default value in MySQL
- Can be indexed with prefix length:
@indexwith manual prefix specification - Use @fulltext for full-text search on TEXT columns
@mediumtext
Syntax: @mediumtext
Example:
Resulting SQL: article_body MEDIUMTEXT NOT NULL
When to use: Very large text content - full articles, documentation, serialized data, large HTML content. Holds up to 16 MB of text, suitable for content too large for TEXT but not requiring LONGTEXT's massive capacity.
Notes:
- Maximum size: 16,777,215 characters (16 MB)
- Takes actual string length + 3 bytes for storage
- Cannot have a default value in MySQL
- Use when TEXT's 64 KB limit is too small
- Good middle ground between TEXT and LONGTEXT
@longtext
Syntax: @longtext
Example:
Resulting SQL: full_content LONGTEXT NOT NULL
When to use: Extremely large text content - complete books, extensive logs, large JSON/XML documents, comprehensive data exports. Holds up to 4 GB of text. Use sparingly as it impacts performance.
Notes:
- Maximum size: 4,294,967,295 characters (4 GB)
- Takes actual string length + 4 bytes for storage
- Cannot have a default value in MySQL
- Significantly impacts query performance when selecting this column
- Consider storing large content in files instead and keeping only file paths in the database
- Use only when you genuinely need to store massive text data
Date/Time Types
Date and time types store temporal data like dates, times, timestamps, and years. Choose the appropriate type based on what precision you need and how you'll query the data.
@date
Syntax: @date
Example:
Resulting SQL: birth_date DATE NULL
When to use: Birth dates, anniversaries, deadlines, or any date-only data where you don't need time-of-day precision.
Notes:
- Stores dates in
YYYY-MM-DDformat (e.g.,2025-12-31) - Range:
1000-01-01to9999-12-31 - Storage: 3 bytes
- No timezone information stored
- Use @datetime if you also need to track the time
@time
Syntax: @time
Example:
Resulting SQL: opening_time TIME NOT NULL DEFAULT '09:00:00'
When to use: Business hours, recurring daily events, duration tracking, or when you only care about time-of-day.
Notes:
- Stores time in
HH:MM:SSformat (e.g.,14:30:00) - Range:
-838:59:59to838:59:59(can represent durations up to ~35 days) - Storage: 3 bytes
- Can store negative values for representing time differences
- Use @datetime if you need both date and time
@year
Syntax: @year
Example:
Resulting SQL: manufacture_year YEAR NULL
When to use: Graduation years, manufacture years, publication years, or any data where only the year matters.
Notes:
- Stores years as 4-digit values (e.g.,
2025) - Range:
1901to2155 - Storage: 1 byte (very efficient)
- MySQL deprecated 2-digit YEAR format, only 4-digit supported
- Use @date if you need month/day precision
@datetime
Syntax: @datetime
Example:
Resulting SQL: published_at DATETIME NULL
When to use: Timestamps for created_at/updated_at fields, scheduled publication times, or event start/end times.
Notes:
- Stores in
YYYY-MM-DD HH:MM:SSformat (e.g.,2025-01-08 14:30:00) - Range:
1000-01-01 00:00:00to9999-12-31 23:59:59 - Storage: 5 bytes, no timezone information stored
- Does not auto-update on record changes
- Use @timestamp if you need auto-updating behavior
@timestamp
Syntax: @timestamp
Example:
Resulting SQL: created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
When to use: Record creation timestamps, last modification timestamps, audit trails, or when you need automatic timestamp behavior.
Notes:
- Range:
1970-01-01 00:00:01UTC to2038-01-19 03:14:07UTC (32-bit limit) - Storage: 4 bytes
- Can use
@default CURRENT_TIMESTAMPfor automatic insertion time - Timezone-aware: MySQL converts between server timezone and UTC for storage
- Use @datetime if you need dates before 1970 or after 2038
Binary Types
Binary types store raw binary data like images, PDFs, files, or encrypted content. Choose based on the maximum file size you need to store.
@blob
Syntax: @blob
Example:
Resulting SQL: profile_image BLOB NULL
When to use: Small binary files like thumbnails, icons, small images, or binary data under 64 KB.
Notes:
- Storage: Up to 64 KB (65,535 bytes)
- Cannot have a default value
- Consider storing files on disk and keeping file paths in the database instead
- Indexes are not supported on BLOB columns
- Can significantly impact query performance
@mediumblob
Syntax: @mediumblob
Example:
Resulting SQL: document MEDIUMBLOB NULL
When to use: Medium-sized files like documents, high-res images, or binary data between 64 KB and 16 MB.
Notes:
- Storage: Up to 16 MB (16,777,215 bytes)
- Cannot have a default value
- Better to store files externally for files larger than a few MB
- Not indexable
- Loading this column loads the entire binary content
@longblob
Syntax: @longblob
Example:
Resulting SQL: video_file LONGBLOB NULL
When to use: Large binary files up to 4 GB - videos, large documents, backups, or archives.
Notes:
- Storage: Up to 4 GB (4,294,967,295 bytes)
- Cannot have a default value
- Storing large files in the database is generally not recommended
- Use external file storage (disk, S3, CDN) for better performance
- Significantly impacts database backup and query performance
Spatial Types
Spatial types store geometric and geographic data for mapping, GIS applications, and location-based features. Requires MySQL spatial extension support.
@point
Syntax: @point
Example:
Resulting SQL: location POINT NULL
When to use: Single coordinate points representing locations on a map - store locations, pins, markers, or GPS coordinates.
Notes:
- Stores a single X,Y coordinate pair (latitude/longitude)
- Can use spatial indexes for fast proximity searches
- Use functions like
ST_GeomFromText()to insert:POINT(40.7128 -74.0060) - Query with spatial functions like
ST_Distance()for distance calculations - Requires MySQL spatial extension enabled
@linestring
Syntax: @linestring
Example:
Resulting SQL: route LINESTRING NULL
When to use: Paths, routes, roads, or any connected sequence of points - delivery routes, hiking trails, road segments.
Notes:
- Stores an ordered sequence of points forming a line
- Useful for representing paths, routes, or boundaries
- Insert with
ST_GeomFromText('LINESTRING(0 0, 1 1, 2 2)') - Can calculate length with
ST_Length()function - Supports spatial indexing for efficient queries
@polygon
Syntax: @polygon
Example:
Resulting SQL: coverage_area POLYGON NULL
When to use: Areas, boundaries, regions, or zones - delivery zones, property boundaries, service areas, geofences.
Notes:
- Stores a closed shape defined by connected points
- Use for area-based queries like "does this point fall within this zone?"
- Insert with
ST_GeomFromText('POLYGON((0 0, 4 0, 4 4, 0 4, 0 0))') - Query with
ST_Contains()orST_Within()for containment checks - First and last points must be identical to close the shape
@geometry
Syntax: @geometry
Example:
Resulting SQL: geo_data GEOMETRY NULL
When to use: Generic spatial column that can store any geometry type - points, lines, polygons, or mixed spatial data.
Notes:
- Most flexible spatial type, can store any geometry
- Use when you need to store different geometry types in the same column
- Slightly less efficient than specific types for specialized queries
- Supports all spatial functions and indexes
- Useful for complex or mixed geographic data
Special Types
Special types provide convenience features or handle specific data formats that don't fit into standard categories.
@boolean / @bool
Syntax: @boolean or @bool
Example:
Resulting SQL: is_active TINYINT(1) NOT NULL DEFAULT 0
When to use: True/false flags, yes/no values, active/inactive status, or any binary state.
Notes:
- Internally stored as TINYINT(1) with values 0 (false) or 1 (true)
- Automatically defaults to 0 if no @default specified
- Both @boolean and @bool work identically
- More readable than using TINYINT directly for boolean logic
- Use with conditional checks:
if ($user->is_active) { ... }
@enum
Syntax: @enum value1,value2,value3
Example:
Resulting SQL: status ENUM('active','inactive','suspended','banned') NOT NULL DEFAULT 'active'
When to use: Fixed set of string options where a record can have exactly one value - status fields, categories, types, priorities.
Notes:
- Values must be comma-separated with no spaces around commas
- Can only store one of the defined values
- More storage-efficient than VARCHAR for fixed options (stored as integers internally)
- MySQL validates values automatically
- Maximum 65,535 distinct values allowed
@set
Syntax: @set value1,value2,value3
Example:
Resulting SQL: permissions SET('read','write','delete','admin') NULL
When to use: Multiple selection from a fixed set of options - permissions, features, tags, flags that can be combined.
Notes:
- Similar to ENUM but allows storing multiple values at once
- Values stored as comma-separated:
'read,write'or'read,write,admin' - More efficient than creating junction tables for simple multi-selects
- Maximum 64 distinct members allowed
- Use
FIND_IN_SET()function to query specific values
@json
Syntax: @json
Example:
Resulting SQL: settings JSON NULL
When to use: Flexible schema data, configuration objects, metadata, nested structures, or API responses.
Notes:
- Stores and validates JSON documents
- MySQL automatically validates JSON format on insert/update
- Can query nested fields with JSON functions:
JSON_EXTRACT(),->operator - More flexible than fixed columns for evolving data structures
- Requires MySQL 5.7.8 or later
@autonumber
Syntax: @autonumber
Example:
Resulting SQL: id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
When to use: Primary keys for most tables - automatically generates unique sequential IDs.
Notes:
- Automatically sets: INT(11), UNSIGNED, AUTO_INCREMENT, PRIMARY KEY
- You don't need to add @primary, @unsigned, or @int manually
- Database generates the value automatically on insert
- Most common way to create primary keys
- Use @uuid if you need globally unique non-sequential keys
@uuid
Syntax: @uuid
Example:
Resulting SQL: id CHAR(36) NOT NULL PRIMARY KEY
When to use: Primary keys when you need distributed systems compatibility, globally unique IDs, or want to avoid sequential numbering.
Notes:
- Automatically sets: CHAR(36), PRIMARY KEY
- Format:
550e8400-e29b-41d4-a716-446655440000(36 characters with dashes) - You must generate the UUID in your application code before inserting
- Use PHP's
uniqid()orRamsey\Uuidlibrary to generate values - Larger storage and slower indexing than @autonumber
Modifiers
Modifiers add metadata, control column positioning, or manage schema changes during migrations.
@comment
Syntax: @comment "your comment text"
Example:
Resulting SQL: email VARCHAR(255) NOT NULL UNIQUE COMMENT 'Used for login and notifications'
When to use: Add documentation directly to your database schema - explain business logic, data sources, validation rules, or special considerations.
Notes:
- Quotes around the comment text are optional but recommended
- Comment appears in database tools and SHOW CREATE TABLE output
- Helps other developers understand column purpose
- Visible in database administration tools
- Maximum length varies by MySQL version (typically 1024 characters)
@tablecomment
Syntax: @tablecomment "your table description" (in class docblock)
Example:
Resulting SQL: CREATE TABLE users (...) COMMENT='Stores user account data and authentication credentials'
When to use: Document the purpose of entire tables in your database schema.
Notes:
- Applied to class docblock, not property docblock
- Appears in SHOW CREATE TABLE and database documentation
- Helps document overall table purpose
- Visible in database administration tools
- Different from column comments - this is table-level
@after
Syntax: @after column_name
Example:
Resulting SQL: ALTER TABLE users ADD COLUMN middle_name VARCHAR(100) NULL AFTER first_name
When to use: Control column ordering when adding new columns to existing tables with php roline model:update.
Notes:
- Only works with ALTER TABLE operations (model:update command)
- Ignored during initial table creation (model:table-create)
- Places the new column immediately after the specified column
- Useful for keeping related columns together visually
- Cannot be used with @first
@first
Syntax: @first
Example:
Resulting SQL: ALTER TABLE users ADD COLUMN legacy_id INT NOT NULL FIRST
When to use: Position a new column as the first column in the table during ALTER TABLE operations.
Notes:
- Only works with ALTER TABLE operations (model:update command)
- Ignored during initial table creation
- Places column at the beginning of the table
- Cannot be used with @after
- Rarely needed - column order doesn't affect functionality
@drop
Syntax: @drop
Example:
Resulting SQL: ALTER TABLE users DROP COLUMN old_field
When to use: Remove columns from existing tables when running php roline model:update.
Notes:
- Only works with model:update command
- Permanently deletes the column and all its data
- Keep the property in model temporarily just to mark it for deletion
- After running update, you can remove the property entirely from the model
- Cannot be undone - backup data before dropping columns
@rename
Syntax: @rename old_column_name
Example:
Resulting SQL: ALTER TABLE users CHANGE COLUMN email_addr email VARCHAR(255) NOT NULL
When to use: Rename existing columns while preserving data when running php roline model:update.
Notes:
- Only works with model:update command
- Preserves existing data during rename
- The property name is the NEW name, @rename value is the OLD name
- Updates any dependent indexes and foreign keys automatically
- More efficient than drop + recreate
Constraints
Constraints enforce data integrity rules and define column behavior at the database level.
@primary
Syntax: @primary
Example:
Resulting SQL: user_code VARCHAR(50) NOT NULL PRIMARY KEY
When to use: Mark a column as the primary key when you need a non-numeric or custom primary key (use @autonumber for standard auto-incrementing IDs).
Notes:
- Only one primary key allowed per table
- Primary key columns are automatically indexed
- Cannot contain NULL values (automatically NOT NULL)
- Use @autonumber instead for standard auto-incrementing integer IDs
- Primary keys uniquely identify each record
@unique
Syntax: @unique
Example:
Resulting SQL: email VARCHAR(255) NOT NULL UNIQUE
When to use: Enforce uniqueness on columns like emails, usernames, slugs, or any value that must be unique across all records.
Notes:
- Prevents duplicate values in the column
- Automatically creates an index on the column
- NULL values are allowed (unless you omit @nullable)
- Multiple NULL values are permitted (NULL != NULL in SQL)
- Use for natural unique identifiers
@nullable
Syntax: @nullable
Example:
Resulting SQL: middle_name VARCHAR(100) NULL
When to use: Allow NULL values when a column is optional or the data might not always be available.
Notes:
- By default, all columns are NOT NULL without this annotation
- NULL is different from empty string ('')
- Useful for optional fields like middle names, phone numbers, descriptions
- Primary keys cannot be nullable
- Consider whether empty string or NULL better represents "no value"
@unsigned
Syntax: @unsigned
Example:
Resulting SQL: quantity INT(11) UNSIGNED NOT NULL DEFAULT 0
When to use: Numeric columns that should never be negative - quantities, counts, ages, prices, IDs.
Notes:
- Only works with numeric types: INT, BIGINT, TINYINT, SMALLINT, MEDIUMINT, DECIMAL, FLOAT, DOUBLE
- Doubles the positive range by removing negative values
- INT UNSIGNED range: 0 to 4,294,967,295 (vs -2.1B to +2.1B signed)
- Use for any naturally non-negative values
- Attempting to store negative values will cause an error
@default
Syntax: @default value
Example:
Resulting SQL: status ENUM('active','inactive','suspended') NOT NULL DEFAULT 'active'
When to use: Set a default value that's automatically used when no value is provided during insert.
Notes:
- String values don't need quotes in the annotation
- Use CURRENT_TIMESTAMP for automatic timestamps:
@default CURRENT_TIMESTAMP - NULL is a valid default: columns without @default and without @nullable get no default
- Cannot set defaults on TEXT/BLOB columns in MySQL
- Reduces the need to specify values for every column
@check
Syntax: @check expression
Example:
Resulting SQL: price DECIMAL(10,2) NOT NULL CHECK (price > 0)
When to use: Enforce custom validation rules at the database level - price ranges, date constraints, conditional logic.
Notes:
- Requires MySQL 8.0.16 or later
- Expression is evaluated on INSERT and UPDATE
- Can reference the column itself or use complex expressions
- Use for business rules that must ALWAYS be true
- Examples:
age >= 18,start_date < end_date,quantity BETWEEN 0 AND 1000
Indexes
Indexes improve query performance by creating fast lookup structures. Use for columns frequently used in WHERE, JOIN, or ORDER BY clauses.
@index
Syntax: @index or @index custom_name
Example:
Resulting SQL: last_name VARCHAR(100) NOT NULL, INDEX last_name_index (last_name)
When to use: Speed up queries that search, filter, or sort by this column.
Notes:
- Automatically creates an index named
{column}_index - Can optionally specify a custom index name:
@index idx_lastname - Improves SELECT performance but slows down INSERT/UPDATE slightly
- Use on foreign keys, frequently searched columns, or ORDER BY columns
- Primary keys and unique columns are automatically indexed
@fulltext
Syntax: @fulltext
Example:
Resulting SQL: content TEXT NOT NULL, FULLTEXT fulltext_content (content)
When to use: Enable natural language search on TEXT or VARCHAR columns - article content, descriptions, comments.
Notes:
- Only works with TEXT and VARCHAR columns
- Enables MATCH() AGAINST() full-text search queries
- Better than LIKE '%keyword%' for searching large text content
- Requires MyISAM or InnoDB storage engine (InnoDB default in MySQL 5.6+)
- Indexes entire words, ignores common stop words
@composite
Syntax: @composite (col1, col2, col3) or @composite idx_name (col1, col2, col3) (in class docblock)
Example:
Resulting SQL: INDEX idx_last_name_first_name (last_name, first_name), INDEX idx_city_state (city, state)
When to use: Index multiple columns together when queries frequently filter or sort by them in combination.
Notes:
- Applied to class docblock, not property docblock
- Column order matters - leftmost columns are most important
- Query benefits only if it uses the leftmost columns first
- Auto-generates name
idx_{col1}_{col2}if no custom name provided - More efficient than multiple single-column indexes for combined queries
@compositeUnique
Syntax: @compositeUnique (col1, col2) or @compositeUnique unq_name (col1, col2) (in class docblock)
Example:
Resulting SQL: UNIQUE INDEX unq_sku_warehouse_id (sku, warehouse_id)
When to use: Enforce uniqueness across multiple columns together - same SKU can exist in different warehouses, but not twice in the same warehouse.
Notes:
- Applied to class docblock, not property docblock
- Prevents duplicate combinations of the specified columns
- Auto-generates name
unq_{col1}_{col2}if no custom name provided - All columns in the combination must be unique together
- Different from multiple @unique annotations (which make each column individually unique)
@partition
Syntax: @partition hash(column) count or @partition key(column) count (in class docblock)
Example:
Resulting SQL: CREATE TABLE logs (...) PARTITION BY HASH(user_id) PARTITIONS 16
When to use: Improve performance on very large tables by dividing data into smaller physical partitions.
Notes:
- Applied to class docblock, not property docblock
- HASH partitioning distributes data evenly across N partitions
- KEY partitioning uses MySQL's internal hashing function
- Best for tables with millions of records
- Improves query performance when filtering by the partition column
Relationships
Relationships define how tables connect through foreign keys, maintaining referential integrity across your database.
@foreign
Syntax: @foreign table(column)
Example:
Resulting SQL: user_id INT UNSIGNED NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
When to use: Create relationships between tables - link posts to users, orders to customers, comments to articles.
Notes:
- Format is
table(column)- the table and column this foreign key references - Referenced column must be a primary key or unique key
- Column types must match exactly (INT to INT, VARCHAR(50) to VARCHAR(50))
- Enforces referential integrity - can't reference non-existent records
- Use with @ondelete and @onupdate to control cascading behavior
@ondelete
Syntax: @ondelete ACTION
Example:
Resulting SQL: customer_id INT UNSIGNED NOT NULL, FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE RESTRICT
When to use: Control what happens when a referenced record is deleted.
Notes:
- CASCADE: Automatically delete this record when the referenced record is deleted
- RESTRICT: Prevent deletion of referenced record if it has dependent records
- SET NULL: Set this column to NULL when referenced record is deleted (requires @nullable)
- NO ACTION: Same as RESTRICT (MySQL default)
- Most common: CASCADE for dependent data, RESTRICT for important references
@onupdate
Syntax: @onupdate ACTION
Example:
Resulting SQL: category_id INT UNSIGNED NOT NULL, FOREIGN KEY (category_id) REFERENCES categories(id) ON UPDATE CASCADE
When to use: Control what happens when a referenced record's primary key is updated.
Notes:
- CASCADE: Automatically update this column when the referenced key changes
- RESTRICT: Prevent updates to referenced key if it has dependent records
- SET NULL: Set this column to NULL when referenced key changes (requires @nullable)
- NO ACTION: Same as RESTRICT (MySQL default)
- CASCADE is most common - keeps relationships intact when keys change
Advanced Features
Full Model Example
Here's a production-ready model showing multiple annotations working together:
Best Practices Shown:
- Organized Sections - Group related columns with comment headers
- Comprehensive Comments - Explain the purpose and constraints of each column
- Proper Indexing - Composite indexes on frequently queried combinations
- Appropriate Types - ENUM for fixed options, SET for multi-select, JSON for flexible data
- Security - CHECK constraints for birth_date, password hashing note
- Soft Deletes - deleted_at pattern for recoverable deletions
- Audit Trail - Track login activity, verification, timestamps
- Unique Constraints - Email uniqueness considering soft deletes
Schema Management Strategies
When to use model:table-create vs model:table-update:
model:table-create- First time creating a table from scratchmodel:table-update- Modifying existing tables (add/remove/rename columns)
Safe migration workflow:
# 1. Check current schema state
php roline model:table-schema User
# 2. Update your model annotations
# 3. Apply changes
php roline model:table-update User
# 4. Verify the result
php roline model:table-schema User
Adding columns safely:
Then run model:table-update. Later, if needed, remove @nullable and add @default.
Renaming columns without data loss:
Run model:table-update to preserve data during rename.
Performance Optimization
Index Strategy:
- Always index: Foreign keys, frequently filtered columns, ORDER BY columns
- Consider composite indexes: When filtering by multiple columns together
- Avoid over-indexing: Each index slows INSERT/UPDATE operations
- Use FULLTEXT: For searching large text content, not LIKE '%term%'
Column Type Selection:
- Use smallest type that fits your data (TINYINT vs INT vs BIGINT)
- CHAR for fixed-length data (country codes, state abbreviations)
- VARCHAR for variable-length strings up to 255 characters
- TEXT only for content over 255 characters
- ENUM for fixed options (more efficient than VARCHAR + CHECK)
Partitioning Large Tables:
For tables with millions of records:
Common Patterns
Timestamps Pattern:
Soft Deletes Pattern:
Status Tracking Pattern:
Audit Fields Pattern:
Troubleshooting
Common Errors
"Column not found" Error
Problem: Database schema doesn't match model annotations.
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'email' in 'field list'
Solutions:
# Check what's in the database
php roline model:table-schema User
# Compare with your model annotations
# Then update the database to match
php roline model:table-update User
Cause: You added @column annotation but haven't run model:table-update yet.
Foreign Key Constraint Fails
Problem: Can't create foreign key relationship.
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint
Solutions:
-
Check column types match exactly:
-
Ensure referenced column exists:
- Run
php roline model:table-create UserBEFORE creating Posts table - Foreign keys can only reference existing columns
- Run
- Verify referenced column is indexed:
- Foreign keys must reference PRIMARY KEY or UNIQUE columns
Schema Mismatch After Update
Problem: Table doesn't reflect your annotation changes.
Solutions:
# Drop and recreate table (DESTROYS DATA - dev only!)
php roline model:table-drop User
php roline model:table-create User
# Or update safely (preserves data)
php roline model:table-update User
If column rename not working:
Type Mismatch Errors
Problem: Data doesn't fit in column type.
SQLSTATE[22001]: String data, right truncated
Solutions:
-
Increase column length:
- Use correct type for data:
Annotation Syntax Errors
Problem: Roline doesn't recognize your annotation.
Common mistakes:
Migration Already Exists
Problem: Can't create migration with same name.
Error: Migration file already exists
Solutions:
# Use a different, more specific name
php roline migration:make add_email_to_users
# Or delete the old migration file if it's a mistake
rm application/database/migrations/2024_01_08_create_users_table.php
Permission Denied Errors
Problem: Can't write to file system or database.
Error: Permission denied: application/models/UserModel.php
Solutions:
# Fix file permissions (Unix/Linux/Mac)
chmod -R 755 application/
# Fix directory ownership
sudo chown -R $USER:$USER application/
# Database permission error - check config/database.php
# Ensure MySQL user has CREATE, ALTER, DROP privileges
CHECK Constraint Not Working
Problem: CHECK constraint syntax error or not enforced.
SQLSTATE[HY000]: General error: 3820 Check constraint 'users_chk_1' is violated
Solutions:
- Requires MySQL 8.0.16+:
mysql --version # Verify you have MySQL 8.0.16 or later
- Fix constraint syntax:
NULL Value in NOT NULL Column
Problem: Inserting NULL into non-nullable column.
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'email' cannot be null
Solutions:
Debugging Tips
Check what Roline sees:
# View parsed model schema
php roline model:table-schema User
# List all tables in database
php roline db:tables
# View complete database schema
php roline db:schema
# Export table as SQL to see exact structure
php roline table:export users
Verify database connection:
# List all databases (tests connection)
php roline db:list
# If connection fails, check config/database.php
Test with fresh table:
# Create test database
php roline db:create test_db
# Update config/database.php to use test_db
# Try creating table fresh
php roline model:table-create User
Common annotation validation:
- Every column MUST have
@columnannotation - Type annotation required:
@varchar,@int,@text, etc. @unsignedonly works with numeric types@foreignrequires matching column types@enumand@setneed comma-separated values (no spaces)@default CURRENT_TIMESTAMPonly works with TIMESTAMP/DATETIME