Files

292 lines
9.6 KiB
PHP
Raw Permalink Normal View History

2026-08-31 11:33:59 +08:00
<?php
namespace core\plugin\traits;
/**
* 依赖安装 Trait
*/
trait DependencyTrait
{
/**
* 合并 Composer 依赖(后端)
*/
protected function installComposerDeps(): void
{
$pluginInfo = $this->getPluginInfo();
$require = $pluginInfo['require']['composer'] ?? [];
if (empty($require)) {
$this->output("📦 No Composer dependencies to merge");
return;
}
$config = $this->getConfig('dependencies.backend', []);
if (empty($config['enabled'])) {
$this->output("📦 Composer dependency merge disabled");
return;
}
$this->output("📦 Merging Composer dependencies...");
$composerFile = base_path('composer.json');
if (!file_exists($composerFile)) {
$this->output(" ⚠️ composer.json not found");
return;
}
$composerContent = file_get_contents($composerFile);
$composer = json_decode($composerContent, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$this->output(" ⚠️ Invalid composer.json format");
return;
}
$merged = false;
// 合并 require
if (!empty($config['merge_require'])) {
foreach ($require as $package => $version) {
if (!isset($composer['require'][$package])) {
$composer['require'][$package] = $version;
$merged = true;
$this->output(" ➕ Added to require: {$package}:{$version}");
}
}
}
// 保存
if ($merged) {
file_put_contents($composerFile, json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n");
$this->output(" ✅ Composer dependencies merged. Run 'composer install' manually.");
} else {
$this->output(" ℹ️ No new dependencies to merge");
}
}
/**
* 合并 NPM 依赖(前端)
*/
protected function installNpmDeps(): void
{
$pluginInfo = $this->getPluginInfo();
$npmRequire = $pluginInfo['npm_require'] ?? [];
if (empty($npmRequire)) {
$this->output("📦 No NPM dependencies to merge");
return;
}
$projectRoot = $this->getProjectRoot();
// 合并 Admin 端依赖(前端代码统一在 frontend 目录下)
$adminConfig = $this->getConfig('dependencies.admin', []);
if (!empty($adminConfig['enabled'])) {
$adminPath = $this->getFrontendProjectPath('admin');
$this->mergeNpmDeps($npmRequire['admin'] ?? [], $adminPath, 'Admin', $adminConfig);
$this->mergeNpmDeps($npmRequire['common'] ?? [], $adminPath, 'Admin (common)', $adminConfig);
}
// 合并 Web 端依赖
$webConfig = $this->getConfig('dependencies.web', []);
if (!empty($webConfig['enabled'])) {
$webPath = $this->getFrontendProjectPath('web');
$this->mergeNpmDeps($npmRequire['web'] ?? [], $webPath, 'Web', $webConfig);
$this->mergeNpmDeps($npmRequire['common'] ?? [], $webPath, 'Web (common)', $webConfig);
}
}
/**
* 合并 NPM 依赖到 package.json
*/
protected function mergeNpmDeps(array $packages, string $workDir, string $endpoint, array $config): void
{
if (empty($packages) || !is_dir($workDir)) {
return;
}
$packageFile = $workDir . '/package.json';
if (!file_exists($packageFile)) {
$this->output(" ⚠️ {$endpoint}: package.json not found");
return;
}
$packageContent = file_get_contents($packageFile);
$package = json_decode($packageContent, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$this->output(" ⚠️ {$endpoint}: Invalid package.json format");
return;
}
$merged = false;
// 合并 dependencies
if (!empty($config['merge_prod'])) {
foreach ($packages as $pkg => $version) {
if (!isset($package['dependencies'][$pkg])) {
$package['dependencies'][$pkg] = $version;
$merged = true;
$this->output(" ➕ {$endpoint}: Added {$pkg}@{$version}");
}
}
}
// 合并 devDependencies
if (!empty($config['merge_dev'])) {
foreach ($packages as $pkg => $version) {
if (!isset($package['devDependencies'][$pkg])) {
$package['devDependencies'][$pkg] = $version;
$merged = true;
$this->output(" ➕ {$endpoint}: Added dev {$pkg}@{$version}");
}
}
}
// 保存
if ($merged) {
file_put_contents($packageFile, json_encode($package, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n");
$this->output(" ✅ {$endpoint}: Dependencies merged. Run 'npm install' manually.");
}
}
/**
* 移除合并的依赖
*/
protected function removeMergedDependencies(): void
{
$this->output("🗑️ Removing merged dependencies...");
$pluginInfo = $this->getPluginInfo();
// 移除 Composer 依赖
$composerRequire = $pluginInfo['require']['composer'] ?? [];
if (!empty($composerRequire)) {
$this->removeComposerDeps($composerRequire);
}
// 移除 NPM 依赖
$npmRequire = $pluginInfo['npm_require'] ?? [];
if (!empty($npmRequire)) {
// 前端代码统一在 frontend 目录下
$this->removeNpmDeps($npmRequire['admin'] ?? [], $this->getFrontendProjectPath('admin'), 'Admin');
$this->removeNpmDeps($npmRequire['common'] ?? [], $this->getFrontendProjectPath('admin'), 'Admin (common)');
$this->removeNpmDeps($npmRequire['web'] ?? [], $this->getFrontendProjectPath('web'), 'Web');
$this->removeNpmDeps($npmRequire['common'] ?? [], $this->getFrontendProjectPath('web'), 'Web (common)');
}
$this->output(" ✅ Dependencies removed. Run 'composer install' or 'npm install' to update.");
}
/**
* 移除 Composer 依赖
*/
protected function removeComposerDeps(array $packages): void
{
$composerFile = base_path('composer.json');
if (!file_exists($composerFile)) {
return;
}
$composer = json_decode(file_get_contents($composerFile), true);
$removed = false;
foreach ($packages as $package => $version) {
if (isset($composer['require'][$package])) {
unset($composer['require'][$package]);
$removed = true;
$this->output(" ➖ Removed composer: {$package}");
}
}
if ($removed) {
file_put_contents($composerFile, json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n");
}
}
/**
* 移除 NPM 依赖
*/
protected function removeNpmDeps(array $packages, string $workDir, string $endpoint): void
{
if (empty($packages) || !is_dir($workDir)) {
return;
}
$packageFile = $workDir . '/package.json';
if (!file_exists($packageFile)) {
return;
}
$package = json_decode(file_get_contents($packageFile), true);
$removed = false;
foreach ($packages as $pkg => $version) {
// 移除 dependencies
if (isset($package['dependencies'][$pkg])) {
unset($package['dependencies'][$pkg]);
$removed = true;
$this->output(" ➖ {$endpoint}: Removed {$pkg}");
}
// 移除 devDependencies
if (isset($package['devDependencies'][$pkg])) {
unset($package['devDependencies'][$pkg]);
$removed = true;
$this->output(" ➖ {$endpoint}: Removed dev {$pkg}");
}
}
if ($removed) {
file_put_contents($packageFile, json_encode($package, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n");
}
}
/**
* 执行 Shell 命令
*/
protected function runShellCommand(string $command, string $workDir, string $label): void
{
if (!is_dir($workDir)) {
$this->output(" ⚠️ {$label}: Directory not found: {$workDir}");
return;
}
$this->output(" 🔧 {$label}: Running '{$command}'");
try {
$descriptorspec = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];
$process = proc_open($command, $descriptorspec, $pipes, $workDir);
if (is_resource($process)) {
stream_get_contents($pipes[1]);
$error = stream_get_contents($pipes[2]);
foreach ($pipes as $pipe) {
fclose($pipe);
}
$exitCode = proc_close($process);
if ($exitCode === 0) {
$this->output(" ✅ {$label}: Completed successfully");
} else {
$this->output(" ❌ {$label}: Failed with exit code {$exitCode}");
if (!empty($error)) {
$this->output(" Error: {$error}");
}
}
}
} catch (\Throwable $e) {
$this->output(" ❌ {$label}: Error - {$e->getMessage()}");
}
}
}