Skip to content

Commit 6c19bb1

Browse files
committed
Added a landing.meta console command that resolves descriptors from CLI arguments or configuration and emits the resulting metadata as formatted JSON.
Registered the new generator in the console kernel so it appears in the Bamboo CLI command list. Added PHPUnit coverage that verifies default metadata output and type-specific overrides supplied via CLI arguments.
1 parent a40e7c9 commit 6c19bb1

3 files changed

Lines changed: 182 additions & 2 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
namespace Bamboo\Console\Command;
3+
4+
use Bamboo\Web\View\LandingPageContent;
5+
use JsonException;
6+
7+
class LandingMeta extends Command {
8+
public function name(): string { return 'landing.meta'; }
9+
10+
public function description(): string {
11+
return 'Generate landing metadata for a given content descriptor';
12+
}
13+
14+
public function handle(array $args): int {
15+
$descriptor = $this->resolveDescriptor($args);
16+
$builder = new LandingPageContent($this->app);
17+
18+
$payload = $builder->payload($descriptor);
19+
$meta = $payload['meta'] ?? [];
20+
21+
if (!is_array($meta) || $meta === []) {
22+
echo "No metadata available.\n";
23+
return 0;
24+
}
25+
26+
try {
27+
$encoded = json_encode($meta, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
28+
} catch (JsonException $exception) {
29+
fwrite(STDERR, 'Failed to encode metadata: ' . $exception->getMessage() . "\n");
30+
return 1;
31+
}
32+
33+
if ($encoded === false) {
34+
fwrite(STDERR, "Failed to encode metadata.\n");
35+
return 1;
36+
}
37+
38+
echo $encoded . "\n";
39+
40+
return 0;
41+
}
42+
43+
/**
44+
* @param list<string> $args
45+
*
46+
* @return array<string, string>
47+
*/
48+
private function resolveDescriptor(array $args): array {
49+
$descriptor = [];
50+
51+
if ($args !== [] && !str_contains($args[0], '=')) {
52+
$type = trim($args[0]);
53+
if ($type !== '') {
54+
$descriptor['type'] = strtolower($type);
55+
}
56+
$args = array_slice($args, 1);
57+
}
58+
59+
foreach ($args as $argument) {
60+
if (!str_contains($argument, '=')) {
61+
continue;
62+
}
63+
64+
[$key, $value] = explode('=', $argument, 2);
65+
$key = trim($key);
66+
$value = trim($value);
67+
68+
if ($key === '' || $value === '') {
69+
continue;
70+
}
71+
72+
if ($key === 'type') {
73+
$descriptor['type'] = strtolower($value);
74+
continue;
75+
}
76+
77+
$descriptor[$key] = $value;
78+
}
79+
80+
if ($descriptor !== []) {
81+
return $descriptor;
82+
}
83+
84+
$configured = $this->app->config('landing.content');
85+
if (!is_array($configured)) {
86+
return [];
87+
}
88+
89+
$clean = [];
90+
foreach ($configured as $key => $value) {
91+
if (!is_scalar($value) || $value === '') {
92+
continue;
93+
}
94+
95+
$clean[(string) $key] = (string) $value;
96+
}
97+
98+
if (isset($clean['type'])) {
99+
$clean['type'] = strtolower($clean['type']);
100+
}
101+
102+
return $clean;
103+
}
104+
}

src/Console/Kernel.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
use Bamboo\Console\Command\{
44
HttpServe, RoutesShow, RoutesCache, CachePurge, AppKeyMake,
55
QueueWork, WsServe, DevWatch, ScheduleRun, PkgInfo, ClientCall,
6-
ConfigValidate, AuthJwtSetup
6+
ConfigValidate, AuthJwtSetup, LandingMeta
77
};
88

99
class Kernel {
1010
protected array $commands = [
1111
HttpServe::class, RoutesShow::class, RoutesCache::class, CachePurge::class,
1212
AppKeyMake::class, QueueWork::class, WsServe::class, DevWatch::class, ScheduleRun::class,
13-
PkgInfo::class, ClientCall::class, ConfigValidate::class, AuthJwtSetup::class
13+
PkgInfo::class, ClientCall::class, ConfigValidate::class, AuthJwtSetup::class,
14+
LandingMeta::class
1415
];
1516
public function __construct(protected \Bamboo\Core\Application $app) {}
1617
public function run(array $argv): int {
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Console;
6+
7+
use Bamboo\Console\Command\LandingMeta;
8+
use Bamboo\Core\Application;
9+
use Bamboo\Core\Config;
10+
use Bamboo\Provider\AppProvider;
11+
use Bamboo\Provider\MetricsProvider;
12+
use PHPUnit\Framework\TestCase;
13+
14+
final class LandingMetaCommandTest extends TestCase
15+
{
16+
public function testOutputsDefaultMetadataAsJson(): void
17+
{
18+
$app = $this->createApplication();
19+
$command = new LandingMeta($app);
20+
21+
ob_start();
22+
$exitCode = $command->handle([]);
23+
$output = ob_get_clean();
24+
25+
if ($output === false) {
26+
$output = '';
27+
}
28+
29+
$this->assertSame(0, $exitCode);
30+
31+
$meta = json_decode(trim($output), true, flags: JSON_THROW_ON_ERROR);
32+
33+
$this->assertIsArray($meta);
34+
$this->assertSame(
35+
sprintf('%s | Modern PHP Microframework', $app->config('app.name', 'Bamboo')),
36+
$meta['title'] ?? null
37+
);
38+
$this->assertSame('Bamboo makes high-performance PHP approachable.', $meta['description'] ?? null);
39+
$this->assertArrayHasKey('generated_at', $meta);
40+
}
41+
42+
public function testAllowsTypeAndOverrideArguments(): void
43+
{
44+
$app = $this->createApplication();
45+
$command = new LandingMeta($app);
46+
47+
ob_start();
48+
$exitCode = $command->handle(['article', 'author=Jane Doe']);
49+
$output = ob_get_clean();
50+
51+
if ($output === false) {
52+
$output = '';
53+
}
54+
55+
$this->assertSame(0, $exitCode);
56+
57+
$meta = json_decode(trim($output), true, flags: JSON_THROW_ON_ERROR);
58+
59+
$this->assertIsArray($meta);
60+
$this->assertSame('Jane Doe', $meta['author'] ?? null);
61+
$this->assertSame('Green Armor Engineering', $meta['publication'] ?? null);
62+
$this->assertStringContainsString('Async PHP in Production', $meta['title'] ?? '');
63+
}
64+
65+
private function createApplication(): Application
66+
{
67+
$config = new Config(dirname(__DIR__, 2) . '/etc');
68+
$app = new Application($config);
69+
$app->register(new AppProvider());
70+
$app->register(new MetricsProvider());
71+
$app->register(new \Bamboo\Provider\ResilienceProvider());
72+
73+
return $app;
74+
}
75+
}

0 commit comments

Comments
 (0)