migration.abstract.class.php 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. <?php
  2. namespace Juju\SQL;
  3. require_once(realpath(dirname(__DIR__).'/sql.class.php'));
  4. use Juju\{SQL, Settings};
  5. abstract class Migration {
  6. public abstract static function up();
  7. public abstract static function down();
  8. public abstract static function change();
  9. const MIGRATE_UP = 'up';
  10. const MIGRATE_DOWN = 'down';
  11. private static $sql;
  12. final public static function version(){
  13. $name = get_called_class();
  14. return substr($name, strrpos($name, '\\') + 1);
  15. }
  16. final public static function version_table(){
  17. if(!class_exists("Juju\\Settings")){
  18. throw new \Exception("Settings not loaded");
  19. }
  20. return Settings::get('db.versions');
  21. }
  22. final public static function installed(){
  23. return self::$sql->query(
  24. "select count(1) count ".
  25. "from `".self::version_table()."` ".
  26. "where version = ?",
  27. 's',
  28. static::version()
  29. )->assoc_result['count'] == 1;
  30. }
  31. final public static function migrations(){
  32. $migrations = array_filter(get_declared_classes(), function($class){
  33. return 0 === strpos($class, "Migration\\");
  34. });
  35. sort($migrations);
  36. return $migrations;
  37. }
  38. final public static function migrate(string $direction, int $amount = 1){
  39. if($amount < 1){
  40. throw new \Exception("Migration amount must be a positive integer");
  41. }
  42. $table = self::version_table();
  43. $sql = self::$sql;
  44. if(count($sql->query("show tables like '{$table}'")->assoc_results) == 0){
  45. $sql->query("CREATE TABLE `{$table}` (version varchar(100) NOT NULL, primary key (version))")->execute();
  46. }
  47. switch($direction){
  48. case self::MIGRATE_UP:
  49. foreach(self::migrations() as $migration){
  50. if(!$migration::installed()){
  51. $migration::up();
  52. $sql->query(
  53. "insert into `{$table}` set version = ?",
  54. 's',
  55. $migration::version()
  56. )->execute();
  57. if(--$amount == 0){
  58. break;
  59. }
  60. }
  61. }
  62. break;
  63. case self::MIGRATE_DOWN:
  64. foreach(array_reverse(self::migrations()) as $migration){
  65. if($migration::installed()){
  66. $migration::down();
  67. $sql->query(
  68. "delete from `{$table}` where version = ?",
  69. 's',
  70. $migration::version()
  71. )->execute();
  72. if(--$amount == 0){
  73. break;
  74. }
  75. }
  76. }
  77. break;
  78. default:
  79. throw new \Exception("Invalid migration direction '{$direction}'");
  80. }
  81. }
  82. final public static function migrate_all(string $direction){
  83. self::migrate($direction, count(self::migrations()));
  84. }
  85. final public static function bind(string $dsn){
  86. self::$sql = SQL::FromDSN($dsn);
  87. }
  88. final public static function release(){
  89. $sql = self::$sql;
  90. unset($sql);
  91. self::$sql = null;
  92. }
  93. }
  94. ?>