diff --git a/composer.json b/composer.json index 13b498d..417daa6 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,6 @@ "php": "8.2.*", "ext-json": "*", "vertexvaar/bluesprints": "@dev", - "vertexvaar/bluefluid": "@dev", "psr/container": "^2.0", "vertexvaar/bluecontainer": "@dev", "vertexvaar/blueauth": "@dev", @@ -40,7 +39,9 @@ "config": { "allow-plugins": { "vertexvaar/bluecontainer": true - }, + } + }, + "extra": { "vertexvaar/bluesprints": { "logs": "var/logs", "locks": "var/locks", diff --git a/packages/blueauth/composer.json b/packages/blueauth/composer.json index 9836a41..1f0020d 100644 --- a/packages/blueauth/composer.json +++ b/packages/blueauth/composer.json @@ -19,5 +19,10 @@ "require": { "php": "8.2.*", "vertexvaar/bluesprints": "*" + }, + "extra": { + "vertexvaar/bluesprints": { + "view": "view" + } } } diff --git a/packages/blueauth/src/Controller/AuthenticationController.php b/packages/blueauth/src/Controller/AuthenticationController.php index 93ff696..0782ca8 100644 --- a/packages/blueauth/src/Controller/AuthenticationController.php +++ b/packages/blueauth/src/Controller/AuthenticationController.php @@ -4,13 +4,14 @@ namespace VerteXVaaR\BlueAuth\Controller; +use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use RuntimeException; +use Twig\Environment; use VerteXVaaR\BlueSprints\Environment\Config; use VerteXVaaR\BlueSprints\Environment\Paths; use VerteXVaaR\BlueSprints\Mvc\AbstractController; use VerteXVaaR\BlueSprints\Mvc\Repository; -use VerteXVaaR\BlueSprints\Mvc\TemplateRenderer; use VerteXVaaR\BlueSprints\Utility\Strings; use function array_key_exists; @@ -18,6 +19,7 @@ use function file_exists; use function file_put_contents; use function getenv; +use function is_dir; use function json_encode; use function mkdir; use function setcookie; @@ -27,18 +29,19 @@ class AuthenticationController extends AbstractController { public function __construct( Repository $repository, - TemplateRenderer $templateRenderer, - private readonly Paths $paths, - private readonly Config $config, + Environment $view, + private Paths $paths, + private Config $config ) { - parent::__construct($repository, $templateRenderer); + parent::__construct($repository, $view); } - public function login(ServerRequestInterface $request): void + public function login(ServerRequestInterface $request): ResponseInterface { + return $this->render('@vertexvaar_blueauth/login.html.twig'); } - public function logout(ServerRequestInterface $request): void + public function logout(ServerRequestInterface $request): ResponseInterface { $sessionIdentifier = $request->getAttribute('session'); if ($sessionIdentifier) { @@ -48,12 +51,11 @@ public function logout(ServerRequestInterface $request): void } setcookie($this->config->cookieAuthName ?: 'bluesprints_auth', '', -1, '/'); } - $this->redirect('/'); + return $this->redirect('/'); } - public function authenticate(ServerRequestInterface $request): void + public function authenticate(ServerRequestInterface $request): ResponseInterface { - $this->renderTemplate = false; $body = $request->getParsedBody(); if (array_key_exists('username', $body) && array_key_exists('password', $body)) { $username = $body['username']; @@ -66,14 +68,14 @@ public function authenticate(ServerRequestInterface $request): void 'username' => $username, 'authenticated' => true, ]; - if (!mkdir($path, $this->config->folderPermissions, true) && !is_dir($path)) { + if (!is_dir($path) && !mkdir($path, $this->config->folderPermissions, true) && !is_dir($path)) { throw new RuntimeException(sprintf('Directory "%s" was not created', $path)); } file_put_contents(concat_paths($path, $sessionIdentifier), json_encode($session)); setcookie($this->config->cookieAuthName ?: 'bluesprints_auth', $sessionIdentifier); - $this->redirect('/'); + return $this->redirect('/'); } } - $this->redirect('/login'); + return $this->redirect('/login'); } } diff --git a/packages/blueauth/view/login.html.twig b/packages/blueauth/view/login.html.twig new file mode 100644 index 0000000..c117d97 --- /dev/null +++ b/packages/blueauth/view/login.html.twig @@ -0,0 +1,22 @@ +
+

Login

