diff --git a/DBV.php b/DBV.php index d2a9e1d..9a02898 100644 --- a/DBV.php +++ b/DBV.php @@ -176,6 +176,60 @@ public function revisionsAction() } } + public function jumptoAction(){ + + $final_revision = isset($_POST['revision']) ? intval($_POST['revision']) : 0; + $current_revision = $this->_getCurrentRevision(); + $revisions = $this->_getRevisions(); + + foreach($revisions as $revision){ + + //move forward + if($revision > $current_revision && $revision <= $final_revision){ + + $files = $this->_getRevisionFiles($revision); + if (count($files)) { + foreach ($files as $file) { + $file = DBV_REVISIONS_PATH . DS . $revision . DS . $file; + if (!$this->_runFile($file)) { + break 2; + } + } + } + + //rollback + }elseif($revision <= $current_revision && $revision > $final_revision){ + + $files = $this->_getRevisionRollbackFiles($revision); + + if (count($files)) { + foreach ($files as $file) { + $file = DBV_REVISIONS_PATH . DS . $revision . DS . 'rollback' . DS . $file; + if (!$this->_runFile($file)) { + break 2; + } + } + } + } + } + + $this->_setCurrentRevision($final_revision); + + $this->confirm(__("Jumped to revision #{revision}", array('revision' => "$final_revision"))); + if ($this->_isXMLHttpRequest()) { + $return = array( + 'messages' => array(), + 'revision' => $this->_getCurrentRevision() + ); + foreach ($this->_log as $message) { + $return['messages'][$message['type']][] = $message['message']; + } + $this->_json($return); + + } else { + $this->indexAction(); + } + } public function saveRevisionFileAction() { @@ -332,18 +386,28 @@ protected function _getRevisions() protected function _getCurrentRevision() { - $file = DBV_META_PATH . DS . 'revision'; - if (file_exists($file)) { - return intval(file_get_contents($file)); + if(DB_REVISION_LOG){ + return $this->_getAdapter()->getCurrentRevision(); + }else{ + $file = DBV_META_PATH . DS . 'revision'; + if (file_exists($file)) { + return intval(file_get_contents($file)); + } } return 0; } protected function _setCurrentRevision($revision) { - $file = DBV_META_PATH . DS . 'revision'; - if (!@file_put_contents($file, $revision)) { - $this->error("Cannot write revision file"); + + if(DB_REVISION_LOG){ + $commit = ($_POST['commit'])? $_POST['commit'] : 'NULL'; + $this->_getAdapter()->setRevision($revision, $commit); + }else{ + $file = DBV_META_PATH . DS . 'revision'; + if (!@file_put_contents($file, $revision)) { + $this->error("Cannot write revision file"); + } } } @@ -362,6 +426,21 @@ protected function _getRevisionFiles($revision) return $return; } + protected function _getRevisionRollbackFiles($revision) + { + $dir = DBV_REVISIONS_PATH . DS . $revision . DS . 'rollback'; + $return = array(); + + foreach (new DirectoryIterator($dir) as $file) { + if ($file->isFile() && pathinfo($file->getFilename(), PATHINFO_EXTENSION) == 'sql') { + $return[] = $file->getBasename(); + } + } + + sort($return, SORT_REGULAR); + return $return; + } + protected function _getRevisionFileContents($revision, $file) { $path = DBV_REVISIONS_PATH . DS . $revision . DS . $file; @@ -372,6 +451,19 @@ protected function _getRevisionFileContents($revision, $file) return false; } + public function findRevisionFromCommit($commit){ + + if(DB_REVISION_LOG && $commit){ + return $this->_getAdapter()->getRevision($commit); + }else{ + $this->error("You can only find revisions if you save them to the database."); + } + } + + public function findLastRevision(){ + return array_shift($this->_getRevisions()); + } + public function log($item) { $this->_log[] = $item; diff --git a/cl.php b/cl.php new file mode 100644 index 0000000..4e434cf --- /dev/null +++ b/cl.php @@ -0,0 +1,44 @@ +findLastRevision(); + $_POST['commit'] = $argv[2]; +}elseif($argv[1] === 'rev' && $argv[2]){ + $_POST['revision'] = $argv[2]; +}elseif($argv[1] === 'commit' && $argv[2]){ + $rev = $dbv->findRevisionFromCommit($argv[2]); + if($rev){ + $_POST['revision'] = $rev; + }else{ + die('Could not find revision'); + } +}else{ + die("No valid arguments found. Please use 'last', 'rev' or 'commit'"); +} + +$dbv->authenticate(); +$dbv->dispatch(); diff --git a/config.php.sample b/config.php.sample index 7a18293..653a231 100644 --- a/config.php.sample +++ b/config.php.sample @@ -26,6 +26,12 @@ define('DB_ADAPTER', 'MySQL'); define('DS', DIRECTORY_SEPARATOR); define('DBV_ROOT_PATH', dirname(__FILE__)); +/** +* Use db for keeping track of current revision in the database and specify the table +*/ +define('DB_REVISION_LOG', true); +define('DB_REVISION_TABLE', 'dbv_revisions'); + /** * Only edit this lines if you want to place your schema files in custom locations * @see http://dbv.vizuina.com/documentation/#optional-settings diff --git a/install.sql b/install.sql new file mode 100644 index 0000000..2c3fb09 --- /dev/null +++ b/install.sql @@ -0,0 +1,6 @@ +CREATE TABLE `dbv_revisions` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `commit` varchar(255) DEFAULT NULL, + `revision` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; \ No newline at end of file diff --git a/lib/adapters/MySQL.php b/lib/adapters/MySQL.php index 7d498a8..6772be4 100644 --- a/lib/adapters/MySQL.php +++ b/lib/adapters/MySQL.php @@ -87,4 +87,17 @@ public function getSchemaObject($name) return $return; } + public function getCurrentRevision(){ + $result = $this->query("SELECT revision FROM " . DB_REVISION_TABLE . " ORDER BY id DESC LIMIT 1")->fetchColumn(); + return ($result)? (int) $result : 0; + } + + public function getRevision($commit){ + $result = $this->query("SELECT revision FROM " . DB_REVISION_TABLE . " WHERE commit='" . $commit . "' ORDER BY id DESC LIMIT 1")->fetchColumn(); + return ($result)? (int) $result : false; + } + + public function setRevision($revision, $commit){ + $this->query("INSERT INTO " . DB_REVISION_TABLE . " (commit, revision) VALUES ('" . $commit . "'," . $revision . ")"); + } } diff --git a/templates/revisions.php b/templates/revisions.php index bc89261..c1d1130 100644 --- a/templates/revisions.php +++ b/templates/revisions.php @@ -57,6 +57,20 @@ +
+

+

If you select a revision lower then the current one it will run the rollback script for every revision inbetween the current and the selected revision. + Place your rollback script in a folder 'rollback' within the revision folder. All scripts within that folder will be run.

+
+ + + +
'' . REVISIONS_PATH . '')) ?>