Generate CakePHP Migration class from existing class definition
Tags: php
Published: 2017-11-15 05:32:53

---
title: Generate CakePHP Migration class from existing class definition
published: true
description: 
tags: PHP
---

Generate CakePHP Migration class from existing class definition
We created a generator that generates CakePHP 3 migration from existing class definition.

I think that I can use it when making a class with many properties and then making a draft for a migration class.

## Generator class

```php

<?php

class MigratinoClassGenerator
{
  public function generate(string $className)
  {
    $ref = new ReflectionClass($className);
    $properties = $ref->getProperties();
    
    $migrationClass = new MigrationClass();
    
    foreach ($properties as $property) {
      $migrationClass->addColumn($property->getName());
    }
    
    return $migrationClass->generate($ref->getName());
  }
}

class MigrationClass
{
  private $columns = [];
  
  public function addColumn(string $name, $type = 'string')
  {
    $this->columns[] = [
      'name' => $name,
      'type' => $type,
    ];
  }
  
  public function generate(string $className)
  {
    $buf = [];
    
    $buf[] = '<?php';
    $buf[] = '';
    $buf[] = 'use Migrations\AbstractMigration;';
    $buf[] = '';
    $buf[] = 'class CreateProduct extends AbstractMigration';
    $buf[] = '{';
    $buf[] = '    public function up()';
    $buf[] = '    {';

    $tableName = strtolower($className);
    $buf[] = sprintf('        $this->table(\'%s\')', $tableName);
    
    foreach ($this->columns as $column) {
      $buf[] = $this->generateColumn($column);
    }
    
    $buf[] = '            ->create();';
    $buf[] = '    }';
    $buf[] = '';
    $buf[] = '    public function down()';
    $buf[] = '    {';
    $buf[] = '        $this->dropTable(\''. $tableName . '\');';
    $buf[] = '    }';
    $buf[] = '}';

    return join("\n", $buf);
  }
  
  private function generateColumn(array $column)
  {
    $template = <<<TPL
            ->addColumn('%s', 'string', [
                'default' => null,
                'limit'   => null,
                'null'    => false,
            ])
TPL;

    return sprintf($template, $this->camelCase($column['name']));
  }
  
  private function camelCase(string $input) {
    preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!',
                   $input,
                   $matches);
                  
    $ret = $matches[0];
    foreach ($ret as &$match) {
      $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
    }
    
    return implode('_', $ret);
  }
}
```

## Execution method

```php
<?php

$g = new MigratinoClassGenerator();
echo $g->generate('Product'); // クラス名を指定する
```


## Output result

```php
<?php

use Migrations\AbstractMigration;

class CreateProduct extends AbstractMigration
{
    public function up()
    {
        $this->table('product')
            ->addColumn('id', 'string', [
                'default' => null,
                'limit'   => null,
                'null'    => false,
            ])
            ->addColumn('code', 'string', [
                'default' => null,
                'limit'   => null,
                'null'    => false,
            ])
            ->create();
    }

    public function down()
    {
        $this->dropTable('product');
    }
}
```