Skip to content
Snippets Groups Projects
Unverified Commit 768ce6fb authored by Thomas Flori's avatar Thomas Flori
Browse files

implement callback progress

parent 715349a6
No related branches found
No related tags found
No related merge requests found
......@@ -45,16 +45,17 @@ class CreateAnimalsTable extends AbstractMigration
{
public function up(): void
{
$this->exec('CREATE TABLE "users" (
"id" bigserial,
"name" character varying (255) NOT NULL,
PRIMARY KEY ("id")
$this->exec('DROP TABLE IF EXISTS animals');
$this->exec('CREATE TABLE animals (
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (id)
)');
}
public function down(): void
{
$this->exec('DROP TABLE "users"');
$this->exec('DROP TABLE IF EXISTS animals');
}
}
```
......@@ -66,7 +67,7 @@ Control structure:
namespace App\Cli\Commands;
class MigrateCommand extends AbstractCommand
class MigrateCommand extends AbstractCommand // implements \Breyta\ProgressInterface
{
/**
* Your database connection
......@@ -76,19 +77,31 @@ class MigrateCommand extends AbstractCommand
public function handle()
{
$breyta = new Breyta\Migrations($this->db, '/path/to/migrations');
$breyta = new \Breyta\Migrations($this->db, '/path/to/migrations', function($class, ...$args) {
// return app()->make($class, $args);
// the closure is optional. default:
if ($class === \Breyta\AdapterInterface::class) {
return new \Breyta\BasicAdapter(...$args); // first arg = closure $executor
}
return new $class(...$args); // first arg = AdapterInterface $adapter
});
// register handler (optional)
$breyta->onStart([$this, 'start']);
$breyta->onBeginMigration([$this, 'beginMigration']);
$breyta->onBeforeExecution([$this, 'beforeExecution']);
$breyta->onAfterExecution([$this, 'afterExecution']);
$breyta->onFinishMigration([$this, 'finishMigration']);
$breyta->onFinish([$this, 'finish']);
/** @var \Breyta\CallbackProgress $callbackProgress */
$callbackProgress = $breyta->getProgress();
$callbackProgress->onStart([$this, 'start'])
->onBeforeMigration([$this, 'beginMigration'])
->onBeforeExecution([$this, 'beforeExecution'])
->onAfterExecution([$this, 'afterExecution'])
->onAfterMigration([$this, 'finishMigration'])
->onFinish([$this, 'finish']);
// alternative: implement Breyta\ProgressInterface and register
$breyta->useProgress($this);
// alternative: implement \Breyta\ProgressInterface and register
// $breyta->setProgress($this);
$breyta->migrate();
}
}
```
Please also have a look at the [reference](reference.md) for a better overview of the api.
<?xml version="1.0" encoding="UTF-8" ?>
<phpdocumentor>
<parser>
<target>/tmp/phpdoc/breyta</target>
</parser>
<transformer>
<target>.</target>
</transformer>
<transformations>
<template name="resources/reference"/>
</transformations>
<files>
<directory>src</directory>
</files>
</phpdocumentor>
## API Reference
### Breyta
* [AbstractMigration](#breytaabstractmigration)
* [AdapterInterface](#breytaadapterinterface)
* [BasicAdapter](#breytabasicadapter)
* [CallbackProgress](#breytacallbackprogress)
* [ProgressInterface](#breytaprogressinterface)
### Breyta\Migration
* [CreateMigrationTable](#breytamigrationcreatemigrationtable)
### Breyta\Model
* [Migration](#breytamodelmigration)
* [Statement](#breytamodelstatement)
---
### Breyta\AdapterInterface
#### Interface AdapterInterface
You may want to define an adapter with additional helpers like creating tables etc. The only adapter provided in this
library is a BasicAdapter that just executes sql statements.
#### Methods
* [__construct](#breytaadapterinterface__construct) Adapter gets a callable $executor
* [exec](#breytaadapterinterfaceexec) Execute an sql statement
#### Breyta\AdapterInterface::__construct
```php
public function __construct( callable $executor ): AdapterInterface
```
##### Adapter gets a callable $executor
The executor requires a Breyta\Model\Statement argument and is the only way an adapter can interact with
the database.
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$executor` | **callable** | |
#### Breyta\AdapterInterface::exec
```php
public function exec( string $sql ): mixed
```
##### Execute an sql statement
Returns false on error and an integer of affected rows on success.
**Visibility:** this method is **public**.
<br />
**Returns**: this method returns **mixed**
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$sql` | **string** | |
**See Also:**
* http://php.net/manual/en/pdo.exec.php - for a details about the return statement
---
### Breyta\Model\Migration
#### Properties
| Visibility | Name | Type | Description |
|------------|------|------|---------------------------------------|
| **public** | `$file` | **string** | |
| **public** | `$executed` | ** \ DateTime** | |
| **public** | `$reverted` | ** \ DateTime** | |
| **public** | `$status` | **string** | |
| **public** | `$statements` | **string &#124; array &#124; array&lt;Statement>** | |
| **public** | `$executionTime` | **double** | |
#### Methods
* [__construct](#breytamodelmigration__construct)
* [createInstance](#breytamodelmigrationcreateinstance)
#### Breyta\Model\Migration::__construct
```php
public function __construct(): Migration
```
**Visibility:** this method is **public**.
<br />
#### Breyta\Model\Migration::createInstance
```php
public static function createInstance( array $data = array() )
```
**Static:** this method is **static**.
<br />**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$data` | **array** | |
---
### Breyta\ProgressInterface
#### Methods
* [afterExecution](#breytaprogressinterfaceafterexecution) Output information about the $statement (after it gets executed)
* [afterMigration](#breytaprogressinterfaceaftermigration) Output information about the $migration (after the migration)
* [beforeExecution](#breytaprogressinterfacebeforeexecution) Output information about the $statement (before it gets executed)
* [beforeMigration](#breytaprogressinterfacebeforemigration) Output information about the $migration (before the migration)
* [finish](#breytaprogressinterfacefinish) Output information about what just happened
* [start](#breytaprogressinterfacestart) Output information about starting the migration process
#### Breyta\ProgressInterface::afterExecution
```php
public function afterExecution( \Breyta\Model\Statement $execution )
```
##### Output information about the $statement (after it gets executed)
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$execution` | **Model\Statement** | |
#### Breyta\ProgressInterface::afterMigration
```php
public function afterMigration( \Breyta\Model\Migration $migration )
```
##### Output information about the $migration (after the migration)
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$migration` | **Model\Migration** | |
#### Breyta\ProgressInterface::beforeExecution
```php
public function beforeExecution( \Breyta\Model\Statement $execution )
```
##### Output information about the $statement (before it gets executed)
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$execution` | **Model\Statement** | |
#### Breyta\ProgressInterface::beforeMigration
```php
public function beforeMigration( \Breyta\Model\Migration $migration )
```
##### Output information about the $migration (before the migration)
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$migration` | **Model\Migration** | |
#### Breyta\ProgressInterface::finish
```php
public function finish( \stdClass $info )
```
##### Output information about what just happened
Info contains:
- `migrations` - an array of Breyta\Model\Migration
- `task` - the task that is going to be executed (migrate or revert)
- `count` - an integer how many migrations are going to be executed
- `executed` - an array of migrations that just got executed
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$info` | **\stdClass** | |
#### Breyta\ProgressInterface::start
```php
public function start( \stdClass $info )
```
##### Output information about starting the migration process
Info contains:
- `migrations` - an array of Breyta\Model\Migration
- `task` - the task that is going to be executed (migrate or revert)
- `count` - an integer how many migrations are going to be executed
- `toExecute` - an array of migrations that are going to be executed
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$info` | **\stdClass** | |
---
### Breyta\Model\Statement
#### Properties
| Visibility | Name | Type | Description |
|------------|------|------|---------------------------------------|
| **public** | `$raw` | **string** | |
| **public** | `$teaser` | **string** | |
| **public** | `$action` | **string** | |
| **public** | `$type` | **string** | |
| **public** | `$name` | **string** | |
| **public** | `$result` | **mixed** | |
| **public** | `$executionTime` | **double** | |
| **public** | `$exception` | ** \ PDOException** | |
#### Methods
* [__toString](#breytamodelstatement__tostring)
* [createInstance](#breytamodelstatementcreateinstance)
#### Breyta\Model\Statement::__toString
```php
public function __toString()
```
**Visibility:** this method is **public**.
<br />
#### Breyta\Model\Statement::createInstance
```php
public static function createInstance( array $data = array() )
```
**Static:** this method is **static**.
<br />**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$data` | **array** | |
---
### Breyta\AbstractMigration
#### Properties
| Visibility | Name | Type | Description |
|------------|------|------|---------------------------------------|
| **private** | `$adapter` | | |
#### Methods
* [__call](#breytaabstractmigration__call)
* [__construct](#breytaabstractmigration__construct)
* [down](#breytaabstractmigrationdown) Bring the migration down
* [up](#breytaabstractmigrationup) Bring the migration up
#### Breyta\AbstractMigration::__call
```php
public function __call( $method, $args )
```
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$method` | | |
| `$args` | | |
#### Breyta\AbstractMigration::__construct
```php
public function __construct(
\Breyta\AdapterInterface $adapter
): AbstractMigration
```
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$adapter` | **AdapterInterface** | |
#### Breyta\AbstractMigration::down
```php
abstract public function down()
```
##### Bring the migration down
**Visibility:** this method is **public**.
<br />
#### Breyta\AbstractMigration::up
```php
abstract public function up()
```
##### Bring the migration up
**Visibility:** this method is **public**.
<br />
---
### Breyta\CallbackProgress
**Implements:** [Breyta\ProgressInterface](#breytaprogressinterface)
Stores callbacks for migration progress.
#### Properties
| Visibility | Name | Type | Description |
|------------|------|------|---------------------------------------|
| **protected** | `$startCallback` | **callable** | |
| **protected** | `$beforeMigrationCallback` | **callable** | |
| **protected** | `$beforeExecutionCallback` | **callable** | |
| **protected** | `$afterExecutionCallback` | **callable** | |
| **protected** | `$afterMigrationCallback` | **callable** | |
| **protected** | `$finishCallback` | **callable** | |
#### Methods
* [afterExecution](#breytacallbackprogressafterexecution) Output information about the $statement (after it gets executed)
* [afterMigration](#breytacallbackprogressaftermigration) Output information about the $migration (after the migration)
* [beforeExecution](#breytacallbackprogressbeforeexecution) Output information about the $statement (before it gets executed)
* [beforeMigration](#breytacallbackprogressbeforemigration) Output information about the $migration (before the migration)
* [finish](#breytacallbackprogressfinish) Output information about what just happened
* [onAfterExecution](#breytacallbackprogressonafterexecution)
* [onAfterMigration](#breytacallbackprogressonaftermigration)
* [onBeforeExecution](#breytacallbackprogressonbeforeexecution)
* [onBeforeMigration](#breytacallbackprogressonbeforemigration)
* [onFinish](#breytacallbackprogressonfinish)
* [onStart](#breytacallbackprogressonstart)
* [start](#breytacallbackprogressstart) Output information about starting the migration process
#### Breyta\CallbackProgress::afterExecution
```php
public function afterExecution( \Breyta\Model\Statement $execution )
```
##### Output information about the $statement (after it gets executed)
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$execution` | **Model\Statement** | |
#### Breyta\CallbackProgress::afterMigration
```php
public function afterMigration( \Breyta\Model\Migration $migration )
```
##### Output information about the $migration (after the migration)
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$migration` | **Model\Migration** | |
#### Breyta\CallbackProgress::beforeExecution
```php
public function beforeExecution( \Breyta\Model\Statement $execution )
```
##### Output information about the $statement (before it gets executed)
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$execution` | **Model\Statement** | |
#### Breyta\CallbackProgress::beforeMigration
```php
public function beforeMigration( \Breyta\Model\Migration $migration )
```
##### Output information about the $migration (before the migration)
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$migration` | **Model\Migration** | |
#### Breyta\CallbackProgress::finish
```php
public function finish( \stdClass $info )
```
##### Output information about what just happened
Info contains:
- `migrations` - an array of Breyta\Model\Migration
- `executed` - an array of migrations that just got executed
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$info` | **\stdClass** | |
#### Breyta\CallbackProgress::onAfterExecution
```php
public function onAfterExecution( callable $callback )
```
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$callback` | **callable** | |
#### Breyta\CallbackProgress::onAfterMigration
```php
public function onAfterMigration( callable $callback )
```
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$callback` | **callable** | |
#### Breyta\CallbackProgress::onBeforeExecution
```php
public function onBeforeExecution( callable $callback )
```
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$callback` | **callable** | |
#### Breyta\CallbackProgress::onBeforeMigration
```php
public function onBeforeMigration( callable $callback )
```
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$callback` | **callable** | |
#### Breyta\CallbackProgress::onFinish
```php
public function onFinish( callable $callback )
```
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$callback` | **callable** | |
#### Breyta\CallbackProgress::onStart
```php
public function onStart( callable $callback )
```
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$callback` | **callable** | |
#### Breyta\CallbackProgress::start
```php
public function start( \stdClass $info )
```
##### Output information about starting the migration process
Info contains:
- `migrations` - an array of Breyta\Model\Migration
- `count` - an integer how many migrations are going to be executed
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$info` | **\stdClass** | |
---
### Breyta\BasicAdapter
**Implements:** [Breyta\AdapterInterface](#breytaadapterinterface)
#### Properties
| Visibility | Name | Type | Description |
|------------|------|------|---------------------------------------|
| **protected** | `$executor` | **callable** | |
#### Methods
* [__construct](#breytabasicadapter__construct) Adapter gets a callable $executor
* [exec](#breytabasicadapterexec) Execute an sql statement
* [getStatement](#breytabasicadaptergetstatement)
#### Breyta\BasicAdapter::__construct
```php
public function __construct( callable $executor ): BasicAdapter
```
##### Adapter gets a callable $executor
The executor requires a Breyta\Model\Statement argument and is the only way an adapter can interact with
the database.
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$executor` | **callable** | |
#### Breyta\BasicAdapter::exec
```php
public function exec( \Breyta\string $sql ): mixed
```
##### Execute an sql statement
Returns false on error and an integer of affected rows on success.
**Visibility:** this method is **public**.
<br />
**Returns**: this method returns **mixed**
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$sql` | **string** | |
#### Breyta\BasicAdapter::getStatement
```php
public function getStatement( \Breyta\string $sql )
```
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$sql` | **string** | |
---
### Breyta\Migration\CreateMigrationTable
**Extends:** [Breyta\AbstractMigration](#breytaabstractmigration)
#### Properties
| Visibility | Name | Type | Description |
|------------|------|------|---------------------------------------|
| **private** | `$adapter` | | |
#### Methods
* [__call](#breytamigrationcreatemigrationtable__call)
* [__construct](#breytamigrationcreatemigrationtable__construct)
* [down](#breytamigrationcreatemigrationtabledown) Bring the migration down
* [up](#breytamigrationcreatemigrationtableup) Bring the migration up
#### Breyta\Migration\CreateMigrationTable::__call
```php
public function __call( $method, $args )
```
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$method` | | |
| `$args` | | |
#### Breyta\Migration\CreateMigrationTable::__construct
```php
public function __construct(
\Breyta\AdapterInterface $adapter
): AbstractMigration
```
**Visibility:** this method is **public**.
<br />
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `$adapter` | **\Breyta\AdapterInterface** | |
#### Breyta\Migration\CreateMigrationTable::down
```php
public function down()
```
##### Bring the migration down
**Visibility:** this method is **public**.
<br />
#### Breyta\Migration\CreateMigrationTable::up
```php
public function up()
```
##### Bring the migration up
**Visibility:** this method is **public**.
<br />
---
### {{ node.FullyQualifiedStructuralElementName|trim('\\') }}
{% if node.parent is not empty %}
**Extends:** {% for parent in node.parent %}
[{{ parent.FullyQualifiedStructuralElementName|trim('\\') }}](#{{ parent.FullyQualifiedStructuralElementName|replace({'\\': ''})|lower }})
{% else %}[{{ node.parent.FullyQualifiedStructuralElementName|trim('\\') }}](#{{ node.parent.FullyQualifiedStructuralElementName|replace({'\\': ''})|lower }})
{% endfor %}
{% endif %}
{% if node.interfaces is not empty %}
**Implements:** {% for interface in node.interfaces %}
[{{ interface.FullyQualifiedStructuralElementName|trim('\\') }}](#{{ interface.FullyQualifiedStructuralElementName|replace({'\\': ''})|lower }})
{% endfor %}
{% endif %}
{% if node.summary is not empty and node.summary != 'Class '~node.name %}
#### {{ node.summary|raw }}
{% endif %}
{{ node.description|raw }}
{% if node.deprecated %}* **Warning:** this class is **deprecated**. This means that this class will likely be removed in a future version.
{% endif %}
{% if node.tags.see is not empty or node.tags.link is not empty %}
**See Also:**
{% for see in node.tags.see %}
* {{ see.reference }} {% if see.description %}- {{ see.description|raw }}{% endif %}
{% endfor %}
{% for link in node.tags.link %}
* [{{ link.description ?: link.link }}]({{ link.link }})
{% endfor %}
{% endif %}{# node.tags.see || node.tags.link #}
{% if node.constants is not empty %}
#### Constants
| Name | Value |
|------|-------|
{% for constant in node.constants %}
| {{ constant.name }} | `{{ constant.value|raw }}` |
{% endfor %}
{% endif %}
{% if (node.inheritedProperties.merge(node.properties)) is not empty %}
#### Properties
| Visibility | Name | Type | Description |
|------------|------|------|---------------------------------------|
{% for property in node.inheritedProperties.merge(node.properties) %}
| **{{ property.visibility }}{{ property.isStatic ? ' static' }}** | `${{ property.name }}` | {% if property.types is not empty %}**{{ property.types ? property.types|join(' &#124; ')|replace({'<mixed,': '&lt;', (node.namespace.FullyQualifiedStructuralElementName~'\\'): '', '\\': ' \\ '})|raw }}**{% endif %} | {{ property.summary }} |
{% endfor %}
{% endif %}
{% if node.methods is not empty %}
#### Methods
{% for method in node.inheritedMethods.merge(node.methods)|sort_asc %}
* [{{ method.name }}](#{{ node.FullyQualifiedStructuralElementName|replace({'\\': ''})|lower }}{{ method.name|lower }}) {{ method.summary }}
{% endfor %}
{% for method in node.inheritedMethods.merge(node.methods)|sort_asc %}
{% include 'method.md.twig' %}
{% endfor %}
{% endif %}
---
## API Reference
{% for namespace in project.indexes.namespaces|sort %}
{% if not namespace.classes.merge(namespace.interfaces) is empty %}
### {{ namespace|trim('\\') }}
{% for node in namespace.classes.merge(namespace.interfaces)|sort_asc %}
* [{{ node.name }}](#{{ node.FullyQualifiedStructuralElementName|replace({'\\': ''})|lower }})
{% endfor %}
{% endif %}
{% endfor %}
---
{% for node in project.indexes.classes.merge(project.indexes.interfaces)|sort %}
{% include 'class.md.twig' %}
{% endfor %}
#### {{ node.FullyQualifiedStructuralElementName|trim('\\') }}::{{ method.name }}
```php
{{ method.getSignature(80)|replace({'<mixed,': '<'})|raw }}
```
{% if method.summary is not empty %}
##### {{ method.summary|raw }}
{% endif %}
{{ method.description|raw }}
{% if method.deprecated %}**Warning:** this method is **deprecated**. This means that this method will likely be removed in a future version.
<br />{% endif %}
{% if method.static %}**Static:** this method is **static**.
<br />{% endif %}
**Visibility:** this method is **{{ method.visibility }}**.
<br />
{% if method.name != '__construct' and method.response %} **Returns**: this method returns **{{ method.response.types[0] == 'self' ? node.name : method.response.types|join('|') }}**
<br />{% endif %}
{% if method.response.description %}**Response description:** {{ method.response.description|raw }}
<br />{% endif %}
{% if method.tags.throws is not empty %}**Throws:** this method may throw {% for throws in method.tags.throws %}
{{ not loop.first ? ' or ' }}**{{ throws.types|join('** or **')|raw }}**{% endfor %}
<br />{% endif %}
{% if method.arguments is not empty %}
##### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
{% for argument in method.arguments %}
| `{{ argument.name }}` | {% if argument.types is not empty %}**{{ argument.types ? argument.types|join(' &#124; ')|replace({'<mixed,': '&lt;', (node.namespace.FullyQualifiedStructuralElementName~'\\'): ''})|raw }}**{% endif %} | {{ argument.description|replace({'|': '&#124;'})|raw }} |
{% endfor %}
{% endif %}
{% if method.tags.see is not empty or method.tags.link is not empty %}
**See Also:**
{% for see in method.tags.see %}
* {{ see.reference }} {% if see.description %}- {{ see.description|raw }}{% endif %}
{% endfor %}
{% for link in method.tags.link %}
* [{{ link.description ?: link.link }}]({{ link.link }})
{% endfor %}
{% endif %}
<?xml version="1.0" encoding="utf-8"?>
<template>
<transformations>
<transformation writer="twig" source="templates/reference/index.md.twig" artifact="reference.md" />
</transformations>
</template>
<?php
namespace Breyta;
use Breyta\Model\Migration;
use Breyta\Model\Statement;
/**
* Class CallbackProgress
*
* Stores callbacks for migration progress.
*
* @package Breyta
* @author Thomas Flori <thflori@gmail.com>
* @codeCoverageIgnore This class has no own code it just stores callbacks
*/
class CallbackProgress implements ProgressInterface
{
/** @var callable */
protected $startCallback;
/** @var callable */
protected $beforeMigrationCallback;
/** @var callable */
protected $beforeExecutionCallback;
/** @var callable */
protected $afterExecutionCallback;
/** @var callable */
protected $afterMigrationCallback;
/** @var callable */
protected $finishCallback;
/**
* Output information about starting the migration process
*
* Info contains:
* - `migrations` - an array of Breyta\Model\Migration
* - `count` - an integer how many migrations are going to be executed
*
* @param \stdClass $info
*/
public function start(\stdClass $info)
{
!$this->startCallback || call_user_func($this->startCallback, $info);
}
public function onStart(callable $callback): self
{
$this->startCallback = $callback;
return $this;
}
/**
* Output information about the $migration (before the migration)
*
* @param Migration $migration
*/
public function beforeMigration(Migration $migration)
{
!$this->beforeMigrationCallback || call_user_func($this->beforeMigrationCallback, $migration);
}
public function onBeforeMigration(callable $callback): self
{
$this->beforeMigrationCallback = $callback;
return $this;
}
/**
* Output information about the $statement (before it gets executed)
*
* @param Statement $execution
*/
public function beforeExecution(Statement $execution)
{
!$this->beforeExecutionCallback || call_user_func($this->beforeExecutionCallback, $execution);
}
public function onBeforeExecution(callable $callback): self
{
$this->beforeExecutionCallback = $callback;
return $this;
}
/**
* Output information about the $statement (after it gets executed)
*
* @param Statement $execution
*/
public function afterExecution(Statement $execution)
{
!$this->afterExecutionCallback || call_user_func($this->afterExecutionCallback, $execution);
}
public function onAfterExecution(callable $callback): self
{
$this->afterExecutionCallback = $callback;
return $this;
}
/**
* Output information about the $migration (after the migration)
*
* @param Migration $migration
*/
public function afterMigration(Migration $migration)
{
!$this->afterMigrationCallback || call_user_func($this->afterMigrationCallback, $migration);
}
public function onAfterMigration(callable $callback): self
{
$this->afterMigrationCallback = $callback;
return $this;
}
/**
* Output information about what just happened
*
* Info contains:
* - `migrations` - an array of Breyta\Model\Migration
* - `executed` - an array of migrations that just got executed
*
* @param \stdClass $info
*/
public function finish(\stdClass $info)
{
!$this->finishCallback || call_user_func($this->finishCallback, $info);
}
public function onFinish(callable $callback): self
{
$this->finishCallback = $callback;
return $this;
}
}
......@@ -3,12 +3,14 @@
namespace Breyta\Migration;
use Breyta\AbstractMigration;
use Breyta\Migrations;
class CreateMigrationTable extends AbstractMigration
{
public function up(): void
{
$this->exec("CREATE TABLE migrations (
$table = Migrations::$table ?? 'migrations';
$this->exec("CREATE TABLE {$table} (
file CHARACTER VARYING (64) NOT NULL,
executed TIMESTAMP NOT NULL,
reverted TIMESTAMP,
......@@ -17,9 +19,9 @@ class CreateMigrationTable extends AbstractMigration
executionTime DOUBLE PRECISION,
PRIMARY KEY (file)
)");
$this->exec("CREATE INDEX migrations_executed_index ON migrations (executed)");
$this->exec("CREATE INDEX migrations_status_index ON migrations (status)");
$this->exec("CREATE INDEX migrations_execution_time ON migrations (executionTime)");
$this->exec("CREATE INDEX {$table}_executed_index ON {$table} (executed)");
$this->exec("CREATE INDEX {$table}_status_index ON {$table} (status)");
$this->exec("CREATE INDEX {$table}_executionTime_index ON {$table} (executionTime)");
}
/** @codeCoverageIgnore */
......
......@@ -5,9 +5,22 @@ namespace Breyta;
use Breyta\Migration\CreateMigrationTable;
use Breyta\Model;
/**
* Class Migrations
*
* The migration engine that puts all parts together.
*
* @package Breyta
* @author Thomas Flori <thflori@gmail.com>
*/
class Migrations
{
const INTERNAL_PREFIX = '@breyta/';
/** The name of the migration table
* @var string */
public static $table = 'migrations';
/** @var \PDO */
protected $db;
......@@ -29,7 +42,10 @@ class Migrations
/** @var callable */
protected $resolver;
public function __construct(\PDO $db, string $path, callable $resolver = null)
/** @var ProgressInterface */
protected $progress;
public function __construct(\PDO $db, string $path, callable $resolver = null, ProgressInterface $progress = null)
{
if (!file_exists($path) || !is_dir($path)) {
throw new \InvalidArgumentException('The path to migrations is not valid');
......@@ -48,8 +64,18 @@ class Migrations
}
return new $class(...$args);
};
$this->progress = $progress ?? new CallbackProgress();
}
/**
* Returns the status of the migrations
*
* It contains an array of all migrations, the count of migrations that are not migrated yet and an array of
* migrations that got removed (if files where removed).
*
* @return \stdClass
*/
public function getStatus(): \stdClass
{
$this->loadMigrations();
......@@ -68,6 +94,11 @@ class Migrations
return $status;
}
/**
* Migrate all migrations that are not migrated yet
*
* @return bool
*/
public function migrate(): bool
{
$this->loadMigrations();
......@@ -80,6 +111,15 @@ class Migrations
return $this->up(...$migrations);
}
/**
* Migrate all migrations to a specific migration or date time
*
* $file can either be a relative file name (or a portion matched with `strpos()`) or a date time string to execute
* all migrations to that time.
*
* @param string $file
* @return bool
*/
public function migrateTo(string $file)
{
$this->loadMigrations();
......@@ -111,9 +151,24 @@ class Migrations
return $this->up(...$migrations);
}
/**
* Migrate specific migrations
*
* @param Model\Migration ...$migrations
* @return bool
*/
public function up(Model\Migration ...$migrations)
{
$started = microtime(true);
$this->progress->start((object)[
'migrations' => $this->migrations,
'task' => 'migrate',
'count' => count($migrations),
'toExecute' => $migrations,
]);
foreach ($migrations as $migration) {
$this->progress->beforeMigration($migration);
$this->statements = [];
$start = microtime(true);
try {
......@@ -130,11 +185,24 @@ class Migrations
$this->saveMigration($migration, 'failed', microtime(true) - $start);
throw $exception;
}
$this->progress->afterMigration($migration);
}
$this->progress->finish((object)[
'migrations' => $this->migrations,
'task' => 'migrate',
'count' => count($migrations),
'executed' => $migrations,
'executionTime' => microtime(true) - $started
]);
return true;
}
/**
* Revert all migrations that have been migrated
*
* @return bool
*/
public function revert()
{
$this->loadMigrations();
......@@ -147,6 +215,18 @@ class Migrations
return $this->down(...array_reverse($migrations));
}
/**
* Revert all migrations to a specific migration or date time
*
* $file can either be a relative file name (or a portion matched with `strpos()`) or a date time string to execute
* all migrations to that time.
*
* **Note:** This will not revert the migration matched the pattern. It is resetting to the state of the database
* to the state when <file> was executed.
*
* @param string $file
* @return bool
*/
public function revertTo(string $file)
{
$this->loadMigrations();
......@@ -180,9 +260,24 @@ class Migrations
return $this->down(...$migrations);
}
/**
* Revert specific migrations
*
* @param Model\Migration ...$migrations
* @return bool
*/
public function down(Model\Migration ...$migrations)
{
$started = microtime(true);
$this->progress->start((object)[
'migrations' => $this->migrations,
'task' => 'revert',
'count' => count($migrations),
'toExecute' => $migrations,
]);
foreach ($migrations as $migration) {
$this->progress->beforeMigration($migration);
$this->statements = $migration->statements;
$start = microtime(true) - $migration->executionTime;
try {
......@@ -198,14 +293,35 @@ class Migrations
$this->db->rollBack();
throw $exception;
}
$this->progress->afterMigration($migration);
}
$this->progress->finish((object)[
'migrations' => $this->migrations,
'task' => 'revert',
'count' => count($migrations),
'executed' => $migrations,
'executionTime' => microtime(true) - $started
]);
return true;
}
/** @codeCoverageIgnore */
public function getProgress(): ProgressInterface
{
return $this->progress;
}
/** @codeCoverageIgnore */
public function setProgress(ProgressInterface $progress)
{
$this->progress = $progress;
}
protected function saveMigration(Model\Migration $migration, $status, $executionTime)
{
$exists = (bool)$migration->executed;
$table = self::$table;
$now = new \DateTime('now', new \DateTimeZone('UTC'));
$status === 'reverted' ? $migration->reverted = $now : $migration->executed = $now;
......@@ -214,7 +330,7 @@ class Migrations
$migration->executionTime = $executionTime;
if (!$exists) {
$this->db->prepare("INSERT INTO migrations
$this->db->prepare("INSERT INTO {$table}
(file, executed, status, statements, executionTime) VALUES
(?, ?, ?, ?, ?)
")->execute([
......@@ -225,7 +341,7 @@ class Migrations
$migration->executionTime
]);
} else {
$this->db->prepare("UPDATE migrations SET
$this->db->prepare("UPDATE {$table} SET
executed = ?, reverted = ?, status = ?, statements = ?, executionTime = ?
WHERE file = ?
")->execute([
......@@ -334,6 +450,7 @@ class Migrations
protected function executeStatement(Model\Statement $statement)
{
$this->progress->beforeExecution($statement);
$start = microtime(true);
try {
$statement->result = $this->db->exec($statement->raw);
......@@ -343,6 +460,7 @@ class Migrations
throw $exception;
} finally {
$statement->executionTime = microtime(true) - $start;
$this->progress->afterExecution($statement);
}
}
......
......@@ -12,7 +12,9 @@ interface ProgressInterface
*
* Info contains:
* - `migrations` - an array of Breyta\Model\Migration
* - `task` - the task that is going to be executed (migrate or revert)
* - `count` - an integer how many migrations are going to be executed
* - `toExecute` - an array of migrations that are going to be executed
*
* @param \stdClass $info
*/
......@@ -47,6 +49,8 @@ interface ProgressInterface
*
* Info contains:
* - `migrations` - an array of Breyta\Model\Migration
* - `task` - the task that is going to be executed (migrate or revert)
* - `count` - an integer how many migrations are going to be executed
* - `executed` - an array of migrations that just got executed
*
* @param \stdClass $info
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment