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

Feature/add factory method #14

Merged
merged 3 commits into from
May 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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