+
+ + + + + + +
+ + + + + +
+
+
diff --git a/packages/bluecontainer/src/Composer/Plugin.php b/packages/bluecontainer/src/Composer/Plugin.php index 6364536..da66397 100644 --- a/packages/bluecontainer/src/Composer/Plugin.php +++ b/packages/bluecontainer/src/Composer/Plugin.php @@ -17,8 +17,11 @@ use VerteXVaaR\BlueContainer\DI; use VerteXVaaR\BlueContainer\Helper\PackageIterator; +use function dirname; use function file_exists; +use function getenv; use function is_dir; +use function putenv; class Plugin implements PluginInterface, EventSubscriberInterface { @@ -57,6 +60,10 @@ public function postAutoloadDump(): void { $this->io->write('Generating container'); + if (!getenv('VXVR_BS_ROOT')) { + putenv('VXVR_BS_ROOT=' . dirname(__DIR__, 4)); + } + $installationManager = $this->composer->getInstallationManager(); $config = $this->composer->getConfig(); $autoloadFile = $config->get('vendor-dir') . '/autoload.php'; @@ -101,7 +108,7 @@ function (Package $package, string $installPath) use ($containerBuilder): void { ); - $packageConfig = $this->composer->getPackage()->getConfig(); + $packageConfig = $this->composer->getPackage()->getExtra(); $configPath = $packageConfig['vertexvaar/bluesprints']['config'] ?? 'config'; if (file_exists($configPath . '/services.yaml')) { diff --git a/packages/bluedebug/composer.json b/packages/bluedebug/composer.json index 1272a75..202e421 100644 --- a/packages/bluedebug/composer.json +++ b/packages/bluedebug/composer.json @@ -19,5 +19,10 @@ "require": { "php": "8.2.*", "vertexvaar/bluesprints": "*" + }, + "extra": { + "vertexvaar/bluesprints": { + "view": "view" + } } } diff --git a/packages/bluedebug/src/Middleware/DebugToolbarMiddleware.php b/packages/bluedebug/src/Middleware/DebugToolbarMiddleware.php index 8d5191a..64b616f 100644 --- a/packages/bluedebug/src/Middleware/DebugToolbarMiddleware.php +++ b/packages/bluedebug/src/Middleware/DebugToolbarMiddleware.php @@ -8,12 +8,12 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; -use VerteXVaaR\BlueSprints\Mvc\TemplateRenderer; +use Twig\Environment; readonly class DebugToolbarMiddleware implements MiddlewareInterface { - public function __construct(private TemplateRenderer $templateRenderer) + public function __construct(private Environment $view) { } @@ -21,12 +21,11 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface { $response = $handler->handle($request); - $this->templateRenderer->setRouteConfiguration(['controller' => 'DebugToolbarMiddleware']); - - $this->templateRenderer->setVariable('route', $request->getAttribute('route')); - $this->templateRenderer->setVariable('authenticated', $request->getAttribute('authenticated')); - $this->templateRenderer->setVariable('username', $request->getAttribute('username')); - $contents = $this->templateRenderer->render('DebugToolbar'); + $contents = $this->view->render('@vertexvaar_bluedebug/debug_toolbar.html.twig', [ + 'route' => $request->getAttribute('route'), + 'authenticated' => $request->getAttribute('authenticated'), + 'username' => $request->getAttribute('username'), + ]); $body = $response->getBody(); $body->seek($body->getSize()); diff --git a/packages/bluedebug/view/debug_toolbar.html.twig b/packages/bluedebug/view/debug_toolbar.html.twig new file mode 100644 index 0000000..6001d55 --- /dev/null +++ b/packages/bluedebug/view/debug_toolbar.html.twig @@ -0,0 +1,8 @@ +
+
Route: {{ route.controller }}::{{ route.action }}
+ {% if authenticated %} +
User (authenticated): {{ username }}
+ {% else %} +
User (anonymous session)
+ {% endif %} +
diff --git a/packages/bluefluid/.editorconfig b/packages/bluefluid/.editorconfig deleted file mode 100644 index aee148b..0000000 --- a/packages/bluefluid/.editorconfig +++ /dev/null @@ -1,23 +0,0 @@ -root = true - -[*] -end_of_line = lf -insert_final_newline = true -charset = utf-8 -trim_trailing_whitespace = true - -[*.html] -indent_style = tab -indent_size = 4 - -[*.php] -indent_style = space -indent_size = 4 - -[*.md] -indent_style = space -indent_size = 4 - -[*.json] -indent_style = tab -indent_size = 4 diff --git a/packages/bluefluid/composer.json b/packages/bluefluid/composer.json deleted file mode 100644 index e53fc90..0000000 --- a/packages/bluefluid/composer.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "vertexvaar/bluefluid", - "description": "BlueFluids provides an adapter for the TYPO3 templating engine Fluid", - "type": "project", - "license": "GPL-3.0+", - "authors": [ - { - "name": "Oliver Eglseder", - "email": "bluesprints@vxvr.de", - "homepage": "http://vxvr.de/", - "role": "Developer" - } - ], - "autoload": { - "psr-4": { - "VerteXVaaR\\BlueFluid\\": "src/" - } - }, - "require": { - "php": "8.2.*", - "typo3fluid/fluid": "^2.2", - "vertexvaar/bluesprints": "@dev" - } -} diff --git a/packages/bluefluid/config/services.yaml b/packages/bluefluid/config/services.yaml deleted file mode 100644 index 75b2c2f..0000000 --- a/packages/bluefluid/config/services.yaml +++ /dev/null @@ -1,9 +0,0 @@ -services: - _defaults: - autowire: true - autoconfigure: true - - VerteXVaaR\BlueFluid\: - resource: '../src/*' - - VerteXVaaR\BlueSprints\Mvc\TemplateRenderer: '@VerteXVaaR\BlueFluid\Mvc\FluidTemplateRenderer' diff --git a/packages/bluefluid/src/Mvc/FluidTemplateRenderer.php b/packages/bluefluid/src/Mvc/FluidTemplateRenderer.php deleted file mode 100644 index f650729..0000000 --- a/packages/bluefluid/src/Mvc/FluidTemplateRenderer.php +++ /dev/null @@ -1,65 +0,0 @@ -view = new TemplateView(); - } - - public function render(string $templateName = ''): string - { - $controller = str_replace('\\', '/', $this->routeConfiguration['controller']); - $viewRootPath = concat_paths(getenv('VXVR_BS_ROOT'), $this->paths->view); - - $this->view->getTemplatePaths()->setTemplateRootPaths( - [concat_paths($viewRootPath, 'Template', $controller, DIRECTORY_SEPARATOR)] - ); - $this->view->getTemplatePaths()->setLayoutRootPaths( - [concat_paths($viewRootPath, 'Layout', $controller, DIRECTORY_SEPARATOR)] - ); - $this->view->getTemplatePaths()->setPartialRootPaths( - [concat_paths($viewRootPath, 'Partial', $controller, DIRECTORY_SEPARATOR)] - ); - if (str_contains($controller, '/')) { - $this->view->getRenderingContext()->setControllerName(substr($controller, strrpos($controller, '/') + 1)); - } else { - $this->view->getRenderingContext()->setControllerName($controller); - } - - if (empty($templateName)) { - $templateName = $this->routeConfiguration['action']; - } - return $this->view->render($templateName); - } - - public function setVariable(string $key, $value = null): void - { - $this->view->assign($key, $value); - } - - public function setRouteConfiguration(array $routeConfiguration): void - { - $this->routeConfiguration = $routeConfiguration; - } -} diff --git a/packages/bluesprints/composer.json b/packages/bluesprints/composer.json index 8ccd5bf..9b85b85 100644 --- a/packages/bluesprints/composer.json +++ b/packages/bluesprints/composer.json @@ -23,7 +23,8 @@ "psr/container": "^2.0", "guzzlehttp/psr7": "^2.6", "co-stack/lib": "^v5.0.0", - "symfony/dotenv": "^v6.3.0" + "symfony/dotenv": "^v6.3.0", + "twig/twig": "^v3.7.1" }, "bin": [ "bin/bluesprints" diff --git a/packages/bluesprints/config/services.php b/packages/bluesprints/config/services.php index 09d69ae..16ce7dd 100644 --- a/packages/bluesprints/config/services.php +++ b/packages/bluesprints/config/services.php @@ -8,6 +8,7 @@ use VerteXVaaR\BlueSprints\Mvc\Controller; use VerteXVaaR\BlueSprints\Mvc\DependencyInjection\PublicServicePass; use VerteXVaaR\BlueSprints\Routing\DependencyInjection\RouteCollectorCompilerPass; +use VerteXVaaR\BlueSprints\Template\DependencyInjection\TemplateRendererCompilerPass; return static function (ContainerBuilder $container): void { $container->addCompilerPass(new EnvironmentCompilerPass()); @@ -15,6 +16,7 @@ $container->addCompilerPass(new ConfigCompilerPass()); $container->addCompilerPass(new MiddlewareCompilerPass()); $container->addCompilerPass(new RouteCollectorCompilerPass()); + $container->addCompilerPass(new TemplateRendererCompilerPass()); $container->registerForAutoconfiguration(Controller::class) ->addTag('vertexvaar.bluesprints.controller'); diff --git a/packages/bluesprints/config/services.yaml b/packages/bluesprints/config/services.yaml index 38fcfe4..e7d2431 100644 --- a/packages/bluesprints/config/services.yaml +++ b/packages/bluesprints/config/services.yaml @@ -27,6 +27,12 @@ services: public: true shared: true + VerteXVaaR\BlueSprints\Template\TwigFactory: + public: true + + Twig\Environment: + factory: ['@VerteXVaaR\BlueSprints\Template\TwigFactory', 'create'] + Psr\Http\Server\RequestHandlerInterface: '@VerteXVaaR\BlueSprints\Http\Server\RequestHandler\ControllerDispatcher' VerteXVaaR\BlueSprints\Mvc\TemplateRenderer: '@VerteXVaaR\BlueSprints\Mvc\PhpTemplateRenderer' diff --git a/packages/bluesprints/src/Environment/DependencyInjection/ConfigCompilerPass.php b/packages/bluesprints/src/Environment/DependencyInjection/ConfigCompilerPass.php index b7ffb11..d523f70 100644 --- a/packages/bluesprints/src/Environment/DependencyInjection/ConfigCompilerPass.php +++ b/packages/bluesprints/src/Environment/DependencyInjection/ConfigCompilerPass.php @@ -15,7 +15,7 @@ public function process(ContainerBuilder $container) { /** @var Composer $composer */ $composer = $container->get('composer'); - $packageConfig = $composer->getPackage()->getConfig(); + $packageConfig = $composer->getPackage()->getExtra(); $config = $packageConfig['vertexvaar/bluesprints']; $permissions = $config['permissions'] ?? []; diff --git a/packages/bluesprints/src/Environment/DependencyInjection/PathsCompilerPass.php b/packages/bluesprints/src/Environment/DependencyInjection/PathsCompilerPass.php index 64209d6..eddb2c5 100644 --- a/packages/bluesprints/src/Environment/DependencyInjection/PathsCompilerPass.php +++ b/packages/bluesprints/src/Environment/DependencyInjection/PathsCompilerPass.php @@ -15,7 +15,7 @@ public function process(ContainerBuilder $container) { /** @var Composer $composer */ $composer = $container->get('composer'); - $packageConfig = $composer->getPackage()->getConfig(); + $packageConfig = $composer->getPackage()->getExtra(); $config = $packageConfig['vertexvaar/bluesprints']; $pathsDefinition = $container->getDefinition(Paths::class); diff --git a/packages/bluesprints/src/Http/Server/RequestHandler/ControllerDispatcher.php b/packages/bluesprints/src/Http/Server/RequestHandler/ControllerDispatcher.php index 150d82a..cc758ae 100644 --- a/packages/bluesprints/src/Http/Server/RequestHandler/ControllerDispatcher.php +++ b/packages/bluesprints/src/Http/Server/RequestHandler/ControllerDispatcher.php @@ -29,26 +29,17 @@ public function __construct( public function handle(ServerRequestInterface $request): ResponseInterface { - ob_start(); - define('VXVR_BS_REQUEST_METHOD', $request->getMethod()); - $route = $request->getAttribute('route'); - $response = new Response(); /** @var AbstractController $controller */ $controller = $this->container->get($route['controller']); - $content = ''; try { - $content = $controller->callActionMethod($route, $request); + return $controller->{$route['action']}($request); } catch (RedirectException $exception) { - $response = $response->withHeader('Location', $exception->getUrl())->withStatus($exception->getStatus()); - } - if ($this->environment->context === Context::Development) { - $content = ob_get_contents() . $content; + $response = new Response(); + return $response + ->withHeader('Location', $exception->getUrl()) + ->withStatus($exception->getStatus()); } - - $response->getBody()->write($content); - ob_end_clean(); - return $response; } } diff --git a/packages/bluesprints/src/Mvc/AbstractController.php b/packages/bluesprints/src/Mvc/AbstractController.php index 9b005c5..840065c 100644 --- a/packages/bluesprints/src/Mvc/AbstractController.php +++ b/packages/bluesprints/src/Mvc/AbstractController.php @@ -4,44 +4,25 @@ namespace VerteXVaaR\BlueSprints\Mvc; -use Psr\Http\Message\ServerRequestInterface; - -use function call_user_func; -use function is_callable; +use GuzzleHttp\Psr7\Response; +use Psr\Http\Message\ResponseInterface; +use Twig\Environment; abstract class AbstractController implements Controller { - - /** - * @var bool Indicates if the template should be rendered after the action has been called - */ - protected bool $renderTemplate = true; - public function __construct( protected readonly Repository $repository, - protected readonly TemplateRenderer $templateRenderer + protected readonly Environment $view ) { } - /** - * @throws RedirectException - */ - public function callActionMethod(array $configuration, ServerRequestInterface $request): string + protected function render(string $template, array $context = []) { - if (is_callable([$this, 'initialize'])) { - call_user_func([$this, 'initialize']); - } - - $this->templateRenderer->setRouteConfiguration($configuration); - $this->{$configuration['action']}($request); - if (true === $this->renderTemplate) { - return $this->templateRenderer->render(); - } - return ''; + return new Response(200, [], $this->view->render($template, $context)); } - protected function redirect($url, $code = RedirectException::SEE_OTHER): void + protected function redirect($url, $code = RedirectException::SEE_OTHER): ResponseInterface { - throw RedirectException::forUrl($url, $code); + return new Response($code, ['Location' => $url]); } } diff --git a/packages/bluesprints/src/Mvc/PhpTemplateRenderer.php b/packages/bluesprints/src/Mvc/PhpTemplateRenderer.php deleted file mode 100644 index bd2efb0..0000000 --- a/packages/bluesprints/src/Mvc/PhpTemplateRenderer.php +++ /dev/null @@ -1,60 +0,0 @@ -templateHelper = new TemplateHelper(); - } - - /** - * @param string $key - * @param mixed $value - */ - public function setVariable(string $key, $value): void - { - $this->variables[$key] = $value; - } - - /** - * @param array $routeConfiguration - */ - public function setRouteConfiguration(array $routeConfiguration): void - { - $this->routeConfiguration = $routeConfiguration; - } - - public function render(string $templateName = ''): string - { - if ($templateName === '') { - $templateName = $this->getDefaultTemplateName(); - } - $this->setVariable('templateHelper', $this->templateHelper); - ob_start(); - Files::requireFile('app/view/Template/' . $templateName . '.php', $this->variables); - $body = ob_get_contents(); - $content = $this->templateHelper->renderLayoutContent($body); - ob_end_clean(); - return $content; - } - - protected function getDefaultTemplateName(): string - { - $templateName = ucfirst($this->routeConfiguration['action']); - $templatePath = Folders::classNameToFolderName($this->routeConfiguration['controller']); - return $templatePath . $templateName; - } -} diff --git a/packages/bluesprints/src/Mvc/TemplateRenderer.php b/packages/bluesprints/src/Mvc/TemplateRenderer.php deleted file mode 100644 index 2daedc6..0000000 --- a/packages/bluesprints/src/Mvc/TemplateRenderer.php +++ /dev/null @@ -1,19 +0,0 @@ -get('io'); - $packageConfig = $composer->getPackage()->getConfig(); + $packageConfig = $composer->getPackage()->getExtra(); $configPath = $packageConfig['vertexvaar/bluesprints']['config'] ?? 'config'; if (!file_exists($configPath . '/routes.php')) { diff --git a/packages/bluesprints/src/Template/DependencyInjection/TemplateRendererCompilerPass.php b/packages/bluesprints/src/Template/DependencyInjection/TemplateRendererCompilerPass.php new file mode 100644 index 0000000..fd5d572 --- /dev/null +++ b/packages/bluesprints/src/Template/DependencyInjection/TemplateRendererCompilerPass.php @@ -0,0 +1,56 @@ +get('composer'); + $packageIterator = new PackageIterator($composer); + $templatePaths = $packageIterator->iterate(static function (Package $package, string $installPath): ?array { + $extra = $package->getExtra(); + if (isset($extra['vertexvaar/bluesprints']['view'])) { + $viewPath = $extra['vertexvaar/bluesprints']['view']; + $fullViewPath = concat_paths($installPath, $viewPath); + return [ + strtr($package->getName(), '/', '_') => $fullViewPath + ]; + } + return null; + }); + + + $rootPaths = []; + $extra = $composer->getPackage()->getExtra(); + if (isset($extra['vertexvaar/bluesprints']['view'])) { + $viewPath = $extra['vertexvaar/bluesprints']['view']; + $fullViewPath = concat_paths(getenv('VXVR_BS_ROOT'), $viewPath); + $rootPaths[FilesystemLoader::MAIN_NAMESPACE] = $fullViewPath; + } + $templatePaths = array_replace($rootPaths, ...array_filter($templatePaths)); + + $definition = $container->getDefinition(TemplatePathsRegistry::class); + $definition->setArgument('$paths', $templatePaths); + } +} diff --git a/packages/bluesprints/src/Template/TemplatePathsRegistry.php b/packages/bluesprints/src/Template/TemplatePathsRegistry.php new file mode 100644 index 0000000..e0c9937 --- /dev/null +++ b/packages/bluesprints/src/Template/TemplatePathsRegistry.php @@ -0,0 +1,12 @@ +templatePathsRegistry->paths as $namespace => $path) { + $loader->addPath($path, $namespace); + } + $twigCachePath = concat_paths(getenv('VXVR_BS_ROOT'), $this->paths->cache, 'twig'); + $filesystemCache = new FilesystemCache($twigCachePath); + $twig = new Environment( + $loader, + [ + 'cache' => $filesystemCache, + 'debug' => $this->environment->context === Context::Development + ] + ); + if ($this->environment->context === Context::Development) { + $twig->addExtension(new DebugExtension()); + } + return $twig; + } +} diff --git a/src/Controller/Welcome.php b/src/Controller/Welcome.php index 0e3fc04..600438e 100644 --- a/src/Controller/Welcome.php +++ b/src/Controller/Welcome.php @@ -4,34 +4,34 @@ namespace VerteXVaaR\BlueDist\Controller; +use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use VerteXVaaR\BlueDist\Model\Fruit; -use VerteXVaaR\BlueDist\Model\SubFolder\Branch; -use VerteXVaaR\BlueDist\Model\SubFolder\Leaf; -use VerteXVaaR\BlueDist\Model\SubFolder\Tree; use VerteXVaaR\BlueSprints\Mvc\AbstractController; use VerteXVaaR\BlueSprints\Utility\Strings; class Welcome extends AbstractController { - protected function index(): void + /** + * @noinspection PhpUnused + */ + public function index(): ResponseInterface { - $this->templateRenderer->setVariable( - 'strings', - [ - 'foo', - 'bar', - 'baz', - ] - ); + return $this->render('index.html.twig', ['strings' => ['foo', 'bar', 'baz']]); } - protected function listFruits(): void + /** + * @noinspection PhpUnused + */ + public function listFruits(): ResponseInterface { - $this->templateRenderer->setVariable('fruits', $this->repository->findAll(Fruit::class)); + return $this->render('fruits.html.twig', ['fruits' => $this->repository->findAll(Fruit::class)]); } - protected function createDemoFruits(): void + /** + * @noinspection PhpUnused + */ + public function createDemoFruits(): ResponseInterface { $fruitsData = [ [ @@ -57,10 +57,13 @@ protected function createDemoFruits(): void $fruit->name = $fruitData['name']; $this->repository->persist($fruit); } - $this->redirect('listFruits'); + return $this->redirect('listFruits'); } - protected function createFruit(ServerRequestInterface $request): void + /** + * @noinspection PhpUnused + */ + public function createFruit(ServerRequestInterface $request): ResponseInterface { $arguments = $request->getParsedBody(); if (isset($arguments['name'], $arguments['color'])) { @@ -69,81 +72,45 @@ protected function createFruit(ServerRequestInterface $request): void $fruit->name = $arguments['name']; $this->repository->persist($fruit); } - $this->redirect('listFruits'); + return $this->redirect('listFruits'); } - protected function editFruit(ServerRequestInterface $request): void + /** + * @noinspection PhpUnused + */ + public function editFruit(ServerRequestInterface $request): ResponseInterface { $fruit = $this->repository->findByUuid(Fruit::class, $request->getQueryParams()['fruit']); - $this->templateRenderer->setVariable('fruit', $fruit); + return $this->render('edit.html.twig', ['fruit' => $fruit]); } - protected function updateFruit(ServerRequestInterface $request): void + /** + * @noinspection PhpUnused + */ + public function updateFruit(ServerRequestInterface $request): ResponseInterface { $arguments = $request->getParsedBody(); if (isset($arguments['uuid'], $arguments['name'], $arguments['color'])) { $fruit = $this->repository->findByUuid(Fruit::class, $arguments['uuid']); + if (null === $fruit) { + return $this->redirect('listFruits'); + } $fruit->name = $arguments['name']; $fruit->color = $arguments['color']; $this->repository->persist($fruit); } - $this->redirect('listFruits'); - } - - protected function createTree(ServerRequestInterface $request): void - { - $arguments = $request->getParsedBody(); - $tree = new Tree(Strings::generateUuid()); - $tree->setGenus($arguments['genus']); - $this->repository->persist($tree); - $this->templateRenderer->setVariable('tree', $tree); - $this->templateRenderer->setVariable('branches', range(1, $arguments['numberOfBranches'])); + return $this->redirect('listFruits'); } - protected function newTree(): void - { - } - - protected function growBranches(ServerRequestInterface $request): void - { - $arguments = $request->getParsedBody(); - $tree = $this->repository->findByUuid(Tree::class, $arguments['tree']); - $branches = []; - foreach ($arguments['branches'] as $data) { - $branch = new Branch(Strings::generateUuid()); - $branch->setLength((int)$data['length']); - $branches[] = $branch; - } - $tree->setBranches($branches); - $this->repository->persist($tree); - $this->redirect('applyLeaves?tree=' . $tree->uuid); - } - - protected function applyLeaves(ServerRequestInterface $request): void - { - $arguments = $request->getQueryParams(); - $this->templateRenderer->setVariable( - 'tree', - $this->repository->findByUuid(Tree::class, $arguments['tree']) - ); - } - - protected function addLeaf(ServerRequestInterface $request): void - { - $arguments = $request->getParsedBody(); - $tree = $this->repository->findByUuid(Tree::class, $arguments['tree']); - $branch = $tree->getBranches()[$arguments['branch']]; - $leaves = $branch->getLeaves(); - $leaves[] = new Leaf(Strings::generateUuid(), count($leaves) + 1); - $branch->setLeaves($leaves); - $this->repository->persist($tree); - $this->redirect('applyLeaves?tree=' . $tree->uuid); - } - - protected function deleteFruit(ServerRequestInterface $request): void + /** + * @noinspection PhpUnused + */ + public function deleteFruit(ServerRequestInterface $request): ResponseInterface { $fruit = $this->repository->findByUuid(Fruit::class, $request->getParsedBody()['fruit']); - $this->repository->delete($fruit); - $this->redirect('listFruits'); + if (null !== $fruit) { + $this->repository->delete($fruit); + } + return $this->redirect('listFruits'); } } diff --git a/view/Layout/VerteXVaaR/BlueAuth/Controller/AuthenticationController/Html.html b/view/Layout/VerteXVaaR/BlueAuth/Controller/AuthenticationController/Html.html deleted file mode 100644 index a3b77af..0000000 --- a/view/Layout/VerteXVaaR/BlueAuth/Controller/AuthenticationController/Html.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - {pageTitle} - - - - - - diff --git a/view/Layout/VerteXVaaR/BlueDist/Controller/Welcome/Html.html b/view/Layout/VerteXVaaR/BlueDist/Controller/Welcome/Html.html deleted file mode 100644 index a3b77af..0000000 --- a/view/Layout/VerteXVaaR/BlueDist/Controller/Welcome/Html.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - {pageTitle} - - - - - - diff --git a/view/Template/DebugToolbarMiddleware/DebugToolbarMiddleware/DebugToolbar.html b/view/Template/DebugToolbarMiddleware/DebugToolbarMiddleware/DebugToolbar.html deleted file mode 100644 index 6f56032..0000000 --- a/view/Template/DebugToolbarMiddleware/DebugToolbarMiddleware/DebugToolbar.html +++ /dev/null @@ -1,13 +0,0 @@ - -
-
Route: {route.controller}::{route.action}
- - -
User (authenticated): {username}
-
- -
User (anonymous session)
-
-
-
- diff --git a/view/Template/VerteXVaaR/BlueAuth/Controller/AuthenticationController/AuthenticationController/Login.html b/view/Template/VerteXVaaR/BlueAuth/Controller/AuthenticationController/AuthenticationController/Login.html deleted file mode 100644 index e72d23c..0000000 --- a/view/Template/VerteXVaaR/BlueAuth/Controller/AuthenticationController/AuthenticationController/Login.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - -
-

Login

-
- - - - - - -
- - - - - -
-
-
-
- diff --git a/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/ApplyLeaves.html b/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/ApplyLeaves.html deleted file mode 100644 index da7047c..0000000 --- a/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/ApplyLeaves.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - -
-

Put some Leaves on {tree.genus}s branches!

- -

- Branch #{i.index} with length: {branch.length} -
- - Leaf #{leaf.number}, - -

- -
- - - -
-
-
-
- diff --git a/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/CreateTree.html b/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/CreateTree.html deleted file mode 100644 index d9dcbfe..0000000 --- a/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/CreateTree.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - -
- -

Grow some branches on {tree.genus}!

- -
- - -

- -

-
- -
-
-
- diff --git a/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/EditFruit.html b/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/EditFruit.html deleted file mode 100644 index f6c7c25..0000000 --- a/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/EditFruit.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - -
-

Change a {fruit.name}

- -

- Objects are target to many modifications, so updating a already persistend object is essential.
- Change the name or color of your selected fruit and save it, or go back to the - list. -

- -
- - -

- -

- -

- -

- -
- -
- - -
- - -

The code behind this object update

- -
-			$arguments = $this->request->getParsedBody();
-			if (isset($arguments['uuid'], $arguments['name'], $arguments['color'])) {
-				$fruit = Fruit::findByUuid($arguments['uuid']);
-				$fruit->setName($arguments['name']);
-				$fruit->setColor($arguments['color']);
-				$fruit->save();
-			}
-			$this->redirect('listFruits');
-		
- -

About safe requests

- -

- HTTP requests are divided into two different types. Safe and not safe requests. - A safe request must not modify an object or persist changes. - Safe requests exist to retrieve information from a service or website without changing any data. - Safe requests are idempotent. - To change the name of a fruit you must make a non-safe request, e.g. POST. - PUT, POST, and DELETE are considered non-safe because they may change data. -

- -

Try it

- -

- This link will not work since the - request parameters are expected to exist in POST. - You will be redirected to the listFruits view. -

-
- -
- diff --git a/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/Index.html b/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/Index.html deleted file mode 100644 index d2224ba..0000000 --- a/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/Index.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - -
- -

Welcome to VerteXVaaR.BlueSprints

- -

An experiment gone right :D

- -

- VerteXVaaR.BlueSprints was created in a few hours as an experiment of "what could be done in 3 hours" - and it's development continued for 6 other hours. After 9 hours it had (all simple) routing, templating, - of course autoloading (thanks composer) and NoDB persistence, all out of the box. But more is to come. -

- -

It will stay simple!

- -

- This PHP Framework is designed to stay as simple as possible but yet provide some indispensable - features. - So there is no Database connection or Dependency Injection and it's not about to come. If you are - searching - for - a framework capable of that, you have to search for another. -

- -

Fast framework, fast Development

- -

- Because there are almost no classes inside of VerteXVaaR.BlueSprints and it has no reflection or - abstraction - it is simply fast by design, without any caching. - This (nearly) slender design is good for performance, but it prevents some features. But if you want to - develop - a simple Application that stores a few models or just prints out content you will be convinced by your - own - development speed -

- -

Templating

- -

- Templating might be something you have to get used to, because it uses pure PHP. There is nothing fancy - like - twig, handlebars.js or TYPO3.Fluid. Just some PHP that is executed right away. Not even cached. - Here is some data set by the controller. Only for your pleasure ;) -

