审查视图

application/admin/command/Addon.php 13.0 KB
Karson authored
1 2 3 4 5 6
<?php

namespace app\admin\command;

use think\addons\AddonException;
use think\addons\Service;
7
use think\Config;
Karson authored
8 9 10 11
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
12
use think\Db;
Karson authored
13
use think\Exception;
14
use think\exception\PDOException;
Karson authored
15 16 17

class Addon extends Command
{
蜗牛 authored
18
Karson authored
19 20 21
    protected function configure()
    {
        $this
22 23 24 25 26 27 28
            ->setName('addon')
            ->addOption('name', 'a', Option::VALUE_REQUIRED, 'addon name', null)
            ->addOption('action', 'c', Option::VALUE_REQUIRED, 'action(create/enable/disable/install/uninstall/refresh/upgrade/package)', 'create')
            ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override', null)
            ->addOption('release', 'r', Option::VALUE_OPTIONAL, 'addon release version', null)
            ->addOption('uid', 'u', Option::VALUE_OPTIONAL, 'fastadmin uid', null)
            ->addOption('token', 't', Option::VALUE_OPTIONAL, 'fastadmin token', null)
蜗牛 authored
29
            ->addOption('local', 'l', Option::VALUE_OPTIONAL, 'local package', null)
30
            ->setDescription('Addon manager');
Karson authored
31 32 33 34 35 36
    }

