From b1d0a464b595683c687b8a75a53289eadf0f8a68 Mon Sep 17 00:00:00 2001 From: pjordaan Date: Sun, 9 Jul 2023 15:00:06 +0000 Subject: [PATCH 01/11] Update file(s) "packages/laravel-apie/." from "apie-lib/apie-lib-monorepo" --- .github/workflows/php.yml | 52 ++++++++ LICENSE | 2 +- README.md | 19 ++- composer.json | 37 ++++++ phpunit.xml | 13 ++ resources/apie.php | 49 +++++++ resources/routes.php | 8 ++ src/ApieServiceProvider.php | 96 ++++++++++++++ src/Providers/ApieServicesServiceProvider.php | 124 ++++++++++++++++++ src/Providers/CmsServiceProvider.php | 19 +++ src/Providers/SecurityServiceProvider.php | 27 ++++ src/Wrappers/Cms/DashboardContents.php | 12 ++ src/Wrappers/Core/BoundedContextSelected.php | 38 ++++++ src/Wrappers/Routing/ApieRouteLoader.php | 50 +++++++ .../Security/ApieUserAuthenticator.php | 60 +++++++++ src/Wrappers/Security/ApieUserDecorator.php | 42 ++++++ src/Wrappers/Security/ApieUserProvider.php | 43 ++++++ .../UserAuthenticationContextBuilder.php | 27 ++++ templates/dashboard.blade.php | 13 ++ templates/error.blade.php | 1 + tests/Fixtures/Actions/Authentication.php | 17 +++ tests/Fixtures/Entities/TestEntity.php | 18 +++ tests/Fixtures/Entities/User.php | 18 +++ .../ValueObjects/TestEntityIdentifier.php | 15 +++ .../Fixtures/ValueObjects/UserIdentifier.php | 15 +++ tests/LaravelApieTest.php | 51 +++++++ 26 files changed, 863 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/php.yml create mode 100644 composer.json create mode 100644 phpunit.xml create mode 100644 resources/apie.php create mode 100644 resources/routes.php create mode 100644 src/ApieServiceProvider.php create mode 100644 src/Providers/ApieServicesServiceProvider.php create mode 100644 src/Providers/CmsServiceProvider.php create mode 100644 src/Providers/SecurityServiceProvider.php create mode 100644 src/Wrappers/Cms/DashboardContents.php create mode 100644 src/Wrappers/Core/BoundedContextSelected.php create mode 100644 src/Wrappers/Routing/ApieRouteLoader.php create mode 100644 src/Wrappers/Security/ApieUserAuthenticator.php create mode 100644 src/Wrappers/Security/ApieUserDecorator.php create mode 100644 src/Wrappers/Security/ApieUserProvider.php create mode 100644 src/Wrappers/Security/UserAuthenticationContextBuilder.php create mode 100644 templates/dashboard.blade.php create mode 100644 templates/error.blade.php create mode 100644 tests/Fixtures/Actions/Authentication.php create mode 100644 tests/Fixtures/Entities/TestEntity.php create mode 100644 tests/Fixtures/Entities/User.php create mode 100644 tests/Fixtures/ValueObjects/TestEntityIdentifier.php create mode 100644 tests/Fixtures/ValueObjects/UserIdentifier.php create mode 100644 tests/LaravelApieTest.php diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000..7ddb50a --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,52 @@ +name: PHPUnit + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + coverage: pcov + ini-values: pcov.directory=src + - uses: actions/checkout@v2 + + - name: Sleep for 30 seconds + uses: jakejarvis/wait-action@master + with: + time: '30s' + + - name: Validate composer.json + run: composer validate + + - name: Install dependencies + if: steps.composer-cache.outputs.cache-hit != 'true' + run: composer install --prefer-dist --no-progress + + - name: Run test suite + run: vendor/bin/phpunit tests --coverage-clover=clover.xml --coverage-html=coverage + + - name: phpunit-coverage-badge + uses: timkrase/phpunit-coverage-badge@v1.2.0 + with: + push_badge: true + repo_token: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/upload-artifact@v3 + with: + name: Code coverage (HTML) + path: coverage + + - uses: actions/upload-artifact@v3 + with: + name: Code coverage (Clover xml) + path: clover.xml \ No newline at end of file diff --git a/LICENSE b/LICENSE index 3eaeb75..f6337ff 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 apie-lib +Copyright (c) 2020 apie-lib Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index b0b9ec4..03c4484 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,17 @@ -# laravel-apie -Connect the Apie library with Laravel + +

laravel-apie