-
    - -
  • {string}
  • -
    -
- -

Persistence?

- -

- Want a demo about Persistence? Just follow me ;) -

-
-
- diff --git a/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/ListFruits.html b/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/ListFruits.html deleted file mode 100644 index 72ba457..0000000 --- a/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/ListFruits.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - -
- -

Some Fruits freshly picked from persistence

- - - -

- Hint: click on a fruit to edit it! -

- - -
- -

OH WAIT! There is no Fruit yet.

-
- -
-
-
- -

- Not enough fruits? Just create your own fruit here: -

- -
-

- -

- -

- -

- -
- -

The NoDB Storage

- -

- Since there is no configuration for any storage or database i owe you an explanation. - BlueSprints just uses the file system. The full qualified class name of a model is converted into a - directory - structure. Inside the last directory all models are stored in files named by their automatically created - uuid. - The objects are serialized, since this is the fastest option to store all simple values without - reflection, - additional configuration or such. -

- -

WIP !

- -

- The Storage function is currently work in progress. Some missing features are automatic index tables for - searching - models by their properties or the deletion of those. -

- -

Like it? Or not?

- -

- Have a look at the code which creates a fruit from the form above: -

- -
-            $arguments = $this->request->getParsedBody();
-            if (isset($arguments['name'], $arguments['color'])) {
-                $fruit = new Fruit();
-                $fruit->setColor($arguments['color']);
-                $fruit->setName($arguments['name']);
-                $fruit->save();
-            }
-            $this->redirect('listFruits');
-        
- -

