[feat] DebugCommand

This commit is contained in:
Lkeme 2022-06-04 15:52:09 +08:00
parent 95e4f9293e
commit d3a046792b
13 changed files with 592 additions and 8 deletions

2
.gitignore vendored
View File

@ -32,3 +32,5 @@ index1.php
# 保留忽略目录下的指定文件夹
/profile/*
!/profile/example
.phpunit.*

View File

@ -61,11 +61,12 @@
"overtrue/pinyin": "dev-master",
"guzzlehttp/guzzle": "^7.4",
"toolkit/pflag": "^2.0",
"symfony/console": "^6.1"
"symfony/console": "^6.1",
"malios/php-to-ascii-table": "^3.0"
},
"autoload": {
"psr-4": {
"Bhp\\": "src"
"Bhp\\": "src/"
},
"files": [
"src/Helpers.php"

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" backupStaticAttributes="false"
bootstrap="test/bootstrap.php" colors="false" convertErrorsToExceptions="true"
bootstrap="tests/bootstrap.php" colors="false" convertErrorsToExceptions="true"
convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnFailure="false"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd">
<coverage>
<include>
<directory suffix=".php">src</directory>

View File

@ -507,7 +507,7 @@ class Login extends BasePlugin
} else {
Log::info('公钥载入完毕');
}
// print_r($data);
//
$public_key = $response['data']['key'];
$hash = $response['data']['hash'];
openssl_public_encrypt($hash . $plaintext, $crypt, $public_key);

View File

@ -69,7 +69,6 @@ class Cache extends SingleTon
self::getInstance()->caches[$class_name] = new Flintstone($database, $options);
// ->set('bob', ['email' => 'bob@site.com', 'password' => '123456']);
}
print_r(array_keys(self::getInstance()->caches));
}

View File

@ -36,6 +36,15 @@ class AppCommand extends Command
public function __construct()
{
parent::__construct('mode:app', $this->desc);
//
$this
->usage(
'<bold> $0</end> <comment>profile mode:app</end> ## 完整命令<eol/>' .
'<bold> $0</end> <comment>profile m:a</end> ## 完整命令(缩写)<eol/>' .
'<bold> $0</end> <comment>profile</end> ## 省略命令(保留profile命令)<eol/>' .
'<bold> $0</end> <comment>mode:app</end> ## 省略命令(保留动作命令)<eol/>' .
'<bold> $0</end> <comment>m:d</end> ## 省略命令(保留动作命令)(缩写)<eol/>'
);
}
/**
@ -54,7 +63,6 @@ class AppCommand extends Command
Log::info("执行 $this->desc");
//
$plugins = Plugin::getPlugins();
print_r($plugins);
foreach ($plugins as $plugin) {
Task::addTask($plugin['hook'], null);
}

View File

@ -0,0 +1,89 @@
<?php declare(strict_types=1);
/**
* Website: https://mudew.com/
* Author: Lkeme
* License: The MIT License
* Email: Useri@live.cn
* Updated: 2022 ~ 2023
*
* _____ _ _ _ _ _ _____ _ _____ _____ _____
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & l、
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /   \、゙ ~ *
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \  じしf_, )
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
*/
namespace Bhp\Console\Command;
use Ahc\Cli\Input\Command;
use Ahc\Cli\IO\Interactor;
use Bhp\Log\Log;
use Bhp\Plugin\Plugin;
use Bhp\Task\Task;
final class DebugCommand extends Command
{
/**
* @var string
*/
protected string $desc = '[Debug模式] 开发测试使用';
/**
*
*/
public function __construct()
{
parent::__construct('mode:debug', $this->desc);
//
$this
->option('-p --plugin', '[默认会同时加载Login]测试插件')
->option('-P --plugins', '[默认会同时加载Login]测试插件列表')
->usage(
'<bold> $0</end> <comment>mode:debug --plugin TestPlugin</end> ## details 1<eol/>' .
'<bold> $0</end> <comment>m:d -p TestPlugin</end> ## details 2<eol/>' .
'<bold> $0</end> <comment>mode:debug --plugins TestPlugin|Test1Plugin</end> ## details 3<eol/>' .
'<bold> $0</end> <comment>m:d -P TestPlugin,Test1Plugin</end> ## details 4<eol/>'
);
}
/**
* @param Interactor $io
* @return void
*/
public function interact(Interactor $io): void
{
}
/**
* @return void
*/
public function execute(): void
{
Log::info("执行 $this->desc");
//
$p = $this->values()['plugin'];
if (is_null($p)) {
$temp = $this->values()['plugins'];
$pp = explode(',', $temp);
} else {
$pp = [$p];
}
//
if (empty($pp)) failExit('没有插件输入');
array_unshift($pp, 'Login');
//
$plugins = Plugin::getPlugins();
foreach ($plugins as $plugin) {
if(!in_array($plugin['hook'],$pp)){
continue;
}
Task::addTask($plugin['hook'], null);
}
//
Task::execTasks();
}
}

