· 8 years ago · Aug 02, 2018, 09:10 PM
1<?php
2class Migrator
3{
4 private $db_host, $db_database, $db_username, $db_password;
5 private $mdb_host, $mdb_database, $mdb_username, $mdb_password;
6
7 private $db, $mdb;
8 private $migration_table = 'schema_migrations';
9 private $migration_path;
10
11 public function __construct($host, $database, $username, $password, $migration_path)
12 {
13 $this->db_host = $this->mdb_host = $host;
14 $this->db_database = $this->mdb_database = $database;
15 $this->db_username = $this->mdb_username = $username;
16 $this->db_password = $this->mdb_password = $password;
17
18 $this->db = $this->mdb = new \PDO("mysql:host=$host;dbname=$database", $username, $password);
19
20 $this->migration_path = $migration_path;
21 }
22
23 public function setMigrationDatabase($host, $database, $username, $password)
24 {
25 $this->mdb_host = $host;
26 $this->mdb_database = $database;
27 $this->mdb_username = $username;
28 $this->mdb_password = $password;
29
30 $this->mdb = new \PDO("mysql:host=$host;dbname=$database", $username, $password);
31 }
32
33 public function setMigrationTable($table)
34 {
35 $this->migration_table = $table;
36 }
37
38 public function diff()
39 {
40 $this->check();
41 $list = $this->getDiffList();
42
43 return $list;
44 }
45
46 public function applydiff()
47 {
48 $this->check();
49 $list = $this->getDiffList();
50
51 $this->db->beginTransaction();
52
53 try
54 {
55 foreach ($list as $file => $sql)
56 {
57 $valid = $this->db->exec($sql);
58
59 if (!$valid)
60 {
61 throw new \Exception($sql);
62 }
63 }
64
65 // TODO: test this for errors as well and roll back the migrations as well
66 $stmt = $this->mdb->prepare("
67 INSERT INTO {$this->migration_table}
68 (version)
69 VALUES
70 (:version)
71 ");
72
73 $stmt->bindParam('version', $file);
74 $stmt->execute();
75
76 $this->db->commit();
77 }
78 catch (\Exception $e)
79 {
80 $this->db->rollBack();
81
82 throw new \Exception($e->getMessage());
83 }
84
85 return $list;
86 }
87
88 private function getDiffList()
89 {
90 $applied_result = $this->mdb->query("
91 SELECT `version`
92 FROM `{$this->migration_table}`
93 ORDER BY `version` DESC
94 ")->fetchAll();
95
96 $applied = [];
97
98 foreach ($applied_result as $a)
99 {
100 $applied[] = $a['version'];
101 }
102
103 $file_list = $this->getFileList();
104
105 $diff = array_diff($file_list, $applied);
106
107 $full_diff = [];
108 foreach ($diff as $d)
109 {
110 $full_diff[$d] = file_get_contents($this->migration_path . '/' . $d);
111 }
112
113 return $full_diff;
114 }
115
116 private function getFileList()
117 {
118 $files = [];
119
120 if ($handle = opendir($this->migration_path))
121 {
122 // read the dir and check for files and sql in the name
123 while (false !== ($file = readdir($handle)))
124 {
125 if (is_file($this->migration_path . '/' . $file) && preg_match("/(\d*)[_](.*)\.sql$/", $file))
126 {
127 $files[] = $file;
128 }
129 }
130
131 closedir($handle);
132 }
133
134 return $files;
135 }
136
137 private function check()
138 {
139
140 $exists = $this->mdb->query('DESC schema_migrations');
141
142 if ($exists === false)
143 {
144 $setup_migrations = <<<EOF
145CREATE TABLE `{$this->migration_table}` (
146 `version` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
147 UNIQUE KEY `unique_schema_migrations` (`version`)
148) ENGINE=InnoDB;
149EOF;
150
151 $this->mdb->exec($setup_migrations);
152 }
153 }
154}