- As i promised you, it is easy as pie. If you want to alter the Model, say add a new property, just do - it. -

- -

- Back to the index -

-
-
- diff --git a/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/NewTree.html b/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/NewTree.html deleted file mode 100644 index bbc56bf..0000000 --- a/view/Template/VerteXVaaR/BlueDist/Controller/Welcome/NewTree.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - -
- -

Plant a tree!

- -

- Create a new Tree object. After the Tree has been planted, it will grow branches and - each branch will grow some leaves. -

- -
-

- -

- -

- -

- -
-
-
- diff --git a/view/edit.html.twig b/view/edit.html.twig new file mode 100644 index 0000000..6f2f33a --- /dev/null +++ b/view/edit.html.twig @@ -0,0 +1,70 @@ +{% extends "layout.html.twig" %} + +{% block content %} +
+

Change a {{ fruit.name }}

+ +

+ Objects are target to many modifications, so updating a already persistend object is essential.
+ Change the name or color of your selected fruit and save it, or go back to the + list. +

+ +
+ + +

+ +

+ +

+ +

+ +
+ +
+ + +
+ + +

The code behind this object update

+ +
+        $arguments = $this->request->getParsedBody();
+        if (isset($arguments['uuid'], $arguments['name'], $arguments['color'])) {
+            $fruit = Fruit::findByUuid($arguments['uuid']);
+            $fruit->setName($arguments['name']);
+            $fruit->setColor($arguments['color']);
+            $fruit->save();
+        }
+        $this->redirect('listFruits');
+    
+ +

