Skip to content

Commit df49f28

Browse files
committed
Initial
0 parents  commit df49f28

16 files changed

+719
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
composer.lock
2+
vendor

README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
PHPCR Migrations
2+
================
3+
4+
Migrations library for PHPCR based heavily on [Doctrine
5+
migrations](https://github.com/doctrine/migrations).
6+
7+
Usage
8+
-----
9+
10+
````php
11+
$storage = new VersionStorage($phpcrSession);
12+
$finder = new VersionFinder(array('/path/to/migrations'));
13+
14+
$versions = $finder->getVersionCollection();
15+
$migrator = new Migrator($session, $versionCollection, $storage);
16+
17+
$to = '201504241744';
18+
$migrator->migrate($to);
19+
````
20+
21+
Versions
22+
--------
23+
24+
Version classes contain `up` and `down` methods. The class is quite simple:
25+
26+
````php
27+
<?php
28+
29+
class Version201504241200 implements VersionInterface
30+
{
31+
public function up(SessionInterface $session)
32+
{
33+
$session->doSomething();
34+
}
35+
36+
public function down(SessionInterface $session)
37+
{
38+
$session->undoSomething();
39+
}
40+
}
41+
````
42+
43+
They must be named `VersionYYYMMDDHHMM`. If they are not so named, then they
44+
will not be detected.

composer.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "dantleech/phpcr-migrations",
3+
"description": "Migrations for PHPCR",
4+
"license": "MIT",
5+
"authors": [
6+
{
7+
"name": "Daniel Leech",
8+
"email": "daniel@dantleech.com"
9+
}
10+
],
11+
"minimum-stability": "dev",
12+
"require": {
13+
"phpcr/phpcr": "~2.1",
14+
"symfony/finder": "~2.1",
15+
"symfony/console": "~2.1"
16+
},
17+
"require-dev": {
18+
"jackalope/jackalope-fs": "dev-master"
19+
},
20+
"autoload": {
21+
"psr-4": {
22+
"DTL\\PhpcrMigrations\\": "lib"
23+
}
24+
},
25+
"autoload-dev": {
26+
"psr-4": {
27+
"DTL\\PhpcrMigrations\\": "tests"
28+
}
29+
}
30+
}

