mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-07-25 22:27:05 -04:00
Add plugin migration system
- Add `runPendingMigrations()` to `PluginManager` for executing plugin-specific migrations. - Create `PluginMigrationModel` for managing plugin migration versions. - Add migration for creating the `plugin_migrations` table to track migration states. Signed-off-by: objec <objecttothis@gmail.com>
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class PluginMigrationsTableCreate extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
helper('migration');
|
||||
execute_script(APPPATH . 'Database/Migrations/sqlscripts/3.5.1_PluginMigrationsTableCreate.sql');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->forge->dropTable('plugin_migrations', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
CREATE TABLE IF NOT EXISTS `ospos_plugin_migrations` (
|
||||
`plugin_id` varchar(100) NOT NULL,
|
||||
`version` bigint(20) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`ran_at` datetime NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||
PRIMARY KEY (`plugin_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Libraries\Plugins;
|
||||
|
||||
use App\Models\PluginConfig;
|
||||
use App\Models\PluginMigrationModel;
|
||||
use CodeIgniter\Events\Events;
|
||||
use Config\Database;
|
||||
use Config\Services;
|
||||
@@ -82,6 +83,8 @@ class PluginManager
|
||||
return;
|
||||
}
|
||||
|
||||
$this->runPendingMigrations();
|
||||
|
||||
foreach ($this->plugins as $pluginId => $plugin) {
|
||||
if ($this->isPluginEnabled($pluginId)) {
|
||||
$this->enabledPlugins[$pluginId] = $plugin;
|
||||
@@ -93,6 +96,71 @@ class PluginManager
|
||||
$this->eventsRegistered = true;
|
||||
}
|
||||
|
||||
private function runPendingMigrations(): void
|
||||
{
|
||||
if (session()->get('plugin_migrations_ran')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$migrationModel = new PluginMigrationModel();
|
||||
$db = Database::connect();
|
||||
$forge = Database::forge();
|
||||
|
||||
foreach ($this->plugins as $pluginId => $plugin) {
|
||||
if (!$this->isPluginEnabled($pluginId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parts = explode('\\', get_class($plugin));
|
||||
if (count($parts) < 4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$pluginDirName = $parts[2];
|
||||
$migrationsPath = APPPATH . "Plugins/{$pluginDirName}/Migrations/";
|
||||
|
||||
if (!is_dir($migrationsPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$files = glob($migrationsPath . '*.php') ?: [];
|
||||
$migrationFiles = array_filter($files, static fn($f) => preg_match('/\/\d{14}_/', $f));
|
||||
sort($migrationFiles);
|
||||
|
||||
$currentVersion = $migrationModel->getVersion($pluginId);
|
||||
|
||||
foreach ($migrationFiles as $file) {
|
||||
$basename = basename($file, '.php');
|
||||
$timestamp = (int) substr($basename, 0, 14);
|
||||
|
||||
if ($timestamp <= $currentVersion) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$className = substr($basename, 15); // strip "20260627120000_"
|
||||
$fqcn = "App\\Plugins\\{$pluginDirName}\\Migrations\\{$className}";
|
||||
|
||||
require_once $file;
|
||||
|
||||
if (!class_exists($fqcn)) {
|
||||
log_message('error', "Plugin migration class not found: {$fqcn}");
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
(new $fqcn($db, $forge))->up();
|
||||
$migrationModel->setVersion($pluginId, $timestamp);
|
||||
log_message('info', "Plugin migration ran: {$pluginId} v{$timestamp}");
|
||||
} catch (Throwable $e) {
|
||||
log_message('error', "Plugin migration failed: {$pluginId} v{$timestamp}: " . $e->getMessage());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
session()->set('plugin_migrations_ran', true);
|
||||
}
|
||||
|
||||
public function getAllPlugins(): array
|
||||
{
|
||||
return $this->plugins;
|
||||
|
||||
43
app/Models/PluginMigrationModel.php
Normal file
43
app/Models/PluginMigrationModel.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class PluginMigrationModel extends Model
|
||||
{
|
||||
protected $table = 'plugin_migrations';
|
||||
protected $primaryKey = 'plugin_id';
|
||||
protected $useAutoIncrement = false;
|
||||
protected $useSoftDeletes = false;
|
||||
protected $allowedFields = ['plugin_id', 'version', 'ran_at'];
|
||||
|
||||
public function getVersion(string $pluginId): int
|
||||
{
|
||||
$row = $this->db->table('plugin_migrations')
|
||||
->where('plugin_id', $pluginId)
|
||||
->get()
|
||||
->getRow();
|
||||
|
||||
return $row ? (int) $row->version : 0;
|
||||
}
|
||||
|
||||
public function setVersion(string $pluginId, int $version): bool
|
||||
{
|
||||
$builder = $this->db->table('plugin_migrations');
|
||||
$exists = $builder->where('plugin_id', $pluginId)->countAllResults() > 0;
|
||||
|
||||
if (!$exists) {
|
||||
return $builder->insert([
|
||||
'plugin_id' => $pluginId,
|
||||
'version' => $version,
|
||||
'ran_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
}
|
||||
|
||||
return $builder->update(
|
||||
['version' => $version, 'ran_at' => date('Y-m-d H:i:s')],
|
||||
['plugin_id' => $pluginId]
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user