Skip to content
This repository has been archived by the owner on Oct 15, 2020. It is now read-only.

Commit

Permalink
Merge pull request #14 from atk4/feature/add-factory-method
Browse files Browse the repository at this point in the history
Feature/add factory method
  • Loading branch information
romaninsh authored May 14, 2019
2 parents a7fa1e5 + 994285f commit 7076539
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 65 deletions.
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,29 @@ The user will see a console which would adjust database to contain required tabl
Of course it's also possible to perform migration without visual feedback:

``` php
$changes = (new \atk4\schema\Migration\MySQL(new User($app->db)))->migrate();
$changes = (\atk4\schema\Migration::getMigration(new User($app->db)))->migrate();
```

If you need a more fine-graned migration, you can define them in great detail.

``` php
// create table
$migration = new \atk4\schema\Migration\MySQL($app->db);
$migration = \atk4\schema\Migration::getMigration($app->db);
$migration->table('user')
->id()
->field('name')
->field('address', ['type'=>'text']);
->create();

// or alter
$migration = new \atk4\schema\Migration\MySQL($app->db);
$migration = \atk4\schema\Migration::getMigration($app->db);
$migration->table('user')
->newField('age', ['type'=>'integer'])
->alter();
```

You can also use `\atk4\schema\Migration\Sqlite`. Other SQL databases are not yet supported. Field declaration uses same types as [ATK Data](https://github.com/atk4/data).
Currently we fully support MySQL and SQLite connections, partly PgSQL and Oracle connections. Other SQL databases are not yet supported.
Field declaration uses same types as [ATK Data](https://github.com/atk4/data).

## Examples

Expand All @@ -63,7 +64,7 @@ queries using DSQL.

``` php
<?php
$m = new \atk4\data\schema\Migration($connection);
$m = \atk4\data\schema\Migration::getMigration($connection);
$m->table('user')->drop();
$m->field('id');
$m->field('name', ['type'=>'string']);
Expand All @@ -72,7 +73,7 @@ $m->field('bio');
$m->create();
```

`schema\Snapshot` is a simple class that can record and restore
`schema\Snapshot` (NOT IMPLEMENTED) is a simple class that can record and restore
table contents:

``` php
Expand Down Expand Up @@ -112,7 +113,7 @@ against any other state.

- Automatically add 'id' field by default
- Create tables for you
- Detect types (int, string, etc)
- Detect types (int, string, date, boolean etc)
- Hides ID values if you don't pass them

## Installation
Expand Down
2 changes: 1 addition & 1 deletion demos/modelmigrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function init()

try {
// apply migrator
(new \atk4\schema\Migration\MySQL($m))->migrate();
(\atk4\schema\Migration::getMigration($m))->migrate();

// ok, now we surely have DB!

Expand Down
117 changes: 86 additions & 31 deletions src/Migration.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
namespace atk4\schema;

use atk4\core\Exception;
use atk4\Data\Model;
use atk4\data\Persistence;
use atk4\dsql\Connection;
use atk4\dsql\Expression;

class Migration extends Expression
Expand All @@ -18,7 +21,7 @@ class Migration extends Expression
'rename' => 'rename table {old_table} to {table}',
];

/** @var \atk4\dsql\Connection Database connection */
/** @var Connection Database connection */
public $connection;

/**
Expand Down Expand Up @@ -65,47 +68,99 @@ class Migration extends Expression
public $mapToAgile = [];

/**
* Create new migration.
* Factory method to get correct Migration subclass object depending on connection given.
*
* @param Connection|Persistence|Model $source
* @param array $params
*
* @param \atk4\dsql\Connection|\atk4\data\Persistence|\atk4\data\Model $source
* @param array $params
* @return Migration Subclass
*/
public function __construct($source, $params = [])
public static function getMigration($source, $params = [])
{
parent::__construct($params);

if ($source instanceof \atk4\dsql\Connection) {
$this->connection = $source;

return;
} elseif ($source instanceof \atk4\data\Persistence\SQL) {
$this->connection = $source->connection;

return;
} elseif ($source instanceof \atk4\data\Model) {
if ($source->persistence && ($source->persistence instanceof \atk4\data\Persistence\SQL)) {
$this->connection = $source->persistence->connection;

$this->setModel($source);
$c = static::getConnection($source);

switch ($c->driver) {
case 'sqlite':
return new Migration\SQLite($source, $params);
case 'mysql':
return new Migration\MySQL($source, $params);
case 'pgsql':
return new Migration\PgSQL($source, $params);
case 'oci':
return new Migration\Oracle($source, $params);
default:
throw new Exception([
'Not sure which migration class to use for your DSN',
'driver' => $c->driver,
'source' => $source,
]);
}
}

return;
}
/**
* Static method to extract DB driver from Connection, Persistence or Model.
*
* @param Connection|Persistence|Model $source
*/
public static function getConnection($source)
{
if ($source instanceof Connection) {
return $source;
} elseif ($source instanceof Persistence\SQL) {
return $source->connection;
} elseif (
$source instanceof Model
&& $source->persistence
&& ($source->persistence instanceof Persistence\SQL)
) {
return $source->persistence->connection;
}

throw new \atk4\core\Exception([
throw new Exception([
'Source is specified incorrectly. Must be Connection, Persistence or initialized Model',
'source' => $source,
]);
}

/**
* Create new migration.
*
* @param Connection|Persistence|Model $source
* @param array $params
*/
public function __construct($source, $params = [])
{
parent::__construct($params);

$this->setSource($source);
}

/**
* Sets source of migration.
*
* @param Connection|Persistence|Model $source
*/
public function setSource($source)
{
$this->connection = static::getConnection($source);

if (
$source instanceof Model
&& $source->persistence
&& ($source->persistence instanceof Persistence\SQL)
) {
$this->setModel($source);
}
}

/**
* Sets model.
*
* @param \atk4\data\Model $m
* @param Model $m
*
* @return \atk4\data\Model
* @return Model
*/
public function setModel(\atk4\data\Model $m)
public function setModel(Model $m)
{
$this->table($m->table);

Expand Down Expand Up @@ -308,14 +363,14 @@ public function _render_statements()
* Create rough model from current set of $this->args['fields']. This is not
* ideal solution but is designed as a drop-in solution.
*
* @param \atk4\data\Persistence $persistence
* @param string $table
* @param Persistence $persistence
* @param string $table
*
* @return \atk4\data\Model
* @return Model
*/
public function createModel($persistence, $table = null)
{
$m = new \atk4\data\Model([$persistence, 'table'=>$table ?: $this['table'] = $table]);
$m = new Model([$persistence, 'table'=>$table ?: $this['table'] = $table]);

foreach ($this->_getFields() as $field => $options) {
if ($field == 'id') {
Expand Down Expand Up @@ -385,7 +440,7 @@ public function dropField($field)
* Return database table descriptions.
* DB engine specific.
*
* @todo Convert to abstract function
* @todo Maybe convert to abstract function
*
* @param string $table
*
Expand Down
32 changes: 6 additions & 26 deletions src/PHPUnit_SchemaTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace atk4\schema;

use atk4\data\Model;
use atk4\data\Persistence;
use atk4\dsql\Connection;

// NOTE: This class should stay here in this namespace because other repos rely on it. For example, atk4\data tests
class PHPUnit_SchemaTestCase extends \atk4\core\PHPUnit_AgileTestCase
Expand Down Expand Up @@ -35,14 +37,7 @@ public function setUp()
$pass = isset($GLOBALS['DB_PASSWD']) ? $GLOBALS['DB_PASSWD'] : null;

$this->db = Persistence::connect($this->dsn, $user, $pass);

// extract dirver
if ($this->debug) {
list($dumper_driver, $this->driver, $junk) = explode(':', $this->dsn, 3);
} else {
list($this->driver, $junk) = explode(':', $this->dsn, 2);
}
$this->driver = strtolower($this->driver);
$this->driver = $this->db->connection->driver;
}

public function tearDown()
Expand All @@ -55,28 +50,13 @@ public function tearDown()
/**
* Create and return appropriate Migration object.
*
* @param \atk4\dsql\Connection|\atk4\data\Persistence|\atk4\data\Model $m
* @param Connection|Persistence|Model $m
*
* @return Migration
*/
public function getMigration($m = null)
{
switch ($this->driver) {
case 'sqlite':
return new \atk4\schema\Migration\SQLite($m ?: $this->db);
case 'mysql':
return new \atk4\schema\Migration\MySQL($m ?: $this->db);
case 'pgsql':
return new \atk4\schema\Migration\PgSQL($m ?: $this->db);
case 'oci':
return new \atk4\schema\Migration\Oracle($m ?: $this->db);
default:
throw new \atk4\core\Exception([
'Not sure which migration class to use for your DSN',
'driver' => $this->driver,
'dsn' => $this->dsn,
]);
}
return \atk4\schema\Migration::getMigration($m ?: $this->db);
}

/**
Expand All @@ -87,7 +67,7 @@ public function getMigration($m = null)
*/
public function dropTable($table)
{
$this->db->connection->expr('drop table if exists {}', [$table])->execute();
$this->getMigration()->table($table)->drop();
}

/**
Expand Down

0 comments on commit 7076539

Please sign in to comment.