About safe requests

+ +

+ HTTP requests are divided into two different types. Safe and not safe requests. + A safe request must not modify an object or persist changes. + Safe requests exist to retrieve information from a service or website without changing any data. + Safe requests are idempotent. + To change the name of a fruit you must make a non-safe request, e.g. POST. + PUT, POST, and DELETE are considered non-safe because they may change data. +

+ +

Try it

+ +

+ This link will not work since the + request parameters are expected to exist in POST. + You will be redirected to the listFruits view. +

+
+{% endblock %} diff --git a/view/fruits.html.twig b/view/fruits.html.twig new file mode 100644 index 0000000..ca95e20 --- /dev/null +++ b/view/fruits.html.twig @@ -0,0 +1,103 @@ +{% extends "layout.html.twig" %} + +{% block content %} +
+ +

Some Fruits freshly picked from persistence

+ + {% if fruits %} +

+ Hint: click on a fruit to edit it! +

+ + + {% else %} +

OH WAIT! There is no Fruit yet.

+
+ +
+ {% endif %} + +

+ Not enough fruits? Just create your own fruit here: +

+ +
+

+ +

+ +

+ +

+ +
+ +

The NoDB Storage

+ +

+ Since there is no configuration for any storage or database i owe you an explanation. + BlueSprints just uses the file system. The full qualified class name of a model is converted into a + directory + structure. Inside the last directory all models are stored in files named by their automatically created + uuid. + The objects are serialized, since this is the fastest option to store all simple values without + reflection, + additional configuration or such. +