+ + + + + + + [![Latest Stable Version](http://poser.pugx.org/apie/laravel-apie/v)](https://packagist.org/packages/apie/laravel-apie) [![Total Downloads](http://poser.pugx.org/apie/laravel-apie/downloads)](https://packagist.org/packages/apie/laravel-apie) [![Latest Unstable Version](http://poser.pugx.org/apie/laravel-apie/v/unstable)](https://packagist.org/packages/apie/laravel-apie) [![License](http://poser.pugx.org/apie/laravel-apie/license)](https://packagist.org/packages/apie/laravel-apie) [![PHP Version Require](http://poser.pugx.org/apie/laravel-apie/require/php)](https://packagist.org/packages/apie/laravel-apie) [![Code coverage](https://raw.githubusercontent.com/apie-lib/laravel-apie/main/coverage_badge.svg)](https://apie-lib.github.io/coverage/laravel-apie/index.html) + +[![PHP Composer](https://github.com/apie-lib/laravel-apie/actions/workflows/php.yml/badge.svg?event=push)](https://github.com/apie-lib/laravel-apie/actions/workflows/php.yml) + +This package is part of the [Apie](https://github.com/apie-lib) library. +The code is maintained in a monorepo, so PR's need to be sent to the [monorepo](https://github.com/apie-lib/apie-lib-monorepo/pulls) + +## Documentation +This package is used internally in Apie or no documentation is available right now diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..eb9d62f --- /dev/null +++ b/composer.json @@ -0,0 +1,37 @@ +{ + "name": "apie/laravel-apie", + "description": "Composer package of the apie library: laravel apie", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Pieter Jordaan", + "email": "pieter_jordaan@hotmail.com" + } + ], + "autoload": { + "psr-4": { + "Apie\\LaravelApie\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Apie\\Tests\\LaravelApie\\": "tests/" + } + }, + "require": { + "php": ">=8.1", + "apie/common": "self.version", + "apie/core": "self.version", + "apie/service-provider-generator": "dev-main", + "laravel/laravel": "7.*|8.*|9.*|10.*", + "symfony/psr-http-message-bridge": "2.*" + }, + "require-dev": { + "apie/rest-api": "self.version", + "phpunit/phpunit": "^9.5", + "phpspec/prophecy-phpunit": "^2.0" + }, + "minimum-stability": "dev", + "prefer-stable": true +} \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..684bed0 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,13 @@ + + + + + ./src + + + + + ./tests + + + diff --git a/resources/apie.php b/resources/apie.php new file mode 100644 index 0000000..f7ebaf0 --- /dev/null +++ b/resources/apie.php @@ -0,0 +1,49 @@ + [ + 'base_url' => '/cms', + 'dashboard_template' => 'apie::dashboard', + 'error_template' => 'apie::error', + 'asset_folders' => [ + // storage_path('overrides') + ] + ], + 'rest_api' => [ + 'base_url' => '/api', + ], + 'datalayers' => [ + 'default_datalayer' => RequestAwareInMemoryDatalayer::class, + 'context_mapping' => [ + // 'bounded context id' => [ + // 'default_datalayer' => DataLayer::class, + // 'entity_mapping' => [ + // ClassName::class => DataLayer::class, + // ] + //] + ] + ], + 'bounded_contexts' => [ + 'default' => [ + 'entities_folder' => app_path('Apie/Entities'), + 'entities_namespace' => 'App\\Apie\\Entities\\', + 'actions_folder' => app_path('Apie/Actions'), + 'actions_namespace' => 'App\\Apie\\Actions\\', + ] + ], + 'enable_core' => true, + 'enable_cms' => class_exists(CmsRouteDefinitionProvider::class), + 'enable_cms_dropdown' => class_exists(DropdownOptionsForExistingObjectRouteDefinition::class), + 'enable_faker' => class_exists(ApieObjectFaker::class), + 'enable_rest_api' => class_exists(OpenApiGenerator::class), + 'enable_console' => class_exists(ConsoleCommandFactory::class), + 'enable_security' => true, +]; diff --git a/resources/routes.php b/resources/routes.php new file mode 100644 index 0000000..00774b0 --- /dev/null +++ b/resources/routes.php @@ -0,0 +1,8 @@ +loadRoutes($group); diff --git a/src/ApieServiceProvider.php b/src/ApieServiceProvider.php new file mode 100644 index 0000000..b57c55f --- /dev/null +++ b/src/ApieServiceProvider.php @@ -0,0 +1,96 @@ + [ + CommonServiceProvider::class, + CmsServiceProvider::class, + HtmlBuilderServiceProvider::class, + SerializerServiceProvider::class, + ], + 'enable_cms_dropdown' => [ + CommonServiceProvider::class, + CmsDropdownServiceProvider::class, + ], + 'enable_core' => [ + CoreServiceProvider::class, + ], + 'enable_console' => [ + CommonServiceProvider::class, + ConsoleServiceProvider::class, + SerializerServiceProvider::class, + ], + 'enable_security' => [ + CommonServiceProvider::class, + SerializerServiceProvider::class, + SecurityServiceProvider::class, + ], + 'enable_rest_api' => [ + CommonServiceProvider::class, + RestApiServiceProvider::class, + SchemaGeneratorServiceProvider::class, + SerializerServiceProvider::class, + ], + 'enable_faker' => [ + FakerServiceProvider::class, + ], + ]; + + public function boot() + { + $this->loadViewsFrom(__DIR__ . '/../templates', 'apie'); + $this->loadRoutesFrom(__DIR__.'/../resources/routes.php'); + } + + public function register() + { + $this->mergeConfigFrom(__DIR__ . '/../resources/apie.php', 'apie'); + + // fix for https://github.com/laravel/framework/issues/30415 + $this->app->extend( + ServerRequestInterface::class, + function (ServerRequestInterface $psrRequest) { + $route = $this->app->make('request')->route(); + if ($route) { + $parameters = $route->parameters(); + foreach ($parameters as $key => $value) { + $psrRequest = $psrRequest->withAttribute($key, $value); + } + } + return $psrRequest; + } + ); + + $this->app->bind(BoundedContextSelection::class, BoundedContextSelected::class); + + $alreadyRegistered = []; + foreach ($this->dependencies as $configKey => $dependencies) { + if (config('apie.' . $configKey, false)) { + foreach ($dependencies as $dependency) { + if (!isset($alreadyRegistered[$dependency])) { + $alreadyRegistered[$dependency] = $dependency; + $this->app->register($dependency); + } + } + } + } + } +} diff --git a/src/Providers/ApieServicesServiceProvider.php b/src/Providers/ApieServicesServiceProvider.php new file mode 100644 index 0000000..5648fb0 --- /dev/null +++ b/src/Providers/ApieServicesServiceProvider.php @@ -0,0 +1,124 @@ +app->singleton( + \Apie\ApieBundle\Routing\ApieRouteLoader::class, + function ($app) { + return new \Apie\ApieBundle\Routing\ApieRouteLoader( + $app->make('apie.route_definitions.provider'), + $app->make('apie.bounded_context.hashmap'), + $app->make(\Apie\Common\RouteDefinitions\PossibleRoutePrefixProvider::class) + ); + } + ); + \Apie\ServiceProviderGenerator\TagMap::register( + $this->app, + \Apie\ApieBundle\Routing\ApieRouteLoader::class, + array( + 0 => 'routing.loader', + ) + ); + $this->app->tag([\Apie\ApieBundle\Routing\ApieRouteLoader::class], 'routing.loader'); + $this->app->singleton( + \Apie\ApieBundle\ContextBuilders\ServiceContextBuilder::class, + function ($app) { + return new \Apie\ApieBundle\ContextBuilders\ServiceContextBuilder( + $this->getTaggedServicesServiceLocator('apie.context') + ); + } + ); + \Apie\ServiceProviderGenerator\TagMap::register( + $this->app, + \Apie\ApieBundle\ContextBuilders\ServiceContextBuilder::class, + array( + 0 => 'apie.core.context_builder', + ) + ); + $this->app->tag([\Apie\ApieBundle\ContextBuilders\ServiceContextBuilder::class], 'apie.core.context_builder'); + $this->app->singleton( + \Apie\ApieBundle\ContextBuilders\SessionContextBuilder::class, + function ($app) { + return new \Apie\ApieBundle\ContextBuilders\SessionContextBuilder( + $app->make('request_stack') + ); + } + ); + \Apie\ServiceProviderGenerator\TagMap::register( + $this->app, + \Apie\ApieBundle\ContextBuilders\SessionContextBuilder::class, + array( + 0 => 'apie.core.context_builder', + ) + ); + $this->app->tag([\Apie\ApieBundle\ContextBuilders\SessionContextBuilder::class], 'apie.core.context_builder'); + $this->app->singleton( + \Apie\ApieBundle\ContextBuilders\CsrfTokenContextBuilder::class, + function ($app) { + return new \Apie\ApieBundle\ContextBuilders\CsrfTokenContextBuilder( + $app->bound(\Symfony\Component\Security\Csrf\CsrfTokenManagerInterface::class) ? $app->make(\Symfony\Component\Security\Csrf\CsrfTokenManagerInterface::class) : null + ); + } + ); + \Apie\ServiceProviderGenerator\TagMap::register( + $this->app, + \Apie\ApieBundle\ContextBuilders\CsrfTokenContextBuilder::class, + array( + 0 => 'apie.core.context_builder', + ) + ); + $this->app->tag([\Apie\ApieBundle\ContextBuilders\CsrfTokenContextBuilder::class], 'apie.core.context_builder'); + $this->app->bind(\Apie\Common\Interfaces\BoundedContextSelection::class, \Apie\ApieBundle\Wrappers\BoundedContextSelected::class); + + $this->app->singleton( + \Apie\ApieBundle\Wrappers\BoundedContextSelected::class, + function ($app) { + return new \Apie\ApieBundle\Wrappers\BoundedContextSelected( + $app->make('request_stack'), + $app->make(\Apie\Core\BoundedContext\BoundedContextHashmap::class) + ); + } + ); + \Apie\ServiceProviderGenerator\TagMap::register( + $this->app, + \Apie\ApieBundle\Wrappers\BoundedContextSelected::class, + array( + 0 => 'apie.context', + ) + ); + $this->app->tag([\Apie\ApieBundle\Wrappers\BoundedContextSelected::class], 'apie.context'); + $this->app->singleton( + \Apie\ApieBundle\EventListeners\RenderErrorListener::class, + function ($app) { + return new \Apie\ApieBundle\EventListeners\RenderErrorListener( + $app->bound(\Apie\HtmlBuilders\Factories\ComponentFactory::class) ? $app->make(\Apie\HtmlBuilders\Factories\ComponentFactory::class) : null, + $app->bound(\Apie\HtmlBuilders\Interfaces\ComponentRendererInterface::class) ? $app->make(\Apie\HtmlBuilders\Interfaces\ComponentRendererInterface::class) : null, + $app->bound(\Twig\Environment::class) ? $app->make(\Twig\Environment::class) : null, + $this->parseArgument('%apie.cms.base_url%'), + $this->parseArgument('%apie.cms.error_template%') + ); + } + ); + \Apie\ServiceProviderGenerator\TagMap::register( + $this->app, + \Apie\ApieBundle\EventListeners\RenderErrorListener::class, + array( + 0 => 'kernel.event_subscriber', + ) + ); + $this->app->tag([\Apie\ApieBundle\EventListeners\RenderErrorListener::class], 'kernel.event_subscriber'); + + } +} diff --git a/src/Providers/CmsServiceProvider.php b/src/Providers/CmsServiceProvider.php new file mode 100644 index 0000000..f5bf8be --- /dev/null +++ b/src/Providers/CmsServiceProvider.php @@ -0,0 +1,19 @@ +app->bind('apie.cms.dashboard_content', DashboardContents::class); + // blade extensions? + + $this->app->bind(DashboardContents::class); + } +} diff --git a/src/Providers/SecurityServiceProvider.php b/src/Providers/SecurityServiceProvider.php new file mode 100644 index 0000000..0c8ea27 --- /dev/null +++ b/src/Providers/SecurityServiceProvider.php @@ -0,0 +1,27 @@ +app->bind(UserAuthenticationContextBuilder::class); + $this->app->tag(UserAuthenticationContextBuilder::class, ['apie.core.context_builder']); + Auth::provider('apie', function ($app) { + return new ApieUserProvider($app->get('apie')); + }); + Auth::viaRequest('apie', function () { + $psrRequest = $this->app->get(ServerRequestInterface::class); + $userAuthenticator = $this->app->get(ApieUserAuthenticator::class); + return $userAuthenticator->authenticate($psrRequest); + }); + } +} diff --git a/src/Wrappers/Cms/DashboardContents.php b/src/Wrappers/Cms/DashboardContents.php new file mode 100644 index 0000000..1c1f868 --- /dev/null +++ b/src/Wrappers/Cms/DashboardContents.php @@ -0,0 +1,12 @@ +route(); + if ($route) { + $parameters = $route->parameters(); + if (isset($parameters[ContextConstants::BOUNDED_CONTEXT_ID])) { + return $this->boundedContextHashmap[$parameters[ContextConstants::BOUNDED_CONTEXT_ID]]; + } + if (isset($parameters[ContextConstants::RESOURCE_NAME])) { + return $this->getBoundedContextFromClassName($parameters[ContextConstants::RESOURCE_NAME]); + } + } + return null; + } + + public function getBoundedContextFromClassName(string $className): ?BoundedContext + { + return null; + } +} diff --git a/src/Wrappers/Routing/ApieRouteLoader.php b/src/Wrappers/Routing/ApieRouteLoader.php new file mode 100644 index 0000000..95784c4 --- /dev/null +++ b/src/Wrappers/Routing/ApieRouteLoader.php @@ -0,0 +1,50 @@ +loaded === true) { + throw new \RuntimeException('Do not load the "ApieRouteLoader" twice!'); + } + $this->loaded = true; + $apieContext = new ApieContext([]); + foreach ($this->boundedContextHashmap as $boundedContextId => $boundedContext) { + foreach ($this->routeProvider->getActionsForBoundedContext($boundedContext, $apieContext) as $routeDefinition) { + /** @var HasRouteDefinition $routeDefinition */ + $prefix = $this->routePrefixProvider->getPossiblePrefixes($routeDefinition); + + $path = $prefix . $boundedContextId . '/' . ltrim($routeDefinition->getUrl(), '/'); + + $method = $routeDefinition->getMethod(); + $defaults = $routeDefinition->getRouteAttributes() + + [ + '_is_apie' => true, + 'uses' => $routeDefinition->getController(), + ]; + /** @var \Illuminate\Routing\Route $route */ + $route = $routeRegistrar->{strtolower($method->value)}($path, $routeDefinition->getController()); + + $route->defaults += $defaults; + $route->wheres = $prefix->getRouteRequirements(); + } + } + } +} diff --git a/src/Wrappers/Security/ApieUserAuthenticator.php b/src/Wrappers/Security/ApieUserAuthenticator.php new file mode 100644 index 0000000..7f08481 --- /dev/null +++ b/src/Wrappers/Security/ApieUserAuthenticator.php @@ -0,0 +1,60 @@ +getAttribute('_is_apie', false) + && $request->getAttribute(ContextConstants::OPERATION_ID) + && str_starts_with($request->getAttribute(ContextConstants::OPERATION_ID), 'call-method-') + && 'verifyAuthentication' === $request->getAttribute(ContextConstants::METHOD_NAME); + } + + public function authenticate(ServerRequestInterface $request): ?ApieUserDecorator + { + try { + $psrRequest = $request->withHeader('Accept', 'application/json'); + if (!$this->supports($psrRequest)) { + return null; + } + $actionClass = $psrRequest->getAttribute(ContextConstants::APIE_ACTION); + /** @var ActionInterface $action */ + $action = new $actionClass($this->apieFacade); + $context = $this->contextBuilderFactory->createFromRequest($psrRequest, $psrRequest->getAttributes()); + $actionResponse = $action($context, $this->decoder->decodeBody($psrRequest)); + + if ($actionResponse->result instanceof EntityInterface) { + $userIdentifier = get_class($actionResponse->result) + . '/' + . $psrRequest->getAttribute(ContextConstants::BOUNDED_CONTEXT_ID) + . '/' + . Utils::toString($actionResponse->result->getId()); + return resolve(ApieUserProvider::class)->retrieveById($userIdentifier); + } + } catch (Exception $error) { + throw new AuthenticationException('Could not authenticate user!', 0, $error); + } + throw new AuthenticationException('Could not authenticate user!'); + } +} diff --git a/src/Wrappers/Security/ApieUserDecorator.php b/src/Wrappers/Security/ApieUserDecorator.php new file mode 100644 index 0000000..f054b0e --- /dev/null +++ b/src/Wrappers/Security/ApieUserDecorator.php @@ -0,0 +1,42 @@ + + */ +final class ApieUserDecorator extends AbstractApieUserDecorator implements Authenticatable +{ + public function getAuthIdentifierName() + { + return $this->entity->getId(); + } + public function getAuthIdentifier() + { + return $this->id->toNative(); + } + + public function getAuthPassword() + { + return ''; + } + + public function getRememberToken() + { + return ''; + } + + public function setRememberToken($token) + { + } + + public function getRememberTokenName() + { + return ''; + } +} diff --git a/src/Wrappers/Security/ApieUserProvider.php b/src/Wrappers/Security/ApieUserProvider.php new file mode 100644 index 0000000..a806f22 --- /dev/null +++ b/src/Wrappers/Security/ApieUserProvider.php @@ -0,0 +1,43 @@ +getBoundedContextId(); + $entity = $this->apieFacade->find($identifier->getIdentifier(), $boundedContextId); + return new ApieUserDecorator($identifier, $entity); + } + + public function retrieveByToken($identifier, $token): ?ApieUserDecorator + { + return null; + } + + public function updateRememberToken(Authenticatable $user, $token): void + { + } + + public function retrieveByCredentials(array $credentials): ?ApieUserDecorator + { + // TODO find the verifyAuthentication action... + } + + public function validateCredentials(Authenticatable $user, array $credentials): bool + { + // TODO find the verifyAuthentication action... + return false; + } +} diff --git a/src/Wrappers/Security/UserAuthenticationContextBuilder.php b/src/Wrappers/Security/UserAuthenticationContextBuilder.php new file mode 100644 index 0000000..fc16596 --- /dev/null +++ b/src/Wrappers/Security/UserAuthenticationContextBuilder.php @@ -0,0 +1,27 @@ +user(); + if ($user) { + $context = $context->registerInstance($user); + + if ($user instanceof UserDecorator) { + $context = $context->withContext('authenticated', $user->getEntity()); + } + } + $token = csrf_token(); + if ($token) { + $context = $context->registerInstance($token); + } + + return $context; + } +} diff --git a/templates/dashboard.blade.php b/templates/dashboard.blade.php new file mode 100644 index 0000000..cb67c58 --- /dev/null +++ b/templates/dashboard.blade.php @@ -0,0 +1,13 @@ +This is a the default dashboard template. + +You can override this in config/apie.php. + +
// apie.php
+return [
+    'cms' => [
+        'dashboard_template' => 'apie/dashboard'
+    ]
+];
+ +Now create a template in your project in templates/apie/dashboard.blade.php without the HTML layout and you have +your own custom dashboard! \ No newline at end of file diff --git a/templates/error.blade.php b/templates/error.blade.php new file mode 100644 index 0000000..4b22570 --- /dev/null +++ b/templates/error.blade.php @@ -0,0 +1 @@ +

An error occurred. Please try again later.

\ No newline at end of file diff --git a/tests/Fixtures/Actions/Authentication.php b/tests/Fixtures/Actions/Authentication.php new file mode 100644 index 0000000..2b071c2 --- /dev/null +++ b/tests/Fixtures/Actions/Authentication.php @@ -0,0 +1,17 @@ +id; + } +} diff --git a/tests/Fixtures/Entities/User.php b/tests/Fixtures/Entities/User.php new file mode 100644 index 0000000..6245efe --- /dev/null +++ b/tests/Fixtures/Entities/User.php @@ -0,0 +1,18 @@ +id; + } +} diff --git a/tests/Fixtures/ValueObjects/TestEntityIdentifier.php b/tests/Fixtures/ValueObjects/TestEntityIdentifier.php new file mode 100644 index 0000000..bb1dc75 --- /dev/null +++ b/tests/Fixtures/ValueObjects/TestEntityIdentifier.php @@ -0,0 +1,15 @@ +make('config'), function (Repository $config) { + $config->set( + 'apie.bounded_contexts', + [ + 'default' => [ + 'entities_folder' => __DIR__ . '/Fixtures/Entities', + 'entities_namespace' => 'Apie\\Tests\\LaravelApie\\Fixtures\\Entities\\', + 'actions_folder' => __DIR__ . '/Fixtures/Actions', + 'actions_namespace' => 'Apie\\Tests\\LaravelApie\\Fixtures\\Actions\\', + ], + ] + ); + }); + } + + /** + * @test + */ + public function it_can_register_apie_as_a_service() + { + $this->assertInstanceOf(ApieFacade::class, resolve('apie')); + } + + /** + * @test + */ + public function it_can_view_swagger_ui() + { + $response = $this->get('/api/default/openapi.yaml'); + $response->assertOk(); + // TODO figure out + //$response->assertSeeText('/api/default/TestEntity'); + } +} From ef73f0935476b6cf3c81aeb4da49df3fcc4ce14a Mon Sep 17 00:00:00 2001 From: pjordaan Date: Wed, 19 Jul 2023 13:58:25 +0000 Subject: [PATCH 02/11] Update file(s) "packages/laravel-apie/." from "apie-lib/apie-lib-monorepo" --- src/Providers/ApieServicesServiceProvider.php | 124 ------------------ src/Providers/SecurityServiceProvider.php | 2 +- 2 files changed, 1 insertion(+), 125 deletions(-) delete mode 100644 src/Providers/ApieServicesServiceProvider.php diff --git a/src/Providers/ApieServicesServiceProvider.php b/src/Providers/ApieServicesServiceProvider.php deleted file mode 100644 index 5648fb0..0000000 --- a/src/Providers/ApieServicesServiceProvider.php +++ /dev/null @@ -1,124 +0,0 @@ -app->singleton( - \Apie\ApieBundle\Routing\ApieRouteLoader::class, - function ($app) { - return new \Apie\ApieBundle\Routing\ApieRouteLoader( - $app->make('apie.route_definitions.provider'), - $app->make('apie.bounded_context.hashmap'), - $app->make(\Apie\Common\RouteDefinitions\PossibleRoutePrefixProvider::class) - ); - } - ); - \Apie\ServiceProviderGenerator\TagMap::register( - $this->app, - \Apie\ApieBundle\Routing\ApieRouteLoader::class, - array( - 0 => 'routing.loader', - ) - ); - $this->app->tag([\Apie\ApieBundle\Routing\ApieRouteLoader::class], 'routing.loader'); - $this->app->singleton( - \Apie\ApieBundle\ContextBuilders\ServiceContextBuilder::class, - function ($app) { - return new \Apie\ApieBundle\ContextBuilders\ServiceContextBuilder( - $this->getTaggedServicesServiceLocator('apie.context') - ); - } - ); - \Apie\ServiceProviderGenerator\TagMap::register( - $this->app, - \Apie\ApieBundle\ContextBuilders\ServiceContextBuilder::class, - array( - 0 => 'apie.core.context_builder', - ) - ); - $this->app->tag([\Apie\ApieBundle\ContextBuilders\ServiceContextBuilder::class], 'apie.core.context_builder'); - $this->app->singleton( - \Apie\ApieBundle\ContextBuilders\SessionContextBuilder::class, - function ($app) { - return new \Apie\ApieBundle\ContextBuilders\SessionContextBuilder( - $app->make('request_stack') - ); - } - ); - \Apie\ServiceProviderGenerator\TagMap::register( - $this->app, - \Apie\ApieBundle\ContextBuilders\SessionContextBuilder::class, - array( - 0 => 'apie.core.context_builder', - ) - ); - $this->app->tag([\Apie\ApieBundle\ContextBuilders\SessionContextBuilder::class], 'apie.core.context_builder'); - $this->app->singleton( - \Apie\ApieBundle\ContextBuilders\CsrfTokenContextBuilder::class, - function ($app) { - return new \Apie\ApieBundle\ContextBuilders\CsrfTokenContextBuilder( - $app->bound(\Symfony\Component\Security\Csrf\CsrfTokenManagerInterface::class) ? $app->make(\Symfony\Component\Security\Csrf\CsrfTokenManagerInterface::class) : null - ); - } - ); - \Apie\ServiceProviderGenerator\TagMap::register( - $this->app, - \Apie\ApieBundle\ContextBuilders\CsrfTokenContextBuilder::class, - array( - 0 => 'apie.core.context_builder', - ) - ); - $this->app->tag([\Apie\ApieBundle\ContextBuilders\CsrfTokenContextBuilder::class], 'apie.core.context_builder'); - $this->app->bind(\Apie\Common\Interfaces\BoundedContextSelection::class, \Apie\ApieBundle\Wrappers\BoundedContextSelected::class); - - $this->app->singleton( - \Apie\ApieBundle\Wrappers\BoundedContextSelected::class, - function ($app) { - return new \Apie\ApieBundle\Wrappers\BoundedContextSelected( - $app->make('request_stack'), - $app->make(\Apie\Core\BoundedContext\BoundedContextHashmap::class) - ); - } - ); - \Apie\ServiceProviderGenerator\TagMap::register( - $this->app, - \Apie\ApieBundle\Wrappers\BoundedContextSelected::class, - array( - 0 => 'apie.context', - ) - ); - $this->app->tag([\Apie\ApieBundle\Wrappers\BoundedContextSelected::class], 'apie.context'); - $this->app->singleton( - \Apie\ApieBundle\EventListeners\RenderErrorListener::class, - function ($app) { - return new \Apie\ApieBundle\EventListeners\RenderErrorListener( - $app->bound(\Apie\HtmlBuilders\Factories\ComponentFactory::class) ? $app->make(\Apie\HtmlBuilders\Factories\ComponentFactory::class) : null, - $app->bound(\Apie\HtmlBuilders\Interfaces\ComponentRendererInterface::class) ? $app->make(\Apie\HtmlBuilders\Interfaces\ComponentRendererInterface::class) : null, - $app->bound(\Twig\Environment::class) ? $app->make(\Twig\Environment::class) : null, - $this->parseArgument('%apie.cms.base_url%'), - $this->parseArgument('%apie.cms.error_template%') - ); - } - ); - \Apie\ServiceProviderGenerator\TagMap::register( - $this->app, - \Apie\ApieBundle\EventListeners\RenderErrorListener::class, - array( - 0 => 'kernel.event_subscriber', - ) - ); - $this->app->tag([\Apie\ApieBundle\EventListeners\RenderErrorListener::class], 'kernel.event_subscriber'); - - } -} diff --git a/src/Providers/SecurityServiceProvider.php b/src/Providers/SecurityServiceProvider.php index 0c8ea27..c8d6f87 100644 --- a/src/Providers/SecurityServiceProvider.php +++ b/src/Providers/SecurityServiceProvider.php @@ -1,8 +1,8 @@ Date: Wed, 23 Aug 2023 13:43:17 +0000 Subject: [PATCH 03/11] Update file(s) "packages/laravel-apie/." from "apie-lib/apie-lib-monorepo" --- src/ApieServiceProvider.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ApieServiceProvider.php b/src/ApieServiceProvider.php index b57c55f..826642b 100644 --- a/src/ApieServiceProvider.php +++ b/src/ApieServiceProvider.php @@ -38,6 +38,15 @@ class ApieServiceProvider extends ServiceProvider ConsoleServiceProvider::class, SerializerServiceProvider::class, ], + 'enable_doctrine_entity_converter' => [ + CoreServiceProvider::class, + DoctrineEntityConverterProvicer::class, + ], + 'enable_doctrine_entity_datalayer' => [ + CoreServiceProvider::class, + DoctrineEntityConverterProvicer::class, + DoctrineEntityDatalayerServiceProvider::class, + ], 'enable_security' => [ CommonServiceProvider::class, SerializerServiceProvider::class, From 5dd07af2817fb6d8afcca7b18fc9a8e9119f931a Mon Sep 17 00:00:00 2001 From: pjordaan Date: Thu, 24 Aug 2023 09:40:27 +0000 Subject: [PATCH 04/11] Update file(s) "packages/laravel-apie/." from "apie-lib/apie-lib-monorepo" --- src/ApieServiceProvider.php | 11 ++++++++--- src/Wrappers/Routing/ApieRouteLoader.php | 2 +- src/Wrappers/Security/ApieUserAuthenticator.php | 4 +++- src/Wrappers/Security/ApieUserDecorator.php | 1 + src/Wrappers/Security/ApieUserProvider.php | 16 +++++++++++++++- .../UserAuthenticationContextBuilder.php | 4 ---- 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/ApieServiceProvider.php b/src/ApieServiceProvider.php index 826642b..56752fe 100644 --- a/src/ApieServiceProvider.php +++ b/src/ApieServiceProvider.php @@ -6,6 +6,8 @@ use Apie\Common\Interfaces\BoundedContextSelection; use Apie\Console\ConsoleServiceProvider; use Apie\Core\CoreServiceProvider; +use Apie\DoctrineEntityConverter\DoctrineEntityConverterProvider; +use Apie\DoctrineEntityDatalayer\DoctrineEntityDatalayerServiceProvider; use Apie\Faker\FakerServiceProvider; use Apie\HtmlBuilders\HtmlBuilderServiceProvider; use Apie\LaravelApie\Providers\CmsServiceProvider; @@ -19,6 +21,9 @@ class ApieServiceProvider extends ServiceProvider { + /** + * @var array>> $dependencies + */ private array $dependencies = [ 'enable_cms' => [ CommonServiceProvider::class, @@ -40,11 +45,11 @@ class ApieServiceProvider extends ServiceProvider ], 'enable_doctrine_entity_converter' => [ CoreServiceProvider::class, - DoctrineEntityConverterProvicer::class, + DoctrineEntityConverterProvider::class, ], 'enable_doctrine_entity_datalayer' => [ CoreServiceProvider::class, - DoctrineEntityConverterProvicer::class, + DoctrineEntityConverterProvider::class, DoctrineEntityDatalayerServiceProvider::class, ], 'enable_security' => [ @@ -63,7 +68,7 @@ class ApieServiceProvider extends ServiceProvider ], ]; - public function boot() + public function boot(): void { $this->loadViewsFrom(__DIR__ . '/../templates', 'apie'); $this->loadRoutesFrom(__DIR__.'/../resources/routes.php'); diff --git a/src/Wrappers/Routing/ApieRouteLoader.php b/src/Wrappers/Routing/ApieRouteLoader.php index 95784c4..e3e9869 100644 --- a/src/Wrappers/Routing/ApieRouteLoader.php +++ b/src/Wrappers/Routing/ApieRouteLoader.php @@ -19,7 +19,7 @@ public function __construct( ) { } - public function loadRoutes(RouteRegistrar $routeRegistrar) + public function loadRoutes(RouteRegistrar $routeRegistrar): void { if ($this->loaded === true) { throw new \RuntimeException('Do not load the "ApieRouteLoader" twice!'); diff --git a/src/Wrappers/Security/ApieUserAuthenticator.php b/src/Wrappers/Security/ApieUserAuthenticator.php index 7f08481..0d635d1 100644 --- a/src/Wrappers/Security/ApieUserAuthenticator.php +++ b/src/Wrappers/Security/ApieUserAuthenticator.php @@ -5,7 +5,6 @@ use Apie\Common\ApieFacade; use Apie\Common\ContextConstants; use Apie\Common\RequestBodyDecoder; -use Apie\Common\Wrappers\ApieUserDecorator; use Apie\Core\Actions\ActionInterface; use Apie\Core\ContextBuilders\ContextBuilderFactory; use Apie\Core\Entities\EntityInterface; @@ -31,6 +30,9 @@ public function supports(ServerRequestInterface $request): ?bool && 'verifyAuthentication' === $request->getAttribute(ContextConstants::METHOD_NAME); } + /** + * @return ApieUserDecorator|null + */ public function authenticate(ServerRequestInterface $request): ?ApieUserDecorator { try { diff --git a/src/Wrappers/Security/ApieUserDecorator.php b/src/Wrappers/Security/ApieUserDecorator.php index f054b0e..fb90e91 100644 --- a/src/Wrappers/Security/ApieUserDecorator.php +++ b/src/Wrappers/Security/ApieUserDecorator.php @@ -2,6 +2,7 @@ namespace Apie\LaravelApie\Wrappers\Security; use Apie\Common\Wrappers\AbstractApieUserDecorator; +use Apie\Core\Entities\EntityInterface; use Illuminate\Contracts\Auth\Authenticatable; /** diff --git a/src/Wrappers/Security/ApieUserProvider.php b/src/Wrappers/Security/ApieUserProvider.php index a806f22..2e44107 100644 --- a/src/Wrappers/Security/ApieUserProvider.php +++ b/src/Wrappers/Security/ApieUserProvider.php @@ -2,8 +2,8 @@ namespace Apie\LaravelApie\Wrappers\Security; use Apie\Common\ApieFacade; -use Apie\Common\Wrappers\ApieUserDecorator; use Apie\Common\Wrappers\ApieUserDecoratorIdentifier; +use Apie\Core\Entities\EntityInterface; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\UserProvider; @@ -13,6 +13,9 @@ public function __construct(private readonly ApieFacade $apieFacade) { } + /** + * @return ApieUserDecorator + */ public function retrieveById($identifier): ApieUserDecorator { $identifier = new ApieUserDecoratorIdentifier($identifier); @@ -21,6 +24,9 @@ public function retrieveById($identifier): ApieUserDecorator return new ApieUserDecorator($identifier, $entity); } + /** + * @return ApieUserDecorator|null + */ public function retrieveByToken($identifier, $token): ?ApieUserDecorator { return null; @@ -30,11 +36,19 @@ public function updateRememberToken(Authenticatable $user, $token): void { } + /** + * @param array $credentials + * @return ApieUserDecorator|null + */ public function retrieveByCredentials(array $credentials): ?ApieUserDecorator { // TODO find the verifyAuthentication action... + return null; } + /** + * @param array $credentials + */ public function validateCredentials(Authenticatable $user, array $credentials): bool { // TODO find the verifyAuthentication action... diff --git a/src/Wrappers/Security/UserAuthenticationContextBuilder.php b/src/Wrappers/Security/UserAuthenticationContextBuilder.php index fc16596..cf6f057 100644 --- a/src/Wrappers/Security/UserAuthenticationContextBuilder.php +++ b/src/Wrappers/Security/UserAuthenticationContextBuilder.php @@ -17,10 +17,6 @@ public function process(ApieContext $context): ApieContext $context = $context->withContext('authenticated', $user->getEntity()); } } - $token = csrf_token(); - if ($token) { - $context = $context->registerInstance($token); - } return $context; } From 1e694c3af97a96b7194eafbc40b2d64a6f327abe Mon Sep 17 00:00:00 2001 From: pjordaan Date: Sun, 3 Sep 2023 16:00:20 +0000 Subject: [PATCH 05/11] Update file(s) "packages/laravel-apie/." from "apie-lib/apie-lib-monorepo" --- src/ApieServiceProvider.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/ApieServiceProvider.php b/src/ApieServiceProvider.php index 56752fe..6d5f13a 100644 --- a/src/ApieServiceProvider.php +++ b/src/ApieServiceProvider.php @@ -16,7 +16,9 @@ use Apie\RestApi\RestApiServiceProvider; use Apie\SchemaGenerator\SchemaGeneratorServiceProvider; use Apie\Serializer\SerializerServiceProvider; +use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Support\ServiceProvider; +use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\ServerRequestInterface; class ApieServiceProvider extends ServiceProvider @@ -78,6 +80,23 @@ public function register() { $this->mergeConfigFrom(__DIR__ . '/../resources/apie.php', 'apie'); + // add PSR-14 support if needed: + if (!$this->app->bound(EventDispatcherInterface::class)) { + $this->app->bind(EventDispatcherInterface::class, function () { + return new class($this->app->make(Dispatcher::class)) implements EventDispatcherInterface { + public function __construct(private readonly Dispatcher $dispatcher) + { + } + + public function dispatch(object $event): object + { + $this->dispatcher->dispatch($event); + return $event; + } + }; + }); + } + // fix for https://github.com/laravel/framework/issues/30415 $this->app->extend( ServerRequestInterface::class, From 0306c74e19a98431fae7fb4f52633b2717fb9135 Mon Sep 17 00:00:00 2001 From: pjordaan Date: Sun, 10 Sep 2023 15:04:38 +0000 Subject: [PATCH 06/11] Update file(s) "packages/laravel-apie/." from "apie-lib/apie-lib-monorepo" --- composer.json | 2 +- resources/apie.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index eb9d62f..ace670c 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "php": ">=8.1", "apie/common": "self.version", "apie/core": "self.version", - "apie/service-provider-generator": "dev-main", + "apie/service-provider-generator": "0.9.2", "laravel/laravel": "7.*|8.*|9.*|10.*", "symfony/psr-http-message-bridge": "2.*" }, diff --git a/resources/apie.php b/resources/apie.php index f7ebaf0..e5c15ca 100644 --- a/resources/apie.php +++ b/resources/apie.php @@ -5,6 +5,8 @@ use Apie\CmsApiDropdownOption\RouteDefinitions\DropdownOptionsForExistingObjectRouteDefinition; use Apie\Common\Wrappers\RequestAwareInMemoryDatalayer; use Apie\Console\ConsoleCommandFactory; +use Apie\DoctrineEntityConverter\EntityBuilder; +use Apie\DoctrineEntityDatalayer\DoctrineEntityDatalayer; use Apie\Faker\ApieObjectFaker; use Apie\RestApi\OpenApi\OpenApiGenerator; @@ -31,6 +33,11 @@ //] ] ], + 'doctrine' => [ + 'build_once' => false, + 'run_migrations' => false, + 'connection_params' => [], + ], 'bounded_contexts' => [ 'default' => [ 'entities_folder' => app_path('Apie/Entities'), @@ -42,6 +49,9 @@ 'enable_core' => true, 'enable_cms' => class_exists(CmsRouteDefinitionProvider::class), 'enable_cms_dropdown' => class_exists(DropdownOptionsForExistingObjectRouteDefinition::class), + 'enable_doctrine_entity_converter' => class_exists(EntityBuilder::class), + 'enable_doctrine_entity_datalayer' => class_exists(DoctrineEntityDatalayer::class), + /* 'enable_doctrine_bundle_connection' symfony only*/ 'enable_faker' => class_exists(ApieObjectFaker::class), 'enable_rest_api' => class_exists(OpenApiGenerator::class), 'enable_console' => class_exists(ConsoleCommandFactory::class), From d9e87ee71900083b1ccde0e78ee5b55fc3c0ac95 Mon Sep 17 00:00:00 2001 From: pjordaan Date: Sun, 10 Sep 2023 21:21:57 +0000 Subject: [PATCH 07/11] Update file(s) "packages/laravel-apie/." from "apie-lib/apie-lib-monorepo" --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ace670c..135f266 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "php": ">=8.1", "apie/common": "self.version", "apie/core": "self.version", - "apie/service-provider-generator": "0.9.2", + "apie/service-provider-generator": "0.9.3", "laravel/laravel": "7.*|8.*|9.*|10.*", "symfony/psr-http-message-bridge": "2.*" }, From e30ec64289fcd7cac25e76eb43285da58ad23755 Mon Sep 17 00:00:00 2001 From: pjordaan Date: Tue, 12 Sep 2023 21:41:12 +0000 Subject: [PATCH 08/11] Update file(s) "packages/laravel-apie/." from "apie-lib/apie-lib-monorepo" --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 135f266..9348c5a 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "php": ">=8.1", "apie/common": "self.version", "apie/core": "self.version", - "apie/service-provider-generator": "0.9.3", + "apie/service-provider-generator": "0.10.1", "laravel/laravel": "7.*|8.*|9.*|10.*", "symfony/psr-http-message-bridge": "2.*" }, From 6b5903cbb4585bd55a63cf8f6ae061e24be646e9 Mon Sep 17 00:00:00 2001 From: pjordaan Date: Thu, 14 Sep 2023 10:12:07 +0000 Subject: [PATCH 09/11] Update file(s) "packages/laravel-apie/." from "apie-lib/apie-lib-monorepo" --- src/ApieServiceProvider.php | 12 ++++- src/ErrorHandler/ApieErrorRenderer.php | 49 +++++++++++++++++++ src/ErrorHandler/Handler.php | 67 ++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 src/ErrorHandler/ApieErrorRenderer.php create mode 100644 src/ErrorHandler/Handler.php diff --git a/src/ApieServiceProvider.php b/src/ApieServiceProvider.php index 6d5f13a..2de6530 100644 --- a/src/ApieServiceProvider.php +++ b/src/ApieServiceProvider.php @@ -9,7 +9,9 @@ use Apie\DoctrineEntityConverter\DoctrineEntityConverterProvider; use Apie\DoctrineEntityDatalayer\DoctrineEntityDatalayerServiceProvider; use Apie\Faker\FakerServiceProvider; +use Apie\HtmlBuilders\ErrorHandler\CmsErrorRenderer; use Apie\HtmlBuilders\HtmlBuilderServiceProvider; +use Apie\LaravelApie\ErrorHandler\ApieErrorRenderer; use Apie\LaravelApie\Providers\CmsServiceProvider; use Apie\LaravelApie\Providers\SecurityServiceProvider; use Apie\LaravelApie\Wrappers\Core\BoundedContextSelected; @@ -112,8 +114,16 @@ function (ServerRequestInterface $psrRequest) { } ); + $this->app->bind(ApieErrorRenderer::class, function () { + return new ApieErrorRenderer( + $this->app->bound(CmsErrorRenderer::class) ? $this->app->make(CmsErrorRenderer::class) : null, + $this->app->make(\Apie\Common\ErrorHandler\ApiErrorRenderer::class), + config('apie.cms.base_url') + ); + }); + $this->app->bind(BoundedContextSelection::class, BoundedContextSelected::class); - + $alreadyRegistered = []; foreach ($this->dependencies as $configKey => $dependencies) { if (config('apie.' . $configKey, false)) { diff --git a/src/ErrorHandler/ApieErrorRenderer.php b/src/ErrorHandler/ApieErrorRenderer.php new file mode 100644 index 0000000..88f7293 --- /dev/null +++ b/src/ErrorHandler/ApieErrorRenderer.php @@ -0,0 +1,49 @@ +attributes->has('_is_apie') || + $this->canCreateCmsResponse($request); + } + + public function canCreateCmsResponse(Request $request): bool + { + if ($request->attributes->has(ContextConstants::CMS) + && null !== $this->cmsErrorRenderer + ) { + return true; + } + return str_starts_with($request->getPathInfo(), $this->cmsBaseUrl); + } + + public function createApiResponse(Throwable $error): Response + { + return $this->apiErrorRenderer->createApiResponse($error); + } + + public function createCmsResponse(Request $request, Throwable $error): Response + { + if (!$this->cmsErrorRenderer) { + return new Response("Internal error", 500); + } + return $this->cmsErrorRenderer->createCmsResponse($request, $error); + } +} diff --git a/src/ErrorHandler/Handler.php b/src/ErrorHandler/Handler.php new file mode 100644 index 0000000..2e0cf1a --- /dev/null +++ b/src/ErrorHandler/Handler.php @@ -0,0 +1,67 @@ + + */ + protected $dontFlash = [ + 'current_password', + 'password', + 'password_confirmation', + ]; + + private static bool $alreadyRenderErrorPage = false; + + /** + * Report or log an exception. + * + * This is a great spot to send exceptions to Sentry, Bugsnag, etc. + * + * @param \Throwable $e + * @return void + */ + public function report(Throwable $e) + { + IntegrationTestLogger::logException($e); + parent::report($e); + } + + /** + * Render an exception into an HTTP response. + * + * @param \Illuminate\Http\Request $request + * @param \Throwable $e + * @return \Symfony\Component\HttpFoundation\Response|\Illuminate\Http\Response + */ + public function render($request, Throwable $e) + { + $response = null; + if (!self::$alreadyRenderErrorPage) { + self::$alreadyRenderErrorPage = true; + try { + /** @var ApieErrorRenderer $apieErrorHandler */ + $apieErrorHandler = resolve(ApieErrorRenderer::class); + if ($apieErrorHandler->isApieRequest($request)) { + if ($apieErrorHandler->canCreateCmsResponse($request)) { + $response = $apieErrorHandler->createCmsResponse($request, $e); + } else { + $response = $apieErrorHandler->createApiResponse($e); + } + + } + } finally { + self::$alreadyRenderErrorPage = false; + } + } + return $response ?? parent::render($request, $e); + } +} From 2e5e0c922c283c4ff2c264ec7dd5b6743102c4e0 Mon Sep 17 00:00:00 2001 From: pjordaan Date: Thu, 14 Sep 2023 15:15:59 +0000 Subject: [PATCH 10/11] Update file(s) "packages/laravel-apie/." from "apie-lib/apie-lib-monorepo" --- src/ApieServiceProvider.php | 5 ++++- src/Providers/CmsServiceProvider.php | 7 ++++++- src/Wrappers/Cms/DashboardContentFactory.php | 14 ++++++++++++++ src/Wrappers/Cms/DashboardContents.php | 10 +++++++++- 4 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 src/Wrappers/Cms/DashboardContentFactory.php diff --git a/src/ApieServiceProvider.php b/src/ApieServiceProvider.php index 2de6530..486dbae 100644 --- a/src/ApieServiceProvider.php +++ b/src/ApieServiceProvider.php @@ -4,6 +4,7 @@ use Apie\CmsApiDropdownOption\CmsDropdownServiceProvider; use Apie\Common\CommonServiceProvider; use Apie\Common\Interfaces\BoundedContextSelection; +use Apie\Common\Interfaces\DashboardContentFactoryInterface; use Apie\Console\ConsoleServiceProvider; use Apie\Core\CoreServiceProvider; use Apie\DoctrineEntityConverter\DoctrineEntityConverterProvider; @@ -14,6 +15,7 @@ use Apie\LaravelApie\ErrorHandler\ApieErrorRenderer; use Apie\LaravelApie\Providers\CmsServiceProvider; use Apie\LaravelApie\Providers\SecurityServiceProvider; +use Apie\LaravelApie\Wrappers\Cms\DashboardContentFactory; use Apie\LaravelApie\Wrappers\Core\BoundedContextSelected; use Apie\RestApi\RestApiServiceProvider; use Apie\SchemaGenerator\SchemaGeneratorServiceProvider; @@ -121,7 +123,8 @@ function (ServerRequestInterface $psrRequest) { config('apie.cms.base_url') ); }); - + + $this->app->bind(DashboardContentFactoryInterface::class, DashboardContentFactory::class); $this->app->bind(BoundedContextSelection::class, BoundedContextSelected::class); $alreadyRegistered = []; diff --git a/src/Providers/CmsServiceProvider.php b/src/Providers/CmsServiceProvider.php index f5bf8be..6062637 100644 --- a/src/Providers/CmsServiceProvider.php +++ b/src/Providers/CmsServiceProvider.php @@ -14,6 +14,11 @@ public function register() $this->app->bind('apie.cms.dashboard_content', DashboardContents::class); // blade extensions? - $this->app->bind(DashboardContents::class); + $this->app->bind(DashboardContents::class, function () { + return new DashboardContents( + config('apie.cms.dashboard_template'), + [] + ); + }); } } diff --git a/src/Wrappers/Cms/DashboardContentFactory.php b/src/Wrappers/Cms/DashboardContentFactory.php new file mode 100644 index 0000000..20790e1 --- /dev/null +++ b/src/Wrappers/Cms/DashboardContentFactory.php @@ -0,0 +1,14 @@ + $templateParameters + */ + public function __construct( + private readonly string $template, + private readonly array $templateParameters + ) { + } public function __toString(): string { - return (string) view(config('apie.cms.dashboard_template')); + return (string) view($this->template, $this->templateParameters); } } From 695966ba507f81bd2c05ee26ea90dbb4dc484454 Mon Sep 17 00:00:00 2001 From: pjordaan Date: Sat, 16 Sep 2023 19:36:42 +0000 Subject: [PATCH 11/11] Update file(s) "packages/laravel-apie/." from "apie-lib/apie-lib-monorepo" --- composer.json | 2 +- src/ApieServiceProvider.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9348c5a..b8c44c2 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "php": ">=8.1", "apie/common": "self.version", "apie/core": "self.version", - "apie/service-provider-generator": "0.10.1", + "apie/service-provider-generator": "0.10.4", "laravel/laravel": "7.*|8.*|9.*|10.*", "symfony/psr-http-message-bridge": "2.*" }, diff --git a/src/ApieServiceProvider.php b/src/ApieServiceProvider.php index 486dbae..06fb32f 100644 --- a/src/ApieServiceProvider.php +++ b/src/ApieServiceProvider.php @@ -20,6 +20,7 @@ use Apie\RestApi\RestApiServiceProvider; use Apie\SchemaGenerator\SchemaGeneratorServiceProvider; use Apie\Serializer\SerializerServiceProvider; +use Apie\ServiceProviderGenerator\TagMap; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Support\ServiceProvider; use Psr\EventDispatcher\EventDispatcherInterface; @@ -78,6 +79,7 @@ public function boot(): void { $this->loadViewsFrom(__DIR__ . '/../templates', 'apie'); $this->loadRoutesFrom(__DIR__.'/../resources/routes.php'); + TagMap::registerEvents($this->app); } public function register()