lib/Migrator.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
/*
3+
* This file is part of the <package> package.
4+
*
5+
* (c) Daniel Leech <daniel@dantleech.com>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace DTL\PhpcrMigrations;
12+
13+
use PHPCR\SessionInterface;
14+
use DTL\PhpcrMigrations\VersionStorage;
15+
use DTL\PhpcrMigrations\VersionCollection;
16+
use Symfony\Component\Console\Output\OutputInterface;
17+
18+
class Migrator
19+
{
20+
private $session;
21+
private $versionCollection;
22+
private $versionStorage;
23+
24+
public function __construct(
25+
SessionInterface $session,
26+
VersionCollection $versionCollection,
27+
VersionStorage $versionStorage
28+
)
29+
{
30+
$this->session = $session;
31+
$this->versionCollection = $versionCollection;
32+
$this->versionStorage = $versionStorage;
33+
}
34+
35+
public function migrate($to = null, OutputInterface $output)
36+
{
37+
if ($to === null) {
38+
$to = $this->versionCollection->getLatestVersion();
39+
}
40+
41+
$to = (string) $to;
42+
43+
if (!$this->versionCollection->has($to)) {
44+
throw MigratorException::unknownVersion($to);
45+
}
46+
47+
$from = $this->versionStorage->getCurrentVersion();
48+
$from = (string) $from;
49+
$direction = $from > $to ? 'down' : 'up';
50+
51+
$versionsToExecute = $this->versionCollection->getVersions($from, $to, $direction);
52+
53+
if (!$versionsToExecute) {
54+
throw MigratorException::noMigrationsToExecute();
55+
}
56+
57+
$start = microtime(true);
58+
foreach ($versionsToExecute as $timestamp => $version) {
59+
$output->writeln('<info>Executing migration version</info>: %s', $timestamp);
60+
$version->$direction($this->session);
61+
62+
if ($direction === 'down') {
63+
$this->versionStorage->remove($timestamp);
64+
} else {
65+
$this->versionStorage->add($timestamp);
66+
}
67+
}
68+
69+
$output->writeln('<info>Done. Executed </info>%s<info> migration versions</info> %s', count($versionsToExecute), number_format(microtime(true) - $start), 4);
70+
}
71+
}

lib/MigratorException.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
/*
3+
* This file is part of the <package> package.
4+
*
5+
* (c) Daniel Leech <daniel@dantleech.com>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace DTL\PhpcrMigrations;
12+
13+
class MigratorException extends \Exception
14+
{
15+
public static function noMigrationsToExecute()
16+
{
17+
return new self('No migrations to execute');
18+
}
19+
20+
public static function unknownVersion($version)
21+
{
22+
return new self(sprintf('Unknown version "%s"', $version));
23+
}
24+
25+
public static function couldNotIntantiateVersionClass($className)
26+
{
27+
return new self(sprintf('Could not instantiate version class "%s", it does not exist', $className));
28+
}
29+
30+
public static function versionNotInstance($className)
31+
{
32+
return new self(sprintf('Version class "%s" is not an instance of DTL\PhpcrMigrations\VersionInterface', $className));
33+
}
34+
}

lib/VersionCollection.php

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
/*
3+
* This file is part of the <package> package.
4+
*
5+
* (c) Daniel Leech <daniel@dantleech.com>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace DTL\PhpcrMigrations;
12+
13+
class VersionCollection
14+
{
15+
private $versions;
16+
17+
public function __construct(array $versions)
18+
{
19+
ksort($versions, SORT_STRING);
20+
$this->versions = $versions;
21+
}
22+
23+
public function has($versionTimestamp)
24+
{
25+
return isset($this->versions[$versionTimestamp]);
26+
}
27+
28+
public function toArray()
29+
{
30+
return $this->versions;
31+
}
32+
33+
public function getVersions($from, $to)
34+
{
35+
$from = (string) $from;
36+
$to = (string) $to;
37+
$direction = $from > $to ? 'down' : 'up';
38+
$result = array();
39+
$versions = $this->versions;
40+
41+
if ($direction === 'up') {
42+
ksort($versions, SORT_STRING);
43+
} else {
44+
krsort($versions, SORT_STRING);
45+
}
46+
47+
$found = false;
48+
foreach ($versions as $timestamp => $version) {
49+
if ($timestamp == $from) {
50+
$found = true;
51+
52+
if ($direction == 'down') {
53+
$result[$timestamp] = $version;
54+
}
55+
56+
continue;
57+
}
58+
59+
if (false === $found) {
60+
continue;
61+
}
62+
63+
64+
if ($timestamp == $to) {
65+
if ($direction == 'up') {
66+
$result[$timestamp] = $version;
67+
}
68+
break;
69+
}
70+
71+
$result[$timestamp] = $version;
72+
}
73+
74+
return $result;
75+
}
76+
77+
public function getLatestVersion()
78+
{
79+
return end($this->versions);
80+
}
81+
}

lib/VersionFinder.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
/*
3+
* This file is part of the <package> package.
4+
*
5+
* (c) Daniel Leech <daniel@dantleech.com>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace DTL\PhpcrMigrations;
12+
13+
use Symfony\Component\Finder\Finder;
14+
15+
class VersionFinder
16+
{
17+
private $paths;
18+
19+
public function __construct(array $paths)
20+
{
21+
$this->paths = $paths;
22+
}
23+
24+
public function getCollection()
25+
{
26+
$versions = array();
27+
$finder = new Finder();
28+
$finder->name('/Version[0-9]{12}.php/');
29+
$finder->files();
30+
31+
foreach ($this->paths as $path) {
32+
$finder->in($path);
33+
}
34+
35+
foreach ($finder as $versionFile) {
36+
$className = $versionFile->getBasename('.php');
37+
require_once($versionFile->getRealPath());
38+
if (!class_exists($className)) {
39+
throw MigratorException::couldNotIntantiateVersionClass($className);
40+
}
41+
$version = new $className();
42+
43+
if (!$version instanceof VersionInterface) {
44+
throw MigratorException::versionNotInstance($className);
45+
}
46+
47+
$versionTimestamp = substr($versionFile->getBaseName(), 8, 12);
48+
$versions[$versionTimestamp] = $version;
49+
}
50+
51+
$collection = new VersionCollection($versions);
52+
53+
return $collection;
54+
}
55+
}

lib/VersionInterface.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
/*
3+
* This file is part of the <package> package.
4+
*
5+
* (c) Daniel Leech <daniel@dantleech.com>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace DTL\PhpcrMigrations;
12+
13+
use PHPCR\SessionInterface;
14+
15+
/**
16+
* Interface for PHPCR migration classes
17+
*
18+
* Version classes MUST be named as follows:
19+
*
20+
* VersionYYYYMMDDHHMM
21+
*
22+
* For example:
23+
*
24+
* Version201504241609
25+
*/
26+
interface VersionInterface
27+
{
28+
/**
29+
* Migrate the repository up
30+
*
31+
* @param SessionInterface $session
32+
*/
33+
public function up(SessionInterface $session);
34+
35+
/**
36+
* Migrate the system down
37+
*
38+
* @param SessionInterface $session
39+
*/
40+
public function down(SessionInterface $session);
41+
}

0 commit comments

Comments
 (0)