Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions manager/cli/Application.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php
declare(strict_types=1);

namespace Evolution\CMS\Cli;

use Evolution\CMS\Cli\Command\CommandInterface;
use Evolution\CMS\Cli\Support\ConsoleOutput;
use Evolution\CMS\Cli\Support\ExitCode;

class Application
{
/**
* @var array<string, CommandInterface>
*/
private $commands = [];

private ConsoleOutput $output;

/**
* @param CommandInterface[] $commands
*/
public function __construct(ConsoleOutput $output, array $commands)
{
$this->output = $output;
foreach ($commands as $command) {
$this->register($command);
}
}

public function run(array $argv): int
{
[$arguments, $options] = $this->separateOptions(array_slice($argv, 1));
$commandName = array_shift($arguments) ?: '';

if (!$commandName) {
$this->output->error('コマンドを指定してください。');
return ExitCode::INVALID;
}

if (!isset($this->commands[$commandName])) {
$this->output->error("未対応のコマンドです: {$commandName}");
return ExitCode::INVALID;
}

$command = $this->commands[$commandName];
return $command->execute($arguments, $options);
}

private function register(CommandInterface $command): void
{
$this->commands[$command->name()] = $command;
}

/**
* @return array{0: array<int, string>, 1: array<string, bool>}
*/
private function separateOptions(array $arguments): array
{
$options = [];
$positionals = [];

foreach ($arguments as $argument) {
if (strpos($argument, '--') === 0) {
$optionName = substr($argument, 2);
if ($optionName !== '') {
$options[$optionName] = true;
}
continue;
}
$positionals[] = $argument;
}

return [$positionals, $options];
}
}
17 changes: 17 additions & 0 deletions manager/cli/Command/CommandInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);

namespace Evolution\CMS\Cli\Command;

interface CommandInterface
{
public function name(): string;

public function description(): string;

/**
* @param array<int, string> $arguments
* @param array<string, bool> $options
*/
public function execute(array $arguments, array $options): int;
}
91 changes: 91 additions & 0 deletions manager/cli/Command/StatusCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php
declare(strict_types=1);

namespace Evolution\CMS\Cli\Command;

use Evolution\CMS\Cli\Service\SystemStatusService;
use Evolution\CMS\Cli\Support\ConsoleOutput;
use Evolution\CMS\Cli\Support\ExitCode;

class StatusCommand implements CommandInterface
{
private SystemStatusService $service;
private ConsoleOutput $output;

public function __construct(SystemStatusService $service, ConsoleOutput $output)
{
$this->service = $service;
$this->output = $output;
}

public function name(): string
{
return 'status';
}

public function description(): string
{
return 'CMSの状態を表示する';
}

/**
* @param array<int, string> $arguments
* @param array<string, bool> $options
*/
public function execute(array $arguments, array $options): int
{
$status = $this->service->getStatus();

if (isset($options['json'])) {
$this->output->json($status);
return ExitCode::SUCCESS;
}

$this->renderHumanReadable($status);
return ExitCode::SUCCESS;
}

/**
* @param array<string, mixed> $status
*/
private function renderHumanReadable(array $status): void
{
$this->output->writeln('システムステータス');
$this->output->writeln(sprintf(
'- CMS: %s (%s / %s)',
$status['cms']['full_name'] ?: $status['cms']['version'],
$status['cms']['branch'],
$status['cms']['release_date']
));
$this->output->writeln(sprintf('- PHP: %s', $status['php']['version']));
$this->output->writeln(sprintf(
'- データベース: %s%s',
$status['database']['version'] ?: '不明',
$status['database']['connected'] ? '' : ' (未接続)'
));
$this->output->writeln(sprintf(
'- キャッシュ: %s (書き込み%s)',
$status['cache']['path'],
$status['cache']['writable'] ? '可能' : '不可'
));
$this->output->writeln(sprintf(
' ファイル数: %d / 合計サイズ: %s',
$status['cache']['files'],
$this->humanReadableSize((int) $status['cache']['total_size'])
));
}

private function humanReadableSize(int $bytes): string
{
if ($bytes === 0) {
return '0 B';
}

$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$position = (int) floor(log($bytes, 1024));
$position = min($position, count($units) - 1);

$value = $bytes / pow(1024, $position);
return sprintf('%.1f %s', $value, $units[$position]);
}
}
81 changes: 81 additions & 0 deletions manager/cli/Infrastructure/CacheStore.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);

namespace Evolution\CMS\Cli\Infrastructure;

use FilesystemIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;

class CacheStore
{
private string $cachePath;

public function __construct(string $cachePath)
{
$this->cachePath = rtrim($cachePath, '/') . '/';
}

/**
* @return array<string, mixed>
*/
public function summarize(): array
{
$this->ensureCacheDirectory();

if (!is_dir($this->cachePath)) {
return [
'path' => $this->cachePath,
'writable' => false,
'files' => 0,
'total_size' => 0,
];
}

[$files, $size] = $this->countFilesAndSize();

return [
'path' => $this->cachePath,
'writable' => is_writable($this->cachePath),
'files' => $files,
'total_size' => $size,
];
}

private function ensureCacheDirectory(): void
{
if (is_dir($this->cachePath)) {
return;
}
mkdir($this->cachePath, 0777, true);
}

/**
* @return array{0: int, 1: int}
*/
private function countFilesAndSize(): array
{
$count = 0;
$bytes = 0;

try {
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$this->cachePath,
FilesystemIterator::SKIP_DOTS
)
);

foreach ($iterator as $file) {
if ($file->isFile()) {
$count++;
$bytes += $file->getSize();
}
}
} catch (\Throwable $throwable) {
return [0, 0];
}

return [$count, $bytes];
}
}
56 changes: 56 additions & 0 deletions manager/cli/Service/SystemStatusService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);

namespace Evolution\CMS\Cli\Service;

use Evolution\CMS\Cli\Infrastructure\CacheStore;

class SystemStatusService
{
private CacheStore $cacheStore;

public function __construct(CacheStore $cacheStore)
{
$this->cacheStore = $cacheStore;
}

/**
* @return array<string, mixed>
*/
public function getStatus(): array
{
$version = evo()->getVersionData();

return [
'cms' => [
'version' => $version['version'] ?? '',
'branch' => $version['branch'] ?? '',
'release_date' => $version['release_date'] ?? '',
'full_name' => $version['full_appname'] ?? '',
],
'php' => [
'version' => PHP_VERSION,
],
'database' => $this->getDatabaseStatus(),
'cache' => $this->cacheStore->summarize(),
];
}

/**
* @return array<string, mixed>
*/
private function getDatabaseStatus(): array
{
$connected = db()->isConnected();
if (!$connected) {
$connected = db()->connect();
}

$version = $connected ? db()->getVersion() : null;

return [
'connected' => $connected,
'version' => $version ?: null,
];
}
}
27 changes: 27 additions & 0 deletions manager/cli/Support/ConsoleOutput.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);

namespace Evolution\CMS\Cli\Support;

class ConsoleOutput
{
public function writeln(string $message = ''): void
{
fwrite(STDOUT, $message . PHP_EOL);
}

public function error(string $message): void
{
fwrite(STDERR, $message . PHP_EOL);
}

public function json(array $payload): void
{
$this->writeln(
json_encode(
$payload,
JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT
) ?: '{}'
);
}
}
Loading