    protected function execute(Input $input, Output $output)
    {
        $name = $input->getOption('name') ?: '';
        $action = $input->getOption('action') ?: '';
37
        if (stripos($name, 'addons/') !== false) {
38 39
            $name = explode('/', $name)[1];
        }
Karson authored
40 41
        //强制覆盖
        $force = $input->getOption('force');
42 43
        //版本
        $release = $input->getOption('release') ?: '';
44 45 46 47
        //uid
        $uid = $input->getOption('uid') ?: '';
        //token
        $token = $input->getOption('token') ?: '';
Karson authored
48 49 50

        include dirname(__DIR__) . DS . 'common.php';
51
        if (!$name) {
Karson authored
52 53
            throw new Exception('Addon name could not be empty');
        }
54
        if (!$action || !in_array($action, ['create', 'disable', 'enable', 'install', 'uninstall', 'refresh', 'upgrade', 'package'])) {
Karson authored
55 56
            throw new Exception('Please input correct action name');
        }
57
58 59
        // 查询一次SQL,判断连接是否正常
        Db::execute("SELECT 1");
60 61

        $addonDir = ADDON_PATH . $name . DS;
62
        switch ($action) {
Karson authored
63 64
            case 'create':
                //非覆盖模式时如果存在则报错
65
                if (is_dir($addonDir) && !$force) {
Karson authored
66 67 68
                    throw new Exception("addon already exists!\nIf you need to create again, use the parameter --force=true ");
                }
                //如果存在先移除
69
                if (is_dir($addonDir)) {
Karson authored
70 71
                    rmdirs($addonDir);
                }
72 73
                mkdir($addonDir, 0755, true);
                mkdir($addonDir . DS . 'controller', 0755, true);
74
                $menuList = \app\common\library\Menu::export($name);
75 76 77
                $createMenu = $this->getCreateMenu($menuList);
                $prefix = Config::get('database.prefix');
                $createTableSql = '';
78
                try {
79
                    $result = Db::query("SHOW CREATE TABLE `" . $prefix . $name . "`;");
80
                    if (isset($result[0]) && isset($result[0]['Create Table'])) {
81 82
                        $createTableSql = $result[0]['Create Table'];
                    }
83
                } catch (PDOException $e) {
蜗牛 authored
84
85 86
                }
Karson authored
87
                $data = [
88 89 90 91 92 93 94
                    'name'               => $name,
                    'addon'              => $name,
                    'addonClassName'     => ucfirst($name),
                    'addonInstallMenu'   => $createMenu ? "\$menu = " . var_export_short($createMenu, "\t") . ";\n\tMenu::create(\$menu);" : '',
                    'addonUninstallMenu' => $menuList ? 'Menu::delete("' . $name . '");' : '',
                    'addonEnableMenu'    => $menuList ? 'Menu::enable("' . $name . '");' : '',
                    'addonDisableMenu'   => $menuList ? 'Menu::disable("' . $name . '");' : '',
Karson authored
95
                ];
96 97 98
                $this->writeToFile("addon", $data, $addonDir . ucfirst($name) . '.php');
                $this->writeToFile("config", $data, $addonDir . 'config.php');
                $this->writeToFile("info", $data, $addonDir . 'info.ini');
99
                $this->writeToFile("controller", $data, $addonDir . 'controller' . DS . 'Index.php');
100
                if ($createTableSql) {
101 102 103 104
                    $createTableSql = str_replace("`" . $prefix, '`__PREFIX__', $createTableSql);
                    file_put_contents($addonDir . 'install.sql', $createTableSql);
                }
Karson authored
105 106 107 108
                $output->info("Create Successed!");
                break;
            case 'disable':
            case 'enable':
109
                try {
Karson authored
110 111
                    //调用启用、禁用的方法
                    Service::$action($name, 0);
112 113
                } catch (AddonException $e) {
                    if ($e->getCode() != -3) {
Karson authored
114 115
                        throw new Exception($e->getMessage());
                    }
116 117 118 119 120 121 122 123 124 125 126
                    if (!$force) {
                        //如果有冲突文件则提醒
                        $data = $e->getData();
                        foreach ($data['conflictlist'] as $k => $v) {
                            $output->warning($v);
                        }
                        $output->info("Are you sure you want to " . ($action == 'enable' ? 'override' : 'delete') . " all those files?  Type 'yes' to continue: ");
                        $line = fgets(STDIN);
                        if (trim($line) != 'yes') {
                            throw new Exception("Operation is aborted!");
                        }
Karson authored
127 128 129
                    }
                    //调用启用、禁用的方法
                    Service::$action($name, 1);
130
                } catch (Exception $e) {
Karson authored
131 132 133 134 135 136
                    throw new Exception($e->getMessage());
                }
                $output->info(ucfirst($action) . " Successed!");
                break;
            case 'install':
                //非覆盖模式时如果存在则报错
137
                if (is_dir($addonDir) && !$force) {
Karson authored
138 139 140
                    throw new Exception("addon already exists!\nIf you need to install again, use the parameter --force=true ");
                }
                //如果存在先移除
141
                if (is_dir($addonDir)) {
Karson authored
142 143
                    rmdirs($addonDir);
                }
蜗牛 authored
144 145
                // 获取本地路径
                $local = $input->getOption('local');
146
                try {
蜗牛 authored
147
                    Service::install($name, 0, ['version' => $release], $local);
148 149
                } catch (AddonException $e) {
                    if ($e->getCode() != -3) {
Karson authored
150 151
                        throw new Exception($e->getMessage());
                    }
152 153 154 155 156 157 158 159 160 161 162
                    if (!$force) {
                        //如果有冲突文件则提醒
                        $data = $e->getData();
                        foreach ($data['conflictlist'] as $k => $v) {
                            $output->warning($v);
                        }
                        $output->info("Are you sure you want to override all those files?  Type 'yes' to continue: ");
                        $line = fgets(STDIN);
                        if (trim($line) != 'yes') {
                            throw new Exception("Operation is aborted!");
                        }
Karson authored
163
                    }
蜗牛 authored
164
                    Service::install($name, 1, ['version' => $release, 'uid' => $uid, 'token' => $token], $local);
165
                } catch (Exception $e) {
Karson authored
166 167 168 169 170 171 172
                    throw new Exception($e->getMessage());
                }

                $output->info("Install Successed!");
                break;
            case 'uninstall':
                //非覆盖模式时如果存在则报错
173
                if (!$force) {
Karson authored
174 175
                    throw new Exception("If you need to uninstall addon, use the parameter --force=true ");
                }
176
                try {
Karson authored
177
                    Service::uninstall($name, 0);
178 179
                } catch (AddonException $e) {
                    if ($e->getCode() != -3) {
Karson authored
180 181
                        throw new Exception($e->getMessage());
                    }
182 183 184 185 186 187 188 189 190 191 192
                    if (!$force) {
                        //如果有冲突文件则提醒
                        $data = $e->getData();
                        foreach ($data['conflictlist'] as $k => $v) {
                            $output->warning($v);
                        }
                        $output->info("Are you sure you want to delete all those files?  Type 'yes' to continue: ");
                        $line = fgets(STDIN);
                        if (trim($line) != 'yes') {
                            throw new Exception("Operation is aborted!");
                        }
Karson authored
193 194
                    }
                    Service::uninstall($name, 1);
195
                } catch (Exception $e) {
Karson authored
196 197 198 199 200 201 202 203 204
                    throw new Exception($e->getMessage());
                }

                $output->info("Uninstall Successed!");
                break;
            case 'refresh':
                Service::refresh();
                $output->info("Refresh Successed!");
                break;
205
            case 'upgrade':
206
                Service::upgrade($name, ['version' => $release, 'uid' => $uid, 'token' => $token]);
207 208 209 210
                $output->info("Upgrade Successed!");
                break;
            case 'package':
                $infoFile = $addonDir . 'info.ini';
211
                if (!is_file($infoFile)) {
212 213 214 215
                    throw new Exception(__('Addon info file was not found'));
                }

                $info = get_addon_info($name);
216
                if (!$info) {
217 218 219
                    throw new Exception(__('Addon info file data incorrect'));
                }
                $infoname = isset($info['name']) ? $info['name'] : '';
220
                if (!$infoname || !preg_match("/^[a-z]+$/i", $infoname) || $infoname != $name) {
221 222 223 224
                    throw new Exception(__('Addon info name incorrect'));
                }

                $infoversion = isset($info['version']) ? $info['version'] : '';
225
                if (!$infoversion || !preg_match("/^\d+\.\d+\.\d+$/i", $infoversion)) {
226 227 228 229
                    throw new Exception(__('Addon info version incorrect'));
                }

                $addonTmpDir = RUNTIME_PATH . 'addons' . DS;
230
                if (!is_dir($addonTmpDir)) {
231 232 233
                    @mkdir($addonTmpDir, 0755, true);
                }
                $addonFile = $addonTmpDir . $infoname . '-' . $infoversion . '.zip';
234
                if (!class_exists('ZipArchive')) {
235 236 237 238 239 240
                    throw new Exception(__('ZinArchive not install'));
                }
                $zip = new \ZipArchive;
                $zip->open($addonFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);

                $files = new \RecursiveIteratorIterator(
蜗牛 authored
241
                    new \RecursiveDirectoryIterator($addonDir), \RecursiveIteratorIterator::LEAVES_ONLY
242 243
                );
244 245
                foreach ($files as $name => $file) {
                    if (!$file->isDir()) {
246
                        $filePath = $file->getRealPath();
247
                        $relativePath = str_replace(DS, '/', substr($filePath, strlen($addonDir)));
248
                        if (!in_array($file->getFilename(), ['.git', '.DS_Store', 'Thumbs.db'])) {
249 250 251 252 253 254 255 256
                            $zip->addFile($filePath, $relativePath);
                        }
                    }
                }
                $zip->close();
                $output->info("Package Successed!");
                break;
蜗牛 authored
257
            default :
Karson authored
258 259 260 261 262
                break;
        }
    }

