<?php
declare(strict_types=1);
* +----------------------------------------------------------------------
* | ThinkAdmin Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\support\command;
use think\admin\extend\ToolsExtend;
use think\admin\service\ModuleService;
use think\admin\service\RuntimeService;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
* 组件安装指令.
* @class Publish
*/
class Publish extends Command
{
* 任务参数配置.
*/
public function configure()
{
$this->setName('xadmin:publish');
$this->addOption('force', 'f', Option::VALUE_NONE, 'Overwrite any existing files');
$this->addOption('migrate', 'm', Option::VALUE_NONE, 'Execute phinx database script');
$this->setDescription('Publish Plugs and Config Assets for ThinkAdmin');
}
* 任务合并执行.
* @return null|void
*/
public function execute(Input $input, Output $output)
{
RuntimeService::clear(false);
$this->parse()->plugin()->output->writeln('<info>Succeed!</info>');
}
* 安装数据库.
* @return $this
*/
private function plugin(): Publish
{
$force = boolval($this->input->getOption('force'));
foreach (ModuleService::getModules() as $appName) {
$appPath = $this->app->getBasePath() . $appName;
is_dir($appPath) && $this->copy($appPath, $force);
}
if ($this->input->getOption('migrate')) {
$this->app->console->call('migrate:run', [], 'console');
}
return $this;
}
* 初始化组件文件.
* @param string $copy 应用资源目录
* @param bool $force 是否强制替换
*/
private function copy(string $copy, bool $force = false)
{
$frdir = rtrim($copy, '\/') . DIRECTORY_SEPARATOR . 'config';
ToolsExtend::copy($frdir, syspath('config'), [], $force, false);
$frdir = rtrim($copy, '\/') . DIRECTORY_SEPARATOR . 'public';
ToolsExtend::copy($frdir, syspath('public'), [], true, false);
$frdir = rtrim($copy, '\/') . DIRECTORY_SEPARATOR . 'database';
$this->cleanupPublishedMigrations($frdir, syspath('database/migrations'));
ToolsExtend::copy($frdir, syspath('database/migrations'), [], $force, false);
}
* 清理已改名但仍残留在根目录的旧迁移脚本.
*/
private function cleanupPublishedMigrations(string $source, string $target): void
{
if (!is_dir($source) || !is_dir($target)) {
return;
}
$sourceMigrations = [];
foreach (ToolsExtend::find($source, 1, function (\SplFileInfo $info) {
return $info->isFile() && strtolower($info->getExtension()) === 'php';
}) as $file) {
$name = basename($file);
if (preg_match('/^\d{14}_(.+\.php)$/', $name, $match)) {
$sourceMigrations[$match[1]] = $name;
}
}
if (empty($sourceMigrations)) {
return;
}
foreach (ToolsExtend::find($target, 1, function (\SplFileInfo $info) {
return $info->isFile() && strtolower($info->getExtension()) === 'php';
}) as $file) {
$name = basename($file);
if (!preg_match('/^(\d{14})_(.+\.php)$/', $name, $match)) {
continue;
}
[$version, $suffix] = [$match[1], $match[2]];
if (($sourceMigrations[$suffix] ?? $name) === $name) {
continue;
}
@unlink(rtrim($target, '\/') . DIRECTORY_SEPARATOR . $name);
if (is_dir($dataPath = rtrim($target, '\/') . DIRECTORY_SEPARATOR . $version)) {
ToolsExtend::remove($dataPath);
}
}
}
* 解析 json 包.
* @return $this
*/
private function parse(): Publish
{
[$services, $versions] = [[], []];
if (is_file($file = syspath('vendor/composer/installed.json'))) {
$packages = json_decode(@file_get_contents($file), true);
foreach ($packages['packages'] ?? $packages as $package) {
$type = $package['type'] ?? '';
$config = $package['extra']['config'] ?? [];
$versions[$package['name']] = [
'type' => $config['type'] ?? ($type === 'think-admin-plugin' ? 'plugin' : 'library'),
'name' => $config['name'] ?? ($package['name'] ?? ''),
'icon' => $config['icon'] ?? '',
'cover' => $config['cover'] ?? '',
'super' => $config['super'] ?? false,
'license' => (array)($config['license'] ?? ($package['license'] ?? [])),
'version' => $config['version'] ?? ($package['version'] ?? ''),
'homepage' => $config['homepage'] ?? ($package['homepage'] ?? ''),
'document' => $config['document'] ?? ($package['document'] ?? ''),
'platforms' => $config['platforms'] ?? [],
'description' => $config['description'] ?? ($package['description'] ?? ''),
];
if (!empty($package['extra']['think']['services'])) {
$services = array_merge($services, (array)$package['extra']['think']['services']);
}
if (!empty($package['extra']['think']['config'])) {
$configPath = $this->app->getConfigPath();
$installPath = syspath("vendor/{$package['name']}/");
foreach ((array)$package['extra']['think']['config'] as $name => $file) {
if (is_file($target = $configPath . $name . '.php')) {
$this->output->info("File {$target} exist!");
continue;
}
if (!is_file($source = $installPath . $file)) {
$this->output->info("File {$source} not exist!");
continue;
}
copy($source, $target);
}
}
}
}
$header = '// Automatically Generated At: ' . date('Y-m-d H:i:s') . PHP_EOL . 'declare(strict_types=1);';
$content = '<?php' . PHP_EOL . $header . PHP_EOL . 'return ' . var_export($services, true) . ';';
@file_put_contents(syspath('vendor/services.php'), $content);
$content = '<?php' . PHP_EOL . $header . PHP_EOL . 'return ' . var_export($versions, true) . ';';
@file_put_contents(syspath('vendor/versions.php'), preg_replace('#\s+=>\s+array\s+\(#m', ' => array (', $content));
return $this;
}
}