summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2021-03-03 23:38:52 +0300
committerAndrew Dolgov <[email protected]>2021-03-03 23:38:52 +0300
commit8256ab5dd901904dfa8f78ebc3f3ed08a969226d (patch)
treef051c8bd3e61e7f7451042e130d9352d7fed2cbb
parent0cb719a40447e30011142714d5e5ce55c051a118 (diff)
wip: initial for db_migrations
-rw-r--r--classes/db/migrations.php140
-rwxr-xr-xclasses/pluginhost.php7
2 files changed, 146 insertions, 1 deletions
diff --git a/classes/db/migrations.php b/classes/db/migrations.php
new file mode 100644
index 000000000..d1eee61d3
--- /dev/null
+++ b/classes/db/migrations.php
@@ -0,0 +1,140 @@
+<?php
+class Db_Migrations {
+
+ private $base_filename = "schema.sql";
+ private $base_path;
+ private $migrations_path;
+ private $migrations_table;
+ private $pdo;
+
+ private $cached_version;
+ private $cached_max_version;
+
+ function initialize_for_plugin(Plugin $plugin, string $schema_suffix = "sql") {
+ $plugin_dir = PluginHost::getInstance()->get_plugin_dir($plugin);
+ $this->initialize($plugin_dir . "/${schema_suffix}",
+ strtolower("ttrss_migrations_plugin_" . get_class($plugin)));
+ }
+
+ function initialize(string $root_path, string $migrations_table) {
+ $this->base_path = "$root_path/" . Config::get(Config::DB_TYPE);
+ $this->migrations_path = $this->base_path . "/migrations";
+
+ $this->migrations_table = $migrations_table;
+ }
+
+ function __construct() {
+ $this->pdo = Db::pdo();
+ }
+
+ private function set_version(int $version) {
+ $sth = $this->pdo->query("SELECT * FROM {$this->migrations_table}");
+
+ if ($res = $sth->fetch()) {
+ $sth = $this->pdo->prepare("UPDATE {$this->migrations_table} SET schema_version = ?");
+ } else {
+ $sth = $this->pdo->prepare("INSERT INTO {$this->migrations_table} (schema_version) VALUES (?)");
+ }
+
+ $sth->execute([$version]);
+
+ $this->cached_version = $version;
+ }
+
+ private function get_version() : int {
+ if (isset($this->cached_version))
+ return $this->cached_version;
+
+ try {
+ $sth = $this->pdo->query("SELECT * FROM {$this->migrations_table}");
+
+ if ($res = $sth->fetch()) {
+ return (int) $res['schema_version'];
+ } else {
+ return -1;
+ }
+ } catch (PDOException $e) {
+ $this->create_migrations_table();
+
+ return -1;
+ }
+ }
+
+ private function create_migrations_table() {
+ $this->pdo->query("CREATE TABLE IF NOT EXISTS {$this->migrations_table} (schema_version integer not null)");
+ }
+
+ private function migrate_to(int $version) {
+ try {
+ $this->pdo->beginTransaction();
+
+ foreach ($this->get_lines($version) as $line) {
+ $this->pdo->query($line);
+ }
+
+ $this->set_version($version);
+
+ $this->pdo->commit();
+ } catch (PDOException $e) {
+ try {
+ $this->pdo->rollback();
+ } catch (PDOException $ie) {
+ //
+ }
+ throw $e;
+ }
+ }
+
+ private function get_max_version() : int {
+ if (isset($this->cached_max_version))
+ return $this->cached_max_version;
+
+ $migrations = glob("{$this->migrations_path}/*.sql");
+
+ if (count($migrations) > 0) {
+ natsort($migrations);
+
+ $this->cached_max_version = (int) basename(array_pop($migrations), ".sql");
+
+ } else {
+ $this->cached_max_version = 0;
+ }
+
+ return $this->cached_max_version;
+ }
+
+ function migrate() : bool {
+
+ for ($i = $this->get_version() + 1; $i <= $this->get_max_version(); $i++)
+ try {
+ $this->migrate_to($i);
+ } catch (PDOException $e) {
+ user_error("Failed applying migration $i on table {$this->migrations_table}: " . $e->getMessage(), E_USER_WARNING);
+ //throw $e;
+ }
+
+ return $this->get_version() == $this->get_max_version();
+ }
+
+ private function get_lines(int $version) : array {
+ if ($version > 0)
+ $filename = "{$this->migrations_path}/${version}.sql";
+ else
+ $filename = "{$this->base_path}/{$this->base_filename}";
+
+ if (file_exists($filename)) {
+ $lines = array_filter(preg_split("/[\r\n]/", file_get_contents($filename)),
+ function ($line) {
+ return strlen(trim($line)) > 0 && strpos($line, "--") !== 0;
+ });
+
+ return array_filter(explode(";", implode("", $lines)), function ($line) {
+ return strlen(trim($line)) > 0;
+ });
+
+ } else {
+ user_error(E_USER_ERROR, "[migrations] requested schema file ${filename} not found.");
+ return [];
+ }
+ }
+}
diff --git a/classes/pluginhost.php b/classes/pluginhost.php
index 746b780e4..366e2b2d3 100755
--- a/classes/pluginhost.php
+++ b/classes/pluginhost.php
@@ -624,9 +624,14 @@ class PluginHost {
}
}
- function is_local(Plugin $plugin) {
+ function get_plugin_dir(Plugin $plugin) {
$ref = new ReflectionClass(get_class($plugin));
+ return dirname($ref->getFileName());
+ }
+ // TODO: use get_plugin_dir()
+ function is_local(Plugin $plugin) {
+ $ref = new ReflectionClass(get_class($plugin));
return basename(dirname(dirname($ref->getFileName()))) == "plugins.local";
}
}