Skip to content

Commit

Permalink
[FEATURE] Load config from configurable path, make controllers public…
Browse files Browse the repository at this point in the history
… services
  • Loading branch information
vertexvaar committed Oct 7, 2023
1 parent 096aab6 commit 75c7baf
Show file tree
Hide file tree
Showing 22 changed files with 292 additions and 117 deletions.
9 changes: 9 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@
"config": {
"allow-plugins": {
"vertexvaar/bluecontainer": true
},
"vertexvaar/bluesprints": {
"logs": "var/logs",
"locks": "var/locks",
"cache": "var/cache",
"database": "var/database",
"config": "config",
"view": "view",
"translations": "translations"
}
}
}
3 changes: 3 additions & 0 deletions config/middlewares.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

return [];
3 changes: 2 additions & 1 deletion config/routes.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use VerteXVaaR\BlueDist\Controller\Welcome;
use VerteXVaaR\BlueSprints\Http\Server\Middleware\RoutingMiddleware;
use VerteXVaaR\BlueSprints\Routing\Middleware\RoutingMiddleware;

return [
// safe methods
Expand Down
7 changes: 7 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
services:
_defaults:
autowire: true
autoconfigure: true

VerteXVaaR\BlueDist\:
resource: '../src/*'
53 changes: 39 additions & 14 deletions packages/bluecontainer/src/Composer/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@
use Composer\Composer;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\IO\IOInterface;
use Composer\Package\Package;
use Composer\Plugin\PluginInterface;
use Psr\Container\ContainerInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use VerteXVaaR\BlueContainer\DI;
use VerteXVaaR\BlueContainer\Helper\PackageIterator;
use VerteXVaaR\BlueSprints\Paths;

use function file_exists;
use function is_dir;
Expand Down Expand Up @@ -45,6 +51,9 @@ public static function getSubscribedEvents(): array
];
}

/**
* @noinspection PhpUnused
*/
public function postAutoloadDump(): void
{
$this->io->write('Generating container');
Expand All @@ -57,24 +66,40 @@ public function postAutoloadDump(): void
}
require $autoloadFile;


$containerBuilder = new ContainerBuilder();
$containerBuilder->set('composer', $this->composer);