    /**
263 264 265 266 267 268 269
     * 获取创建菜单的数组
     * @param array $menu
     * @return array
     */
    protected function getCreateMenu($menu)
    {
        $result = [];
270
        foreach ($menu as $k => & $v) {
271 272 273 274
            $arr = [
                'name'  => $v['name'],
                'title' => $v['title'],
            ];
275
            if ($v['icon'] != 'fa fa-circle-o') {
276 277
                $arr['icon'] = $v['icon'];
            }
278
            if ($v['ismenu']) {
279 280
                $arr['ismenu'] = $v['ismenu'];
            }
281
            if (isset($v['childlist']) && $v['childlist']) {
282 283 284 285 286 287 288 289
                $arr['sublist'] = $this->getCreateMenu($v['childlist']);
            }
            $result[] = $arr;
        }
        return $result;
    }

    /**
Karson authored
290 291 292 293 294 295 296 297 298
     * 写入到文件
     * @param string $name
     * @param array $data
     * @param string $pathname
     * @return mixed
     */
    protected function writeToFile($name, $data, $pathname)
    {
        $search = $replace = [];
299
        foreach ($data as $k => $v) {
Karson authored
300 301 302 303 304 305
            $search[] = "{%{$k}%}";
            $replace[] = $v;
        }
        $stub = file_get_contents($this->getStub($name));
        $content = str_replace($search, $replace, $stub);
306
        if (!is_dir(dirname($pathname))) {
Karson authored
307 308 309 310 311 312 313 314 315 316 317 318 319 320
            mkdir(strtolower(dirname($pathname)), 0755, true);
        }
        return file_put_contents($pathname, $content);
    }

    /**
     * 获取基础模板
     * @param string $name
     * @return string
     */
    protected function getStub($name)
    {
        return __DIR__ . '/Addon/stubs/' . $name . '.stub';
    }
蜗牛 authored
321
Karson authored
322
}