Implement M5 service providers, M6 MVC bases, and URL extension negotiation; update docs and tests
• M5: Add ServiceProviderInterface and ProviderRepository; integrate providers into Kernel (register before container build, boot after); add RouteRegistry with clear(); add default core providers (Routing, Template, ORM, Flags, Testing) and AppServiceProvider; add contracts and default drivers (Template/Eyrie, Orm/Pairity, Flags/Flagpole, Testing/Codeception)
• Routing: allow providers to contribute routes; add ProviderRouteTest
• Config: add config/providers.php; extend config/app.php with driver keys; document env keys
• M6: Introduce MVC bases: Controller, APIController (JSON helpers), ViewController (html + renderView helpers), View (transformData + renderer); add ViewWithDefaultTemplate and default-template flow; adjust method signatures to data-first and delegate template override to View
• HTTP: Add UrlExtensionNegotiationMiddleware (opt-in via URL_EXTENSION_NEGOTIATION, whitelist via URL_EXTENSION_WHITELIST with default json|php|none); wire before ContentNegotiationMiddleware
• Tests: add UrlExtensionNegotiationTest and MvcViewTest; ensure RouteRegistry::clear prevents duplicate routes in tests
• Docs: Update README with M5 provider usage, M6 MVC examples and template selection conventions, and URL extension negotiation; mark M5 complete in MILESTONES; add M12 task to provide XML support and enable xml in whitelist by default
2025-12-15 22:08:57 +00:00
|
|
|
<?php
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace Phred\Support;
|
|
|
|
|
|
|
|
|
|
use DI\Container;
|
|
|
|
|
use DI\ContainerBuilder;
|
|
|
|
|
use Phred\Support\Contracts\ConfigInterface;
|
|
|
|
|
use Phred\Support\Contracts\ServiceProviderInterface;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Loads and executes service providers in deterministic order.
|
|
|
|
|
* Order: core → app → modules
|
|
|
|
|
*/
|
|
|
|
|
final class ProviderRepository
|
|
|
|
|
{
|
|
|
|
|
/** @var list<ServiceProviderInterface> */
|
|
|
|
|
private array $providers = [];
|
|
|
|
|
|
|
|
|
|
public function __construct(private readonly ConfigInterface $config)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function load(): void
|
|
|
|
|
{
|
|
|
|
|
$this->providers = [];
|
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
|
|
|
// Merge providers from config/providers.php file (authoritative) with any runtime Config entries
|
|
|
|
|
$fileCore = $fileApp = $fileModules = [];
|
|
|
|
|
$configFile = dirname(__DIR__, 2) . '/config/providers.php';
|
|
|
|
|
if (is_file($configFile)) {
|
|
|
|
|
/** @noinspection PhpIncludeInspection */
|
|
|
|
|
$arr = require $configFile;
|
|
|
|
|
if (is_array($arr)) {
|
|
|
|
|
$fileCore = (array)($arr['core'] ?? []);
|
|
|
|
|
$fileApp = (array)($arr['app'] ?? []);
|
|
|
|
|
$fileModules = (array)($arr['modules'] ?? []);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$core = array_values(array_unique(array_merge($fileCore, (array) Config::get('providers.core', []))));
|
|
|
|
|
$app = array_values(array_unique(array_merge($fileApp, (array) Config::get('providers.app', []))));
|
|
|
|
|
$modules = array_values(array_unique(array_merge($fileModules, (array) Config::get('providers.modules', []))));
|
Implement M5 service providers, M6 MVC bases, and URL extension negotiation; update docs and tests
• M5: Add ServiceProviderInterface and ProviderRepository; integrate providers into Kernel (register before container build, boot after); add RouteRegistry with clear(); add default core providers (Routing, Template, ORM, Flags, Testing) and AppServiceProvider; add contracts and default drivers (Template/Eyrie, Orm/Pairity, Flags/Flagpole, Testing/Codeception)
• Routing: allow providers to contribute routes; add ProviderRouteTest
• Config: add config/providers.php; extend config/app.php with driver keys; document env keys
• M6: Introduce MVC bases: Controller, APIController (JSON helpers), ViewController (html + renderView helpers), View (transformData + renderer); add ViewWithDefaultTemplate and default-template flow; adjust method signatures to data-first and delegate template override to View
• HTTP: Add UrlExtensionNegotiationMiddleware (opt-in via URL_EXTENSION_NEGOTIATION, whitelist via URL_EXTENSION_WHITELIST with default json|php|none); wire before ContentNegotiationMiddleware
• Tests: add UrlExtensionNegotiationTest and MvcViewTest; ensure RouteRegistry::clear prevents duplicate routes in tests
• Docs: Update README with M5 provider usage, M6 MVC examples and template selection conventions, and URL extension negotiation; mark M5 complete in MILESTONES; add M12 task to provide XML support and enable xml in whitelist by default
2025-12-15 22:08:57 +00:00
|
|
|
|
|
|
|
|
foreach ([$core, $app, $modules] as $group) {
|
|
|
|
|
foreach ($group as $class) {
|
|
|
|
|
if (is_string($class) && class_exists($class)) {
|
|
|
|
|
$instance = new $class();
|
|
|
|
|
if ($instance instanceof ServiceProviderInterface) {
|
|
|
|
|
$this->providers[] = $instance;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
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
|
|
|
|
|
|
|
|
// Initial module discovery: scan modules/*/Providers/*ServiceProvider.php
|
|
|
|
|
$root = dirname(__DIR__, 2);
|
|
|
|
|
$modulesDir = $root . '/modules';
|
|
|
|
|
if (is_dir($modulesDir)) {
|
|
|
|
|
foreach (scandir($modulesDir) ?: [] as $entry) {
|
|
|
|
|
if ($entry === '.' || $entry === '..') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$modulePath = $modulesDir . '/' . $entry;
|
|
|
|
|
if (!is_dir($modulePath)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$providersPath = $modulePath . '/Providers';
|
|
|
|
|
if (!is_dir($providersPath)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
foreach (scandir($providersPath) ?: [] as $file) {
|
|
|
|
|
if ($file === '.' || $file === '..' || !str_ends_with($file, '.php')) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$classBase = substr($file, 0, -4);
|
|
|
|
|
if (!str_ends_with($classBase, 'ServiceProvider')) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$fqcn = "Project\\\\Modules\\\\{$entry}\\\\Providers\\\\{$classBase}";
|
|
|
|
|
if (class_exists($fqcn)) {
|
|
|
|
|
$instance = new $fqcn();
|
|
|
|
|
if ($instance instanceof ServiceProviderInterface) {
|
|
|
|
|
$this->providers[] = $instance;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
Implement M5 service providers, M6 MVC bases, and URL extension negotiation; update docs and tests
• M5: Add ServiceProviderInterface and ProviderRepository; integrate providers into Kernel (register before container build, boot after); add RouteRegistry with clear(); add default core providers (Routing, Template, ORM, Flags, Testing) and AppServiceProvider; add contracts and default drivers (Template/Eyrie, Orm/Pairity, Flags/Flagpole, Testing/Codeception)
• Routing: allow providers to contribute routes; add ProviderRouteTest
• Config: add config/providers.php; extend config/app.php with driver keys; document env keys
• M6: Introduce MVC bases: Controller, APIController (JSON helpers), ViewController (html + renderView helpers), View (transformData + renderer); add ViewWithDefaultTemplate and default-template flow; adjust method signatures to data-first and delegate template override to View
• HTTP: Add UrlExtensionNegotiationMiddleware (opt-in via URL_EXTENSION_NEGOTIATION, whitelist via URL_EXTENSION_WHITELIST with default json|php|none); wire before ContentNegotiationMiddleware
• Tests: add UrlExtensionNegotiationTest and MvcViewTest; ensure RouteRegistry::clear prevents duplicate routes in tests
• Docs: Update README with M5 provider usage, M6 MVC examples and template selection conventions, and URL extension negotiation; mark M5 complete in MILESTONES; add M12 task to provide XML support and enable xml in whitelist by default
2025-12-15 22:08:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function registerAll(ContainerBuilder $builder): void
|
|
|
|
|
{
|
|
|
|
|
foreach ($this->providers as $provider) {
|
|
|
|
|
$provider->register($builder, $this->config);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function bootAll(Container $container): void
|
|
|
|
|
{
|
|
|
|
|
foreach ($this->providers as $provider) {
|
|
|
|
|
$provider->boot($container);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|