View File

@ -19,6 +19,7 @@ namespace Bhp\Console;
use Ahc\Cli\Application;
use Bhp\Console\Command\AppCommand;
use Bhp\Console\Command\DebugCommand;
use Bhp\Console\Command\RestoreCommand;
use Bhp\Console\Command\ScriptCommand;
use Bhp\Util\DesignPattern\SingleTon;
@ -95,6 +96,7 @@ LOGO;
->add(new AppCommand(), 'm:a', true) // 模式1
->add(new ScriptCommand(), 'm:s') // 模式2
->add(new RestoreCommand(), 'm:r') // 模式3
->add(new DebugCommand(), 'm:d') // 模式4
->logo($this->logo)
->handle($this->argv);
}

View File

@ -181,6 +181,7 @@ class Plugin extends SingleTon
}
}
$this->sortPlugins();
$this->preloadPlugins();
}
/**

View File

@ -47,7 +47,6 @@ class TimeLock extends SingleTon
if (!array_key_exists($class_name, self::getInstance()->locks)) {
self::getInstance()->locks[$class_name] = ['times' => $times, 'pause' => $status];
}
print_r(self::getInstance()->locks);
}
/**

View File

@ -0,0 +1,373 @@
<?php declare(strict_types=1);
/**
* Website: https://mudew.com/
* Author: Lkeme
* License: The MIT License
* Email: Useri@live.cn
* Updated: 2022 ~ 2023
*
* _____ _ _ _ _ _ _____ _ _____ _____ _____
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & l、
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /   \、゙ ~ *
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \  じしf_, )
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
*/
namespace Bhp\Util\AsciiTable;
use AsciiTable\Builder;
use AsciiTable\Exception\BuilderException;
use Closure;
class AsciiTable
{
const AlignLeft = STR_PAD_RIGHT;
const AlignCenter = STR_PAD_BOTH;
const AlignRight = STR_PAD_LEFT;
/**
* @var array
*/
protected array $data;
/**
* @var array
*/
protected array $keys;
/**
* @var array
*/
protected array $widths;
/**
* @var string
*/
protected string $indentation;
/**
* @var bool
*/
protected bool $displayHeader = true;
/**
* @var int
*/
protected int $keysAlignment;
/**
* @var int
*/
protected int $valuesAlignment;
/**
* @var mixed
*/
protected mixed $formatter;
/**
* @param array $data
*/
public function __construct(array $data = [])
{
$this->setData($data)
->setIndentation('')
->setKeysAlignment(self::AlignCenter)
->setValuesAlignment(self::AlignLeft)
->setFormatter(null);
}
/**
* @return string
*/
public function __toString()
{
return $this->getTable();
}
/**
* @param array|null $data
* @return string
*/
public function getTable(?array $data = null): string
{
if (!is_null($data))
$this->setData($data);
$data = $this->prepare();
$i = $this->indentation;
$table = $i . $this->line('┌', '─', '┬', '┐') . PHP_EOL;
if ($this->displayHeader) {
//绘制table header
$headerRows = array_combine($this->keys, $this->keys);
$table .= $i . $this->row($headerRows, $this->keysAlignment) . PHP_EOL;
$table .= $i . $this->line('├', '─', '┼', '┤') . PHP_EOL;
}
foreach ($data as $row) {
$table .= $i . $this->row($row, $this->valuesAlignment) . PHP_EOL;
}
$table .= $i . $this->line('└', '─', '┴', '┘') . PHP_EOL;
return $table;
}
/**
* @param string $indentation
* @return $this
*/
public function setIndentation(string $indentation): static
{
$this->indentation = $indentation;
return $this;
}
/**
* @param bool $displayHeader
* @return $this
*/
public function isDisplayHeader(bool $displayHeader): static
{
$this->displayHeader = $displayHeader;
return $this;
}
/**
* @param int $keysAlignment
* @return $this
*/
public function setKeysAlignment(int $keysAlignment): static
{
$this->keysAlignment = $keysAlignment;
return $this;
}
/**
* @param int $valuesAlignment
* @return $this
*/
public function setValuesAlignment(int $valuesAlignment): static
{
$this->valuesAlignment = $valuesAlignment;
return $this;
}
/**
* @param Closure|null $formatter
* @return $this
*/
public function setFormatter(?Closure $formatter): static
{
$this->formatter = $formatter;
return $this;
}
/**
* @param string|null $left
* @param string $horizontal
* @param string $link
* @param string|null $right
* @return string
*/
protected function line(?string $left, string $horizontal, string $link, ?string $right): string
{
$line = $left;
foreach ($this->keys as $key) {
$line .= str_repeat($horizontal, $this->widths[$key] + 2) . $link;
}
if (mb_strlen($line) > mb_strlen($left)) {
$line = mb_substr($line, 0, -mb_strlen($horizontal));
}
return $line . $right;
}
/**
* @param array $row
* @param int $alignment
* @return string
*/
protected function row(array $row, int $alignment): string
{
$line = '│';
foreach ($this->keys as $key) {
$value = (string)($row[$key] ?? '');
$line .= ' ' . static::mbStrPad($value, $this->widths[$key], ' ', $alignment) . ' ' . '│';
}
if (empty($row)) {
$line .= '│';
}
return $line;
}
/**
* @return array
*/
protected function prepare(): array
{
$this->keys = [];
$this->widths = [];
$data = $this->data;
//合并全部数组的key
foreach ($data as $row) {
$this->keys = array_merge($this->keys, array_keys($row));
}
$this->keys = array_unique($this->keys);
//补充缺陷数组
foreach ($data as $index => $row) {
foreach ($this->keys as $key) {
if (!array_key_exists($key, $row)) {
$data[$index][$key] = null;
}
}
}
//执行formatter
if ($this->formatter instanceof Closure) {
foreach ($data as &$row) {
array_walk($row, $this->formatter);
}
unset($row);
}
foreach ($this->keys as $key) {
$this->setWidth($key, $key);
}
foreach ($data as $row) {
foreach ($row as $columnKey => $columnValue) {
$this->setWidth($columnKey, $columnValue);
}
}
return $data;
}
/**
* @param mixed $key
* @param mixed $value
* @return void
*/
protected function setWidth(mixed $key, mixed $value): void
{
if (!isset($this->widths[$key])) {
$this->widths[$key] = 0;
}
// Deprecated: strlen(): Passing null to parameter #1 ($string) of type string is deprecated
// Deprecated: mb_strlen(): Passing null to parameter #1 ($string) of type string is deprecated
$value = (string)($value ?: '');
$width = (strlen($value) + mb_strlen($value, 'UTF8')) / 2;
if ($width > $this->widths[$key]) {
$this->widths[$key] = $width;
}
}
/**
* @param string $data
* @return bool|int|null
*/
protected static function countCJK(string $data): bool|int|null
{
return preg_match_all('/[\p{Han}\p{Katakana}\p{Hiragana}\p{Hangul}]/u', $data);
}
/**
* @param string $input
* @param int $pad_length
* @param string $pad_string
* @param int $pad_type
* @param string|null $encoding
* @return string
*/
protected function mbStrPad(string $input, int $pad_length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string
{
// $encoding = $encoding === null ? mb_internal_encoding() : $encoding;
// $diff = strlen($input) - (strlen($input) + mb_strlen($input, $encoding)) / 2;
// return str_pad($input, $pad_length + $diff, $pad_string, $pad_type);
// https://github.com/viossat/arraytotexttable/blob/6b1af924478cb9c3a903269e304fff006fe0dbf4/src/ArrayToTextTable.php#L255
$encoding = $encoding === null ? mb_internal_encoding() : $encoding;
$pad_before = $pad_type === STR_PAD_BOTH || $pad_type === STR_PAD_LEFT;
$pad_after = $pad_type === STR_PAD_BOTH || $pad_type === STR_PAD_RIGHT;
$pad_length -= mb_strlen($input, $encoding) + static::countCJK($input);
$target_length = $pad_before && $pad_after ? $pad_length / 2 : $pad_length;
$repeat_times = ceil($target_length / mb_strlen($pad_string, $encoding));
$repeated_string = str_repeat($pad_string, max(0, (int)$repeat_times));
$before = $pad_before ? mb_substr($repeated_string, 0, (int)floor($target_length), $encoding) : '';
$after = $pad_after ? mb_substr($repeated_string, 0, (int)ceil($target_length), $encoding) : '';
return $before . $input . $after;
}
/**
* @param array $data
* @return $this
*/
protected function setData(array $data = []): static
{
if (!is_array($data)) {
$data = [];
}
$arrayData = [];
foreach ($data as $row) {
if (is_array($row)) {
$arrayData[] = $row;
} else if (is_object($row)) {
$arrayData[] = get_object_vars($row);
}
}
$this->data = $arrayData;
return $this;
}
/**
* @param string $string
* @param string $color
* @return string
*/
protected function asciiColorWrap(string $string, string $color): string
{
// 30: 黑
// 31: 红
// 32: 绿
// 33: 黄
// 34: 蓝
// 35: 紫
// 36: 深绿
// 37: 白色
return "\033[1;" . $color . 'm' . $string . "\033[0m";
}
/**
* @use 数组转表格(外置)
* @param array $data
* @param string|null $title
* @return array
*/
public static function array2table(array $data, ?string $title = null): array
{
$th_list = [];
//
$builder = new Builder();
$builder->addRows($data);
//
if (!is_null($title)) {
$builder->setTitle($title);
}
//
foreach (explode("\r\n", $builder->renderTable()) as $value) {
if ($value) {
echo $value.PHP_EOL;
$th_list[] = $value;
}
}
return $th_list;
}
}

69
tests/AsciiTableTest.php Normal file
View File

@ -0,0 +1,69 @@
<?php
/**
* Website: https://mudew.com/
* Author: Lkeme
* License: The MIT License
* Email: Useri@live.cn
* Updated: 2022 ~ 2023
*
* _____ _ _ _ _ _ _____ _ _____ _____ _____
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & l、
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /   \、゙ ~ *
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \  じしf_, )
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
*/
namespace Tests;
use Bhp\Util\AsciiTable\AsciiTable;
use PHPUnit\Framework\TestCase;
class AsciiTableTest extends TestCase
{
/**
* @doesNotPerformAssertions
*/
public function testGetTable()
{
$data = [
[
'firstname' => 'Mo 啊大苏打allie',
'surname' => 'Alv萨达速度asarez',
'email' => 'molliealvarez@example.com',
],
[
'firstname' => 'Dianna',
'surname' => 'Mcbride',
'age' => 1111,
'email' => 'diannamcbride@example.com',
],
[
'firstname' => '撒旦撒旦asra',
'surname' => 'Muel大大是打算的ler',
'age' => 50,
'email' => 'elviramueller@example.com',
],
[
'firstname' => 'Corine',
'surname' => 'Morton',
'age' => 0,
],
[
'firstname' => 'James',
'surname' => 'Allison',
],
[
'firstname' => 'Bowen这是哥',
'surname' => 'Kelley',
'age' => 50,
'email' => 'bowenkelley@example.com',
],
];
$renderer = new AsciiTable($data);
echo $renderer->getTable();
}
}

41
tests/bootstrap.php Normal file
View File

@ -0,0 +1,41 @@
<?php declare(strict_types=1);
/**
* Website: https://mudew.com/
* Author: Lkeme
* License: The MIT License
* Email: Useri@live.cn
* Updated: 2022 ~ 2023
*
* _____ _ _ _ _ _ _____ _ _____ _____ _____
* | _ \ | | | | | | | | | | | ____| | | | _ \ | ____| | _ \ & l、
* | |_| | | | | | | | | |_| | | |__ | | | |_| | | |__ | |_| | (゚、
* | _ { | | | | | | | _ | | __| | | | ___/ | __| | _ /   \、゙ ~ *
* | |_| | | | | |___ | | | | | | | |___ | |___ | | | |___ | | \ \  じしf_, )
* |_____/ |_| |_____| |_| |_| |_| |_____| |_____| |_| |_____| |_| \_\
*/
error_reporting(E_ALL | E_STRICT);
date_default_timezone_set('Asia/Shanghai');
$libDir = dirname(__DIR__);
$npMap = [
'Tests\\' => $libDir . '/tests/',
"Bhp\\" => $libDir . '/src/',
];
spl_autoload_register(static function ($class) use ($npMap) {
foreach ($npMap as $np => $dir) {
$file = $dir . str_replace('\\', '/', substr($class, strlen($np))) . '.php';
if (file_exists($file)) {
include $file;
}
}
});
if (is_file(dirname(__DIR__, 3) . '/autoload.php')) {
require dirname(__DIR__, 3) . '/autoload.php';
} elseif (is_file(dirname(__DIR__) . '/vendor/autoload.php')) {
require dirname(__DIR__) . '/vendor/autoload.php';
}