+ +

WIP !

+ +

+ The Storage function is currently work in progress. Some missing features are automatic index tables for + searching + models by their properties or the deletion of those. +

+ +

Like it? Or not?

+ +

+ Have a look at the code which creates a fruit from the form above: +

+ +
+            $arguments = $this->request->getParsedBody();
+            if (isset($arguments['name'], $arguments['color'])) {
+                $fruit = new Fruit();
+                $fruit->setColor($arguments['color']);
+                $fruit->setName($arguments['name']);
+                $fruit->save();
+            }
+            $this->redirect('listFruits');
+        
+ +

+ As i promised you, it is easy as pie. If you want to alter the Model, say add a new property, just do + it. +

+ +

+ Back to the index +

+
+{% endblock %} diff --git a/view/index.html.twig b/view/index.html.twig new file mode 100644 index 0000000..b5fe613 --- /dev/null +++ b/view/index.html.twig @@ -0,0 +1,58 @@ +{% extends "layout.html.twig" %} + +{% block content %} +
+ +

Welcome to VerteXVaaR.BlueSprints

+ +

An experiment gone right :D

+ +

+ VerteXVaaR.BlueSprints was created in a few hours as an experiment of "what could be done in 3 hours" + and it's development continued for 6 other hours. After 9 hours it had (all simple) routing, templating, + of course autoloading (thanks composer) and NoDB persistence, all out of the box. But more is to come. +

