2.3. Timeline¶
A Timeline
is an object comprised of a version collection that’s ordered by version.
2.3.1. Public Methods¶
The Timeline is in charge of executing one or more migrations in any of four different ways:
upTowards(target)
- Executes all migrations in ascending sequential order, starting from the first “pending”
version, up to and including the “target” version - and skipping any versions that have already been migrated.
Calls each migration’s
up()
method upon execution. downTowards(target)
- Executes all migrations in descending sequential order, starting from the last
migration and down until and including the “target” version. Calls each migration’s
down()
method upon execution. goTowards(target)
- Combines the previous two operations into one. Executes all migrations
up()
to and including the “target” version. And then executes all remaining versionsdown()
, starting from the last available version and ending in the version immediately after the “target” version. Useful to make sure all versions before and including “target” are migrated, while all others are pending. runSingle(version, options)
- Runs a single version’s migration using the specified options. Can be called directly and useful mostly for testing purposes in a controlled environment.
2.3.2. Constructor¶
When being instantiated the Timeline requires a version collection and a comparator as arguments.
VersionCollection $versions
The version collection must contain at least one Delta. All versions in the collection must have a migration assigned to them or otherwise an exception will be thrown.
Something to note is that the
VersionCollection
object will be cloned before being stored in the Timeline. Since the Timeline doesn’t have any public methods available to access the internal version collection this effectively means that once the Timeline is created its collection cannot be altered.callable $comparator
(optional)The comparator must be a
callable
that receives two Versions as arguments and returns a number less than, equal to, or greater than zero (0) if the first version should be executed before than, is the same as, or should be executed after the second version (respectively).The default comparator simply extracts the first number from each version and subtracts the second one from the first one. See class
Delta\Comparator\DefaultComparator
for the source code.MigrationBus $migrationBus
(optional)The
MigrationBus
(colloquially “bus”) is an object that can handle aMigrationCommand
(“command”). The bus consists if a series ofAbstractMiddleware
(middleware), at least one of which must be aMigrationHandler
(handler). Each middleware object receives the command, handles it (e.g. logs some info), and then calls the next middleware. This goes on until the command arrives at the handler (which is also a middleware), who calls theup()
ordown()
function in the command’s migration and ends the chain.A default
MigrationBus
is automatically created if none is specified.
2.3.3. Events¶
Events are an useful to tap into the migration behaviour quickly and cleanly. The Timeline is coupled with a
TimelineEmitter
class that fires domain events for each operation if an EventDispatcher
is present. Events that
will be fired are:
- Before Collection
DomainEventInterface::COLLECTION_BEFORE
- Fired before the Timeline executes one of the collection methods (upTowards, downTowards, goTowards). The listener callback will receive a CollectionEvent object as a parameter, which includes information about the collection of versions, the Options and the target version.
- After Collection
DomainEventInterface::COLLECTION_AFTER
- Same as above, but fired once the the collection method has finished executing all scheduled migrations.
- Before Migration
DomainEventInterface::MIGRATION_BEFORE
- Fired before the Timeline executes a single migration, which occurs both as part of executing
runSingle
and also for each of the migrations executed by any collection method. - After Migration
DomainEventInterface::MIGRATION_AFTER
- Same as above, but fired once the migration has finished.
Baleen uses Symfony’s Event Dispatcher component, so listening to timeline events is very easy:
<?php
use Baleen\Migrations\Event;
$dispatcher = $timeline->getEventDispatcher();
$dispatcher->addListener(
DomainEventInterface::COLLECTION_BEFORE,
function ($event, $name) {
// do something
}
);
$dispatcher->addListener( /* ... */ );
You can also inject your own dispatcher (useful for shared listeners e.g. across different Timeline instances):
<?php
use Symfony\Component\EventDispatcher;
$dispatcher = new EventDispatcher();
$dispatcher->addListener( /* ... */ );
$dispatcher->addListener( /* ... */ );
$timeline->setEventDispatcher($dispatcher);
2.3.4. Custom MigrationBus¶
As indicated in the Timeline Constructor section, a Timeline can receive a
MigrationBus
as an optional parameter. The MigrationBus
is simply a specialised CommandBus
that helps
provide strong typing for the MigrateCommand
in PHP 5. Its currently powered by the
Tactician command bus library.
The Middleware attached to that bus will be used to execute each individual migration, which means behaviors can easily be customised if needed.
The default migration bus and its middleware stack is created by MigrationBusFactory
- its very simple:
<?php
new MigrationBus([
// injects Options into the migration
new SetOptionsMiddleware(),
// wraps each migration into a transaction (most commonly a DB transaction)
new TransactionMiddleware(),
// in charge of executing the MigrateCommand
new MigrateHandler(),
]);
You can override the default MigrationBus
by simply passing a different instance as a parameter for the Timeline’s
constructor.
Creating your own middleware is easy too: just create a new class that extends AbstractMiddleware
and add it to the
chain when you create the MigrationBus
. See any of the default middleware classes for an example of what middleware
can do.