Phinx Documentation

repository·0.x·Indexed 26 days ago

https://github.com/cakephp/phinx

Phinx is a lightweight PHP database migration tool for managing database schemas using database-agnostic PHP code. It supports MySQL, PostgreSQL, SQLite, and Microsoft SQL Server. The tool provides CLI commands for initializing configurations, creating and running migrations, rolling back changes with breakpoints, and managing database seeds. It can be installed via Composer or as a Phar archive and can be integrated into Symfony Console applications or PHPUnit tests.

Tokens
19.1K
Snippets
56
Records
97
Agent score
86%

What's inside Phinx

  1. Introduction to Phinx

    0.x
    Phinx is a database migration tool for PHP that allows you to alter and manipulate database schemas using a PHP-based API instead of writing manual SQL. This approach makes migrations portable across different database systems and allows you to version your database schema using a Source Control Management (SCM) system. Phinx tracks which migrations have already been executed to manage the state of your database automatically.
  2. Introduction to Phinx

    0.x

    Phinx is a tool designed to make managing database migrations for PHP applications easy. It focuses strictly on migrations without the overhead of a full database ORM or application framework.

    Requirement: Phinx requires a 64-bit version of PHP to function.

  3. Rename a table

    0.x

    To rename an existing table, use the rename() method on the Table object and then call update() to commit the change.

    <?php
    
    use Phinx\Migration\AbstractMigration;
    
    class MyNewMigration extends AbstractMigration
    {
        /**
         * Migrate Up.
         */
        public function up()
        {
            $table = $this->table('users');
            $table
                ->rename('legacy_users')
                ->update();
        }
    
        /**
         * Migrate Down.
         */
        public function down()
        {
            $table = $this->table('legacy_users');
            $table
                ->rename('users')
                ->update();
        }
    }
  4. Create a new migration skeleton

    0.x

    To generate a new migration file, use the create command. Phinx will create a file named with a timestamp prefix (e.g., YYYYMMDDHHMMSS_my_new_migration.php). If multiple migration paths are configured, you will be prompted to select one.

    vendor/bin/phinx create MyNewMigration
  5. Drop a table

    0.x

    To remove a table, call drop() on the Table object. You must call save() to execute the operation. It is recommended to recreate the table in the down() method to allow for rollbacks.

    <?php
    
    use Phinx\Migration\AbstractMigration;
    
    class MyNewMigration extends AbstractMigration
    {
        public function up()
        {
            $this->table('users')->drop()->save();
        }
    
        public function down()
        {
            $users = $this->table('users');
            $users->addColumn('username', 'string', ['limit' => 20])
                  ->addColumn('password', 'string', ['limit' => 40])
                  ->addColumn('password_salt', 'string', ['limit' => 40])
                  ->addColumn('email', 'string', ['limit' => 100])
                  ->addColumn('first__name', 'string', ['limit' => 30])
                  ->addColumn('last_name', 'string', ['limit' => 30])
                  ->addColumn('created', 'datetime')
                  ->addColumn('updated', 'datetime', ['null' => true])
                  ->addIndex(['username', 'email'], ['unique' => true])
                  ->save();
        }
    }
  6. Retrieve results from a Query

    0.x

    After executing a query, you can retrieve the data in two primary ways:

    1. Iterate directly: The builder object can be used in a foreach loop.
    2. Fetch all: Call execute() to get a statement object, then use fetchAll('assoc') to get an associative array.
    <?php
    // Option 1: Iterate
    foreach ($builder as $row) {
        echo $row['title'];
    }
    
    // Option 2: Fetch all results
    $results = $builder->execute()->fetchAll('assoc');
  7. Build SELECT queries with the Query Builder

    0.x

    Use the Select Query Builder to fetch data. You can specify fields, use aliases, and apply complex WHERE conditions using arrays or closures.

    Selecting Fields

    • Pass an array of column names: select(['id', 'title'])
    • Use associative arrays for aliasing: select(['alias' => 'column_name'])
    • Use a closure for dynamic selection.

    Where Conditions

    • Simple arrays: where(['id' => 1]) or where(['id >' => 1]). You can include operators like >, <, etc., in the key string.
    • Logical operators: Use andWhere() for chaining or pass an 'OR' key in the array: where(['OR' => ['id >' => 1, 'title' => 'My title']]).
    • Closures and Expressions: For complex logic, pass a closure that receives an expression object ($exp).
    <?php
    // Selecting with aliases
    $builder->select(['pk' => 'id', 'aliased_title' => 'title', 'body']);
    
    // Simple WHERE
    $builder->where(['id >' => 1])->andWhere(['title' => 'My Title']);
    
    // Complex WHERE with expression object
    $builder->select('*')
        ->from('articles')
        ->where(function ($exp) {
            return $exp
                ->eq('author_id', 2)
                ->gt('view_count', 10);
        });
  8. Configure Phinx using PHP, YAML, JSON, or YAML

    0.x

    Phinx supports multiple configuration formats: yaml, yml, json, and php. When running Phinx commands, you can specify a custom file using the --configuration flag. If not specified, Phinx searches for phinx.php, phinx.json, phinx.yml, or phinx.yaml in the current directory.

    Using a PHP configuration file: When using a .php file, the file is included rather than parsed. It must return an array of configuration items. This allows you to pass an existing PDO instance via the connection key, which is useful for sharing connections with your application. Note that you must still explicitly provide the name (database name) as Phinx cannot infer it from the PDO instance.

    $app = require 'app/phinx.php';
    $pdo = $app->getDatabase()->getPdo();
    
    return [
        'environments' => [
            'default_environment' => 'development',
            'development' => [
                'name' => 'devdb',
                'connection' => $pdo
            ]
        ]
    ];
  9. Use Phinx within PHPUnit tests

    0.x

    You can programmatically use Phinx to prepare or seed your database during unit tests.

    To run migrations via the PhinxApplication class, instantiate it, set setAutoExit(false) to prevent the application from terminating the process, and use the run() method with a StringInput command (e.g., 'migrate').

    If you are using an in-memory database (like SQLite :memory:), you must provide a specific PDO instance to Phinx via the configuration to ensure the test runner and Phinx share the same connection.

    public function setUp()
    {
        $app = new PhinxApplication();
        $app->setAutoExit(false);
        $app->run(new StringInput('migrate'), new NullOutput());
    }
  10. Create a new table

    0.x

    To create a table, use the table() method to initialize the object, chain addColumn() and addIndex() calls to define the schema, and finally call create() to commit the changes.

    Phinx automatically creates an auto-incrementing primary key column named id.

    Customizing Primary Keys

    • Disable automatic ID: Pass ['id' => false] in the options array to the table() method. If you disable id, you must specify a primary_key (or array of columns) to avoid having no primary key.
    • Change ID name: Pass ['id' => 'your_custom_name'] to the table() method.
    • Composite Primary Key: Pass an array of column names to the primary_key option: ['primary_key' => ['col1', 'col2']].
    <?php
    
    use Phinx\Migration\AbstractMigration;
    
    class MyNewMigration extends AbstractMigration
    {
        public function change()
        {
            $users = $this->table('users');
            $users->addColumn('username', 'string', ['limit' => 20])
                  ->addColumn('password', 'string', ['limit' => 40])
                  ->addColumn('password_salt', 'string', ['limit' => 40])
                  ->addColumn('email', 'string', ['limit' => 100])
                  ->addColumn('first_name', 'string', ['limit' => 30])
                  ->addColumn('last_name', 'string', ['limit' => 30])
                  ->addColumn('created', 'datetime')
                  ->addColumn('updated', 'datetime', ['null' => true])
                  ->addIndex(['username', 'email'], ['unique' => true])
                  ->create();
        }
    }
  11. Use the change() method for reversible migrations

    0.x

    The change() method is the default for writing reversible migrations. When using the Table API within change(), Phinx automatically determines how to undo actions like creating/renaming tables, adding columns/indexes, or adding foreign keys.

    Important:

    • When working with the Table class inside change(), you must use create() or update() instead of save() to ensure Phinx can track the operation for reversal.
    • If an action cannot be automatically reversed, Phinx will throw an IrreversibleMigrationException during a rollback. To handle non-reversible logic (like inserting data) within change(), wrap it in a conditional check using $this->isMigratingUp().
    <?php
    
    use Phinx\
    Migration\\AbstractMigration;
    
    class CreateUserLoginsTable extends AbstractMigration
    {
        public function change()
        {
            // create the table
            $table = $this->table('user_logins');
            $table->addColumn('user_id', 'integer')
                  ->addColumn('created', 'datetime')
                  ->create();
    
            if ($this->isMigratingUp()) {
                $table->insert([['user_id' => 1, 'created' => '2020-01-19 03:14:07']])
                      ->save();
            }
        }
    }