first commit
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
build
|
||||
vendor
|
||||
.idea
|
||||
.vscode
|
||||
.phpunit*
|
||||
composer.lock
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
# console
|
||||
webman console
|
||||
https://www.workerman.net/plugin/1
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "webman/console",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"webman console"
|
||||
],
|
||||
"homepage": "http://www.workerman.net",
|
||||
"license": "MIT",
|
||||
"description": "Webman console",
|
||||
"authors": [
|
||||
{
|
||||
"name": "walkor",
|
||||
"email": "walkor@workerman.net",
|
||||
"homepage": "http://www.workerman.net",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"email": "walkor@workerman.net",
|
||||
"issues": "https://github.com/webman-php/console/issues",
|
||||
"forum": "http://www.workerman.net/questions",
|
||||
"wiki": "http://www.workerman.net/doc/webman",
|
||||
"source": "https://github.com/webman-php/console"
|
||||
},
|
||||
"require": {
|
||||
"symfony/console": ">=5.0",
|
||||
"doctrine/inflector": "^2.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webman\\Console\\" : "src"
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"workerman/webman": "^1.0"
|
||||
}
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
namespace Webman\Console;
|
||||
|
||||
use support\Container;
|
||||
use support\Log;
|
||||
use support\Request;
|
||||
use Webman\App;
|
||||
use Webman\Config;
|
||||
use Workerman\Connection\TcpConnection;
|
||||
use Workerman\Protocols\Http;
|
||||
use Workerman\Worker;
|
||||
use Dotenv\Dotenv;
|
||||
|
||||
ini_set('display_errors', 'on');
|
||||
error_reporting(E_ALL);
|
||||
|
||||
|
||||
class Application
|
||||
{
|
||||
public static function run()
|
||||
{
|
||||
$runtime_logs_path = runtime_path() . DIRECTORY_SEPARATOR . 'logs';
|
||||
if ( !file_exists($runtime_logs_path) || !is_dir($runtime_logs_path) ) {
|
||||
if (!mkdir($runtime_logs_path,0777,true)) {
|
||||
throw new \RuntimeException("Failed to create runtime logs directory. Please check the permission.");
|
||||
}
|
||||
}
|
||||
|
||||
$runtime_views_path = runtime_path() . DIRECTORY_SEPARATOR . 'views';
|
||||
if ( !file_exists($runtime_views_path) || !is_dir($runtime_views_path) ) {
|
||||
if (!mkdir($runtime_views_path,0777,true)) {
|
||||
throw new \RuntimeException("Failed to create runtime views directory. Please check the permission.");
|
||||
}
|
||||
}
|
||||
|
||||
if (class_exists('Dotenv\Dotenv') && file_exists(base_path() . '/.env')) {
|
||||
if (method_exists('Dotenv\Dotenv', 'createUnsafeImmutable')) {
|
||||
Dotenv::createUnsafeImmutable(base_path())->load();
|
||||
} else {
|
||||
Dotenv::createMutable(base_path())->load();
|
||||
}
|
||||
}
|
||||
|
||||
Config::reload(config_path(), ['route', 'container']);
|
||||
|
||||
Worker::$onMasterReload = function (){
|
||||
if (function_exists('opcache_get_status')) {
|
||||
if ($status = opcache_get_status()) {
|
||||
if (isset($status['scripts']) && $scripts = $status['scripts']) {
|
||||
foreach (array_keys($scripts) as $file) {
|
||||
opcache_invalidate($file, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$config = config('server');
|
||||
Worker::$pidFile = $config['pid_file'];
|
||||
Worker::$stdoutFile = $config['stdout_file'];
|
||||
Worker::$logFile = $config['log_file'];
|
||||
Worker::$eventLoopClass = $config['event_loop'] ?? '';
|
||||
TcpConnection::$defaultMaxPackageSize = $config['max_package_size'] ?? 10*1024*1024;
|
||||
if (property_exists(Worker::class, 'statusFile')) {
|
||||
Worker::$statusFile = $config['status_file'] ?? '';
|
||||
}
|
||||
if (property_exists(Worker::class, 'stopTimeout')) {
|
||||
Worker::$stopTimeout = $config['stop_timeout'] ?? 2;
|
||||
}
|
||||
|
||||
if ($config['listen']) {
|
||||
$worker = new Worker($config['listen'], $config['context']);
|
||||
$property_map = [
|
||||
'name',
|
||||
'count',
|
||||
'user',
|
||||
'group',
|
||||
'reusePort',
|
||||
'transport',
|
||||
'protocol'
|
||||
];
|
||||
foreach ($property_map as $property) {
|
||||
if (isset($config[$property])) {
|
||||
$worker->$property = $config[$property];
|
||||
}
|
||||
}
|
||||
|
||||
$worker->onWorkerStart = function ($worker) {
|
||||
require_once base_path() . '/support/bootstrap.php';
|
||||
$app = new App($worker, Container::instance(), Log::channel('default'), app_path(), public_path());
|
||||
Http::requestClass(config('app.request_class', config('server.request_class', Request::class)));
|
||||
$worker->onMessage = [$app, 'onMessage'];
|
||||
};
|
||||
}
|
||||
|
||||
// Windows does not support custom processes.
|
||||
if (\DIRECTORY_SEPARATOR === '/') {
|
||||
foreach (config('process', []) as $process_name => $config) {
|
||||
// Remove monitor process.
|
||||
if (class_exists(\Phar::class, false) && \Phar::running() && 'monitor' === $process_name) {
|
||||
continue;
|
||||
}
|
||||
worker_start($process_name, $config);
|
||||
}
|
||||
foreach (config('plugin', []) as $firm => $projects) {
|
||||
foreach ($projects as $name => $project) {
|
||||
foreach ($project['process'] ?? [] as $process_name => $config) {
|
||||
worker_start("plugin.$firm.$name.$process_name", $config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Worker::runAll();
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console;
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Command\Command as Commands;
|
||||
use support\Container;
|
||||
|
||||
class Command extends Application
|
||||
{
|
||||
public function installInternalCommands()
|
||||
{
|
||||
$this->installCommands(__DIR__ . '/Commands', 'Webman\Console\Commands');
|
||||
}
|
||||
|
||||
public function installCommands($path, $namspace = 'app\command')
|
||||
{
|
||||
$dir_iterator = new \RecursiveDirectoryIterator($path);
|
||||
$iterator = new \RecursiveIteratorIterator($dir_iterator);
|
||||
foreach ($iterator as $file) {
|
||||
/** @var \SplFileInfo $file */
|
||||
if (strpos($file->getFilename(), '.') === 0) {
|
||||
continue;
|
||||
}
|
||||
if ($file->getExtension() !== 'php') {
|
||||
continue;
|
||||
}
|
||||
// abc\def.php
|
||||
$relativePath = str_replace(str_replace('/', '\\', $path . '\\'), '', str_replace('/', '\\', $file->getRealPath()));
|
||||
// app\command\abc
|
||||
$realNamespace = trim($namspace . '\\' . trim(dirname(str_replace('\\', DIRECTORY_SEPARATOR, $relativePath)), '.'), '\\');
|
||||
// app\command\doc\def
|
||||
$class_name = trim($realNamespace . '\\' . $file->getBasename('.php'), '\\');
|
||||
if (!class_exists($class_name) || !is_a($class_name, Commands::class, true)) {
|
||||
continue;
|
||||
}
|
||||
$this->add(Container::get($class_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,507 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Webman\Console\Util;
|
||||
|
||||
class AppPluginCreateCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'app-plugin:create';
|
||||
protected static $defaultDescription = 'App Plugin Create';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument('name', InputArgument::REQUIRED, 'App plugin name');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
$output->writeln("Create App Plugin $name");
|
||||
|
||||
if (strpos($name, '/') !== false) {
|
||||
$output->writeln('<error>Bad name, name must not contain character \'/\'</error>');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
// Create dir config/plugin/$name
|
||||
if (is_dir($plugin_config_path = base_path()."/plugin/$name")) {
|
||||
$output->writeln("<error>Dir $plugin_config_path already exists</error>");
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$this->createAll($name);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return void
|
||||
*/
|
||||
protected function createAll($name)
|
||||
{
|
||||
$base_path = base_path();
|
||||
$this->mkdir("$base_path/plugin/$name/app/controller", 0777, true);
|
||||
$this->mkdir("$base_path/plugin/$name/app/exception", 0777, true);
|
||||
$this->mkdir("$base_path/plugin/$name/app/model", 0777, true);
|
||||
$this->mkdir("$base_path/plugin/$name/app/middleware", 0777, true);
|
||||
$this->mkdir("$base_path/plugin/$name/app/view/index", 0777, true);
|
||||
$this->mkdir("$base_path/plugin/$name/config", 0777, true);
|
||||
$this->mkdir("$base_path/plugin/$name/public", 0777, true);
|
||||
$this->mkdir("$base_path/plugin/$name/api", 0777, true);
|
||||
$this->createFunctionsFile("$base_path/plugin/$name/app/functions.php");
|
||||
$this->createControllerFile("$base_path/plugin/$name/app/controller/IndexController.php", $name);
|
||||
$this->createViewFile("$base_path/plugin/$name/app/view/index/index.html");
|
||||
$this->createExceptionFile("$base_path/plugin/$name/app/exception/Handler.php", $name);
|
||||
$this->createConfigFiles("$base_path/plugin/$name/config", $name);
|
||||
$this->createApiFiles("$base_path/plugin/$name/api", $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @return void
|
||||
*/
|
||||
protected function mkdir($path)
|
||||
{
|
||||
if (is_dir($path)) {
|
||||
return;
|
||||
}
|
||||
echo "Create $path\r\n";
|
||||
mkdir($path, 0777, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @param $name
|
||||
* @return void
|
||||
*/
|
||||
protected function createControllerFile($path, $name)
|
||||
{
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
|
||||
namespace plugin\\$name\\app\\controller;
|
||||
|
||||
use support\\Request;
|
||||
|
||||
class IndexController
|
||||
{
|
||||
|
||||
public function index()
|
||||
{
|
||||
return view('index/index', ['name' => '$name']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EOF;
|
||||
file_put_contents($path, $content);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @return void
|
||||
*/
|
||||
protected function createViewFile($path)
|
||||
{
|
||||
$content = <<<EOF
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="shortcut icon" href="/favicon.ico"/>
|
||||
<title>webman app plugin</title>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
hello <?=htmlspecialchars(\$name)?>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
EOF;
|
||||
file_put_contents($path, $content);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @return void
|
||||
*/
|
||||
protected function createExceptionFile($path, $name)
|
||||
{
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
namespace plugin\\$name\\app\\exception;
|
||||
|
||||
use Throwable;
|
||||
use Webman\\Http\\Request;
|
||||
use Webman\\Http\\Response;
|
||||
|
||||
/**
|
||||
* Class Handler
|
||||
* @package Support\Exception
|
||||
*/
|
||||
class Handler extends \\support\\exception\\Handler
|
||||
{
|
||||
public function render(Request \$request, Throwable \$exception): Response
|
||||
{
|
||||
\$code = \$exception->getCode();
|
||||
if (\$request->expectsJson()) {
|
||||
\$json = ['code' => \$code ? \$code : 500, 'message' => \$this->_debug ? \$exception->getMessage() : 'Server internal error', 'type' => 'failed'];
|
||||
\$this->_debug && \$json['traces'] = (string)\$exception;
|
||||
return new Response(200, ['Content-Type' => 'application/json'],
|
||||
\json_encode(\$json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
\$error = \$this->_debug ? \\nl2br((string)\$exception) : 'Server internal error';
|
||||
return new Response(500, [], \$error);
|
||||
}
|
||||
}
|
||||
|
||||
EOF;
|
||||
file_put_contents($path, $content);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
* @return void
|
||||
*/
|
||||
protected function createFunctionsFile($file)
|
||||
{
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
/**
|
||||
* Here is your custom functions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
EOF;
|
||||
file_put_contents($file, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $base
|
||||
* @param $name
|
||||
* @return void
|
||||
*/
|
||||
protected function createApiFiles($base, $name)
|
||||
{
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
|
||||
namespace plugin\\$name\api;
|
||||
|
||||
use plugin\admin\api\Menu;
|
||||
|
||||
class Install
|
||||
{
|
||||
/**
|
||||
* 安装
|
||||
*
|
||||
* @param \$version
|
||||
* @return void
|
||||
*/
|
||||
public static function install(\$version)
|
||||
{
|
||||
// 导入菜单
|
||||
Menu::import(static::getMenus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 卸载
|
||||
*
|
||||
* @param \$version
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstall(\$version)
|
||||
{
|
||||
// 删除菜单
|
||||
foreach (static::getMenus() as \$menu) {
|
||||
Menu::delete(\$menu['name']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新
|
||||
*
|
||||
* @param \$from_version
|
||||
* @param \$to_version
|
||||
* @param \$context
|
||||
* @return void
|
||||
*/
|
||||
public static function update(\$from_version, \$to_version, \$context = null)
|
||||
{
|
||||
// 删除不用的菜单
|
||||
if (isset(\$context['previous_menus'])) {
|
||||
static::removeUnnecessaryMenus(\$context['previous_menus']);
|
||||
}
|
||||
// 导入新菜单
|
||||
Menu::import(static::getMenus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新前数据收集等
|
||||
*
|
||||
* @param \$from_version
|
||||
* @param \$to_version
|
||||
* @return array|array[]
|
||||
*/
|
||||
public static function beforeUpdate(\$from_version, \$to_version)
|
||||
{
|
||||
// 在更新之前获得老菜单,通过context传递给 update
|
||||
return ['previous_menus' => static::getMenus()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
public static function getMenus()
|
||||
{
|
||||
clearstatcache();
|
||||
if (is_file(\$menu_file = __DIR__ . '/../config/menu.php')) {
|
||||
\$menus = include \$menu_file;
|
||||
return \$menus ?: [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除不需要的菜单
|
||||
*
|
||||
* @param \$previous_menus
|
||||
* @return void
|
||||
*/
|
||||
public static function removeUnnecessaryMenus(\$previous_menus)
|
||||
{
|
||||
\$menus_to_remove = array_diff(Menu::column(\$previous_menus, 'name'), Menu::column(static::getMenus(), 'name'));
|
||||
foreach (\$menus_to_remove as \$name) {
|
||||
Menu::delete(\$name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
EOF;
|
||||
|
||||
file_put_contents("$base/Install.php", $content);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $base
|
||||
* @param $name
|
||||
* @return void
|
||||
*/
|
||||
protected function createConfigFiles($base, $name)
|
||||
{
|
||||
// app.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
|
||||
use support\\Request;
|
||||
|
||||
return [
|
||||
'debug' => true,
|
||||
'controller_suffix' => 'Controller',
|
||||
'controller_reuse' => false,
|
||||
];
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/app.php", $content);
|
||||
|
||||
// menu.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
|
||||
return [];
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/menu.php", $content);
|
||||
|
||||
// autoload.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
return [
|
||||
'files' => [
|
||||
base_path() . '/plugin/$name/app/functions.php',
|
||||
]
|
||||
];
|
||||
EOF;
|
||||
file_put_contents("$base/autoload.php", $content);
|
||||
|
||||
// container.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
return new Webman\\Container;
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/container.php", $content);
|
||||
|
||||
|
||||
// database.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
return [];
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/database.php", $content);
|
||||
|
||||
// exception.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
|
||||
return [
|
||||
'' => \\plugin\\$name\\app\\exception\\Handler::class,
|
||||
];
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/exception.php", $content);
|
||||
|
||||
// log.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
|
||||
return [
|
||||
'default' => [
|
||||
'handlers' => [
|
||||
[
|
||||
'class' => Monolog\\Handler\\RotatingFileHandler::class,
|
||||
'constructor' => [
|
||||
runtime_path() . '/logs/$name.log',
|
||||
7,
|
||||
Monolog\\Logger::DEBUG,
|
||||
],
|
||||
'formatter' => [
|
||||
'class' => Monolog\\Formatter\\LineFormatter::class,
|
||||
'constructor' => [null, 'Y-m-d H:i:s', true],
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/log.php", $content);
|
||||
|
||||
// middleware.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
|
||||
return [
|
||||
'' => [
|
||||
|
||||
]
|
||||
];
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/middleware.php", $content);
|
||||
|
||||
// process.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
return [];
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/process.php", $content);
|
||||
|
||||
// redis.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
return [
|
||||
'default' => [
|
||||
'host' => '127.0.0.1',
|
||||
'password' => null,
|
||||
'port' => 6379,
|
||||
'database' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/redis.php", $content);
|
||||
|
||||
// route.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
|
||||
use Webman\\Route;
|
||||
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/route.php", $content);
|
||||
|
||||
// static.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
|
||||
return [
|
||||
'enable' => true,
|
||||
'middleware' => [], // Static file Middleware
|
||||
];
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/static.php", $content);
|
||||
|
||||
// translation.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
|
||||
return [
|
||||
// Default language
|
||||
'locale' => 'zh_CN',
|
||||
// Fallback language
|
||||
'fallback_locale' => ['zh_CN', 'en'],
|
||||
// Folder where language files are stored
|
||||
'path' => "$base/resource/translations",
|
||||
];
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/translation.php", $content);
|
||||
|
||||
// view.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
|
||||
use support\\view\\Raw;
|
||||
use support\\view\\Twig;
|
||||
use support\\view\\Blade;
|
||||
use support\\view\\ThinkPHP;
|
||||
|
||||
return [
|
||||
'handler' => Raw::class
|
||||
];
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/view.php", $content);
|
||||
|
||||
// thinkorm.php
|
||||
$content = <<<EOF
|
||||
<?php
|
||||
|
||||
return [];
|
||||
|
||||
EOF;
|
||||
file_put_contents("$base/thinkorm.php", $content);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Webman\Console\Application;
|
||||
|
||||
class ConnectionsCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'connections';
|
||||
protected static $defaultDescription = 'Get worker connections.';
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (\class_exists(\Support\App::class)) {
|
||||
\Support\App::run();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
Application::run();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
|
||||
class InstallCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'install';
|
||||
protected static $defaultDescription = 'Execute webman installation script';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$output->writeln("Execute installation for webman");
|
||||
$install_function = "\\Webman\\Install::install";
|
||||
if (is_callable($install_function)) {
|
||||
$install_function();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
$output->writeln('<error>This command requires webman-framework version >= 1.3.0</error>');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Webman\Console\Util;
|
||||
|
||||
|
||||
class MakeBootstrapCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:bootstrap';
|
||||
protected static $defaultDescription = 'Make bootstrap';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument('name', InputArgument::REQUIRED, 'Bootstrap name');
|
||||
$this->addArgument('enable', InputArgument::OPTIONAL, 'Enable or not');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
$enable = in_array($input->getArgument('enable'), ['no', '0', 'false', 'n']) ? false : true;
|
||||
$output->writeln("Make bootstrap $name");
|
||||
|
||||
$name = str_replace('\\', '/', $name);
|
||||
if (!$bootstrap_str = Util::guessPath(app_path(), 'bootstrap')) {
|
||||
$bootstrap_str = Util::guessPath(app_path(), 'controller') === 'Controller' ? 'Bootstrap' : 'bootstrap';
|
||||
}
|
||||
$upper = $bootstrap_str === 'Bootstrap';
|
||||
if (!($pos = strrpos($name, '/'))) {
|
||||
$name = ucfirst($name);
|
||||
$file = app_path() . "/$bootstrap_str/$name.php";
|
||||
$namespace = $upper ? 'App\Bootstrap' : 'app\bootstrap';
|
||||
} else {
|
||||
if($real_name = Util::guessPath(app_path(), $name)) {
|
||||
$name = $real_name;
|
||||
}
|
||||
if ($upper && !$real_name) {
|
||||
$name = preg_replace_callback('/\/([a-z])/', function ($matches) {
|
||||
return '/' . strtoupper($matches[1]);
|
||||
}, ucfirst($name));
|
||||
}
|
||||
$path = "$bootstrap_str/" . substr($upper ? ucfirst($name) : $name, 0, $pos);
|
||||
$name = ucfirst(substr($name, $pos + 1));
|
||||
$file = app_path() . "/$path/$name.php";
|
||||
$namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
|
||||
}
|
||||
|
||||
$this->createBootstrap($name, $namespace, $file);
|
||||
if ($enable) {
|
||||
$this->addConfig("$namespace\\$name", config_path() . '/bootstrap.php');
|
||||
}
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $namespace
|
||||
* @param $file
|
||||
* @return void
|
||||
*/
|
||||
protected function createBootstrap($name, $namespace, $file)
|
||||
{
|
||||
$path = pathinfo($file, PATHINFO_DIRNAME);
|
||||
if (!is_dir($path)) {
|
||||
mkdir($path, 0777, true);
|
||||
}
|
||||
$bootstrap_content = <<<EOF
|
||||
<?php
|
||||
|
||||
namespace $namespace;
|
||||
|
||||
use Webman\Bootstrap;
|
||||
|
||||
class $name implements Bootstrap
|
||||
{
|
||||
public static function start(\$worker)
|
||||
{
|
||||
// Is it console environment ?
|
||||
\$is_console = !\$worker;
|
||||
if (\$is_console) {
|
||||
// If you do not want to execute this in console, just return.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EOF;
|
||||
file_put_contents($file, $bootstrap_content);
|
||||
}
|
||||
|
||||
public function addConfig($class, $config_file)
|
||||
{
|
||||
$config = include $config_file;
|
||||
if(!in_array($class, $config ?? [])) {
|
||||
$config_file_content = file_get_contents($config_file);
|
||||
$config_file_content = preg_replace('/\];/', " $class::class,\n];", $config_file_content);
|
||||
file_put_contents($config_file, $config_file_content);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Webman\Console\Util;
|
||||
|
||||
|
||||
class MakeCommandCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:command';
|
||||
protected static $defaultDescription = 'Make command';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument('name', InputArgument::REQUIRED, 'Command name');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$command = $name = trim($input->getArgument('name'));
|
||||
$output->writeln("Make command $name");
|
||||
|
||||
// make:command 不支持子目录
|
||||
$name = str_replace(['\\', '/'], '', $name);
|
||||
if (!$command_str = Util::guessPath(app_path(), 'command')) {
|
||||
$command_str = Util::guessPath(app_path(), 'controller') === 'Controller' ? 'Command' : 'command';
|
||||
}
|
||||
$items= explode(':', $name);
|
||||
$name='';
|
||||
foreach ($items as $item) {
|
||||
$name.=ucfirst($item);
|
||||
}
|
||||
$file = app_path() . "/$command_str/$name.php";
|
||||
$upper = $command_str === 'Command';
|
||||
$namespace = $upper ? 'App\Command' : 'app\command';
|
||||
$this->createCommand($name, $namespace, $file, $command);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
protected function getClassName($name)
|
||||
{
|
||||
return preg_replace_callback('/:([a-zA-Z])/', function ($matches) {
|
||||
return strtoupper($matches[1]);
|
||||
}, ucfirst($name)) . 'Command';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $namespace
|
||||
* @param $path
|
||||
* @return void
|
||||
*/
|
||||
protected function createCommand($name, $namespace, $file, $command)
|
||||
{
|
||||
$path = pathinfo($file, PATHINFO_DIRNAME);
|
||||
if (!is_dir($path)) {
|
||||
mkdir($path, 0777, true);
|
||||
}
|
||||
$desc = str_replace(':', ' ', $command);
|
||||
$command_content = <<<EOF
|
||||
<?php
|
||||
|
||||
namespace $namespace;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
|
||||
class $name extends Command
|
||||
{
|
||||
protected static \$defaultName = '$command';
|
||||
protected static \$defaultDescription = '$desc';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
\$this->addArgument('name', InputArgument::OPTIONAL, 'Name description');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface \$input
|
||||
* @param OutputInterface \$output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface \$input, OutputInterface \$output)
|
||||
{
|
||||
\$name = \$input->getArgument('name');
|
||||
\$output->writeln('Hello $command');
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EOF;
|
||||
file_put_contents($file, $command_content);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Webman\Console\Util;
|
||||
|
||||
|
||||
class MakeControllerCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:controller';
|
||||
protected static $defaultDescription = 'Make controller';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument('name', InputArgument::REQUIRED, 'Controller name');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
$output->writeln("Make controller $name");
|
||||
$suffix = config('app.controller_suffix', '');
|
||||
|
||||
if ($suffix && !strpos($name, $suffix)) {
|
||||
$name .= $suffix;
|
||||
}
|
||||
|
||||
$name = str_replace('\\', '/', $name);
|
||||
if (!($pos = strrpos($name, '/'))) {
|
||||
$name = ucfirst($name);
|
||||
$controller_str = Util::guessPath(app_path(), 'controller') ?: 'controller';
|
||||
$file = app_path() . "/$controller_str/$name.php";
|
||||
$namespace = $controller_str === 'Controller' ? 'App\Controller' : 'app\controller';
|
||||
} else {
|
||||
$name_str = substr($name, 0, $pos);
|
||||
if($real_name_str = Util::guessPath(app_path(), $name_str)) {
|
||||
$name_str = $real_name_str;
|
||||
} else if ($real_section_name = Util::guessPath(app_path(), strstr($name_str, '/', true))) {
|
||||
$upper = strtolower($real_section_name[0]) !== $real_section_name[0];
|
||||
} else if ($real_base_controller = Util::guessPath(app_path(), 'controller')) {
|
||||
$upper = strtolower($real_base_controller[0]) !== $real_base_controller[0];
|
||||
}
|
||||
$upper = $upper ?? strtolower($name_str[0]) !== $name_str[0];
|
||||
if ($upper && !$real_name_str) {
|
||||
$name_str = preg_replace_callback('/\/([a-z])/', function ($matches) {
|
||||
return '/' . strtoupper($matches[1]);
|
||||
}, ucfirst($name_str));
|
||||
}
|
||||
$path = "$name_str/" . ($upper ? 'Controller' : 'controller');
|
||||
$name = ucfirst(substr($name, $pos + 1));
|
||||
$file = app_path() . "/$path/$name.php";
|
||||
$namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
|
||||
}
|
||||
$this->createController($name, $namespace, $file);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $namespace
|
||||
* @param $file
|
||||
* @return void
|
||||
*/
|
||||
protected function createController($name, $namespace, $file)
|
||||
{
|
||||
$path = pathinfo($file, PATHINFO_DIRNAME);
|
||||
if (!is_dir($path)) {
|
||||
mkdir($path, 0777, true);
|
||||
}
|
||||
$controller_content = <<<EOF
|
||||
<?php
|
||||
|
||||
namespace $namespace;
|
||||
|
||||
use support\Request;
|
||||
|
||||
class $name
|
||||
{
|
||||
public function index(Request \$request)
|
||||
{
|
||||
return response(__CLASS__);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EOF;
|
||||
file_put_contents($file, $controller_content);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Webman\Console\Util;
|
||||
|
||||
|
||||
class MakeMiddlewareCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:middleware';
|
||||
protected static $defaultDescription = 'Make middleware';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument('name', InputArgument::REQUIRED, 'Middleware name');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
$output->writeln("Make middleware $name");
|
||||
|
||||
$name = str_replace('\\', '/', $name);
|
||||
if (!$middleware_str = Util::guessPath(app_path(), 'middleware')) {
|
||||
$middleware_str = Util::guessPath(app_path(), 'controller') === 'Controller' ? 'Middleware' : 'middleware';
|
||||
}
|
||||
$upper = $middleware_str === 'Middleware';
|
||||
if (!($pos = strrpos($name, '/'))) {
|
||||
$name = ucfirst($name);
|
||||
$file = app_path() . "/$middleware_str/$name.php";
|
||||
$namespace = $upper ? 'App\Middleware' : 'app\middleware';
|
||||
} else {
|
||||
if($real_name = Util::guessPath(app_path(), $name)) {
|
||||
$name = $real_name;
|
||||
}
|
||||
if ($upper && !$real_name) {
|
||||
$name = preg_replace_callback('/\/([a-z])/', function ($matches) {
|
||||
return '/' . strtoupper($matches[1]);
|
||||
}, ucfirst($name));
|
||||
}
|
||||
$path = "$middleware_str/" . substr($upper ? ucfirst($name) : $name, 0, $pos);
|
||||
$name = ucfirst(substr($name, $pos + 1));
|
||||
$file = app_path() . "/$path/$name.php";
|
||||
$namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
|
||||
}
|
||||
|
||||
$this->createMiddleware($name, $namespace, $file);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $namespace
|
||||
* @param $path
|
||||
* @return void
|
||||
*/
|
||||
protected function createMiddleware($name, $namespace, $file)
|
||||
{
|
||||
$path = pathinfo($file, PATHINFO_DIRNAME);
|
||||
if (!is_dir($path)) {
|
||||
mkdir($path, 0777, true);
|
||||
}
|
||||
$middleware_content = <<<EOF
|
||||
<?php
|
||||
namespace $namespace;
|
||||
|
||||
use Webman\MiddlewareInterface;
|
||||
use Webman\Http\Response;
|
||||
use Webman\Http\Request;
|
||||
|
||||
class $name implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request \$request, callable \$next) : Response
|
||||
{
|
||||
return \$next(\$request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EOF;
|
||||
file_put_contents($file, $middleware_content);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Doctrine\Inflector\InflectorFactory;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Webman\Console\Util;
|
||||
|
||||
|
||||
class MakeModelCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:model';
|
||||
protected static $defaultDescription = 'Make model';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument('name', InputArgument::REQUIRED, 'Model name');
|
||||
$this->addArgument('type', InputArgument::OPTIONAL, 'Type');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
$name = Util::nameToClass($name);
|
||||
$type = $input->getArgument('type');
|
||||
$output->writeln("Make model $name");
|
||||
if (!($pos = strrpos($name, '/'))) {
|
||||
$name = ucfirst($name);
|
||||
$model_str = Util::guessPath(app_path(), 'model') ?: 'model';
|
||||
$file = app_path() . "/$model_str/$name.php";
|
||||
$namespace = $model_str === 'Model' ? 'App\Model' : 'app\model';
|
||||
} else {
|
||||
$name_str = substr($name, 0, $pos);
|
||||
if($real_name_str = Util::guessPath(app_path(), $name_str)) {
|
||||
$name_str = $real_name_str;
|
||||
} else if ($real_section_name = Util::guessPath(app_path(), strstr($name_str, '/', true))) {
|
||||
$upper = strtolower($real_section_name[0]) !== $real_section_name[0];
|
||||
} else if ($real_base_controller = Util::guessPath(app_path(), 'controller')) {
|
||||
$upper = strtolower($real_base_controller[0]) !== $real_base_controller[0];
|
||||
}
|
||||
$upper = $upper ?? strtolower($name_str[0]) !== $name_str[0];
|
||||
if ($upper && !$real_name_str) {
|
||||
$name_str = preg_replace_callback('/\/([a-z])/', function ($matches) {
|
||||
return '/' . strtoupper($matches[1]);
|
||||
}, ucfirst($name_str));
|
||||
}
|
||||
$path = "$name_str/" . ($upper ? 'Model' : 'model');
|
||||
$name = ucfirst(substr($name, $pos + 1));
|
||||
$file = app_path() . "/$path/$name.php";
|
||||
$namespace = str_replace('/', '\\', ($upper ? 'App/' : 'app/') . $path);
|
||||
}
|
||||
if (!$type) {
|
||||
$database = config('database');
|
||||
if (isset($database['default']) && strpos($database['default'], 'plugin.') === 0) {
|
||||
$database = false;
|
||||
}
|
||||
$thinkorm = config('thinkorm');
|
||||
if (isset($thinkorm['default']) && strpos($thinkorm['default'], 'plugin.') === 0) {
|
||||
$thinkorm = false;
|
||||
}
|
||||
$type = !$database && $thinkorm ? 'tp' : 'laravel';
|
||||
}
|
||||
if ($type == 'tp') {
|
||||
$this->createTpModel($name, $namespace, $file);
|
||||
} else {
|
||||
$this->createModel($name, $namespace, $file);
|
||||
}
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $namespace
|
||||
* @param $file
|
||||
* @return void
|
||||
*/
|
||||
protected function createModel($class, $namespace, $file)
|
||||
{
|
||||
$path = pathinfo($file, PATHINFO_DIRNAME);
|
||||
if (!is_dir($path)) {
|
||||
mkdir($path, 0777, true);
|
||||
}
|
||||
$table = Util::classToName($class);
|
||||
$table_val = 'null';
|
||||
$pk = 'id';
|
||||
$properties = '';
|
||||
try {
|
||||
$prefix = config('database.connections.mysql.prefix') ?? '';
|
||||
$database = config('database.connections.mysql.database');
|
||||
$inflector = InflectorFactory::create()->build();
|
||||
$table_plura = $inflector->pluralize($inflector->tableize($class));
|
||||
if (\support\Db::select("show tables like '{$prefix}{$table_plura}'")) {
|
||||
$table = "{$prefix}{$table_plura}";
|
||||
} else if (\support\Db::select("show tables like '{$prefix}{$table}'")) {
|
||||
$table_val = "'$table'";
|
||||
$table = "{$prefix}{$table}";
|
||||
}
|
||||
foreach (\support\Db::select("select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,COLUMN_COMMENT from INFORMATION_SCHEMA.COLUMNS where table_name = '$table' and table_schema = '$database'") as $item) {
|
||||
if ($item->COLUMN_KEY === 'PRI') {
|
||||
$pk = $item->COLUMN_NAME;
|
||||
$item->COLUMN_COMMENT .= "(主键)";
|
||||
}
|
||||
$type = $this->getType($item->DATA_TYPE);
|
||||
$properties .= " * @property $type \${$item->COLUMN_NAME} {$item->COLUMN_COMMENT}\n";
|
||||
}
|
||||
} catch (\Throwable $e) {}
|
||||
$properties = rtrim($properties) ?: ' *';
|
||||
$model_content = <<<EOF
|
||||
<?php
|
||||
|
||||
namespace $namespace;
|
||||
|
||||
use support\Model;
|
||||
|
||||
/**
|
||||
$properties
|
||||
*/
|
||||
class $class extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected \$table = $table_val;
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected \$primaryKey = '$pk';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public \$timestamps = false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
EOF;
|
||||
file_put_contents($file, $model_content);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $namespace
|
||||
* @param $path
|
||||
* @return void
|
||||
*/
|
||||
protected function createTpModel($class, $namespace, $file)
|
||||
{
|
||||
$path = pathinfo($file, PATHINFO_DIRNAME);
|
||||
if (!is_dir($path)) {
|
||||
mkdir($path, 0777, true);
|
||||
}
|
||||
$table = Util::classToName($class);
|
||||
$table_val = 'null';
|
||||
$pk = 'id';
|
||||
$properties = '';
|
||||
try {
|
||||
$prefix = config('thinkorm.connections.mysql.prefix') ?? '';
|
||||
$database = config('thinkorm.connections.mysql.database');
|
||||
if (\think\facade\Db::query("show tables like '{$prefix}{$table}'")) {
|
||||
$table = "{$prefix}{$table}";
|
||||
$table_val = "'$table'";
|
||||
} else if (\think\facade\Db::query("show tables like '{$prefix}{$table}s'")) {
|
||||
$table = "{$prefix}{$table}s";
|
||||
$table_val = "'$table'";
|
||||
}
|
||||
foreach (\think\facade\Db::query("select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,COLUMN_COMMENT from INFORMATION_SCHEMA.COLUMNS where table_name = '$table' and table_schema = '$database'") as $item) {
|
||||
if ($item['COLUMN_KEY'] === 'PRI') {
|
||||
$pk = $item['COLUMN_NAME'];
|
||||
$item['COLUMN_COMMENT'] .= "(主键)";
|
||||
}
|
||||
$type = $this->getType($item['DATA_TYPE']);
|
||||
$properties .= " * @property $type \${$item['COLUMN_NAME']} {$item['COLUMN_COMMENT']}\n";
|
||||
}
|
||||
} catch (\Throwable $e) {}
|
||||
$properties = rtrim($properties) ?: ' *';
|
||||
$model_content = <<<EOF
|
||||
<?php
|
||||
|
||||
namespace $namespace;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
$properties
|
||||
*/
|
||||
class $class extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected \$table = $table_val;
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected \$pk = '$pk';
|
||||
|
||||
|
||||
}
|
||||
|
||||
EOF;
|
||||
file_put_contents($file, $model_content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
protected function getType(string $type)
|
||||
{
|
||||
if (strpos($type, 'int') !== false) {
|
||||
return 'integer';
|
||||
}
|
||||
switch ($type) {
|
||||
case 'varchar':
|
||||
case 'string':
|
||||
case 'text':
|
||||
case 'date':
|
||||
case 'time':
|
||||
case 'guid':
|
||||
case 'datetimetz':
|
||||
case 'datetime':
|
||||
case 'decimal':
|
||||
case 'enum':
|
||||
return 'string';
|
||||
case 'boolean':
|
||||
return 'integer';
|
||||
case 'float':
|
||||
return 'float';
|
||||
default:
|
||||
return 'mixed';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Phar;
|
||||
use RuntimeException;
|
||||
|
||||
class PharPackCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'phar:pack';
|
||||
protected static $defaultDescription = 'Can be easily packaged a project into phar files. Easy to distribute and use.';
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->checkEnv();
|
||||
|
||||
$phar_file_output_dir = config('plugin.webman.console.app.phar_file_output_dir');
|
||||
if (empty($phar_file_output_dir)) {
|
||||
throw new RuntimeException('Please set the phar file output directory.');
|
||||
}
|
||||
if (!file_exists($phar_file_output_dir) && !is_dir($phar_file_output_dir)) {
|
||||
if (!mkdir($phar_file_output_dir,0777,true)) {
|
||||
throw new RuntimeException("Failed to create phar file output directory. Please check the permission.");
|
||||
}
|
||||
}
|
||||
|
||||
$phar_filename = config('plugin.webman.console.app.phar_filename');
|
||||
if (empty($phar_filename)) {
|
||||
throw new RuntimeException('Please set the phar filename.');
|
||||
}
|
||||
|
||||
$phar_file = rtrim($phar_file_output_dir,DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $phar_filename;
|
||||
if (file_exists($phar_file)) {
|
||||
unlink($phar_file);
|
||||
}
|
||||
|
||||
$exclude_pattern = config('plugin.webman.console.app.exclude_pattern','');
|
||||
$phar = new Phar($phar_file,0,'webman');
|
||||
|
||||
$phar->startBuffering();
|
||||
|
||||
$signature_algorithm = config('plugin.webman.console.app.signature_algorithm');
|
||||
if (!in_array($signature_algorithm,[Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512,Phar::OPENSSL])) {
|
||||
throw new RuntimeException('The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.');
|
||||
}
|
||||
if ($signature_algorithm === Phar::OPENSSL) {
|
||||
$private_key_file = config('plugin.webman.console.app.private_key_file');
|
||||
if (!file_exists($private_key_file)) {
|
||||
throw new RuntimeException("If the value of the signature algorithm is 'Phar::OPENSSL', you must set the private key file.");
|
||||
}
|
||||
$private = openssl_get_privatekey(file_get_contents($private_key_file));
|
||||
$pkey = '';
|
||||
openssl_pkey_export($private, $pkey);
|
||||
$phar->setSignatureAlgorithm($signature_algorithm, $pkey);
|
||||
} else {
|
||||
$phar->setSignatureAlgorithm($signature_algorithm);
|
||||
}
|
||||
|
||||
$phar->buildFromDirectory(BASE_PATH,$exclude_pattern);
|
||||
|
||||
$exclude_files = config('plugin.webman.console.app.exclude_files');
|
||||
|
||||
foreach ($exclude_files as $file) {
|
||||
if($phar->offsetExists($file)){
|
||||
$phar->delete($file);
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln('Files collect complete, begin add file to Phar.');
|
||||
|
||||
$phar->setStub("#!/usr/bin/env php
|
||||
<?php
|
||||
define('IN_PHAR', true);
|
||||
Phar::mapPhar('webman');
|
||||
require 'phar://webman/webman';
|
||||
__HALT_COMPILER();
|
||||
");
|
||||
|
||||
$output->writeln('Write requests to the Phar archive, save changes to disk.');
|
||||
|
||||
$phar->stopBuffering();
|
||||
unset($phar);
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function checkEnv(): void
|
||||
{
|
||||
if (!class_exists(Phar::class, false)) {
|
||||
throw new RuntimeException("The 'phar' extension is required for build phar package");
|
||||
}
|
||||
|
||||
if (ini_get('phar.readonly')) {
|
||||
throw new RuntimeException(
|
||||
"The 'phar.readonly' is 'On', build phar must setting it 'Off' or exec with 'php -d phar.readonly=0 ./webman phar:pack'"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Webman\Console\Util;
|
||||
|
||||
class PluginCreateCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'plugin:create';
|
||||
protected static $defaultDescription = 'Plugin create';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->addOption('name', 'name', InputOption::VALUE_REQUIRED, 'Plugin name, for example foo/my-admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = strtolower($input->getOption('name'));
|
||||
$output->writeln("Create Plugin $name");
|
||||
if (!strpos($name, '/')) {
|
||||
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$namespace = Util::nameToNamespace($name);
|
||||
|
||||
// Create dir config/plugin/$name
|
||||
if (is_dir($plugin_config_path = config_path()."/plugin/$name")) {
|
||||
$output->writeln("<error>Dir $plugin_config_path already exists</error>");
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
if (is_dir($plugin_path = base_path()."/vendor/$name")) {
|
||||
$output->writeln("<error>Dir $plugin_path already exists</error>");
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
// Add psr-4
|
||||
if ($err = $this->addAutoloadToComposerJson($name, $namespace)) {
|
||||
$output->writeln("<error>$err</error>");
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$this->createConfigFiles($plugin_config_path);
|
||||
|
||||
$this->createVendorFiles($name, $namespace, $plugin_path, $output);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
protected function addAutoloadToComposerJson($name, $namespace)
|
||||
{
|
||||
if (!is_file($composer_json_file = base_path()."/composer.json")) {
|
||||
return "$composer_json_file not exists";
|
||||
}
|
||||
$composer_json = json_decode($composer_json_str = file_get_contents($composer_json_file), true);
|
||||
if (!$composer_json) {
|
||||
return "Bad $composer_json_file";
|
||||
}
|
||||
if(isset($composer_json['autoload']['psr-4'][$namespace."\\"])) {
|
||||
return;
|
||||
}
|
||||
$namespace = str_replace("\\", "\\\\", $namespace);
|
||||
$composer_json_str = str_replace('"psr-4": {', '"psr-4": {'."\n \"$namespace\\\\\" : \"vendor/$name/src\",", $composer_json_str);
|
||||
file_put_contents($composer_json_file, $composer_json_str);
|
||||
}
|
||||
|
||||
protected function createConfigFiles($plugin_config_path)
|
||||
{
|
||||
mkdir($plugin_config_path, 0777, true);
|
||||
$app_str = <<<EOF
|
||||
<?php
|
||||
return [
|
||||
'enable' => true,
|
||||
];
|
||||
EOF;
|
||||
file_put_contents("$plugin_config_path/app.php", $app_str);
|
||||
}
|
||||
|
||||
protected function createVendorFiles($name, $namespace, $plugin_path, $output)
|
||||
{
|
||||
mkdir("$plugin_path/src", 0777, true);
|
||||
$this->createComposerJson($name, $namespace, $plugin_path);
|
||||
if (is_callable('exec')) {
|
||||
exec("composer dumpautoload");
|
||||
} else {
|
||||
$output->writeln("<info>Please run command 'composer dumpautoload'</info>");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $namespace
|
||||
* @param $dest
|
||||
* @return void
|
||||
*/
|
||||
protected function createComposerJson($name, $namespace, $dest)
|
||||
{
|
||||
$namespace = str_replace('\\', '\\\\', $namespace);
|
||||
$composer_json_content = <<<EOT
|
||||
{
|
||||
"name": "$name",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"description": "Webman plugin $name",
|
||||
"require": {
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"$namespace\\\\": "src"
|
||||
}
|
||||
}
|
||||
}
|
||||
EOT;
|
||||
file_put_contents("$dest/composer.json", $composer_json_content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $namespace
|
||||
* @param $path_relations
|
||||
* @param $dest_dir
|
||||
* @return void
|
||||
*/
|
||||
protected function writeInstallFile($namespace, $path_relations, $dest_dir)
|
||||
{
|
||||
if (!is_dir($dest_dir)) {
|
||||
mkdir($dest_dir, 0777, true);
|
||||
}
|
||||
$relations = [];
|
||||
foreach($path_relations as $relation) {
|
||||
$relations[$relation] = $relation;
|
||||
}
|
||||
$relations = var_export($relations, true);
|
||||
$install_php_content = <<<EOT
|
||||
<?php
|
||||
namespace $namespace;
|
||||
|
||||
class Install
|
||||
{
|
||||
const WEBMAN_PLUGIN = true;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static \$pathRelation = $relations;
|
||||
|
||||
/**
|
||||
* Install
|
||||
* @return void
|
||||
*/
|
||||
public static function install()
|
||||
{
|
||||
static::installByRelation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstall()
|
||||
{
|
||||
self::uninstallByRelation();
|
||||
}
|
||||
|
||||
/**
|
||||
* installByRelation
|
||||
* @return void
|
||||
*/
|
||||
public static function installByRelation()
|
||||
{
|
||||
foreach (static::\$pathRelation as \$source => \$dest) {
|
||||
if (\$pos = strrpos(\$dest, '/')) {
|
||||
\$parent_dir = base_path().'/'.substr(\$dest, 0, \$pos);
|
||||
if (!is_dir(\$parent_dir)) {
|
||||
mkdir(\$parent_dir, 0777, true);
|
||||
}
|
||||
}
|
||||
//symlink(__DIR__ . "/\$source", base_path()."/\$dest");
|
||||
copy_dir(__DIR__ . "/\$source", base_path()."/\$dest");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* uninstallByRelation
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstallByRelation()
|
||||
{
|
||||
foreach (static::\$pathRelation as \$source => \$dest) {
|
||||
/*if (is_link(base_path()."/\$dest")) {
|
||||
unlink(base_path()."/\$dest");
|
||||
}*/
|
||||
remove_dir(base_path()."/\$dest");
|
||||
}
|
||||
}
|
||||
}
|
||||
EOT;
|
||||
file_put_contents("$dest_dir/Install.php", $install_php_content);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
||||
|
||||
class PluginDisableCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'plugin:disable';
|
||||
protected static $defaultDescription = 'Disable plugin by name';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument('name', InputArgument::REQUIRED, 'Plugin name, for example foo/my-admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
$output->writeln("Disable plugin $name");
|
||||
if (!strpos($name, '/')) {
|
||||
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
|
||||
return self::FAILURE;
|
||||
}
|
||||
$config_file = config_path() . "/plugin/$name/app.php";
|
||||
if (!is_file($config_file)) {
|
||||
return self::SUCCESS;
|
||||
}
|
||||
$config = include $config_file;
|
||||
if (empty($config['enable'])) {
|
||||
return self::SUCCESS;
|
||||
}
|
||||
$config_content = file_get_contents($config_file);
|
||||
$config_content = preg_replace('/(\'enable\' *?=> *?)(true)/', '$1false', $config_content);
|
||||
file_put_contents($config_file, $config_content);
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
||||
|
||||
class PluginEnableCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'plugin:enable';
|
||||
protected static $defaultDescription = 'Enable plugin by name';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument('name', InputArgument::REQUIRED, 'Plugin name, for example foo/my-admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
$output->writeln("Enable plugin $name");
|
||||
if (!strpos($name, '/')) {
|
||||
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
|
||||
return self::FAILURE;
|
||||
}
|
||||
$config_file = config_path() . "/plugin/$name/app.php";
|
||||
if (!is_file($config_file)) {
|
||||
$output->writeln("<error>$config_file not found</error>");
|
||||
return self::FAILURE;
|
||||
}
|
||||
$config = include $config_file;
|
||||
if (!isset($config['enable'])) {
|
||||
$output->writeln("<error>Config key 'enable' not found</error>");
|
||||
return self::FAILURE;
|
||||
}
|
||||
if ($config['enable']) {
|
||||
return self::SUCCESS;
|
||||
}
|
||||
$config_content = file_get_contents($config_file);
|
||||
$config_content = preg_replace('/(\'enable\' *?=> *?)(false)/', '$1true', $config_content);
|
||||
file_put_contents($config_file, $config_content);
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Webman\Console\Util;
|
||||
|
||||
class PluginExportCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'plugin:export';
|
||||
protected static $defaultDescription = 'Plugin export';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->addOption('name', 'name', InputOption::VALUE_REQUIRED, 'Plugin name, for example foo/my-admin');
|
||||
$this->addOption('source', 'source', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Directories to export');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$output->writeln('Export Plugin');
|
||||
$name = strtolower($input->getOption('name'));
|
||||
if (!strpos($name, '/')) {
|
||||
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
|
||||
return self::INVALID;
|
||||
}
|
||||
$namespace = Util::nameToNamespace($name);
|
||||
$path_relations = $input->getOption('source');
|
||||
if (!in_array("config/plugin/$name", $path_relations)) {
|
||||
if (is_dir("config/plugin/$name")) {
|
||||
$path_relations[] = "config/plugin/$name";
|
||||
}
|
||||
}
|
||||
$original_dest = $dest = base_path()."/vendor/$name";
|
||||
$dest .= '/src';
|
||||
$this->writeInstallFile($namespace, $path_relations, $dest);
|
||||
$output->writeln("<info>Create $dest/Install.php</info>");
|
||||
foreach ($path_relations as $source) {
|
||||
$base_path = pathinfo("$dest/$source", PATHINFO_DIRNAME);
|
||||
if (!is_dir($base_path)) {
|
||||
mkdir($base_path, 0777, true);
|
||||
}
|
||||
$output->writeln("<info>Copy $source to $dest/$source </info>");
|
||||
copy_dir($source, "$dest/$source");
|
||||
}
|
||||
$output->writeln("<info>Saved $name to $original_dest</info>");
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $namespace
|
||||
* @param $path_relations
|
||||
* @param $dest_dir
|
||||
* @return void
|
||||
*/
|
||||
protected function writeInstallFile($namespace, $path_relations, $dest_dir)
|
||||
{
|
||||
if (!is_dir($dest_dir)) {
|
||||
mkdir($dest_dir, 0777, true);
|
||||
}
|
||||
$relations = [];
|
||||
foreach($path_relations as $relation) {
|
||||
$relations[$relation] = $relation;
|
||||
}
|
||||
$relations = var_export($relations, true);
|
||||
$install_php_content = <<<EOT
|
||||
<?php
|
||||
namespace $namespace;
|
||||
|
||||
class Install
|
||||
{
|
||||
const WEBMAN_PLUGIN = true;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static \$pathRelation = $relations;
|
||||
|
||||
/**
|
||||
* Install
|
||||
* @return void
|
||||
*/
|
||||
public static function install()
|
||||
{
|
||||
static::installByRelation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstall()
|
||||
{
|
||||
self::uninstallByRelation();
|
||||
}
|
||||
|
||||
/**
|
||||
* installByRelation
|
||||
* @return void
|
||||
*/
|
||||
public static function installByRelation()
|
||||
{
|
||||
foreach (static::\$pathRelation as \$source => \$dest) {
|
||||
if (\$pos = strrpos(\$dest, '/')) {
|
||||
\$parent_dir = base_path().'/'.substr(\$dest, 0, \$pos);
|
||||
if (!is_dir(\$parent_dir)) {
|
||||
mkdir(\$parent_dir, 0777, true);
|
||||
}
|
||||
}
|
||||
//symlink(__DIR__ . "/\$source", base_path()."/\$dest");
|
||||
copy_dir(__DIR__ . "/\$source", base_path()."/\$dest");
|
||||
echo "Create \$dest\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* uninstallByRelation
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstallByRelation()
|
||||
{
|
||||
foreach (static::\$pathRelation as \$source => \$dest) {
|
||||
\$path = base_path()."/\$dest";
|
||||
if (!is_dir(\$path) && !is_file(\$path)) {
|
||||
continue;
|
||||
}
|
||||
echo "Remove \$dest\r\n";
|
||||
if (is_file(\$path) || is_link(\$path)) {
|
||||
unlink(\$path);
|
||||
continue;
|
||||
}
|
||||
remove_dir(\$path);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
EOT;
|
||||
file_put_contents("$dest_dir/Install.php", $install_php_content);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Webman\Console\Util;
|
||||
|
||||
|
||||
class PluginInstallCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'plugin:install';
|
||||
protected static $defaultDescription = 'Execute plugin installation script';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument('name', InputArgument::REQUIRED, 'Plugin name, for example foo/my-admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
$output->writeln("Execute installation for plugin $name");
|
||||
$namespace = Util::nameToNamespace($name);
|
||||
$install_function = "\\{$namespace}\\Install::install";
|
||||
$plugin_const = "\\{$namespace}\\Install::WEBMAN_PLUGIN";
|
||||
if (defined($plugin_const) && is_callable($install_function)) {
|
||||
$install_function();
|
||||
}
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Webman\Console\Util;
|
||||
|
||||
|
||||
class PluginUninstallCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'plugin:uninstall';
|
||||
protected static $defaultDescription = 'Execute plugin uninstall script';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument('name', InputArgument::REQUIRED, 'Plugin name, for example foo/my-admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
$output->writeln("Execute uninstall for plugin $name");
|
||||
if (!strpos($name, '/')) {
|
||||
$output->writeln('<error>Bad name, name must contain character \'/\' , for example foo/MyAdmin</error>');
|
||||
return self::FAILURE;
|
||||
}
|
||||
$namespace = Util::nameToNamespace($name);
|
||||
$uninstall_function = "\\{$namespace}\\Install::uninstall";
|
||||
$plugin_const = "\\{$namespace}\\Install::WEBMAN_PLUGIN";
|
||||
if (defined($plugin_const) && is_callable($uninstall_function)) {
|
||||
$uninstall_function();
|
||||
}
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Webman\Console\Application;
|
||||
|
||||
class ReStartCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'restart';
|
||||
protected static $defaultDescription = 'Restart workers. Use mode -d to start in DAEMON mode. Use mode -g to stop gracefully.';
|
||||
|
||||
protected function configure() : void
|
||||
{
|
||||
$this
|
||||
->addOption('daemon', 'd', InputOption::VALUE_NONE, 'DAEMON mode')
|
||||
->addOption('graceful', 'g', InputOption::VALUE_NONE, 'graceful stop');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (\class_exists(\Support\App::class)) {
|
||||
\Support\App::run();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
Application::run();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Webman\Console\Application;
|
||||
|
||||
class ReloadCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'reload';
|
||||
protected static $defaultDescription = 'Reload codes. Use mode -g to reload gracefully.';
|
||||
|
||||
protected function configure() : void
|
||||
{
|
||||
$this
|
||||
->addOption('graceful', 'd', InputOption::VALUE_NONE, 'graceful reload');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (\class_exists(\Support\App::class)) {
|
||||
\Support\App::run();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
Application::run();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Webman\Route;
|
||||
|
||||
class RouteListCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'route:list';
|
||||
protected static $defaultDescription = 'Route list';
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$headers = ['uri', 'method', 'callback', 'middleware', 'name'];
|
||||
$rows = [];
|
||||
foreach (Route::getRoutes() as $route) {
|
||||
foreach ($route->getMethods() as $method) {
|
||||
$cb = $route->getCallback();
|
||||
$cb = $cb instanceof \Closure ? 'Closure' : (is_array($cb) ? json_encode($cb) : var_export($cb, 1));
|
||||
$rows[] = [$route->getPath(), $method, $cb, json_encode($route->getMiddleware() ?: null), $route->getName()];
|
||||
}
|
||||
}
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders($headers);
|
||||
$table->setRows($rows);
|
||||
$table->render();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Webman\Console\Application;
|
||||
|
||||
class StartCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'start';
|
||||
protected static $defaultDescription = 'Start worker in DEBUG mode. Use mode -d to start in DAEMON mode.';
|
||||
|
||||
protected function configure() : void
|
||||
{
|
||||
$this->addOption('daemon', 'd', InputOption::VALUE_NONE, 'DAEMON mode');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (\class_exists(\Support\App::class)) {
|
||||
\Support\App::run();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
Application::run();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Webman\Console\Application;
|
||||
|
||||
class StatusCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'status';
|
||||
protected static $defaultDescription = 'Get worker status. Use mode -d to show live status.';
|
||||
|
||||
protected function configure() : void
|
||||
{
|
||||
$this->addOption('live', 'd', InputOption::VALUE_NONE, 'show live status');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (\class_exists(\Support\App::class)) {
|
||||
\Support\App::run();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
Application::run();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Webman\Console\Application;
|
||||
|
||||
class StopCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'stop';
|
||||
protected static $defaultDescription = 'Stop worker. Use mode -g to stop gracefully.';
|
||||
protected function configure() : void
|
||||
{
|
||||
$this
|
||||
->addOption('graceful', 'g',InputOption::VALUE_NONE, 'graceful stop');
|
||||
}
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (\class_exists(\Support\App::class)) {
|
||||
\Support\App::run();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
Application::run();
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Webman\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class VersionCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'version';
|
||||
protected static $defaultDescription = 'Show webman version';
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$installed_file = base_path() . '/vendor/composer/installed.php';
|
||||
if (is_file($installed_file)) {
|
||||
$version_info = include $installed_file;
|
||||
}
|
||||
$webman_framework_version = $version_info['versions']['workerman/webman-framework']['pretty_version'] ?? '';
|
||||
$output->writeln("Webman-framework $webman_framework_version");
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace Webman\Console;
|
||||
|
||||
class Install
|
||||
{
|
||||
const WEBMAN_PLUGIN = true;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $pathRelation = array (
|
||||
'config/plugin/webman/console' => 'config/plugin/webman/console',
|
||||
);
|
||||
|
||||
/**
|
||||
* Install
|
||||
* @return void
|
||||
*/
|
||||
public static function install()
|
||||
{
|
||||
copy(__DIR__ . "/webman", base_path()."/webman");
|
||||
chmod(base_path()."/webman", 0755);
|
||||
|
||||
static::installByRelation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstall()
|
||||
{
|
||||
if (is_file(base_path()."/webman")) {
|
||||
unlink(base_path() . "/webman");
|
||||
}
|
||||
|
||||
self::uninstallByRelation();
|
||||
}
|
||||
|
||||
/**
|
||||
* installByRelation
|
||||
* @return void
|
||||
*/
|
||||
public static function installByRelation()
|
||||
{
|
||||
foreach (static::$pathRelation as $source => $dest) {
|
||||
if ($pos = strrpos($dest, '/')) {
|
||||
$parent_dir = base_path().'/'.substr($dest, 0, $pos);
|
||||
if (!is_dir($parent_dir)) {
|
||||
mkdir($parent_dir, 0777, true);
|
||||
}
|
||||
}
|
||||
//symlink(__DIR__ . "/$source", base_path()."/$dest");
|
||||
copy_dir(__DIR__ . "/$source", base_path()."/$dest");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* uninstallByRelation
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstallByRelation()
|
||||
{
|
||||
foreach (static::$pathRelation as $source => $dest) {
|
||||
$path = base_path()."/$dest";
|
||||
if (!is_dir($path) && !is_file($path)) {
|
||||
continue;
|
||||
}
|
||||
/*if (is_link($path) {
|
||||
unlink($path);
|
||||
}*/
|
||||
remove_dir($path);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+66
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
namespace Webman\Console;
|
||||
|
||||
use Doctrine\Inflector\InflectorFactory;
|
||||
|
||||
class Util
|
||||
{
|
||||
public static function nameToNamespace($name)
|
||||
{
|
||||
$namespace = ucfirst($name);
|
||||
$namespace = preg_replace_callback(['/-([a-zA-Z])/', '/(\/[a-zA-Z])/'], function ($matches) {
|
||||
return strtoupper($matches[1]);
|
||||
}, $namespace);
|
||||
return str_replace('/', '\\' ,ucfirst($namespace));
|
||||
}
|
||||
|
||||
public static function classToName($class)
|
||||
{
|
||||
$class = lcfirst($class);
|
||||
return preg_replace_callback(['/([A-Z])/'], function ($matches) {
|
||||
return '_' . strtolower($matches[1]);
|
||||
}, $class);
|
||||
}
|
||||
|
||||
public static function nameToClass($class)
|
||||
{
|
||||
$class = preg_replace_callback(['/-([a-zA-Z])/', '/_([a-zA-Z])/'], function ($matches) {
|
||||
return strtoupper($matches[1]);
|
||||
}, $class);
|
||||
|
||||
if (!($pos = strrpos($class, '/'))) {
|
||||
$class = ucfirst($class);
|
||||
} else {
|
||||
$path = substr($class, 0, $pos);
|
||||
$class = ucfirst(substr($class, $pos + 1));
|
||||
$class = "$path/$class";
|
||||
}
|
||||
return $class;
|
||||
}
|
||||
|
||||
public static function guessPath($base_path, $name, $return_full_path = false)
|
||||
{
|
||||
if (!is_dir($base_path)) {
|
||||
return false;
|
||||
}
|
||||
$names = explode('/', trim(strtolower($name), '/'));
|
||||
$realname = [];
|
||||
$path = $base_path;
|
||||
foreach ($names as $name) {
|
||||
$finded = false;
|
||||
foreach (scandir($path) ?: [] as $tmp_name) {
|
||||
if (strtolower($tmp_name) === $name && is_dir("$path/$tmp_name")) {
|
||||
$path = "$path/$tmp_name";
|
||||
$realname[] = $tmp_name;
|
||||
$finded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$finded) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$realname = implode(DIRECTORY_SEPARATOR, $realname);
|
||||
return $return_full_path ? get_realpath($base_path . DIRECTORY_SEPARATOR . $realname) : $realname;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
return [
|
||||
'enable' => true,
|
||||
|
||||
'phar_file_output_dir' => BASE_PATH . DIRECTORY_SEPARATOR . 'build',
|
||||
|
||||
'phar_filename' => 'webman.phar',
|
||||
|
||||
'signature_algorithm'=> Phar::SHA256, //set the signature algorithm for a phar and apply it. The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL.
|
||||
|
||||
'private_key_file' => '', // The file path for certificate or OpenSSL private key file.
|
||||
|
||||
//'exclude_pattern' => '#^(?!.*(config/plugin/webman/console/app.php|webman/console/src/Commands/(PharPackCommand.php|ReloadCommand.php)|LICENSE|composer.json|.github|.idea|doc|docs|.git|.setting|runtime|test|test_old|tests|Tests|vendor-bin|.md))(.*)$#',
|
||||
|
||||
'exclude_files' => [
|
||||
'.env', 'LICENSE', 'composer.json', 'composer.lock','start.php'
|
||||
]
|
||||
];
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use Webman\Config;
|
||||
use Webman\Console\Command;
|
||||
use Webman\Console\Util;
|
||||
use support\Container;
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
if (!in_array($argv[1] ?? '', ['start', 'restart', 'stop', 'status', 'reload', 'connections'])) {
|
||||
require_once __DIR__ . '/support/bootstrap.php';
|
||||
} else {
|
||||
if (class_exists('Support\App')) {
|
||||
Support\App::loadAllConfig(['route']);
|
||||
} else {
|
||||
Config::reload(config_path(), ['route', 'container']);
|
||||
}
|
||||
}
|
||||
|
||||
$cli = new Command();
|
||||
$cli->setName('webman cli');
|
||||
$cli->installInternalCommands();
|
||||
if (is_dir($command_path = Util::guessPath(app_path(), '/command', true))) {
|
||||
$cli->installCommands($command_path);
|
||||
}
|
||||
|
||||
foreach (config('plugin', []) as $firm => $projects) {
|
||||
if (isset($projects['app'])) {
|
||||
if ($command_str = Util::guessPath(base_path() . "/plugin/$firm", 'command')) {
|
||||
$command_path = base_path() . "/plugin/$firm/$command_str";
|
||||
$cli->installCommands($command_path, "plugin\\$firm\\$command_str");
|
||||
}
|
||||
}
|
||||
foreach ($projects as $name => $project) {
|
||||
if (!is_array($project)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($project['command'] ?? [] as $command) {
|
||||
$cli->add(Container::get($command));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$cli->run();
|
||||
Reference in New Issue
Block a user