Files
nnterp-react-admin/app/Console/Commands/InstallCommand.php
2026-03-13 20:49:46 +08:00

170 lines
5.1 KiB
PHP

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
use App\Models\AddOn;
use Illuminate\Support\Facades\DB;
class InstallCommand extends Command
{
protected $signature = 'app:install
{--force : Force installation even if already installed}';
protected $description = 'Install the application';
public function handle()
{
if ($this->isInstalled() && !$this->option('force')) {
$this->error('Application is already installed. Use --force to reinstall.');
return 1;
}
$this->info('Starting application installation...');
// Generate app key if not exists
if (empty(config('app.key'))) {
$this->info('Generating application key...');
Artisan::call('key:generate', ['--force' => true]);
}
// Handle foreign key constraints based on database type
$dbType = config('database.default');
if ($dbType === 'mysql') {
DB::statement('SET FOREIGN_KEY_CHECKS=0');
}
// Drop all tables if they exist
Artisan::call('migrate:fresh', ['--force' => true]);
if ($dbType === 'mysql') {
DB::statement('SET FOREIGN_KEY_CHECKS=1');
}
Artisan::call('db:seed', ['--force' => true]);
// Install packages
$this->installPackages();
// Create installed file
$this->createInstalledFile();
$this->info('Application installed successfully!');
return 0;
}
private function createInstalledFile()
{
File::put(storage_path('installed'), 'install ' . date('Y-m-d H:i:s'));
}
private function installPackages()
{
$this->info('Installing packages...');
try {
$modules = $this->getAllAvailableModules();
foreach ($modules as $module) {
$this->info("Installing module: {$module['alias']}");
try {
$this->enableModule($module['name']);
$this->info("✓ Module {$module['alias']} installed successfully");
} catch (\Exception $e) {
$this->error("✗ Failed to install {$module['alias']}: " . $e->getMessage());
}
}
$this->info('All packages installed successfully.');
} catch (\Exception $e) {
$this->error('Package installation failed: ' . $e->getMessage());
}
}
private function getAllAvailableModules()
{
$modules = [];
$packagesPath = base_path('packages/workdo');
if (!File::exists($packagesPath)) {
return $modules;
}
$directories = File::directories($packagesPath);
foreach ($directories as $directory) {
$moduleName = basename($directory);
$moduleJsonPath = "{$directory}/module.json";
if (File::exists($moduleJsonPath)) {
$moduleData = json_decode(File::get($moduleJsonPath), true);
if ($moduleData) {
$modules[] = [
'name' => $moduleData['name'],
'alias' => $moduleData['alias'],
'description' => $moduleData['description'] ?? '',
'priority' => $moduleData['priority'] ?? 10,
];
}
}
}
usort($modules, function ($a, $b) {
return $a['priority'] - $b['priority'];
});
return $modules;
}
private function enableModule($moduleName)
{
// Validate module name to prevent path traversal
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $moduleName)) {
throw new \Exception('Invalid module name');
}
$addon = AddOn::where('module', $moduleName)->first();
if (empty($addon)) {
$filePath = base_path('packages/workdo/' . $moduleName . '/module.json');
if (!file_exists($filePath)) {
throw new \Exception('Module configuration not found');
}
$jsonContent = file_get_contents($filePath);
$data = json_decode($jsonContent, true);
if (!$data) {
throw new \Exception('Invalid module configuration');
}
Artisan::call('package:seed ' . $moduleName);
$addon = new AddOn;
$addon->module = $data['name'];
$addon->name = $data['alias'];
$addon->monthly_price = $data['monthly_price'] ?? 0;
$addon->yearly_price = $data['yearly_price'] ?? 0;
$addon->package_name = $data['package_name'] ?? null;
$addon->for_admin = $data['for_admin'] ?? false;
$addon->priority = $data['priority'] ?? 0;
$addon->is_enable = 1;
$addon->save();
} else {
Artisan::call('package:seed ' . $moduleName);
$addon->is_enable = 1;
$addon->save();
}
}
private function isInstalled(): bool
{
return File::exists(storage_path('installed'));
}
}