$packages = $this->composer->getRepositoryManager()->getLocalRepository()->getPackages();
foreach ($packages as $package) {
$installPath = $installationManager->getInstallPath($package);
$configPath = $installPath . '/config';
if (file_exists($configPath) && is_dir($configPath)) {
if (file_exists($configPath . '/services.yaml')) {
$loader = new YamlFileLoader($containerBuilder, new FileLocator($configPath));
$loader->load('services.yaml');
}
if (file_exists($configPath . '/services.php')) {
$loader = new PhpFileLoader($containerBuilder, new FileLocator($configPath));
$loader->load('services.php');
$containerBuilder->set('io', $this->io);
$diDefinition = new Definition(DI::class);
$diDefinition->setPublic(true);
$diDefinition->setShared(true);
$containerBuilder->setDefinition(ContainerInterface::class, $diDefinition);

$packageIterator = new PackageIterator($this->composer);
$packageIterator->iterate(
static function (Package $package, string $installPath) use ($containerBuilder): void {
$configPath = $installPath . '/config';
if (file_exists($configPath) && is_dir($configPath)) {
if (file_exists($configPath . '/services.yaml')) {
$loader = new YamlFileLoader($containerBuilder, new FileLocator($configPath));
$loader->load('services.yaml');
}
if (file_exists($configPath . '/services.php')) {
$loader = new PhpFileLoader($containerBuilder, new FileLocator($configPath));
$loader->load('services.php');
}
}
}
);

$pathsDefinition = $containerBuilder->getDefinition(Paths::class);
$configPath = $pathsDefinition->getArgument('$config');
if (file_exists($configPath . '/services.yaml')) {
$loader = new YamlFileLoader($containerBuilder, new FileLocator($configPath));
$loader->load('services.yaml');
}
if (file_exists($configPath . '/services.php')) {
$loader = new PhpFileLoader($containerBuilder, new FileLocator($configPath));
$loader->load('services.php');
}

$containerBuilder->compile();
Expand Down
31 changes: 31 additions & 0 deletions packages/bluecontainer/src/Helper/PackageIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace VerteXVaaR\BlueContainer\Helper;

use Closure;
use Composer\Composer;

readonly class PackageIterator
{
public function __construct(private Composer $composer)
{
}

/**
* Iterates over all installed packages, passing the package to the closure
* and collecting the return values in an array which is returned.
*/
public function iterate(Closure $closure): array
{
$return = [];
$installationManager = $this->composer->getInstallationManager();
$packages = $this->composer->getRepositoryManager()->getLocalRepository()->getPackages();
foreach ($packages as $package) {
$installPath = $installationManager->getInstallPath($package);
$return[] = $closure($package, $installPath);
}
return $return;
}
}
2 changes: 1 addition & 1 deletion packages/bluesprints/config/middlewares.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

use VerteXVaaR\BlueSprints\Http\Server\Middleware\RoutingMiddleware;
use VerteXVaaR\BlueSprints\Routing\Middleware\RoutingMiddleware;

return [
'vertexvaar/bluesprints/routing' => [
Expand Down
44 changes: 39 additions & 5 deletions packages/bluesprints/config/services.php
Original file line number Diff line number Diff line change
@@ -1,25 +1,59 @@
<?php

use Composer\Composer;
use Composer\Package\Package;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use VerteXVaaR\BlueContainer\Helper\PackageIterator;
use VerteXVaaR\BlueSprints\Http\Server\Middleware\MiddlewareRegistry;
use VerteXVaaR\BlueSprints\Mvc\Controller;
use VerteXVaaR\BlueSprints\Mvc\DependencyInjection\PublicServicePass;
use VerteXVaaR\BlueSprints\Paths;
use VerteXVaaR\BlueSprints\Routing\DependencyInjection\RouteCollectorCompilerPass;

return static function (ContainerBuilder $containerBuilder): void {
/** @var Composer $composer */
$composer = $containerBuilder->get('composer');
$installationManager = $composer->getInstallationManager();
$packages = $composer->getRepositoryManager()->getLocalRepository()->getPackages();
$middlewares = [];
foreach ($packages as $package) {
$installPath = $installationManager->getInstallPath($package);

$packageIterator = new PackageIterator($composer);
$middlewares = $packageIterator->iterate(static function (Package $package, string $installPath): array {
$middlewares = [];
if (file_exists($installPath . '/config/middlewares.php')) {
$packageMiddlewares = require $installPath . '/config/middlewares.php';
foreach ($packageMiddlewares as $packageMiddleware) {
$middlewares[] = new Reference($packageMiddleware['service']);
}
}
return $middlewares;
});

$packageConfig = $composer->getPackage()->getConfig();
$config = $packageConfig['vertexvaar/bluesprints'];
$pathsDefinition = $containerBuilder->getDefinition(Paths::class);
$pathsDefinition->setArguments([
'$logs' => $config['logs'] ?? 'var/logs',
'$locks' => $config['locks'] ?? 'var/locks',
'$cache' => $config['cache'] ?? 'var/cache',
'$database' => $config['database'] ?? 'var/database',
'$config' => $config['config'] ?? 'config',
'$view' => $config['view'] ?? 'view',
'$translations' => $config['translations'] ?? 'translations',
]);

$packageMiddlewares = [];
$middlewaresPath = $pathsDefinition->getArgument('$config') . '/middlewares.php';
if (file_exists($middlewaresPath)) {
$packageMiddlewares = require $middlewaresPath;
}

$middlewares = array_replace($packageMiddlewares, ...$middlewares);

$registry = $containerBuilder->getDefinition(MiddlewareRegistry::class);
$registry->setArgument('$middlewares', $middlewares);

$containerBuilder->addCompilerPass(new RouteCollectorCompilerPass());

$containerBuilder->registerForAutoconfiguration(Controller::class)
->addTag('vertexvaar.bluesprints.controller');
$containerBuilder->addCompilerPass(new PublicServicePass('vertexvaar.bluesprints.controller'));
};
3 changes: 3 additions & 0 deletions packages/bluesprints/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ services:
VerteXVaaR\BlueSprints\Http\Application:
public: true

VerteXVaaR\BlueSprints\Http\HttpResponseEmitter:
public: true

Psr\Http\Server\RequestHandlerInterface: '@VerteXVaaR\BlueSprints\Http\Server\RequestHandler\ControllerDispatcher'
2 changes: 1 addition & 1 deletion packages/bluesprints/resources/public/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@
Error::registerErrorHandler();
$di = new DI();
$response = $di->get(Application::class)->run($request);
(new HttpResponseEmitter())->emit($response);
$di->get(HttpResponseEmitter::class)->emit($response);
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use VerteXVaaR\BlueSprints\Http\Server\RequestHandler\MiddlewareHandler;

use function array_reverse;
use function current;
use function next;
use function reset;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

namespace VerteXVaaR\BlueSprints\Http\Server\Middleware;

class MiddlewareRegistry
use Psr\Http\Server\MiddlewareInterface;

readonly class MiddlewareRegistry
{
public function __construct(public readonly array $middlewares)
/**
* @param array<MiddlewareInterface> $middlewares
*/
public function __construct(public array $middlewares)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace VerteXVaaR\BlueSprints\Http\Server\RequestHandler;

use GuzzleHttp\Psr7\Response;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
Expand All @@ -19,6 +20,10 @@

class ControllerDispatcher implements RequestHandlerInterface
{
public function __construct(private readonly ContainerInterface $container)
{
}

public function handle(ServerRequestInterface $request): ResponseInterface
{
ob_start();
Expand All @@ -28,10 +33,10 @@ public function handle(ServerRequestInterface $request): ResponseInterface
$response = new Response();

/** @var AbstractController $controller */
$controller = new $route['controller']($request);
$controller = $this->container->get($route['controller']);
$content = '';
try {
$content = $controller->callActionMethod($route);
$content = $controller->callActionMethod($route, $request);
} catch (RedirectException $exception) {
$response = $response->withHeader('Location', $exception->getUrl())->withStatus($exception->getStatus());
}
Expand Down

This file was deleted.

30 changes: 14 additions & 16 deletions packages/bluesprints/src/Mvc/AbstractController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,28 @@
use Psr\Http\Message\ServerRequestInterface;
use VerteXVaaR\BlueFluid\Mvc\FluidAdapter;

abstract class AbstractController
{
protected ServerRequestInterface $request;
use function call_user_func;
use function class_exists;
use function is_callable;

abstract class AbstractController implements Controller
{
protected TemplateRendererInterface $templateRenderer;

/**
* @var bool Indicates if the template should be rendered after the action has been called
*/
private bool $renderTemplate = true;

final public function __construct(ServerRequestInterface $request)
/**
* @param array $configuration
*
* @return string
*
* @throws RedirectException
*/
public function callActionMethod(array $configuration, ServerRequestInterface $request): string
{
$this->request = $request;
if (class_exists(FluidAdapter::class)) {
$this->templateRenderer = new FluidAdapter();
} else {
Expand All @@ -29,19 +37,9 @@ final public function __construct(ServerRequestInterface $request)
if (is_callable([$this, 'initialize'])) {
call_user_func([$this, 'initialize']);
}
}

/**
* @param array $configuration
*
* @return string
*
* @throws RedirectException
*/
public function callActionMethod(array $configuration): string
{
$this->templateRenderer->setRouteConfiguration($configuration);
$this->{$configuration['action']}();
$this->{$configuration['action']}($request);
if (true === $this->renderTemplate) {
return $this->templateRenderer->render();
}
Expand Down
Loading

0 comments on commit 75c7baf

Please sign in to comment.