diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PhpSlim4ServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PhpSlim4ServerCodegen.java
index 7e318dee204..dc6fefcee77 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PhpSlim4ServerCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PhpSlim4ServerCodegen.java
@@ -50,6 +50,8 @@ public class PhpSlim4ServerCodegen extends AbstractPhpCodegen {
protected String artifactId = "openapi-server";
protected String authDirName = "Auth";
protected String authPackage = "";
+ protected String appDirName = "App";
+ protected String appPackage = "";
protected String psr7Implementation = "slim-psr7";
protected String interfacesDirName = "Interfaces";
protected String interfacesPackage = "";
@@ -92,6 +94,7 @@ public class PhpSlim4ServerCodegen extends AbstractPhpCodegen {
modelPackage = invokerPackage + "\\" + modelDirName;
authPackage = invokerPackage + "\\" + authDirName;
interfacesPackage = invokerPackage + "\\" + interfacesDirName;
+ appPackage = invokerPackage + "\\" + appDirName;
outputFolder = "generated-code" + File.separator + "slim4";
modelTestTemplateFiles.put("model_test.mustache", ".php");
@@ -167,6 +170,8 @@ public class PhpSlim4ServerCodegen extends AbstractPhpCodegen {
authPackage = invokerPackage + "\\" + authDirName;
// Update interfacesPackage
interfacesPackage = invokerPackage + "\\" + interfacesDirName;
+ // update appPackage
+ appPackage = invokerPackage + "\\" + appDirName;
}
// make auth src path available in mustache template
@@ -178,6 +183,10 @@ public class PhpSlim4ServerCodegen extends AbstractPhpCodegen {
additionalProperties.put("interfacesSrcPath", "./" + toSrcPath(interfacesPackage, srcBasePath));
additionalProperties.put("interfacesTestPath", "./" + toSrcPath(interfacesPackage, testBasePath));
+ // same for app classes
+ additionalProperties.put("appPackage", appPackage);
+ additionalProperties.put("appSrcPath", "./" + toSrcPath(appPackage, srcBasePath));
+
if (additionalProperties.containsKey(PSR7_IMPLEMENTATION)) {
this.setPsr7Implementation((String) additionalProperties.get(PSR7_IMPLEMENTATION));
}
@@ -213,7 +222,9 @@ public class PhpSlim4ServerCodegen extends AbstractPhpCodegen {
supportingFiles.add(new SupportingFile("composer.mustache", "", "composer.json"));
supportingFiles.add(new SupportingFile("index.mustache", "public", "index.php"));
supportingFiles.add(new SupportingFile(".htaccess", "public", ".htaccess"));
- supportingFiles.add(new SupportingFile("SlimRouter.mustache", toSrcPath(invokerPackage, srcBasePath), "SlimRouter.php"));
+ supportingFiles.add(new SupportingFile("register_dependencies.mustache", toSrcPath(appPackage, srcBasePath), "RegisterDependencies.php"));
+ supportingFiles.add(new SupportingFile("register_middlewares.mustache", toSrcPath(appPackage, srcBasePath), "RegisterMiddlewares.php"));
+ supportingFiles.add(new SupportingFile("register_routes.mustache", toSrcPath(appPackage, srcBasePath), "RegisterRoutes.php"));
// don't generate phpunit config when tests generation disabled
if (Boolean.TRUE.equals(generateApiTests) || Boolean.TRUE.equals(generateModelTests)) {
@@ -224,8 +235,8 @@ public class PhpSlim4ServerCodegen extends AbstractPhpCodegen {
supportingFiles.add(new SupportingFile("phpcs.xml.mustache", "", "phpcs.xml.dist"));
supportingFiles.add(new SupportingFile("htaccess_deny_all", "config", ".htaccess"));
- supportingFiles.add(new SupportingFile("config_example.mustache", "config" + File.separator + "dev", "example.inc.php"));
- supportingFiles.add(new SupportingFile("config_example.mustache", "config" + File.separator + "prod", "example.inc.php"));
+ supportingFiles.add(new SupportingFile("config_dev_default.mustache", "config" + File.separator + "dev", "default.inc.php"));
+ supportingFiles.add(new SupportingFile("config_prod_default.mustache", "config" + File.separator + "prod", "default.inc.php"));
if (Boolean.TRUE.equals(generateModels)) {
supportingFiles.add(new SupportingFile("base_model.mustache", toSrcPath(invokerPackage, srcBasePath), "BaseModel.php"));
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/.htaccess b/modules/openapi-generator/src/main/resources/php-slim4-server/.htaccess
index f6a2ceb3952..57c2185f0e4 100644
--- a/modules/openapi-generator/src/main/resources/php-slim4-server/.htaccess
+++ b/modules/openapi-generator/src/main/resources/php-slim4-server/.htaccess
@@ -1,3 +1,7 @@
+
+ SetEnv APP_ENV 'production'
+
+
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/README.mustache b/modules/openapi-generator/src/main/resources/php-slim4-server/README.mustache
index d85b12e3bd4..dcd71930123 100644
--- a/modules/openapi-generator/src/main/resources/php-slim4-server/README.mustache
+++ b/modules/openapi-generator/src/main/resources/php-slim4-server/README.mustache
@@ -15,6 +15,7 @@ This server has been generated with [Guzzle PSR-7](https://github.com/guzzle/psr
{{#isZendDiactoros}}
This server has been generated with [Laminas (Zend) PSR-7 implementation](https://github.com/laminas/laminas-diactoros).
{{/isZendDiactoros}}
+[PHP-DI](https://php-di.org/doc/frameworks/slim.html) package used as dependency container.
## Requirements
@@ -34,7 +35,10 @@ $ composer install
## Add configs
-Application requires at least one config file(`config/dev/config.inc.php` or `config/prod/config.inc.php`). You can use [config/dev/example.inc.php](config/dev/example.inc.php) as starting point.
+[PHP-DI package](https://php-di.org/doc/getting-started.html) helps to decouple configuration from implementation. App loads configuration files in straight order(`$env` can be `prod` or `dev`):
+1. `config/$env/default.inc.php` (contains safe values, can be committed to vcs)
+2. `config/$env/config.inc.php` (user config, excluded from vcs, can contain sensitive values, passwords etc.)
+3. `lib/App/RegisterDependencies.php`
## Start devserver
@@ -103,25 +107,14 @@ $ composer phplint
## Show errors
-Switch on option in your application config file like:
-```diff
- return [
- 'slimSettings' => [
-- 'displayErrorDetails' => false,
-+ 'displayErrorDetails' => true,
- 'logErrors' => true,
- 'logErrorDetails' => true,
- ],
+Switch your app environment to development in `public/.htaccess` file:
+```ini
+## .htaccess
+
+ SetEnv APP_ENV 'development'
+
```
-## Mock Server
-For a quick start uncomment [mocker middleware options](config/dev/example.inc.php#L67-L94) in your application config file.
-
-Used packages:
-* [Openapi Data Mocker](https://github.com/ybelenko/openapi-data-mocker) - first implementation of OAS3 fake data generator.
-* [Openapi Data Mocker Server Middleware](https://github.com/ybelenko/openapi-data-mocker-server-middleware) - PSR-15 HTTP server middleware.
-* [Openapi Data Mocker Interfaces](https://github.com/ybelenko/openapi-data-mocker-interfaces) - package with mocking interfaces.
-
{{#generateApiDocs}}
## API Endpoints
@@ -135,17 +128,22 @@ All URIs are relative to *{{{basePath}}}*
namespace {{apiPackage}};
use {{apiPackage}}\AbstractPetApi;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\ResponseInterface;
class PetApi extends AbstractPetApi
{
-
- public function addPet($request, $response, $args)
- {
+ public function addPet(
+ ServerRequestInterface $request,
+ ResponseInterface $response
+ ): ResponseInterface {
// your implementation of addPet method here
}
}
```
+When you need to inject dependencies into API controller check [PHP-DI - Controllers as services](https://github.com/PHP-DI/Slim-Bridge#controllers-as-services) guide.
+
Place all your implementation classes in `./src` folder accordingly.
For instance, when abstract class located at `./lib/Api/AbstractPetApi.php` you need to create implementation class at `./src/Api/PetApi.php`.
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/SlimRouter.mustache b/modules/openapi-generator/src/main/resources/php-slim4-server/SlimRouter.mustache
deleted file mode 100644
index ded9ca8cfad..00000000000
--- a/modules/openapi-generator/src/main/resources/php-slim4-server/SlimRouter.mustache
+++ /dev/null
@@ -1,331 +0,0 @@
-licenseInfo}}
-
-/**
- * NOTE: This class is auto generated by the openapi generator program.
- * https://github.com/openapitools/openapi-generator
- * Do not edit the class manually.
- */{{#apiInfo}}
-namespace {{invokerPackage}};
-
-use Slim\Factory\AppFactory;
-use Slim\Interfaces\RouteInterface;
-use Slim\Exception\HttpNotImplementedException;
-use Psr\Container\ContainerInterface;
-use InvalidArgumentException;
-use Dyorg\TokenAuthentication;
-use Dyorg\TokenAuthentication\TokenSearch;
-use Psr\Http\Message\ServerRequestInterface;
-use OpenAPIServer\Mock\OpenApiDataMocker;
-use OpenAPIServer\Mock\OpenApiDataMockerRouteMiddleware;
-{{#isSlimPsr7}}
-use Slim\Psr7\Factory\ResponseFactory;
-{{/isSlimPsr7}}
-{{#isNyholmPsr7}}
-use Nyholm\Psr7\Factory\Psr17Factory
-{{/isNyholmPsr7}}
-{{#isGuzzlePsr7}}
-use GuzzleHttp\Psr7\HttpFactory;
-{{/isGuzzlePsr7}}
-{{#isZendDiactoros}}
-use Zend\Diactoros\ResponseFactory;
-{{/isZendDiactoros}}
-use Exception;
-
-/**
- * SlimRouter Class Doc Comment
- *
- * @package {{invokerPackage}}
- * @author OpenAPI Generator team
- * @link https://github.com/openapitools/openapi-generator
- */
-class SlimRouter
-{
-
- /** @var App instance */
- private $slimApp;
-
- /** @var array[] list of all api operations */
- private $operations = [
- {{#apis}}
- {{#operations}}
- {{#operation}}
- [
- 'httpMethod' => '{{httpMethod}}',
- 'basePathWithoutHost' => '{{{basePathWithoutHost}}}',
- 'path' => '{{{path}}}',
- 'apiPackage' => '{{apiPackage}}',
- 'classname' => '{{classname}}',
- 'userClassname' => '{{userClassname}}',
- 'operationId' => '{{operationId}}',
- 'responses' => [
- {{#responses}}
- '{{#isDefault}}default{{/isDefault}}{{^isDefault}}{{code}}{{/isDefault}}' => [
- 'jsonSchema' => '{{{jsonSchema}}}',
- ],
- {{/responses}}
- ],
- 'authMethods' => [
- {{#hasAuthMethods}}
- {{#authMethods}}
- // {{type}} security schema named '{{name}}'
- {{#isBasicBasic}}
- [
- 'type' => '{{type}}',
- 'isBasic' => true,
- 'isBearer' => false,
- 'isApiKey' => false,
- 'isOAuth' => false,
- ],
- {{/isBasicBasic}}
- {{#isBasicBearer}}
- [
- 'type' => '{{type}}',
- 'isBasic' => true,
- 'isBearer' => true,
- 'isApiKey' => false,
- 'isOAuth' => false,
- ],
- {{/isBasicBearer}}
- {{#isApiKey}}
- [
- 'type' => '{{type}}',
- 'isBasic' => false,
- 'isBearer' => false,
- 'isApiKey' => true,
- 'isOAuth' => false,
- 'keyParamName' => '{{keyParamName}}',
- 'isKeyInHeader' => {{#isKeyInHeader}}true{{/isKeyInHeader}}{{^isKeyInHeader}}false{{/isKeyInHeader}},
- 'isKeyInQuery' => {{#isKeyInQuery}}true{{/isKeyInQuery}}{{^isKeyInQuery}}false{{/isKeyInQuery}},
- 'isKeyInCookie' => {{#isKeyInCookie}}true{{/isKeyInCookie}}{{^isKeyInCookie}}false{{/isKeyInCookie}},
- ],
- {{/isApiKey}}
- {{#isOAuth}}
- [
- 'type' => '{{type}}',
- 'isBasic' => false,
- 'isBearer' => false,
- 'isApiKey' => false,
- 'isOAuth' => true,
- 'scopes' => [
- {{#scopes}}
- '{{scope}}',{{#description}} // {{.}}{{/description}}
- {{/scopes}}
- ],
- ],
- {{/isOAuth}}
- {{/authMethods}}
- {{/hasAuthMethods}}
- ],
- ],
- {{/operation}}
- {{/operations}}
- {{/apis}}
- ];
-
- /**
- * Class constructor
- *
- * @param ContainerInterface|array $settings Either a ContainerInterface or an associative array of app settings
- *
- * @throws HttpNotImplementedException When implementation class doesn't exists
- * @throws Exception when not supported authorization schema type provided
- */
- public function __construct($settings = [])
- {
- if ($settings instanceof ContainerInterface) {
- // Set container to create App with on AppFactory
- AppFactory::setContainer($settings);
- }
- $this->slimApp = AppFactory::create();
-
- // middlewares requires Psr\Container\ContainerInterface
- $container = $this->slimApp->getContainer();
-
- {{#hasAuthMethods}}
- $authPackage = '{{authPackage}}';
- $basicAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) {
- $message = "How about extending {{abstractNamePrefix}}Authenticator{{abstractNameSuffix}} class by {$authPackage}\BasicAuthenticator?";
- throw new HttpNotImplementedException($request, $message);
- };
- $apiKeyAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) {
- $message = "How about extending {{abstractNamePrefix}}Authenticator{{abstractNameSuffix}} class by {$authPackage}\ApiKeyAuthenticator?";
- throw new HttpNotImplementedException($request, $message);
- };
- $oAuthAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) {
- $message = "How about extending {{abstractNamePrefix}}Authenticator{{abstractNameSuffix}} class by {$authPackage}\OAuthAuthenticator?";
- throw new HttpNotImplementedException($request, $message);
- };
- {{/hasAuthMethods}}
-
- $userOptions = $this->getSetting($settings, 'tokenAuthenticationOptions', null);
-
- // mocker options
- $mockerOptions = $this->getSetting($settings, 'mockerOptions', null);
- $dataMocker = $mockerOptions['dataMocker'] ?? new OpenApiDataMocker();
- {{#isSlimPsr7}}
- $responseFactory = new ResponseFactory();
- {{/isSlimPsr7}}
- {{#isNyholmPsr7}}
- $responseFactory = new Psr17Factory();
- {{/isNyholmPsr7}}
- {{#isGuzzlePsr7}}
- $responseFactory = new HttpFactory();
- {{/isGuzzlePsr7}}
- {{#isZendDiactoros}}
- $responseFactory = new ResponseFactory();
- {{/isZendDiactoros}}
- $getMockStatusCodeCallback = $mockerOptions['getMockStatusCodeCallback'] ?? null;
- $mockAfterCallback = $mockerOptions['afterCallback'] ?? null;
-
- foreach ($this->operations as $operation) {
- $callback = function ($request, $response, $arguments) use ($operation) {
- $message = "How about extending {$operation['classname']} by {$operation['apiPackage']}\\{$operation['userClassname']} class implementing {$operation['operationId']} as a {$operation['httpMethod']} method?";
- throw new HttpNotImplementedException($request, $message);
- };
- $middlewares = [];
-
- if (class_exists("\\{$operation['apiPackage']}\\{$operation['userClassname']}")) {
- $callback = "\\{$operation['apiPackage']}\\{$operation['userClassname']}:{$operation['operationId']}";
- }
-
- {{#hasAuthMethods}}
- foreach ($operation['authMethods'] as $authMethod) {
- switch ($authMethod['type']) {
- case 'http':
- $authenticatorClassname = "\\{$authPackage}\\BasicAuthenticator";
- if (class_exists($authenticatorClassname)) {
- $basicAuthenticator = new $authenticatorClassname($container);
- }
-
- $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([
- 'authenticator' => $basicAuthenticator,
- 'regex' => $authMethod['isBearer'] ? '/Bearer\s+(.*)$/i' : '/Basic\s+(.*)$/i',
- 'header' => 'Authorization',
- 'parameter' => null,
- 'cookie' => null,
- 'argument' => null,
- ], $userOptions));
- break;
- case 'apiKey':
- $authenticatorClassname = "\\{$authPackage}\\ApiKeyAuthenticator";
- if (class_exists($authenticatorClassname)) {
- $apiKeyAuthenticator = new $authenticatorClassname($container);
- }
-
- $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([
- 'authenticator' => $apiKeyAuthenticator,
- 'regex' => '/^(.*)$/i',
- 'header' => $authMethod['isKeyInHeader'] ? $authMethod['keyParamName'] : null,
- 'parameter' => $authMethod['isKeyInQuery'] ? $authMethod['keyParamName'] : null,
- 'cookie' => $authMethod['isKeyInCookie'] ? $authMethod['keyParamName'] : null,
- 'argument' => null,
- ], $userOptions));
- break;
- case 'oauth2':
- $authenticatorClassname = "\\{$authPackage}\\OAuthAuthenticator";
- if (class_exists($authenticatorClassname)) {
- $oAuthAuthenticator = new $authenticatorClassname($container, $authMethod['scopes']);
- }
-
- $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([
- 'authenticator' => $oAuthAuthenticator,
- 'regex' => '/Bearer\s+(.*)$/i',
- 'header' => 'Authorization',
- 'parameter' => null,
- 'cookie' => null,
- 'argument' => null,
- ], $userOptions));
- break;
- default:
- throw new Exception('Unknown authorization schema type');
- }
- }
- {{/hasAuthMethods}}
-
- if (is_callable($getMockStatusCodeCallback)) {
- $mockSchemaResponses = array_map(function ($item) {
- return json_decode($item['jsonSchema'], true);
- }, $operation['responses']);
- $middlewares[] = new OpenApiDataMockerRouteMiddleware($dataMocker, $mockSchemaResponses, $responseFactory, $getMockStatusCodeCallback, $mockAfterCallback);
- }
-
- $this->addRoute(
- [$operation['httpMethod']],
- "{$operation['basePathWithoutHost']}{$operation['path']}",
- $callback,
- $middlewares
- )->setName($operation['operationId']);
- }
- }
-
- /**
- * Merges user defined options with dynamic params
- *
- * @param array $staticOptions Required static options
- * @param array $userOptions User options
- *
- * @return array Merged array
- */
- private function getTokenAuthenticationOptions(array $staticOptions, array $userOptions = null)
- {
- if (is_array($userOptions) === false) {
- return $staticOptions;
- }
-
- return array_merge($userOptions, $staticOptions);
- }
-
- /**
- * Returns app setting by name.
- *
- * @param ContainerInterface|array $settings Either a ContainerInterface or an associative array of app settings
- * @param string $settingName Setting name
- * @param mixed $default Default setting value.
- *
- * @return mixed
- */
- private function getSetting($settings, $settingName, $default = null)
- {
- if ($settings instanceof ContainerInterface && $settings->has($settingName)) {
- return $settings->get($settingName);
- } elseif (is_array($settings) && array_key_exists($settingName, $settings)) {
- return $settings[$settingName];
- }
-
- return $default;
- }
-
- /**
- * Add route with multiple methods
- *
- * @param string[] $methods Numeric array of HTTP method names
- * @param string $pattern The route URI pattern
- * @param callable|string $callable The route callback routine
- * @param array|null $middlewares List of middlewares
- *
- * @return RouteInterface
- *
- * @throws InvalidArgumentException If the route pattern isn't a string
- */
- public function addRoute(array $methods, string $pattern, $callable, $middlewares = [])
- {
- $route = $this->slimApp->map($methods, $pattern, $callable);
- foreach ($middlewares as $middleware) {
- $route->add($middleware);
- }
- return $route;
- }
-
- /**
- * Returns Slim Framework instance
- *
- * @return App
- */
- public function getSlimApp()
- {
- return $this->slimApp;
- }
-}
-{{/apiInfo}}
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/abstract_authenticator.mustache b/modules/openapi-generator/src/main/resources/php-slim4-server/abstract_authenticator.mustache
index 82fd8f648ea..3aef910d9f1 100644
--- a/modules/openapi-generator/src/main/resources/php-slim4-server/abstract_authenticator.mustache
+++ b/modules/openapi-generator/src/main/resources/php-slim4-server/abstract_authenticator.mustache
@@ -9,7 +9,6 @@
*/{{#apiInfo}}
namespace {{authPackage}};
-use Psr\Container\ContainerInterface;
use Psr\Http\Message\ServerRequestInterface;
use Dyorg\TokenAuthentication;
use Dyorg\TokenAuthentication\TokenSearch;
@@ -24,12 +23,6 @@ use Dyorg\TokenAuthentication\Exceptions\UnauthorizedExceptionInterface;
*/
abstract class {{abstractNamePrefix}}Authenticator{{abstractNameSuffix}}
{
-
- /**
- * @var ContainerInterface|null Slim app container instance
- */
- protected $container;
-
/**
* @var string[]|null List of required scopes
*/
@@ -49,12 +42,10 @@ abstract class {{abstractNamePrefix}}Authenticator{{abstractNameSuffix}}
/**
* Authenticator constructor
*
- * @param ContainerInterface|null $container Slim app container instance
- * @param string[]|null $requiredScope List of required scopes
+ * @param string[]|null $requiredScope List of required scopes
*/
- public function __construct(ContainerInterface $container = null, $requiredScope = null)
+ public function __construct($requiredScope = null)
{
- $this->container = $container;
$this->requiredScope = $requiredScope;
}
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/api.mustache b/modules/openapi-generator/src/main/resources/php-slim4-server/api.mustache
index f76f11f29af..83de70ff5c4 100644
--- a/modules/openapi-generator/src/main/resources/php-slim4-server/api.mustache
+++ b/modules/openapi-generator/src/main/resources/php-slim4-server/api.mustache
@@ -6,10 +6,11 @@
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
+ * Extend this class with your controller. You can inject dependencies via class constructor,
+ * @see https://github.com/PHP-DI/Slim-Bridge basic example.
*/
namespace {{apiPackage}};
-use Psr\Container\ContainerInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Slim\Exception\HttpNotImplementedException;
@@ -23,25 +24,8 @@ use Slim\Exception\HttpNotImplementedException;
*/
abstract class {{classname}}
{
-
- /**
- * @var ContainerInterface|null Slim app container instance
- */
- protected $container;
-
- /**
- * Route Controller constructor receives container
- *
- * @param ContainerInterface|null $container Slim app container instance
- */
- public function __construct(ContainerInterface $container = null)
- {
- $this->container = $container;
- }
-
{{#operations}}
{{#operation}}
-
/**
* {{httpMethod}} {{operationId}}
{{#summary}}
@@ -56,7 +40,11 @@ abstract class {{classname}}
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
+ {{#hasPathParams}}
+ {{#pathParams}}
+ * @param {{{dataType}}} ${{paramName}}{{#description}} {{.}}{{/description}}{{^description}} {{paramName}}{{/description}}
+ {{/pathParams}}
+ {{/hasPathParams}}
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
@@ -64,19 +52,21 @@ abstract class {{classname}}
* @deprecated
{{/isDeprecated}}
*/
- public function {{operationId}}(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
+ public function {{operationId}}(
+ ServerRequestInterface $request,
+ ResponseInterface $response{{#hasPathParams}},{{/hasPathParams}}
+ {{#hasPathParams}}
+ {{#pathParams}}
+ {{{dataType}}} ${{paramName}}{{^-last}},{{/-last}}
+ {{/pathParams}}
+ {{/hasPathParams}}
+ ): ResponseInterface {
{{#hasHeaderParams}}
$headers = $request->getHeaders();
{{#headerParams}}
${{paramName}} = $request->hasHeader('{{baseName}}') ? $headers['{{baseName}}'] : null;
{{/headerParams}}
{{/hasHeaderParams}}
- {{#hasPathParams}}
- {{#pathParams}}
- ${{paramName}} = $args['{{baseName}}'];
- {{/pathParams}}
- {{/hasPathParams}}
{{#hasQueryParams}}
$queryParams = $request->getQueryParams();
{{#queryParams}}
@@ -105,6 +95,9 @@ abstract class {{classname}}
$message = "How about implementing {{nickname}} as a {{httpMethod}} method in {{apiPackage}}\{{userClassname}} class?";
throw new HttpNotImplementedException($request, $message);
}
+ {{^-last}}
+
+ {{/-last}}
{{/operation}}
{{/operations}}
}
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/composer.mustache b/modules/openapi-generator/src/main/resources/php-slim4-server/composer.mustache
index e514b055f54..6d8d0bcbac2 100644
--- a/modules/openapi-generator/src/main/resources/php-slim4-server/composer.mustache
+++ b/modules/openapi-generator/src/main/resources/php-slim4-server/composer.mustache
@@ -9,30 +9,30 @@
],
"require": {
"php": "^7.4 || ^8.0",
- "slim/slim": "^4.5.0",
"dyorg/slim-token-authentication": "dev-slim4",
- "ybelenko/openapi-data-mocker": "^1.0",
- "ybelenko/openapi-data-mocker-server-middleware": "^1.0",
- {{#isSlimPsr7}}
- "slim/psr7": "^1.1.0"
- {{/isSlimPsr7}}
- {{#isNyholmPsr7}}
- "nyholm/psr7": "^1.3.0",
- "nyholm/psr7-server": "^0.4.1"
- {{/isNyholmPsr7}}
{{#isGuzzlePsr7}}
"guzzlehttp/psr7": "^1.6.1",
- "http-interop/http-factory-guzzle": "^1.0.0"
+ "http-interop/http-factory-guzzle": "^1.0.0",
{{/isGuzzlePsr7}}
{{#isZendDiactoros}}
- "laminas/laminas-diactoros": "^2.3.0"
+ "laminas/laminas-diactoros": "^2.3.0",
{{/isZendDiactoros}}
+ {{#isNyholmPsr7}}
+ "nyholm/psr7": "^1.3.0",
+ "nyholm/psr7-server": "^0.4.1",
+ {{/isNyholmPsr7}}
+ "php-di/slim-bridge": "^3.2",
+ {{#isSlimPsr7}}
+ "slim/psr7": "^1.1.0",
+ {{/isSlimPsr7}}
+ "ybelenko/openapi-data-mocker": "^1.0",
+ "ybelenko/openapi-data-mocker-server-middleware": "^1.0"
},
"require-dev": {
+ "overtrue/phplint": "^2.0.2",
{{#generateTests}}
"phpunit/phpunit": "^8.0 || ^9.0",
{{/generateTests}}
- "overtrue/phplint": "^2.0.2",
"squizlabs/php_codesniffer": "^3.5"
},
"autoload": {
@@ -58,5 +58,8 @@
{{/generateTests}}
"phpcs": "phpcs",
"phplint": "phplint ./ --exclude=vendor"
+ },
+ "config": {
+ "sort-packages": true
}
}
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/config_dev_default.mustache b/modules/openapi-generator/src/main/resources/php-slim4-server/config_dev_default.mustache
new file mode 100644
index 00000000000..42588052160
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/php-slim4-server/config_dev_default.mustache
@@ -0,0 +1,35 @@
+ 'development',
+
+ // slim framework settings
+ 'slim.displayErrorDetails' => true,
+ 'slim.logErrors' => false,
+ 'slim.logErrorDetails' => false,
+
+ // PDO
+ 'pdo.dsn' => 'mysql:host=localhost;charset=utf8mb4',
+ 'pdo.username' => 'root',
+ 'pdo.password' => 'root',
+ 'pdo.options' => [
+ \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
+ ],
+];
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/config_example.mustache b/modules/openapi-generator/src/main/resources/php-slim4-server/config_example.mustache
deleted file mode 100644
index 52755f25385..00000000000
--- a/modules/openapi-generator/src/main/resources/php-slim4-server/config_example.mustache
+++ /dev/null
@@ -1,83 +0,0 @@
-licenseInfo}}
-
-/**
- * App configuration file example.
- *
- * Copy file to config/dev/config.inc.php and config/prod/config.inc.php
- * App loads dev config only when prod doesn't exist
- * in other words if both configs presented - prod config applies
- */
-
-use Psr\Http\Message\ServerRequestInterface;
-use Psr\Http\Message\ResponseInterface;
-use OpenAPIServer\Mock\OpenApiDataMocker;
-
-$mocker = new OpenApiDataMocker();
-$mocker->setModelsNamespace('{{modelPackage}}\\');
-
-return [
- 'slimSettings' => [
- 'displayErrorDetails' => false,
- 'logErrors' => true,
- 'logErrorDetails' => true,
- ],
-
- 'tokenAuthenticationOptions' => [
- /**
- * Tokens are essentially passwords. You should treat them as such and you should always
- * use HTTPS. If the middleware detects insecure usage over HTTP it will return unauthorized
- * with a message Required HTTPS for token authentication. This rule is relaxed for requests
- * on localhost. To allow insecure usage you must enable it manually by setting secure to
- * false.
- * Default: true
- */
- // 'secure' => true,
-
- /**
- * Alternatively you can list your development host to have relaxed security.
- * Default: ['localhost', '127.0.0.1']
- */
- // 'relaxed' => ['localhost', '127.0.0.1'],
-
- /**
- * By default on occurred a fail on authentication, is sent a response on json format with a
- * message (`Invalid Token` or `Not found Token`) and with the token (if found), with status
- * `401 Unauthorized`. You can customize it by setting a callable function on error option.
- * Default: null
- */
- // 'error' => null,
- ],
-
- 'mockerOptions' => [
- // 'dataMocker' => $mocker,
-
- // 'getMockStatusCodeCallback' => function (ServerRequestInterface $request, array $responses) {
- // // check if client clearly asks for mocked response
- // $pingHeader = 'X-{{invokerPackage}}-Mock';
- // $pingHeaderCode = 'X-{{invokerPackage}}-Mock-Code';
- // if (
- // $request->hasHeader($pingHeader)
- // && $request->getHeader($pingHeader)[0] === 'ping'
- // ) {
- // $responses = (array) $responses;
- // $requestedResponseCode = ($request->hasHeader($pingHeaderCode)) ? $request->getHeader($pingHeaderCode)[0] : 'default';
- // if (array_key_exists($requestedResponseCode, $responses)) {
- // return $requestedResponseCode;
- // }
-
- // // return first response key
- // reset($responses);
- // return key($responses);
- // }
-
- // return false;
- // },
-
- // 'afterCallback' => function (ServerRequestInterface $request, ResponseInterface $response) {
- // // mark mocked response to distinguish real and fake responses
- // return $response->withHeader('X-{{invokerPackage}}-Mock', 'pong');
- // },
- ],
-];
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/config_prod_default.mustache b/modules/openapi-generator/src/main/resources/php-slim4-server/config_prod_default.mustache
new file mode 100644
index 00000000000..d6853fbcf53
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/php-slim4-server/config_prod_default.mustache
@@ -0,0 +1,35 @@
+ 'production',
+
+ // slim framework settings
+ 'slim.displayErrorDetails' => false,
+ 'slim.logErrors' => true,
+ 'slim.logErrorDetails' => true,
+
+ // PDO
+ 'pdo.dsn' => 'mysql:host=localhost;charset=utf8mb4',
+ 'pdo.username' => 'root',
+ 'pdo.password' => 'root',
+ 'pdo.options' => [
+ \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
+ ],
+];
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/gitignore b/modules/openapi-generator/src/main/resources/php-slim4-server/gitignore
index e12b356ade0..27433d90949 100644
--- a/modules/openapi-generator/src/main/resources/php-slim4-server/gitignore
+++ b/modules/openapi-generator/src/main/resources/php-slim4-server/gitignore
@@ -20,5 +20,5 @@ composer.phar
# Application config may contain sensitive data
/config/**/*.*
!/config/.htaccess
-!/config/dev/example.inc.php
-!/config/prod/example.inc.php
+!/config/dev/default.inc.php
+!/config/prod/default.inc.php
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/index.mustache b/modules/openapi-generator/src/main/resources/php-slim4-server/index.mustache
index 305f7cf8b56..ead7d817f87 100644
--- a/modules/openapi-generator/src/main/resources/php-slim4-server/index.mustache
+++ b/modules/openapi-generator/src/main/resources/php-slim4-server/index.mustache
@@ -9,49 +9,64 @@
require_once __DIR__ . '/../vendor/autoload.php';
-use {{invokerPackage}}\SlimRouter;
-use Psr\Http\Message\ServerRequestInterface;
-use Psr\Http\Message\ResponseInterface;
-use OpenAPIServer\Mock\OpenApiDataMocker;
+use DI\Bridge\Slim\Bridge;
+use DI\ContainerBuilder;
+use {{appPackage}}\RegisterDependencies;
+use {{appPackage}}\RegisterRoutes;
+use {{appPackage}}\RegisterMiddlewares;
+use Slim\Factory\ServerRequestCreatorFactory;
+use Slim\ResponseEmitter;
{{/apiInfo}}
-// load config file
-$config = [];
-if (is_array($prodConfig = @include(__DIR__ . '/../config/prod/config.inc.php'))) {
- $config = $prodConfig;
-} elseif (is_array($devConfig = @include(__DIR__ . '/../config/dev/config.inc.php'))) {
- $config = $devConfig;
-} else {
- throw new InvalidArgumentException('Config file missed or broken.');
+// Instantiate PHP-DI ContainerBuilder
+$builder = new ContainerBuilder();
+
+// consider prod by default
+$env;
+switch (strtolower($_SERVER['APP_ENV'] ?? 'prod')) {
+ case 'development':
+ case 'dev':
+ $env = 'dev';
+ break;
+ case 'production':
+ case 'prod':
+ default:
+ $env = 'prod';
}
-$router = new SlimRouter($config);
-$app = $router->getSlimApp();
+// Main configuration
+$builder->addDefinitions(__DIR__ . "/../config/{$env}/default.inc.php");
-// Parse json, form data and xml
-$app->addBodyParsingMiddleware();
+// Config file for the environment if exists
+$userConfig = __DIR__ . "/../config/{$env}/config.inc.php";
+if (file_exists($userConfig)) {
+ $builder->addDefinitions($userConfig);
+}
-/**
- * The routing middleware should be added before the ErrorMiddleware
- * Otherwise exceptions thrown from it will not be handled
- */
-$app->addRoutingMiddleware();
+// Set up dependencies
+$dependencies = new RegisterDependencies();
+$dependencies($builder);
-/**
- * Add Error Handling Middleware
- *
- * @param bool $displayErrorDetails -> Should be set to false in production
- * @param bool $logErrors -> Parameter is passed to the default ErrorHandler
- * @param bool $logErrorDetails -> Display error details in error log
- * which can be replaced by a callable of your choice.
+// Build PHP-DI Container instance
+$container = $builder->build();
- * Note: This middleware should be added last. It will not handle any exceptions/errors
- * for middleware added after it.
- */
-$app->addErrorMiddleware(
- $config['slimSettings']['displayErrorDetails'] ?? false,
- $config['slimSettings']['logErrors'] ?? true,
- $config['slimSettings']['logErrorDetails'] ?? true
-);
+// Instantiate the app
+$app = Bridge::create($container);
-$app->run();
+// Register middleware
+$middleware = new RegisterMiddlewares();
+$middleware($app);
+
+// Register routes
+// yes, it's anti-pattern you shouldn't get deps from container directly
+$routes = $container->get(RegisterRoutes::class);
+$routes($app);
+
+// Create Request object from globals
+$serverRequestCreator = ServerRequestCreatorFactory::create();
+$request = $serverRequestCreator->createServerRequestFromGlobals();
+
+// Run App & Emit Response
+$response = $app->handle($request);
+$responseEmitter = new ResponseEmitter();
+$responseEmitter->emit($response);
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/register_dependencies.mustache b/modules/openapi-generator/src/main/resources/php-slim4-server/register_dependencies.mustache
new file mode 100644
index 00000000000..0f48fb9de1c
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/php-slim4-server/register_dependencies.mustache
@@ -0,0 +1,58 @@
+licenseInfo}}
+
+declare(strict_types=1);
+
+/**
+ * NOTE: This class is auto generated by the openapi generator program.
+ * https://github.com/openapitools/openapi-generator
+ * Do not edit the class manually.
+ */
+namespace {{appPackage}};
+
+/**
+ * RegisterDependencies
+ *
+ * Recommendations from template creator:
+ *
+ * I don't use imports(eg. use Slim\Middleware\ErrorMiddleware) here because each package unlikely
+ * be used in code twice. It helps to keep that file short and make Git history cleaner.
+ *
+ * This class declared as final because two classes with dependency injections can cause confusion. Edit
+ * template of this class or use your own implementation instead(overwrite index.php to import your
+ * custom class).
+ */
+final class RegisterDependencies
+{
+ /**
+ * Adds dependency definitions.
+ *
+ * @param \DI\ContainerBuilder $containerBuilder Container builder.
+ *
+ * @see https://php-di.org/doc/php-definitions.html
+ */
+ public function __invoke(\DI\ContainerBuilder $containerBuilder): void
+ {
+ $containerBuilder->addDefinitions([
+ // Response factory required as typed argument in next ErrorMiddleware injection
+ \Psr\Http\Message\ResponseFactoryInterface::class => \DI\factory([\Slim\Factory\AppFactory::class, 'determineResponseFactory']),
+
+ // Slim error middleware
+ // @see https://www.slimframework.com/docs/v4/middleware/error-handling.html
+ \Slim\Middleware\ErrorMiddleware::class => \DI\autowire()
+ ->constructorParameter('displayErrorDetails', \DI\get('slim.displayErrorDetails', false))
+ ->constructorParameter('logErrors', \DI\get('slim.logErrors', true))
+ ->constructorParameter('logErrorDetails', \DI\get('slim.logErrorDetails', true)),
+
+ // PDO class for database managing
+ \PDO::class => \DI\create()
+ ->constructor(
+ \DI\get('pdo.dsn'),
+ \DI\get('pdo.username'),
+ \DI\get('pdo.password'),
+ \DI\get('pdo.options', null)
+ ),
+ ]);
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/register_middlewares.mustache b/modules/openapi-generator/src/main/resources/php-slim4-server/register_middlewares.mustache
new file mode 100644
index 00000000000..b0f42676430
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/php-slim4-server/register_middlewares.mustache
@@ -0,0 +1,51 @@
+licenseInfo}}
+
+declare(strict_types=1);
+
+/**
+ * NOTE: This class is auto generated by the openapi generator program.
+ * https://github.com/openapitools/openapi-generator
+ * Do not edit the class manually.
+ */
+namespace {{appPackage}};
+
+/**
+ * RegisterMiddlewares
+ *
+ * Recommendations from template creator:
+ *
+ * There is no way to add route related middlewares here, add global ones. Route related middlewares
+ * can be applied in \{{appPackage}}\RegisterRoutes class.
+ *
+ * I add middlewares by full class names(\Slim\Middleware\ErrorMiddleware::class) because that way
+ * Slim initiates them with options from Container. They already configured, don't need to pass any
+ * options manually.
+ *
+ * I don't use imports(eg. use Slim\Middleware\ErrorMiddleware) here because each package unlikely
+ * be used in code twice. It helps to keep that file short and make Git history cleaner.
+ *
+ * This class declared as final because two classes with middlewares can cause confusion. Edit
+ * template of this class or use your own implementation instead(overwrite index.php to import your
+ * custom class).
+ */
+final class RegisterMiddlewares
+{
+ /**
+ * Adds middlewares to Slim app instance.
+ *
+ * @param \Slim\App $app App instance.
+ */
+ public function __invoke(\Slim\App $app): void
+ {
+ // Parse json, form data and xml
+ $app->addBodyParsingMiddleware();
+
+ // Add Routing Middleware
+ $app->addRoutingMiddleware();
+
+ // Add Error Middleware
+ $app->add(\Slim\Middleware\ErrorMiddleware::class);
+ }
+}
diff --git a/modules/openapi-generator/src/main/resources/php-slim4-server/register_routes.mustache b/modules/openapi-generator/src/main/resources/php-slim4-server/register_routes.mustache
new file mode 100644
index 00000000000..b027ebc46e7
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/php-slim4-server/register_routes.mustache
@@ -0,0 +1,137 @@
+licenseInfo}}
+
+declare(strict_types=1);
+
+/**
+ * NOTE: This class is auto generated by the openapi generator program.
+ * https://github.com/openapitools/openapi-generator
+ * Do not edit the class manually.
+ */{{#apiInfo}}
+namespace {{appPackage}};
+
+use Slim\Exception\HttpNotImplementedException;
+
+/**
+ * RegisterRoutes Class Doc Comment
+ *
+ * @package {{invokerPackage}}
+ * @author OpenAPI Generator team
+ * @link https://github.com/openapitools/openapi-generator
+ */
+class RegisterRoutes
+{
+ /** @var array[] list of all api operations */
+ private $operations = [
+ {{#apis}}
+ {{#operations}}
+ {{#operation}}
+ [
+ 'httpMethod' => '{{httpMethod}}',
+ 'basePathWithoutHost' => '{{{basePathWithoutHost}}}',
+ 'path' => '{{{path}}}',
+ 'apiPackage' => '{{apiPackage}}',
+ 'classname' => '{{classname}}',
+ 'userClassname' => '{{userClassname}}',
+ 'operationId' => '{{operationId}}',
+ 'responses' => [
+ {{#responses}}
+ '{{#isDefault}}default{{/isDefault}}{{^isDefault}}{{code}}{{/isDefault}}' => [
+ 'jsonSchema' => '{{{jsonSchema}}}',
+ ],
+ {{/responses}}
+ ],
+ 'authMethods' => [
+ {{#hasAuthMethods}}
+ {{#authMethods}}
+ // {{type}} security schema named '{{name}}'
+ {{#isBasicBasic}}
+ [
+ 'type' => '{{type}}',
+ 'isBasic' => true,
+ 'isBearer' => false,
+ 'isApiKey' => false,
+ 'isOAuth' => false,
+ ],
+ {{/isBasicBasic}}
+ {{#isBasicBearer}}
+ [
+ 'type' => '{{type}}',
+ 'isBasic' => true,
+ 'isBearer' => true,
+ 'isApiKey' => false,
+ 'isOAuth' => false,
+ ],
+ {{/isBasicBearer}}
+ {{#isApiKey}}
+ [
+ 'type' => '{{type}}',
+ 'isBasic' => false,
+ 'isBearer' => false,
+ 'isApiKey' => true,
+ 'isOAuth' => false,
+ 'keyParamName' => '{{keyParamName}}',
+ 'isKeyInHeader' => {{#isKeyInHeader}}true{{/isKeyInHeader}}{{^isKeyInHeader}}false{{/isKeyInHeader}},
+ 'isKeyInQuery' => {{#isKeyInQuery}}true{{/isKeyInQuery}}{{^isKeyInQuery}}false{{/isKeyInQuery}},
+ 'isKeyInCookie' => {{#isKeyInCookie}}true{{/isKeyInCookie}}{{^isKeyInCookie}}false{{/isKeyInCookie}},
+ ],
+ {{/isApiKey}}
+ {{#isOAuth}}
+ [
+ 'type' => '{{type}}',
+ 'isBasic' => false,
+ 'isBearer' => false,
+ 'isApiKey' => false,
+ 'isOAuth' => true,
+ 'scopes' => [
+ {{#scopes}}
+ '{{scope}}',{{#description}} // {{.}}{{/description}}
+ {{/scopes}}
+ ],
+ ],
+ {{/isOAuth}}
+ {{/authMethods}}
+ {{/hasAuthMethods}}
+ ],
+ ],
+ {{/operation}}
+ {{/operations}}
+ {{/apis}}
+ ];
+
+ /**
+ * Add routes to Slim app.
+ *
+ * @param \Slim\App $app Pre-configured Slim application instance
+ *
+ * @throws HttpNotImplementedException When implementation class doesn't exists
+ */
+ public function __invoke(\Slim\App $app): void
+ {
+ foreach ($this->operations as $operation) {
+ $callback = function ($request) use ($operation) {
+ $message = "How about extending {$operation['classname']} by {$operation['apiPackage']}\\{$operation['userClassname']} class implementing {$operation['operationId']} as a {$operation['httpMethod']} method?";
+ throw new HttpNotImplementedException($request, $message);
+ };
+ $middlewares = [];
+
+ if (class_exists("\\{$operation['apiPackage']}\\{$operation['userClassname']}")) {
+ // Notice how we register the controller using the class name?
+ // PHP-DI will instantiate the class for us only when it's actually necessary
+ $callback = ["\\{$operation['apiPackage']}\\{$operation['userClassname']}", $operation['operationId']];
+ }
+
+ $route = $app->map(
+ [$operation['httpMethod']],
+ "{$operation['basePathWithoutHost']}{$operation['path']}",
+ $callback
+ )->setName($operation['operationId']);
+
+ foreach ($middlewares as $middleware) {
+ $route->add($middleware);
+ }
+ }
+ }
+}
+{{/apiInfo}}
diff --git a/samples/server/petstore/php-slim4/.gitignore b/samples/server/petstore/php-slim4/.gitignore
index e12b356ade0..27433d90949 100644
--- a/samples/server/petstore/php-slim4/.gitignore
+++ b/samples/server/petstore/php-slim4/.gitignore
@@ -20,5 +20,5 @@ composer.phar
# Application config may contain sensitive data
/config/**/*.*
!/config/.htaccess
-!/config/dev/example.inc.php
-!/config/prod/example.inc.php
+!/config/dev/default.inc.php
+!/config/prod/default.inc.php
diff --git a/samples/server/petstore/php-slim4/.openapi-generator/FILES b/samples/server/petstore/php-slim4/.openapi-generator/FILES
index 40c7067f108..08a1e9c294c 100644
--- a/samples/server/petstore/php-slim4/.openapi-generator/FILES
+++ b/samples/server/petstore/php-slim4/.openapi-generator/FILES
@@ -2,11 +2,14 @@
README.md
composer.json
config/.htaccess
-config/dev/example.inc.php
-config/prod/example.inc.php
+config/dev/default.inc.php
+config/prod/default.inc.php
lib/Api/AbstractPetApi.php
lib/Api/AbstractStoreApi.php
lib/Api/AbstractUserApi.php
+lib/App/RegisterDependencies.php
+lib/App/RegisterMiddlewares.php
+lib/App/RegisterRoutes.php
lib/Auth/AbstractAuthenticator.php
lib/BaseModel.php
lib/Model/ApiResponse.php
@@ -15,7 +18,6 @@ lib/Model/Order.php
lib/Model/Pet.php
lib/Model/Tag.php
lib/Model/User.php
-lib/SlimRouter.php
phpcs.xml.dist
phpunit.xml.dist
public/.htaccess
diff --git a/samples/server/petstore/php-slim4/README.md b/samples/server/petstore/php-slim4/README.md
index ac51de45d1e..a99f4a13cc4 100644
--- a/samples/server/petstore/php-slim4/README.md
+++ b/samples/server/petstore/php-slim4/README.md
@@ -4,6 +4,7 @@
* [Slim 4 Documentation](https://www.slimframework.com/docs/v4/)
This server has been generated with [Slim PSR-7](https://github.com/slimphp/Slim-Psr7) implementation.
+[PHP-DI](https://php-di.org/doc/frameworks/slim.html) package used as dependency container.
## Requirements
@@ -23,7 +24,10 @@ $ composer install
## Add configs
-Application requires at least one config file(`config/dev/config.inc.php` or `config/prod/config.inc.php`). You can use [config/dev/example.inc.php](config/dev/example.inc.php) as starting point.
+[PHP-DI package](https://php-di.org/doc/getting-started.html) helps to decouple configuration from implementation. App loads configuration files in straight order(`$env` can be `prod` or `dev`):
+1. `config/$env/default.inc.php` (contains safe values, can be committed to vcs)
+2. `config/$env/config.inc.php` (user config, excluded from vcs, can contain sensitive values, passwords etc.)
+3. `lib/App/RegisterDependencies.php`
## Start devserver
@@ -86,25 +90,14 @@ $ composer phplint
## Show errors
-Switch on option in your application config file like:
-```diff
- return [
- 'slimSettings' => [
-- 'displayErrorDetails' => false,
-+ 'displayErrorDetails' => true,
- 'logErrors' => true,
- 'logErrorDetails' => true,
- ],
+Switch your app environment to development in `public/.htaccess` file:
+```ini
+## .htaccess
+
+ SetEnv APP_ENV 'development'
+
```
-## Mock Server
-For a quick start uncomment [mocker middleware options](config/dev/example.inc.php#L67-L94) in your application config file.
-
-Used packages:
-* [Openapi Data Mocker](https://github.com/ybelenko/openapi-data-mocker) - first implementation of OAS3 fake data generator.
-* [Openapi Data Mocker Server Middleware](https://github.com/ybelenko/openapi-data-mocker-server-middleware) - PSR-15 HTTP server middleware.
-* [Openapi Data Mocker Interfaces](https://github.com/ybelenko/openapi-data-mocker-interfaces) - package with mocking interfaces.
-
## API Endpoints
All URIs are relative to *http://petstore.swagger.io/v2*
@@ -117,17 +110,22 @@ All URIs are relative to *http://petstore.swagger.io/v2*
namespace OpenAPIServer\Api;
use OpenAPIServer\Api\AbstractPetApi;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\ResponseInterface;
class PetApi extends AbstractPetApi
{
-
- public function addPet($request, $response, $args)
- {
+ public function addPet(
+ ServerRequestInterface $request,
+ ResponseInterface $response
+ ): ResponseInterface {
// your implementation of addPet method here
}
}
```
+When you need to inject dependencies into API controller check [PHP-DI - Controllers as services](https://github.com/PHP-DI/Slim-Bridge#controllers-as-services) guide.
+
Place all your implementation classes in `./src` folder accordingly.
For instance, when abstract class located at `./lib/Api/AbstractPetApi.php` you need to create implementation class at `./src/Api/PetApi.php`.
diff --git a/samples/server/petstore/php-slim4/composer.json b/samples/server/petstore/php-slim4/composer.json
index 529f8f93715..4f31f4b28ff 100644
--- a/samples/server/petstore/php-slim4/composer.json
+++ b/samples/server/petstore/php-slim4/composer.json
@@ -9,15 +9,15 @@
],
"require": {
"php": "^7.4 || ^8.0",
- "slim/slim": "^4.5.0",
"dyorg/slim-token-authentication": "dev-slim4",
+ "php-di/slim-bridge": "^3.2",
+ "slim/psr7": "^1.1.0",
"ybelenko/openapi-data-mocker": "^1.0",
- "ybelenko/openapi-data-mocker-server-middleware": "^1.0",
- "slim/psr7": "^1.1.0"
+ "ybelenko/openapi-data-mocker-server-middleware": "^1.0"
},
"require-dev": {
- "phpunit/phpunit": "^8.0 || ^9.0",
"overtrue/phplint": "^2.0.2",
+ "phpunit/phpunit": "^8.0 || ^9.0",
"squizlabs/php_codesniffer": "^3.5"
},
"autoload": {
@@ -37,5 +37,8 @@
"test-models": "phpunit --testsuite Models",
"phpcs": "phpcs",
"phplint": "phplint ./ --exclude=vendor"
+ },
+ "config": {
+ "sort-packages": true
}
}
diff --git a/samples/server/petstore/php-slim4/config/dev/default.inc.php b/samples/server/petstore/php-slim4/config/dev/default.inc.php
new file mode 100644
index 00000000000..be4bd6530b0
--- /dev/null
+++ b/samples/server/petstore/php-slim4/config/dev/default.inc.php
@@ -0,0 +1,35 @@
+ 'development',
+
+ // slim framework settings
+ 'slim.displayErrorDetails' => true,
+ 'slim.logErrors' => false,
+ 'slim.logErrorDetails' => false,
+
+ // PDO
+ 'pdo.dsn' => 'mysql:host=localhost;charset=utf8mb4',
+ 'pdo.username' => 'root',
+ 'pdo.password' => 'root',
+ 'pdo.options' => [
+ \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
+ ],
+];
diff --git a/samples/server/petstore/php-slim4/config/dev/example.inc.php b/samples/server/petstore/php-slim4/config/dev/example.inc.php
deleted file mode 100644
index 2a2e65d4a59..00000000000
--- a/samples/server/petstore/php-slim4/config/dev/example.inc.php
+++ /dev/null
@@ -1,96 +0,0 @@
-setModelsNamespace('OpenAPIServer\Model\\');
-
-return [
- 'slimSettings' => [
- 'displayErrorDetails' => false,
- 'logErrors' => true,
- 'logErrorDetails' => true,
- ],
-
- 'tokenAuthenticationOptions' => [
- /**
- * Tokens are essentially passwords. You should treat them as such and you should always
- * use HTTPS. If the middleware detects insecure usage over HTTP it will return unauthorized
- * with a message Required HTTPS for token authentication. This rule is relaxed for requests
- * on localhost. To allow insecure usage you must enable it manually by setting secure to
- * false.
- * Default: true
- */
- // 'secure' => true,
-
- /**
- * Alternatively you can list your development host to have relaxed security.
- * Default: ['localhost', '127.0.0.1']
- */
- // 'relaxed' => ['localhost', '127.0.0.1'],
-
- /**
- * By default on occurred a fail on authentication, is sent a response on json format with a
- * message (`Invalid Token` or `Not found Token`) and with the token (if found), with status
- * `401 Unauthorized`. You can customize it by setting a callable function on error option.
- * Default: null
- */
- // 'error' => null,
- ],
-
- 'mockerOptions' => [
- // 'dataMocker' => $mocker,
-
- // 'getMockStatusCodeCallback' => function (ServerRequestInterface $request, array $responses) {
- // // check if client clearly asks for mocked response
- // $pingHeader = 'X-OpenAPIServer-Mock';
- // $pingHeaderCode = 'X-OpenAPIServer-Mock-Code';
- // if (
- // $request->hasHeader($pingHeader)
- // && $request->getHeader($pingHeader)[0] === 'ping'
- // ) {
- // $responses = (array) $responses;
- // $requestedResponseCode = ($request->hasHeader($pingHeaderCode)) ? $request->getHeader($pingHeaderCode)[0] : 'default';
- // if (array_key_exists($requestedResponseCode, $responses)) {
- // return $requestedResponseCode;
- // }
-
- // // return first response key
- // reset($responses);
- // return key($responses);
- // }
-
- // return false;
- // },
-
- // 'afterCallback' => function (ServerRequestInterface $request, ResponseInterface $response) {
- // // mark mocked response to distinguish real and fake responses
- // return $response->withHeader('X-OpenAPIServer-Mock', 'pong');
- // },
- ],
-];
diff --git a/samples/server/petstore/php-slim4/config/prod/default.inc.php b/samples/server/petstore/php-slim4/config/prod/default.inc.php
new file mode 100644
index 00000000000..333c7768b43
--- /dev/null
+++ b/samples/server/petstore/php-slim4/config/prod/default.inc.php
@@ -0,0 +1,35 @@
+ 'production',
+
+ // slim framework settings
+ 'slim.displayErrorDetails' => false,
+ 'slim.logErrors' => true,
+ 'slim.logErrorDetails' => true,
+
+ // PDO
+ 'pdo.dsn' => 'mysql:host=localhost;charset=utf8mb4',
+ 'pdo.username' => 'root',
+ 'pdo.password' => 'root',
+ 'pdo.options' => [
+ \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
+ ],
+];
diff --git a/samples/server/petstore/php-slim4/config/prod/example.inc.php b/samples/server/petstore/php-slim4/config/prod/example.inc.php
deleted file mode 100644
index 2a2e65d4a59..00000000000
--- a/samples/server/petstore/php-slim4/config/prod/example.inc.php
+++ /dev/null
@@ -1,96 +0,0 @@
-setModelsNamespace('OpenAPIServer\Model\\');
-
-return [
- 'slimSettings' => [
- 'displayErrorDetails' => false,
- 'logErrors' => true,
- 'logErrorDetails' => true,
- ],
-
- 'tokenAuthenticationOptions' => [
- /**
- * Tokens are essentially passwords. You should treat them as such and you should always
- * use HTTPS. If the middleware detects insecure usage over HTTP it will return unauthorized
- * with a message Required HTTPS for token authentication. This rule is relaxed for requests
- * on localhost. To allow insecure usage you must enable it manually by setting secure to
- * false.
- * Default: true
- */
- // 'secure' => true,
-
- /**
- * Alternatively you can list your development host to have relaxed security.
- * Default: ['localhost', '127.0.0.1']
- */
- // 'relaxed' => ['localhost', '127.0.0.1'],
-
- /**
- * By default on occurred a fail on authentication, is sent a response on json format with a
- * message (`Invalid Token` or `Not found Token`) and with the token (if found), with status
- * `401 Unauthorized`. You can customize it by setting a callable function on error option.
- * Default: null
- */
- // 'error' => null,
- ],
-
- 'mockerOptions' => [
- // 'dataMocker' => $mocker,
-
- // 'getMockStatusCodeCallback' => function (ServerRequestInterface $request, array $responses) {
- // // check if client clearly asks for mocked response
- // $pingHeader = 'X-OpenAPIServer-Mock';
- // $pingHeaderCode = 'X-OpenAPIServer-Mock-Code';
- // if (
- // $request->hasHeader($pingHeader)
- // && $request->getHeader($pingHeader)[0] === 'ping'
- // ) {
- // $responses = (array) $responses;
- // $requestedResponseCode = ($request->hasHeader($pingHeaderCode)) ? $request->getHeader($pingHeaderCode)[0] : 'default';
- // if (array_key_exists($requestedResponseCode, $responses)) {
- // return $requestedResponseCode;
- // }
-
- // // return first response key
- // reset($responses);
- // return key($responses);
- // }
-
- // return false;
- // },
-
- // 'afterCallback' => function (ServerRequestInterface $request, ResponseInterface $response) {
- // // mark mocked response to distinguish real and fake responses
- // return $response->withHeader('X-OpenAPIServer-Mock', 'pong');
- // },
- ],
-];
diff --git a/samples/server/petstore/php-slim4/lib/Api/AbstractPetApi.php b/samples/server/petstore/php-slim4/lib/Api/AbstractPetApi.php
index ff8c7224526..7975aabc6fe 100644
--- a/samples/server/petstore/php-slim4/lib/Api/AbstractPetApi.php
+++ b/samples/server/petstore/php-slim4/lib/Api/AbstractPetApi.php
@@ -19,10 +19,11 @@
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
+ * Extend this class with your controller. You can inject dependencies via class constructor,
+ * @see https://github.com/PHP-DI/Slim-Bridge basic example.
*/
namespace OpenAPIServer\Api;
-use Psr\Container\ContainerInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Slim\Exception\HttpNotImplementedException;
@@ -36,23 +37,6 @@ use Slim\Exception\HttpNotImplementedException;
*/
abstract class AbstractPetApi
{
-
- /**
- * @var ContainerInterface|null Slim app container instance
- */
- protected $container;
-
- /**
- * Route Controller constructor receives container
- *
- * @param ContainerInterface|null $container Slim app container instance
- */
- public function __construct(ContainerInterface $container = null)
- {
- $this->container = $container;
- }
-
-
/**
* POST addPet
* Summary: Add a new pet to the store
@@ -60,13 +44,14 @@ abstract class AbstractPetApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function addPet(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
+ public function addPet(
+ ServerRequestInterface $request,
+ ResponseInterface $response
+ ): ResponseInterface {
$body = $request->getParsedBody();
$message = "How about implementing addPet as a POST method in OpenAPIServer\Api\PetApi class?";
throw new HttpNotImplementedException($request, $message);
@@ -78,16 +63,18 @@ abstract class AbstractPetApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
+ * @param int $petId Pet id to delete
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function deletePet(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
+ public function deletePet(
+ ServerRequestInterface $request,
+ ResponseInterface $response,
+ int $petId
+ ): ResponseInterface {
$headers = $request->getHeaders();
$apiKey = $request->hasHeader('api_key') ? $headers['api_key'] : null;
- $petId = $args['petId'];
$message = "How about implementing deletePet as a DELETE method in OpenAPIServer\Api\PetApi class?";
throw new HttpNotImplementedException($request, $message);
}
@@ -100,13 +87,14 @@ abstract class AbstractPetApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function findPetsByStatus(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
+ public function findPetsByStatus(
+ ServerRequestInterface $request,
+ ResponseInterface $response
+ ): ResponseInterface {
$queryParams = $request->getQueryParams();
$status = (key_exists('status', $queryParams)) ? $queryParams['status'] : null;
$message = "How about implementing findPetsByStatus as a GET method in OpenAPIServer\Api\PetApi class?";
@@ -121,14 +109,15 @@ abstract class AbstractPetApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
* @deprecated
*/
- public function findPetsByTags(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
+ public function findPetsByTags(
+ ServerRequestInterface $request,
+ ResponseInterface $response
+ ): ResponseInterface {
$queryParams = $request->getQueryParams();
$tags = (key_exists('tags', $queryParams)) ? $queryParams['tags'] : null;
$message = "How about implementing findPetsByTags as a GET method in OpenAPIServer\Api\PetApi class?";
@@ -143,14 +132,16 @@ abstract class AbstractPetApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
+ * @param int $petId ID of pet to return
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function getPetById(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
- $petId = $args['petId'];
+ public function getPetById(
+ ServerRequestInterface $request,
+ ResponseInterface $response,
+ int $petId
+ ): ResponseInterface {
$message = "How about implementing getPetById as a GET method in OpenAPIServer\Api\PetApi class?";
throw new HttpNotImplementedException($request, $message);
}
@@ -162,13 +153,14 @@ abstract class AbstractPetApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function updatePet(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
+ public function updatePet(
+ ServerRequestInterface $request,
+ ResponseInterface $response
+ ): ResponseInterface {
$body = $request->getParsedBody();
$message = "How about implementing updatePet as a PUT method in OpenAPIServer\Api\PetApi class?";
throw new HttpNotImplementedException($request, $message);
@@ -180,14 +172,16 @@ abstract class AbstractPetApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
+ * @param int $petId ID of pet that needs to be updated
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function updatePetWithForm(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
- $petId = $args['petId'];
+ public function updatePetWithForm(
+ ServerRequestInterface $request,
+ ResponseInterface $response,
+ int $petId
+ ): ResponseInterface {
$body = $request->getParsedBody();
$name = (isset($body['name'])) ? $body['name'] : null;
$status = (isset($body['status'])) ? $body['status'] : null;
@@ -202,14 +196,16 @@ abstract class AbstractPetApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
+ * @param int $petId ID of pet to update
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function uploadFile(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
- $petId = $args['petId'];
+ public function uploadFile(
+ ServerRequestInterface $request,
+ ResponseInterface $response,
+ int $petId
+ ): ResponseInterface {
$body = $request->getParsedBody();
$additionalMetadata = (isset($body['additionalMetadata'])) ? $body['additionalMetadata'] : null;
$file = (key_exists('file', $request->getUploadedFiles())) ? $request->getUploadedFiles()['file'] : null;
diff --git a/samples/server/petstore/php-slim4/lib/Api/AbstractStoreApi.php b/samples/server/petstore/php-slim4/lib/Api/AbstractStoreApi.php
index 2542047a669..0c153911aac 100644
--- a/samples/server/petstore/php-slim4/lib/Api/AbstractStoreApi.php
+++ b/samples/server/petstore/php-slim4/lib/Api/AbstractStoreApi.php
@@ -19,10 +19,11 @@
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
+ * Extend this class with your controller. You can inject dependencies via class constructor,
+ * @see https://github.com/PHP-DI/Slim-Bridge basic example.
*/
namespace OpenAPIServer\Api;
-use Psr\Container\ContainerInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Slim\Exception\HttpNotImplementedException;
@@ -36,23 +37,6 @@ use Slim\Exception\HttpNotImplementedException;
*/
abstract class AbstractStoreApi
{
-
- /**
- * @var ContainerInterface|null Slim app container instance
- */
- protected $container;
-
- /**
- * Route Controller constructor receives container
- *
- * @param ContainerInterface|null $container Slim app container instance
- */
- public function __construct(ContainerInterface $container = null)
- {
- $this->container = $container;
- }
-
-
/**
* DELETE deleteOrder
* Summary: Delete purchase order by ID
@@ -60,14 +44,16 @@ abstract class AbstractStoreApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
+ * @param string $orderId ID of the order that needs to be deleted
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function deleteOrder(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
- $orderId = $args['orderId'];
+ public function deleteOrder(
+ ServerRequestInterface $request,
+ ResponseInterface $response,
+ string $orderId
+ ): ResponseInterface {
$message = "How about implementing deleteOrder as a DELETE method in OpenAPIServer\Api\StoreApi class?";
throw new HttpNotImplementedException($request, $message);
}
@@ -80,13 +66,14 @@ abstract class AbstractStoreApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function getInventory(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
+ public function getInventory(
+ ServerRequestInterface $request,
+ ResponseInterface $response
+ ): ResponseInterface {
$message = "How about implementing getInventory as a GET method in OpenAPIServer\Api\StoreApi class?";
throw new HttpNotImplementedException($request, $message);
}
@@ -99,14 +86,16 @@ abstract class AbstractStoreApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
+ * @param int $orderId ID of pet that needs to be fetched
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function getOrderById(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
- $orderId = $args['orderId'];
+ public function getOrderById(
+ ServerRequestInterface $request,
+ ResponseInterface $response,
+ int $orderId
+ ): ResponseInterface {
$message = "How about implementing getOrderById as a GET method in OpenAPIServer\Api\StoreApi class?";
throw new HttpNotImplementedException($request, $message);
}
@@ -118,13 +107,14 @@ abstract class AbstractStoreApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function placeOrder(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
+ public function placeOrder(
+ ServerRequestInterface $request,
+ ResponseInterface $response
+ ): ResponseInterface {
$body = $request->getParsedBody();
$message = "How about implementing placeOrder as a POST method in OpenAPIServer\Api\StoreApi class?";
throw new HttpNotImplementedException($request, $message);
diff --git a/samples/server/petstore/php-slim4/lib/Api/AbstractUserApi.php b/samples/server/petstore/php-slim4/lib/Api/AbstractUserApi.php
index eee2c7d2ccf..fb9b1e5c7b4 100644
--- a/samples/server/petstore/php-slim4/lib/Api/AbstractUserApi.php
+++ b/samples/server/petstore/php-slim4/lib/Api/AbstractUserApi.php
@@ -19,10 +19,11 @@
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
+ * Extend this class with your controller. You can inject dependencies via class constructor,
+ * @see https://github.com/PHP-DI/Slim-Bridge basic example.
*/
namespace OpenAPIServer\Api;
-use Psr\Container\ContainerInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Slim\Exception\HttpNotImplementedException;
@@ -36,23 +37,6 @@ use Slim\Exception\HttpNotImplementedException;
*/
abstract class AbstractUserApi
{
-
- /**
- * @var ContainerInterface|null Slim app container instance
- */
- protected $container;
-
- /**
- * Route Controller constructor receives container
- *
- * @param ContainerInterface|null $container Slim app container instance
- */
- public function __construct(ContainerInterface $container = null)
- {
- $this->container = $container;
- }
-
-
/**
* POST createUser
* Summary: Create user
@@ -60,13 +44,14 @@ abstract class AbstractUserApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function createUser(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
+ public function createUser(
+ ServerRequestInterface $request,
+ ResponseInterface $response
+ ): ResponseInterface {
$body = $request->getParsedBody();
$message = "How about implementing createUser as a POST method in OpenAPIServer\Api\UserApi class?";
throw new HttpNotImplementedException($request, $message);
@@ -78,13 +63,14 @@ abstract class AbstractUserApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function createUsersWithArrayInput(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
+ public function createUsersWithArrayInput(
+ ServerRequestInterface $request,
+ ResponseInterface $response
+ ): ResponseInterface {
$body = $request->getParsedBody();
$message = "How about implementing createUsersWithArrayInput as a POST method in OpenAPIServer\Api\UserApi class?";
throw new HttpNotImplementedException($request, $message);
@@ -96,13 +82,14 @@ abstract class AbstractUserApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function createUsersWithListInput(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
+ public function createUsersWithListInput(
+ ServerRequestInterface $request,
+ ResponseInterface $response
+ ): ResponseInterface {
$body = $request->getParsedBody();
$message = "How about implementing createUsersWithListInput as a POST method in OpenAPIServer\Api\UserApi class?";
throw new HttpNotImplementedException($request, $message);
@@ -115,14 +102,16 @@ abstract class AbstractUserApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
+ * @param string $username The name that needs to be deleted
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function deleteUser(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
- $username = $args['username'];
+ public function deleteUser(
+ ServerRequestInterface $request,
+ ResponseInterface $response,
+ string $username
+ ): ResponseInterface {
$message = "How about implementing deleteUser as a DELETE method in OpenAPIServer\Api\UserApi class?";
throw new HttpNotImplementedException($request, $message);
}
@@ -134,14 +123,16 @@ abstract class AbstractUserApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
+ * @param string $username The name that needs to be fetched. Use user1 for testing.
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function getUserByName(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
- $username = $args['username'];
+ public function getUserByName(
+ ServerRequestInterface $request,
+ ResponseInterface $response,
+ string $username
+ ): ResponseInterface {
$message = "How about implementing getUserByName as a GET method in OpenAPIServer\Api\UserApi class?";
throw new HttpNotImplementedException($request, $message);
}
@@ -153,13 +144,14 @@ abstract class AbstractUserApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function loginUser(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
+ public function loginUser(
+ ServerRequestInterface $request,
+ ResponseInterface $response
+ ): ResponseInterface {
$queryParams = $request->getQueryParams();
$username = (key_exists('username', $queryParams)) ? $queryParams['username'] : null;
$password = (key_exists('password', $queryParams)) ? $queryParams['password'] : null;
@@ -173,13 +165,14 @@ abstract class AbstractUserApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function logoutUser(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
+ public function logoutUser(
+ ServerRequestInterface $request,
+ ResponseInterface $response
+ ): ResponseInterface {
$message = "How about implementing logoutUser as a GET method in OpenAPIServer\Api\UserApi class?";
throw new HttpNotImplementedException($request, $message);
}
@@ -191,14 +184,16 @@ abstract class AbstractUserApi
*
* @param ServerRequestInterface $request Request
* @param ResponseInterface $response Response
- * @param array|null $args Path arguments
+ * @param string $username name that need to be deleted
*
* @return ResponseInterface
* @throws HttpNotImplementedException to force implementation class to override this method
*/
- public function updateUser(ServerRequestInterface $request, ResponseInterface $response, array $args)
- {
- $username = $args['username'];
+ public function updateUser(
+ ServerRequestInterface $request,
+ ResponseInterface $response,
+ string $username
+ ): ResponseInterface {
$body = $request->getParsedBody();
$message = "How about implementing updateUser as a PUT method in OpenAPIServer\Api\UserApi class?";
throw new HttpNotImplementedException($request, $message);
diff --git a/samples/server/petstore/php-slim4/lib/App/RegisterDependencies.php b/samples/server/petstore/php-slim4/lib/App/RegisterDependencies.php
new file mode 100644
index 00000000000..8c21bc3dca6
--- /dev/null
+++ b/samples/server/petstore/php-slim4/lib/App/RegisterDependencies.php
@@ -0,0 +1,71 @@
+addDefinitions([
+ // Response factory required as typed argument in next ErrorMiddleware injection
+ \Psr\Http\Message\ResponseFactoryInterface::class => \DI\factory([\Slim\Factory\AppFactory::class, 'determineResponseFactory']),
+
+ // Slim error middleware
+ // @see https://www.slimframework.com/docs/v4/middleware/error-handling.html
+ \Slim\Middleware\ErrorMiddleware::class => \DI\autowire()
+ ->constructorParameter('displayErrorDetails', \DI\get('slim.displayErrorDetails', false))
+ ->constructorParameter('logErrors', \DI\get('slim.logErrors', true))
+ ->constructorParameter('logErrorDetails', \DI\get('slim.logErrorDetails', true)),
+
+ // PDO class for database managing
+ \PDO::class => \DI\create()
+ ->constructor(
+ \DI\get('pdo.dsn'),
+ \DI\get('pdo.username'),
+ \DI\get('pdo.password'),
+ \DI\get('pdo.options', null)
+ ),
+ ]);
+ }
+}
diff --git a/samples/server/petstore/php-slim4/lib/App/RegisterMiddlewares.php b/samples/server/petstore/php-slim4/lib/App/RegisterMiddlewares.php
new file mode 100644
index 00000000000..120d91dede9
--- /dev/null
+++ b/samples/server/petstore/php-slim4/lib/App/RegisterMiddlewares.php
@@ -0,0 +1,64 @@
+addBodyParsingMiddleware();
+
+ // Add Routing Middleware
+ $app->addRoutingMiddleware();
+
+ // Add Error Middleware
+ $app->add(\Slim\Middleware\ErrorMiddleware::class);
+ }
+}
diff --git a/samples/server/petstore/php-slim4/lib/SlimRouter.php b/samples/server/petstore/php-slim4/lib/App/RegisterRoutes.php
similarity index 75%
rename from samples/server/petstore/php-slim4/lib/SlimRouter.php
rename to samples/server/petstore/php-slim4/lib/App/RegisterRoutes.php
index 1f81b223d2b..52c5533f2ab 100644
--- a/samples/server/petstore/php-slim4/lib/SlimRouter.php
+++ b/samples/server/petstore/php-slim4/lib/App/RegisterRoutes.php
@@ -15,39 +15,26 @@
* Generated by: https://github.com/openapitools/openapi-generator.git
*/
+declare(strict_types=1);
+
/**
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
*/
-namespace OpenAPIServer;
+namespace OpenAPIServer\App;
-use Slim\Factory\AppFactory;
-use Slim\Interfaces\RouteInterface;
use Slim\Exception\HttpNotImplementedException;
-use Psr\Container\ContainerInterface;
-use InvalidArgumentException;
-use Dyorg\TokenAuthentication;
-use Dyorg\TokenAuthentication\TokenSearch;
-use Psr\Http\Message\ServerRequestInterface;
-use OpenAPIServer\Mock\OpenApiDataMocker;
-use OpenAPIServer\Mock\OpenApiDataMockerRouteMiddleware;
-use Slim\Psr7\Factory\ResponseFactory;
-use Exception;
/**
- * SlimRouter Class Doc Comment
+ * RegisterRoutes Class Doc Comment
*
* @package OpenAPIServer
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
-class SlimRouter
+class RegisterRoutes
{
-
- /** @var App instance */
- private $slimApp;
-
/** @var array[] list of all api operations */
private $operations = [
[
@@ -843,191 +830,36 @@ class SlimRouter
];
/**
- * Class constructor
+ * Add routes to Slim app.
*
- * @param ContainerInterface|array $settings Either a ContainerInterface or an associative array of app settings
+ * @param \Slim\App $app Pre-configured Slim application instance
*
* @throws HttpNotImplementedException When implementation class doesn't exists
- * @throws Exception when not supported authorization schema type provided
*/
- public function __construct($settings = [])
+ public function __invoke(\Slim\App $app): void
{
- if ($settings instanceof ContainerInterface) {
- // Set container to create App with on AppFactory
- AppFactory::setContainer($settings);
- }
- $this->slimApp = AppFactory::create();
-
- // middlewares requires Psr\Container\ContainerInterface
- $container = $this->slimApp->getContainer();
-
- $authPackage = 'OpenAPIServer\Auth';
- $basicAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) {
- $message = "How about extending AbstractAuthenticator class by {$authPackage}\BasicAuthenticator?";
- throw new HttpNotImplementedException($request, $message);
- };
- $apiKeyAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) {
- $message = "How about extending AbstractAuthenticator class by {$authPackage}\ApiKeyAuthenticator?";
- throw new HttpNotImplementedException($request, $message);
- };
- $oAuthAuthenticator = function (ServerRequestInterface &$request, TokenSearch $tokenSearch) use ($authPackage) {
- $message = "How about extending AbstractAuthenticator class by {$authPackage}\OAuthAuthenticator?";
- throw new HttpNotImplementedException($request, $message);
- };
-
- $userOptions = $this->getSetting($settings, 'tokenAuthenticationOptions', null);
-
- // mocker options
- $mockerOptions = $this->getSetting($settings, 'mockerOptions', null);
- $dataMocker = $mockerOptions['dataMocker'] ?? new OpenApiDataMocker();
- $responseFactory = new ResponseFactory();
- $getMockStatusCodeCallback = $mockerOptions['getMockStatusCodeCallback'] ?? null;
- $mockAfterCallback = $mockerOptions['afterCallback'] ?? null;
-
foreach ($this->operations as $operation) {
- $callback = function ($request, $response, $arguments) use ($operation) {
+ $callback = function ($request) use ($operation) {
$message = "How about extending {$operation['classname']} by {$operation['apiPackage']}\\{$operation['userClassname']} class implementing {$operation['operationId']} as a {$operation['httpMethod']} method?";
throw new HttpNotImplementedException($request, $message);
};
$middlewares = [];
if (class_exists("\\{$operation['apiPackage']}\\{$operation['userClassname']}")) {
- $callback = "\\{$operation['apiPackage']}\\{$operation['userClassname']}:{$operation['operationId']}";
+ // Notice how we register the controller using the class name?
+ // PHP-DI will instantiate the class for us only when it's actually necessary
+ $callback = ["\\{$operation['apiPackage']}\\{$operation['userClassname']}", $operation['operationId']];
}
- foreach ($operation['authMethods'] as $authMethod) {
- switch ($authMethod['type']) {
- case 'http':
- $authenticatorClassname = "\\{$authPackage}\\BasicAuthenticator";
- if (class_exists($authenticatorClassname)) {
- $basicAuthenticator = new $authenticatorClassname($container);
- }
-
- $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([
- 'authenticator' => $basicAuthenticator,
- 'regex' => $authMethod['isBearer'] ? '/Bearer\s+(.*)$/i' : '/Basic\s+(.*)$/i',
- 'header' => 'Authorization',
- 'parameter' => null,
- 'cookie' => null,
- 'argument' => null,
- ], $userOptions));
- break;
- case 'apiKey':
- $authenticatorClassname = "\\{$authPackage}\\ApiKeyAuthenticator";
- if (class_exists($authenticatorClassname)) {
- $apiKeyAuthenticator = new $authenticatorClassname($container);
- }
-
- $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([
- 'authenticator' => $apiKeyAuthenticator,
- 'regex' => '/^(.*)$/i',
- 'header' => $authMethod['isKeyInHeader'] ? $authMethod['keyParamName'] : null,
- 'parameter' => $authMethod['isKeyInQuery'] ? $authMethod['keyParamName'] : null,
- 'cookie' => $authMethod['isKeyInCookie'] ? $authMethod['keyParamName'] : null,
- 'argument' => null,
- ], $userOptions));
- break;
- case 'oauth2':
- $authenticatorClassname = "\\{$authPackage}\\OAuthAuthenticator";
- if (class_exists($authenticatorClassname)) {
- $oAuthAuthenticator = new $authenticatorClassname($container, $authMethod['scopes']);
- }
-
- $middlewares[] = new TokenAuthentication($this->getTokenAuthenticationOptions([
- 'authenticator' => $oAuthAuthenticator,
- 'regex' => '/Bearer\s+(.*)$/i',
- 'header' => 'Authorization',
- 'parameter' => null,
- 'cookie' => null,
- 'argument' => null,
- ], $userOptions));
- break;
- default:
- throw new Exception('Unknown authorization schema type');
- }
- }
-
- if (is_callable($getMockStatusCodeCallback)) {
- $mockSchemaResponses = array_map(function ($item) {
- return json_decode($item['jsonSchema'], true);
- }, $operation['responses']);
- $middlewares[] = new OpenApiDataMockerRouteMiddleware($dataMocker, $mockSchemaResponses, $responseFactory, $getMockStatusCodeCallback, $mockAfterCallback);
- }
-
- $this->addRoute(
+ $route = $app->map(
[$operation['httpMethod']],
"{$operation['basePathWithoutHost']}{$operation['path']}",
- $callback,
- $middlewares
+ $callback
)->setName($operation['operationId']);
+
+ foreach ($middlewares as $middleware) {
+ $route->add($middleware);
+ }
}
}
-
- /**
- * Merges user defined options with dynamic params
- *
- * @param array $staticOptions Required static options
- * @param array $userOptions User options
- *
- * @return array Merged array
- */
- private function getTokenAuthenticationOptions(array $staticOptions, array $userOptions = null)
- {
- if (is_array($userOptions) === false) {
- return $staticOptions;
- }
-
- return array_merge($userOptions, $staticOptions);
- }
-
- /**
- * Returns app setting by name.
- *
- * @param ContainerInterface|array $settings Either a ContainerInterface or an associative array of app settings
- * @param string $settingName Setting name
- * @param mixed $default Default setting value.
- *
- * @return mixed
- */
- private function getSetting($settings, $settingName, $default = null)
- {
- if ($settings instanceof ContainerInterface && $settings->has($settingName)) {
- return $settings->get($settingName);
- } elseif (is_array($settings) && array_key_exists($settingName, $settings)) {
- return $settings[$settingName];
- }
-
- return $default;
- }
-
- /**
- * Add route with multiple methods
- *
- * @param string[] $methods Numeric array of HTTP method names
- * @param string $pattern The route URI pattern
- * @param callable|string $callable The route callback routine
- * @param array|null $middlewares List of middlewares
- *
- * @return RouteInterface
- *
- * @throws InvalidArgumentException If the route pattern isn't a string
- */
- public function addRoute(array $methods, string $pattern, $callable, $middlewares = [])
- {
- $route = $this->slimApp->map($methods, $pattern, $callable);
- foreach ($middlewares as $middleware) {
- $route->add($middleware);
- }
- return $route;
- }
-
- /**
- * Returns Slim Framework instance
- *
- * @return App
- */
- public function getSlimApp()
- {
- return $this->slimApp;
- }
}
diff --git a/samples/server/petstore/php-slim4/lib/Auth/AbstractAuthenticator.php b/samples/server/petstore/php-slim4/lib/Auth/AbstractAuthenticator.php
index de2e6011364..699fd1fdbc7 100644
--- a/samples/server/petstore/php-slim4/lib/Auth/AbstractAuthenticator.php
+++ b/samples/server/petstore/php-slim4/lib/Auth/AbstractAuthenticator.php
@@ -22,7 +22,6 @@
*/
namespace OpenAPIServer\Auth;
-use Psr\Container\ContainerInterface;
use Psr\Http\Message\ServerRequestInterface;
use Dyorg\TokenAuthentication;
use Dyorg\TokenAuthentication\TokenSearch;
@@ -37,12 +36,6 @@ use Dyorg\TokenAuthentication\Exceptions\UnauthorizedExceptionInterface;
*/
abstract class AbstractAuthenticator
{
-
- /**
- * @var ContainerInterface|null Slim app container instance
- */
- protected $container;
-
/**
* @var string[]|null List of required scopes
*/
@@ -62,12 +55,10 @@ abstract class AbstractAuthenticator
/**
* Authenticator constructor
*
- * @param ContainerInterface|null $container Slim app container instance
- * @param string[]|null $requiredScope List of required scopes
+ * @param string[]|null $requiredScope List of required scopes
*/
- public function __construct(ContainerInterface $container = null, $requiredScope = null)
+ public function __construct($requiredScope = null)
{
- $this->container = $container;
$this->requiredScope = $requiredScope;
}
diff --git a/samples/server/petstore/php-slim4/public/.htaccess b/samples/server/petstore/php-slim4/public/.htaccess
index f6a2ceb3952..57c2185f0e4 100644
--- a/samples/server/petstore/php-slim4/public/.htaccess
+++ b/samples/server/petstore/php-slim4/public/.htaccess
@@ -1,3 +1,7 @@
+
+ SetEnv APP_ENV 'production'
+
+
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
diff --git a/samples/server/petstore/php-slim4/public/index.php b/samples/server/petstore/php-slim4/public/index.php
index 9993535af75..e336d00f81b 100644
--- a/samples/server/petstore/php-slim4/public/index.php
+++ b/samples/server/petstore/php-slim4/public/index.php
@@ -22,48 +22,63 @@
require_once __DIR__ . '/../vendor/autoload.php';
-use OpenAPIServer\SlimRouter;
-use Psr\Http\Message\ServerRequestInterface;
-use Psr\Http\Message\ResponseInterface;
-use OpenAPIServer\Mock\OpenApiDataMocker;
+use DI\Bridge\Slim\Bridge;
+use DI\ContainerBuilder;
+use OpenAPIServer\App\RegisterDependencies;
+use OpenAPIServer\App\RegisterRoutes;
+use OpenAPIServer\App\RegisterMiddlewares;
+use Slim\Factory\ServerRequestCreatorFactory;
+use Slim\ResponseEmitter;
-// load config file
-$config = [];
-if (is_array($prodConfig = @include(__DIR__ . '/../config/prod/config.inc.php'))) {
- $config = $prodConfig;
-} elseif (is_array($devConfig = @include(__DIR__ . '/../config/dev/config.inc.php'))) {
- $config = $devConfig;
-} else {
- throw new InvalidArgumentException('Config file missed or broken.');
+// Instantiate PHP-DI ContainerBuilder
+$builder = new ContainerBuilder();
+
+// consider prod by default
+$env;
+switch (strtolower($_SERVER['APP_ENV'] ?? 'prod')) {
+ case 'development':
+ case 'dev':
+ $env = 'dev';
+ break;
+ case 'production':
+ case 'prod':
+ default:
+ $env = 'prod';
}
-$router = new SlimRouter($config);
-$app = $router->getSlimApp();
+// Main configuration
+$builder->addDefinitions(__DIR__ . "/../config/{$env}/default.inc.php");
-// Parse json, form data and xml
-$app->addBodyParsingMiddleware();
+// Config file for the environment if exists
+$userConfig = __DIR__ . "/../config/{$env}/config.inc.php";
+if (file_exists($userConfig)) {
+ $builder->addDefinitions($userConfig);
+}
-/**
- * The routing middleware should be added before the ErrorMiddleware
- * Otherwise exceptions thrown from it will not be handled
- */
-$app->addRoutingMiddleware();
+// Set up dependencies
+$dependencies = new RegisterDependencies();
+$dependencies($builder);
-/**
- * Add Error Handling Middleware
- *
- * @param bool $displayErrorDetails -> Should be set to false in production
- * @param bool $logErrors -> Parameter is passed to the default ErrorHandler
- * @param bool $logErrorDetails -> Display error details in error log
- * which can be replaced by a callable of your choice.
+// Build PHP-DI Container instance
+$container = $builder->build();
- * Note: This middleware should be added last. It will not handle any exceptions/errors
- * for middleware added after it.
- */
-$app->addErrorMiddleware(
- $config['slimSettings']['displayErrorDetails'] ?? false,
- $config['slimSettings']['logErrors'] ?? true,
- $config['slimSettings']['logErrorDetails'] ?? true
-);
+// Instantiate the app
+$app = Bridge::create($container);
-$app->run();
+// Register middleware
+$middleware = new RegisterMiddlewares();
+$middleware($app);
+
+// Register routes
+// yes, it's anti-pattern you shouldn't get deps from container directly
+$routes = $container->get(RegisterRoutes::class);
+$routes($app);
+
+// Create Request object from globals
+$serverRequestCreator = ServerRequestCreatorFactory::create();
+$request = $serverRequestCreator->createServerRequestFromGlobals();
+
+// Run App & Emit Response
+$response = $app->handle($request);
+$responseEmitter = new ResponseEmitter();
+$responseEmitter->emit($response);