first commit

This commit is contained in:
Mr.Qin
2022-08-19 19:48:37 +08:00
commit afdd648b65
3275 changed files with 631084 additions and 0 deletions

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,114 @@
<?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 = $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';
}
$upper = $command_str === 'Command';
$name = ucfirst($name);
$file = app_path() . "/$command_str/$name.php";
$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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,245 @@
<?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 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');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = $input->getArgument('name');
$name = Util::nameToClass($name);
$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 (!config('database') && config('thinkorm')) {
$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');
if (\support\Db::select("show tables like '{$prefix}{$table}s'")) {
$table = "{$prefix}{$table}s";
} 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';
}
}
}

View File

@@ -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'"
);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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'];
$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)];
}
}
$table = new Table($output);
$table->setHeaders($headers);
$table->setRows($rows);
$table->render();
return self::SUCCESS;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}