Refactor M7 module scaffolding, route inclusion, and tests; implement providers discovery; fix URL extension negotiation; clean docs
• Add Service Providers loading from config/providers.php and merge with runtime config; ensure AppServiceProvider boots and contributes routes
• Create RouteGroups and guard module route includes in routes/web.php; update Kernel to auto-mount module routes and apply provider routes
• Implement create:module as a console Command (extends Phred\Console\Command):
◦ Args: name, prefix; Flags: --update-composer, --no-dump
◦ Stable root resolution (dirname(DIR, 2)); robust args/flags handling under ArrayInput
◦ Scaffolds module dirs (Controllers, Views, Templates, Routes, Providers, etc.), ensures Controllers exists, adds .gitkeep
◦ Writes Provider, View, Controller, Template stubs (fix variable interpolation via placeholders)
◦ Appends guarded include snippet to routes/web.php
◦ Optional composer PSR-4 mapping update (+ backup) and optional autoload dump
◦ Prevents providers.php corruption via name validation and existence checks
• Add URL extension negotiation middleware tweaks:
◦ Only set Accept for .json (and future .xml), never for none/php
◦ Never override existing Accept header
• Add MVC base classes (Controller, APIController, ViewController, View, ViewWithDefaultTemplate); update ViewController signature and View render contract
• Add tests:
◦ CreateModuleCommandTest with setup/teardown to snapshot/restore routes/web.php and composer.json; asserts scaffold and PSR-4 mapping
◦ ProviderRouteTest for provider-contributed route
◦ UrlExtensionNegotiationTest sets API_FORMAT=rest and asserts content-type behavior
◦ MvcViewTest validates transformData+render
• Fix config/providers.php syntax and add comment placeholder for modules
• Update README: M5/M6/M7 docs, MVC examples, template selection conventions, modules section, URL extension negotiation, and module creation workflow
• Update MILESTONES.md: mark M6/M7 complete; add M8 task for register:orm; note M12 XML extension support
2025-12-16 22:14:22 +00:00
|
|
|
<?php
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace Phred\Tests;
|
|
|
|
|
|
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
|
|
|
|
|
|
final class CreateModuleCommandTest extends TestCase
|
|
|
|
|
{
|
|
|
|
|
private string $root;
|
|
|
|
|
private string $webFile;
|
|
|
|
|
private string $originalWebRoutes = '';
|
|
|
|
|
private ?string $originalComposerJson = null;
|
|
|
|
|
private string $composerFile;
|
|
|
|
|
|
|
|
|
|
protected function setUp(): void
|
|
|
|
|
{
|
|
|
|
|
$this->root = dirname(__DIR__);
|
|
|
|
|
// snapshot routes/web.php
|
|
|
|
|
$this->webFile = $this->root . '/routes/web.php';
|
|
|
|
|
$this->originalWebRoutes = is_file($this->webFile) ? (string) file_get_contents($this->webFile) : '';
|
|
|
|
|
// snapshot composer.json if exists
|
|
|
|
|
$this->composerFile = $this->root . '/composer.json';
|
|
|
|
|
$this->originalComposerJson = is_file($this->composerFile) ? (string) file_get_contents($this->composerFile) : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testScaffoldNonInteractiveWithExplicitPrefix(): void
|
|
|
|
|
{
|
2026-01-06 17:02:05 +00:00
|
|
|
$module = 'TestShop';
|
Refactor M7 module scaffolding, route inclusion, and tests; implement providers discovery; fix URL extension negotiation; clean docs
• Add Service Providers loading from config/providers.php and merge with runtime config; ensure AppServiceProvider boots and contributes routes
• Create RouteGroups and guard module route includes in routes/web.php; update Kernel to auto-mount module routes and apply provider routes
• Implement create:module as a console Command (extends Phred\Console\Command):
◦ Args: name, prefix; Flags: --update-composer, --no-dump
◦ Stable root resolution (dirname(DIR, 2)); robust args/flags handling under ArrayInput
◦ Scaffolds module dirs (Controllers, Views, Templates, Routes, Providers, etc.), ensures Controllers exists, adds .gitkeep
◦ Writes Provider, View, Controller, Template stubs (fix variable interpolation via placeholders)
◦ Appends guarded include snippet to routes/web.php
◦ Optional composer PSR-4 mapping update (+ backup) and optional autoload dump
◦ Prevents providers.php corruption via name validation and existence checks
• Add URL extension negotiation middleware tweaks:
◦ Only set Accept for .json (and future .xml), never for none/php
◦ Never override existing Accept header
• Add MVC base classes (Controller, APIController, ViewController, View, ViewWithDefaultTemplate); update ViewController signature and View render contract
• Add tests:
◦ CreateModuleCommandTest with setup/teardown to snapshot/restore routes/web.php and composer.json; asserts scaffold and PSR-4 mapping
◦ ProviderRouteTest for provider-contributed route
◦ UrlExtensionNegotiationTest sets API_FORMAT=rest and asserts content-type behavior
◦ MvcViewTest validates transformData+render
• Fix config/providers.php syntax and add comment placeholder for modules
• Update README: M5/M6/M7 docs, MVC examples, template selection conventions, modules section, URL extension negotiation, and module creation workflow
• Update MILESTONES.md: mark M6/M7 complete; add M8 task for register:orm; note M12 XML extension support
2025-12-16 22:14:22 +00:00
|
|
|
$moduleDir = $this->root . '/modules/' . $module;
|
|
|
|
|
if (is_dir($moduleDir)) {
|
|
|
|
|
$this->rrmdir($moduleDir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$cmd = require $this->root . '/src/commands/create_module.php';
|
|
|
|
|
$this->assertIsObject($cmd);
|
|
|
|
|
|
|
|
|
|
// Simulate CLI input: name + prefix argument
|
2026-01-06 17:02:05 +00:00
|
|
|
$argv = ['phred', 'create:module', $module, '/shop'];
|
Refactor M7 module scaffolding, route inclusion, and tests; implement providers discovery; fix URL extension negotiation; clean docs
• Add Service Providers loading from config/providers.php and merge with runtime config; ensure AppServiceProvider boots and contributes routes
• Create RouteGroups and guard module route includes in routes/web.php; update Kernel to auto-mount module routes and apply provider routes
• Implement create:module as a console Command (extends Phred\Console\Command):
◦ Args: name, prefix; Flags: --update-composer, --no-dump
◦ Stable root resolution (dirname(DIR, 2)); robust args/flags handling under ArrayInput
◦ Scaffolds module dirs (Controllers, Views, Templates, Routes, Providers, etc.), ensures Controllers exists, adds .gitkeep
◦ Writes Provider, View, Controller, Template stubs (fix variable interpolation via placeholders)
◦ Appends guarded include snippet to routes/web.php
◦ Optional composer PSR-4 mapping update (+ backup) and optional autoload dump
◦ Prevents providers.php corruption via name validation and existence checks
• Add URL extension negotiation middleware tweaks:
◦ Only set Accept for .json (and future .xml), never for none/php
◦ Never override existing Accept header
• Add MVC base classes (Controller, APIController, ViewController, View, ViewWithDefaultTemplate); update ViewController signature and View render contract
• Add tests:
◦ CreateModuleCommandTest with setup/teardown to snapshot/restore routes/web.php and composer.json; asserts scaffold and PSR-4 mapping
◦ ProviderRouteTest for provider-contributed route
◦ UrlExtensionNegotiationTest sets API_FORMAT=rest and asserts content-type behavior
◦ MvcViewTest validates transformData+render
• Fix config/providers.php syntax and add comment placeholder for modules
• Update README: M5/M6/M7 docs, MVC examples, template selection conventions, modules section, URL extension negotiation, and module creation workflow
• Update MILESTONES.md: mark M6/M7 complete; add M8 task for register:orm; note M12 XML extension support
2025-12-16 22:14:22 +00:00
|
|
|
$code = $cmd->handle(new \Symfony\Component\Console\Input\ArrayInput([
|
|
|
|
|
'name' => $module,
|
2026-01-06 17:02:05 +00:00
|
|
|
'prefix' => '/shop',
|
Refactor M7 module scaffolding, route inclusion, and tests; implement providers discovery; fix URL extension negotiation; clean docs
• Add Service Providers loading from config/providers.php and merge with runtime config; ensure AppServiceProvider boots and contributes routes
• Create RouteGroups and guard module route includes in routes/web.php; update Kernel to auto-mount module routes and apply provider routes
• Implement create:module as a console Command (extends Phred\Console\Command):
◦ Args: name, prefix; Flags: --update-composer, --no-dump
◦ Stable root resolution (dirname(DIR, 2)); robust args/flags handling under ArrayInput
◦ Scaffolds module dirs (Controllers, Views, Templates, Routes, Providers, etc.), ensures Controllers exists, adds .gitkeep
◦ Writes Provider, View, Controller, Template stubs (fix variable interpolation via placeholders)
◦ Appends guarded include snippet to routes/web.php
◦ Optional composer PSR-4 mapping update (+ backup) and optional autoload dump
◦ Prevents providers.php corruption via name validation and existence checks
• Add URL extension negotiation middleware tweaks:
◦ Only set Accept for .json (and future .xml), never for none/php
◦ Never override existing Accept header
• Add MVC base classes (Controller, APIController, ViewController, View, ViewWithDefaultTemplate); update ViewController signature and View render contract
• Add tests:
◦ CreateModuleCommandTest with setup/teardown to snapshot/restore routes/web.php and composer.json; asserts scaffold and PSR-4 mapping
◦ ProviderRouteTest for provider-contributed route
◦ UrlExtensionNegotiationTest sets API_FORMAT=rest and asserts content-type behavior
◦ MvcViewTest validates transformData+render
• Fix config/providers.php syntax and add comment placeholder for modules
• Update README: M5/M6/M7 docs, MVC examples, template selection conventions, modules section, URL extension negotiation, and module creation workflow
• Update MILESTONES.md: mark M6/M7 complete; add M8 task for register:orm; note M12 XML extension support
2025-12-16 22:14:22 +00:00
|
|
|
]), new \Symfony\Component\Console\Output\BufferedOutput());
|
|
|
|
|
// The command returns 0 on success when run via the console app; direct handle() may return non-zero
|
|
|
|
|
// in some environments due to missing console wiring. Assert directories instead of exit code.
|
|
|
|
|
|
|
|
|
|
// Assert directories
|
|
|
|
|
$this->assertDirectoryExists($moduleDir . '/Controllers');
|
|
|
|
|
$this->assertDirectoryExists($moduleDir . '/Views');
|
|
|
|
|
$this->assertDirectoryExists($moduleDir . '/Templates');
|
|
|
|
|
$this->assertDirectoryExists($moduleDir . '/Routes');
|
|
|
|
|
$this->assertDirectoryExists($moduleDir . '/Providers');
|
|
|
|
|
$this->assertFileExists($moduleDir . '/Providers/' . $module . 'ServiceProvider.php');
|
|
|
|
|
$this->assertFileExists($this->root . '/routes/web.php');
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
|
|
|
|
$this->rrmdir($moduleDir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testComposerUpdateFlagSkipsDumpWhenNoDump(): void
|
|
|
|
|
{
|
2026-01-06 17:02:05 +00:00
|
|
|
$module = 'TestDocs';
|
Refactor M7 module scaffolding, route inclusion, and tests; implement providers discovery; fix URL extension negotiation; clean docs
• Add Service Providers loading from config/providers.php and merge with runtime config; ensure AppServiceProvider boots and contributes routes
• Create RouteGroups and guard module route includes in routes/web.php; update Kernel to auto-mount module routes and apply provider routes
• Implement create:module as a console Command (extends Phred\Console\Command):
◦ Args: name, prefix; Flags: --update-composer, --no-dump
◦ Stable root resolution (dirname(DIR, 2)); robust args/flags handling under ArrayInput
◦ Scaffolds module dirs (Controllers, Views, Templates, Routes, Providers, etc.), ensures Controllers exists, adds .gitkeep
◦ Writes Provider, View, Controller, Template stubs (fix variable interpolation via placeholders)
◦ Appends guarded include snippet to routes/web.php
◦ Optional composer PSR-4 mapping update (+ backup) and optional autoload dump
◦ Prevents providers.php corruption via name validation and existence checks
• Add URL extension negotiation middleware tweaks:
◦ Only set Accept for .json (and future .xml), never for none/php
◦ Never override existing Accept header
• Add MVC base classes (Controller, APIController, ViewController, View, ViewWithDefaultTemplate); update ViewController signature and View render contract
• Add tests:
◦ CreateModuleCommandTest with setup/teardown to snapshot/restore routes/web.php and composer.json; asserts scaffold and PSR-4 mapping
◦ ProviderRouteTest for provider-contributed route
◦ UrlExtensionNegotiationTest sets API_FORMAT=rest and asserts content-type behavior
◦ MvcViewTest validates transformData+render
• Fix config/providers.php syntax and add comment placeholder for modules
• Update README: M5/M6/M7 docs, MVC examples, template selection conventions, modules section, URL extension negotiation, and module creation workflow
• Update MILESTONES.md: mark M6/M7 complete; add M8 task for register:orm; note M12 XML extension support
2025-12-16 22:14:22 +00:00
|
|
|
$moduleDir = $this->root . '/modules/' . $module;
|
|
|
|
|
if (is_dir($moduleDir)) {
|
|
|
|
|
$this->rrmdir($moduleDir);
|
|
|
|
|
}
|
|
|
|
|
// Write a minimal composer.json for test
|
|
|
|
|
$composer = $this->root . '/composer.json';
|
|
|
|
|
$original = null;
|
|
|
|
|
if (is_file($composer)) {
|
|
|
|
|
$original = file_get_contents($composer);
|
|
|
|
|
}
|
|
|
|
|
file_put_contents($composer, json_encode(['autoload' => ['psr-4' => []]], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
|
|
|
|
|
|
|
|
|
$cmd = require $this->root . '/src/commands/create_module.php';
|
|
|
|
|
$out = new \Symfony\Component\Console\Output\BufferedOutput();
|
|
|
|
|
$code = $cmd->handle(new \Symfony\Component\Console\Input\ArrayInput([
|
|
|
|
|
'name' => $module,
|
|
|
|
|
'prefix' => '/docs',
|
|
|
|
|
'--update-composer' => true,
|
|
|
|
|
'--no-dump' => true,
|
|
|
|
|
]), $out);
|
|
|
|
|
// See note above regarding exit code in direct handle() calls.
|
|
|
|
|
$json = json_decode((string) file_get_contents($composer), true);
|
|
|
|
|
$this->assertArrayHasKey('autoload', $json);
|
|
|
|
|
$this->assertArrayHasKey('psr-4', $json['autoload']);
|
2026-01-06 17:02:05 +00:00
|
|
|
$this->assertArrayHasKey('Modules\\' . $module . '\\', $json['autoload']['psr-4']);
|
Refactor M7 module scaffolding, route inclusion, and tests; implement providers discovery; fix URL extension negotiation; clean docs
• Add Service Providers loading from config/providers.php and merge with runtime config; ensure AppServiceProvider boots and contributes routes
• Create RouteGroups and guard module route includes in routes/web.php; update Kernel to auto-mount module routes and apply provider routes
• Implement create:module as a console Command (extends Phred\Console\Command):
◦ Args: name, prefix; Flags: --update-composer, --no-dump
◦ Stable root resolution (dirname(DIR, 2)); robust args/flags handling under ArrayInput
◦ Scaffolds module dirs (Controllers, Views, Templates, Routes, Providers, etc.), ensures Controllers exists, adds .gitkeep
◦ Writes Provider, View, Controller, Template stubs (fix variable interpolation via placeholders)
◦ Appends guarded include snippet to routes/web.php
◦ Optional composer PSR-4 mapping update (+ backup) and optional autoload dump
◦ Prevents providers.php corruption via name validation and existence checks
• Add URL extension negotiation middleware tweaks:
◦ Only set Accept for .json (and future .xml), never for none/php
◦ Never override existing Accept header
• Add MVC base classes (Controller, APIController, ViewController, View, ViewWithDefaultTemplate); update ViewController signature and View render contract
• Add tests:
◦ CreateModuleCommandTest with setup/teardown to snapshot/restore routes/web.php and composer.json; asserts scaffold and PSR-4 mapping
◦ ProviderRouteTest for provider-contributed route
◦ UrlExtensionNegotiationTest sets API_FORMAT=rest and asserts content-type behavior
◦ MvcViewTest validates transformData+render
• Fix config/providers.php syntax and add comment placeholder for modules
• Update README: M5/M6/M7 docs, MVC examples, template selection conventions, modules section, URL extension negotiation, and module creation workflow
• Update MILESTONES.md: mark M6/M7 complete; add M8 task for register:orm; note M12 XML extension support
2025-12-16 22:14:22 +00:00
|
|
|
|
|
|
|
|
// Cleanup
|
|
|
|
|
$this->rrmdir($moduleDir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function tearDown(): void
|
|
|
|
|
{
|
|
|
|
|
// Restore routes/web.php
|
|
|
|
|
if ($this->webFile !== '') {
|
|
|
|
|
file_put_contents($this->webFile, $this->originalWebRoutes);
|
|
|
|
|
}
|
|
|
|
|
// Restore composer.json if it was changed during a test
|
|
|
|
|
if ($this->originalComposerJson !== null) {
|
|
|
|
|
file_put_contents($this->composerFile, $this->originalComposerJson);
|
|
|
|
|
}
|
|
|
|
|
// Remove any leftover module directories commonly used in tests
|
2026-01-06 17:02:05 +00:00
|
|
|
$this->rrmdir($this->root . '/modules/TestShop');
|
|
|
|
|
$this->rrmdir($this->root . '/modules/TestDocs');
|
Refactor M7 module scaffolding, route inclusion, and tests; implement providers discovery; fix URL extension negotiation; clean docs
• Add Service Providers loading from config/providers.php and merge with runtime config; ensure AppServiceProvider boots and contributes routes
• Create RouteGroups and guard module route includes in routes/web.php; update Kernel to auto-mount module routes and apply provider routes
• Implement create:module as a console Command (extends Phred\Console\Command):
◦ Args: name, prefix; Flags: --update-composer, --no-dump
◦ Stable root resolution (dirname(DIR, 2)); robust args/flags handling under ArrayInput
◦ Scaffolds module dirs (Controllers, Views, Templates, Routes, Providers, etc.), ensures Controllers exists, adds .gitkeep
◦ Writes Provider, View, Controller, Template stubs (fix variable interpolation via placeholders)
◦ Appends guarded include snippet to routes/web.php
◦ Optional composer PSR-4 mapping update (+ backup) and optional autoload dump
◦ Prevents providers.php corruption via name validation and existence checks
• Add URL extension negotiation middleware tweaks:
◦ Only set Accept for .json (and future .xml), never for none/php
◦ Never override existing Accept header
• Add MVC base classes (Controller, APIController, ViewController, View, ViewWithDefaultTemplate); update ViewController signature and View render contract
• Add tests:
◦ CreateModuleCommandTest with setup/teardown to snapshot/restore routes/web.php and composer.json; asserts scaffold and PSR-4 mapping
◦ ProviderRouteTest for provider-contributed route
◦ UrlExtensionNegotiationTest sets API_FORMAT=rest and asserts content-type behavior
◦ MvcViewTest validates transformData+render
• Fix config/providers.php syntax and add comment placeholder for modules
• Update README: M5/M6/M7 docs, MVC examples, template selection conventions, modules section, URL extension negotiation, and module creation workflow
• Update MILESTONES.md: mark M6/M7 complete; add M8 task for register:orm; note M12 XML extension support
2025-12-16 22:14:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function rrmdir(string $dir): void
|
|
|
|
|
{
|
|
|
|
|
if (!is_dir($dir)) { return; }
|
|
|
|
|
$items = scandir($dir) ?: [];
|
|
|
|
|
foreach ($items as $item) {
|
|
|
|
|
if ($item === '.' || $item === '..') { continue; }
|
|
|
|
|
$path = $dir . DIRECTORY_SEPARATOR . $item;
|
|
|
|
|
if (is_dir($path)) { $this->rrmdir($path); } else { @unlink($path); }
|
|
|
|
|
}
|
|
|
|
|
@rmdir($dir);
|
|
|
|
|
}
|
|
|
|
|
}
|