+ +

It will stay simple!

+ +

+ This PHP Framework is designed to stay as simple as possible but yet provide some indispensable + features. + So there is no Database connection or Dependency Injection and it's not about to come. If you are + searching + for + a framework capable of that, you have to search for another. +

+ +

Fast framework, fast Development

+ +

+ Because there are almost no classes inside of VerteXVaaR.BlueSprints and it has no reflection or + abstraction + it is simply fast by design, without any caching. + This (nearly) slender design is good for performance, but it prevents some features. But if you want to + develop + a simple Application that stores a few models or just prints out content you will be convinced by your + own + development speed +

+ +

Templating

+ +

+ Templating might be something you have don't have to get used to, because it uses Twig. + Here is some data set by the controller: +

+
    + {% for string in strings %} +
  • {{ string }}
  • + {% endfor %} +
+ +

Persistence?

+ +

+ Want a demo about Persistence? Just follow me ;) +

+
+{% endblock %} diff --git a/view/layout.html.twig b/view/layout.html.twig new file mode 100644 index 0000000..1e894c5 --- /dev/null +++ b/view/layout.html.twig @@ -0,0 +1,14 @@ + + + + + {% block head %} + + {% endblock %} + {{ pageTitle }} + + + + {% block content %}No content in here{% endblock %} + +