Application::run()   D
last analyzed

Complexity

Conditions 9
Paths 1

Size

Total Lines 169
Code Lines 95

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 0
loc 169
ccs 0
cts 140
cp 0
rs 4.8196
c 0
b 0
f 0
cc 9
eloc 95
nc 1
nop 3
crap 90

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Phrest;
4
5
use Zend\ConfigAggregator\PhpFileProvider;
6
use Zend\ConfigAggregator\ArrayProvider;
7
use Zend\ConfigAggregator\ConfigAggregator;
8
9
use Zend\ServiceManager\Config;
10
use Zend\ServiceManager\ServiceManager;
11
12
class Application
13
{
14
    const DEFAULT_CONFIG_DIRECTORY_PATTERN = 'config/{{,*.}global,{,*.}local}.php';
15
    const USER_CONFIG = 'phrest_user_config';
16
17
    const CONFIG_SWAGGER_SCAN_DIRECTORY = 'phrest_config_swagger_scan_directory';
18
    const CONFIG_ENABLE_CACHE = 'phrest_config_enable_cache';
19
    const CONFIG_CACHE_DIRECTORY = 'phrest_config_cache_directory';
20
    const CONFIG_MONOLOG_HANDLER = 'phrest_config_monolog_handler';
21
    const CONFIG_MONOLOG_PROCESSOR = 'phrest_config_monolog_processor';
22
    const CONFIG_PRE_ROUTING_MIDDLEWARE = 'phrest_config_pre_routing_middleware';
23
    const CONFIG_PRE_DISPATCHING_MIDDLEWARE = 'phrest_config_pre_dispatching_middleware';
24
    const CONFIG_ROUTES = 'phrest_config_routes';
25
    const CONFIG_DEPENDENCIES = 'phrest_config_dependencies';
26
    const CONFIG_ERROR_CODES = 'phrest_config_error_codes';
27
28
    const ACTION_SWAGGER = 'phrest_action_swagger';
29
    const ACTION_ERROR_CODES = 'phrest_action_error_codes';
30
31
    const SERVICE_LOGGER = 'phrest_service_logger';
32
    const SERVICE_ROUTER = 'phrest_service_router';
33
    const SERVICE_SWAGGER = 'phrest_service_swagger';
34
    const SERVICE_HATEOAS = 'phrest_service_hateoas';
35
    const SERVICE_HATEOAS_RESPONSE_GENERATOR = 'phrest_service_hateoas_response_generator';
36
    const SERVICE_REQUEST_SWAGGER_VALIDATOR = 'phrest_service_request_swagger_validator';
37
38
    static public function run(
39
        string $applicationName = 'phrest-application',
40
        string $configDirectoryPattern = self::DEFAULT_CONFIG_DIRECTORY_PATTERN,
41
        ?\Psr\Http\Message\ServerRequestInterface $request = null
42
    )
43
    {
44
        $logger = new \Monolog\Logger($applicationName, [new \Monolog\Handler\StreamHandler('php://stdout')]);
45
        \Monolog\ErrorHandler::register($logger);
46
47
        $userConfigAggregator = new ConfigAggregator([
48
            new PhpFileProvider($configDirectoryPattern),
49
        ]);
50
        $userConfig = $userConfigAggregator->getMergedConfig();
51
52
        $swaggerScanDirectory = (string)($userConfig[\Phrest\Application::CONFIG_SWAGGER_SCAN_DIRECTORY] ?? null);
53
54
        $enableCache = (boolean)($userConfig[\Phrest\Application::CONFIG_ENABLE_CACHE] ?? false);
55
        $cacheDirectory = $userConfig[\Phrest\Application::CONFIG_CACHE_DIRECTORY] ?? null;
56
57
        $monologHandler = $userConfig[\Phrest\Application::CONFIG_MONOLOG_HANDLER] ?? [];
58
        $monologProcessor = $userConfig[\Phrest\Application::CONFIG_MONOLOG_PROCESSOR] ?? [];
59
60
        $errorCodes = $userConfig[\Phrest\Application::CONFIG_ERROR_CODES] ?? null;
61
62
        $cache = self::createCache($enableCache, $cacheDirectory);
63
64
        $internalConfigAggregator = new ConfigAggregator([
65
            new ArrayProvider([
66
                'dependencies' => $userConfig[\Phrest\Application::CONFIG_DEPENDENCIES] ?? []
67
            ]),
68
            new ArrayProvider([
69
                ConfigAggregator::ENABLE_CACHE => $enableCache,
70
                'zend-expressive' => [
71
                    'programmatic_pipeline' => true,
72
                ],
73
                'dependencies' => [
74
                    'factories' => [
75
                        \Zend\Expressive\Helper\UrlHelper::class => \Zend\Expressive\Helper\UrlHelperFactory::class,
76
77
                        \Phrest\Application::SERVICE_LOGGER => function (\Interop\Container\ContainerInterface $container) use ($logger, $monologHandler, $monologProcessor) {
78
                            $handlers = [];
79
                            foreach ($monologHandler as $handler) {
80
                                $handlers[] = $container->get($handler);
81
                            }
82
                            foreach ($monologProcessor as $processor) {
83
                                $logger->pushProcessor($container->get($processor));
84
                            }
85
                            $logger->setHandlers($handlers);
86
                            return $logger;
87
                        },
88
89
                        \Phrest\Application::SERVICE_SWAGGER => function () use ($cache, $swaggerScanDirectory) {
90
                            return new \Phrest\Swagger($cache, $swaggerScanDirectory);
91
                        },
92
93
                        \Phrest\Application::SERVICE_HATEOAS => function (\Interop\Container\ContainerInterface $container) use ($enableCache, $cacheDirectory) {
94
                            /** @var \Zend\Expressive\Router\RouterInterface $router */
95
                            $router = $container->get(\Zend\Expressive\Router\RouterInterface::class);
96
97
                            /** @var \Zend\Expressive\Helper\ServerUrlHelper $serverUrlHelper */
98
                            $serverUrlHelper = $container->get(\Zend\Expressive\Helper\ServerUrlHelper::class);
99
100
                            /* @todo registerLoader is deprecated! */
101
                            \Doctrine\Common\Annotations\AnnotationRegistry::registerLoader('class_exists');
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\Common\Annotati...istry::registerLoader() has been deprecated: this method is deprecated and will be removed in doctrine/annotations 2.0 autoloading should be deferred to the globally registered autoloader by then. For now, use @example AnnotationRegistry::registerLoader('class_exists') ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

101
                            /** @scrutinizer ignore-deprecated */ \Doctrine\Common\Annotations\AnnotationRegistry::registerLoader('class_exists');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
102
                            $hateoasBuilder = \Hateoas\HateoasBuilder::create();
103
                            if ($enableCache) {
104
                                $hateoasBuilder->setCacheDir($cacheDirectory);
105
                            }
106
                            $hateoasBuilder->setUrlGenerator(
107
                                null,
108
                                new \Hateoas\UrlGenerator\CallableUrlGenerator(
109
                                    function ($route, array $parameters, $absolute) use ($router, $serverUrlHelper) {
110
                                        $uri = $router->generateUri($route, $parameters);
111
                                        if ($absolute) {
112
                                            return $serverUrlHelper($uri);
113
                                        }
114
                                        return $uri;
115
                                    }
116
                                )
117
                            );
118
                            return $hateoasBuilder->build();
119
                        },
120
121
                        \Phrest\Application::ACTION_SWAGGER => function (\Interop\Container\ContainerInterface $container) {
122
                            return new \Phrest\API\Action\Swagger($container->get(\Phrest\Application::SERVICE_SWAGGER));
123
                        },
124
125
                        \Phrest\Application::ACTION_ERROR_CODES => function (\Interop\Container\ContainerInterface $container) use ($cache, $errorCodes) {
126
                            if ($errorCodes) {
127
                                $errorCodesInstance = $container->get($errorCodes);
128
                            } else {
129
                                $errorCodesInstance = new API\ErrorCodes();
130
                            }
131
                            return new \Phrest\API\Action\ErrorCodes($cache, $errorCodesInstance);
132
                        },
133
134
                        \Phrest\Application::SERVICE_HATEOAS_RESPONSE_GENERATOR => function (\Interop\Container\ContainerInterface $container) {
135
                            return new \Phrest\API\HateoasResponseGenerator(
136
                                $container->get(\Phrest\Application::SERVICE_HATEOAS)
137
                            );
138
                        },
139
140
                        \Phrest\Application::SERVICE_REQUEST_SWAGGER_VALIDATOR => function (\Interop\Container\ContainerInterface $container) {
141
                            /** @var \Phrest\Swagger $swagger */
142
                            $swagger = $container->get(\Phrest\Application::SERVICE_SWAGGER);
143
                            $jsonValidator = new \JsonSchema\Validator(
144
                                new \JsonSchema\Constraints\Factory($swagger->getSchemaStorage())
145
                            );
146
                            return new \Phrest\API\RequestSwaggerValidator($swagger, $jsonValidator);
147
                        },
148
149
                        \Phrest\Application::SERVICE_ROUTER => function () {
150
                            return new \Zend\Expressive\Router\FastRouteRouter();
151
                        },
152
153
                        \Zend\Expressive\Router\RouterInterface::class => function (\Interop\Container\ContainerInterface $container) {
154
                            return $container->get(\Phrest\Application::SERVICE_ROUTER);
155
                        }
156
                    ],
157
                    'invokables' => [
158
                        \Zend\Expressive\Helper\ServerUrlHelper::class => \Zend\Expressive\Helper\ServerUrlHelper::class
159
                    ],
160
                    'initializers' => [
161
                        \Psr\Log\LoggerAwareInterface::class => function (\Interop\Container\ContainerInterface $container, $service) {
162
                            if ($service instanceof \Psr\Log\LoggerAwareInterface) {
163
                                $service->setLogger(
164
                                    $container->get(\Phrest\Application::SERVICE_LOGGER)
165
                                );
166
                            }
167
                        },
168
                        API\RequestSwaggerValidatorAwareInterface::class => function (\Interop\Container\ContainerInterface $container, $service) {
169
                            if ($service instanceof API\RequestSwaggerValidatorAwareInterface) {
170
                                $service->setRequestSwaggerValidator(
171
                                    $container->get(\Phrest\Application::SERVICE_REQUEST_SWAGGER_VALIDATOR)
172
                                );
173
                            }
174
                        },
175
                        API\HateoasResponseGeneratorAwareInterface::class => function (\Interop\Container\ContainerInterface $container, $service) {
176
                            if ($service instanceof API\HateoasResponseGeneratorAwareInterface) {
177
                                $service->setHateoasResponseGenerator(
178
                                    $container->get(\Phrest\Application::SERVICE_HATEOAS_RESPONSE_GENERATOR)
179
                                );
180
                            }
181
                        },
182
                    ]
183
                ]
184
            ]),
185
        ]);
186
187
        $container = self::createContainer(
188
            $internalConfigAggregator->getMergedConfig(),
189
            $userConfig
190
        );
191
192
        // Register logging handler / processors - can only happen after loaded user dependencies
193
        $container->get(\Phrest\Application::SERVICE_LOGGER);
194
195
        $app = new \Zend\Expressive\Application($container->get(\Zend\Expressive\Router\RouterInterface::class), $container);
196
197
        self::registerRoutes($app, $userConfig[\Phrest\Application::CONFIG_ROUTES] ?? []);
198
        self::pipeMiddleware(
199
            $app,
200
            $userConfig[\Phrest\Application::CONFIG_PRE_ROUTING_MIDDLEWARE] ?? [],
201
            $userConfig[\Phrest\Application::CONFIG_PRE_DISPATCHING_MIDDLEWARE] ?? []
202
        );
203
204
        $logger->debug('application init completed', ['userConfig' => $userConfig]);
205
206
        $app->run($request);
207
    }
208
209
    static function createCache(bool $enableCache, ?string $cacheDirectory): \Zend\Cache\Storage\StorageInterface
210
    {
211
        $cache = new \Zend\Cache\Storage\Adapter\BlackHole();
212
        if ($enableCache) {
213
            $cache = new \Zend\Cache\Storage\Adapter\Filesystem();
214
            $cache->setOptions([
215
                'cache_dir' => $cacheDirectory,
216
                'ttl' => 0
217
            ]);
218
        }
219
        return $cache;
220
    }
221
222
    static function createContainer(array $internalConfig, array $userConfig): \Interop\Container\ContainerInterface
223
    {
224
        $container = new ServiceManager();
225
        (new Config($internalConfig['dependencies'] ?? []))->configureServiceManager($container);
226
        $container->setService(self::USER_CONFIG, $userConfig);
227
        return $container;
228
    }
229
230
    static private function registerRoutes(\Zend\Expressive\Application $app, array $routes)
231
    {
232
        foreach ($routes as $name => $routeConfig) {
233
            $route = $app->route($routeConfig['path'], $routeConfig['action'], ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], $name);
234
            $route->setOptions([
235
                'operationIds' => $routeConfig['operationIds'] ?? []
236
            ]);
237
        }
238
    }
239
240
    static private function pipeMiddleware(\Zend\Expressive\Application $app, array $preRoutingMiddleware, array $preDispatchingMiddleware)
241
    {
242
        $container = $app->getContainer();
243
        $logger = $container->get(\Phrest\Application::SERVICE_LOGGER);
244
245
        $app->pipe(array_merge(
246
            [
247
                new \Phrest\Middleware\Error($logger),
248
                new \Phrest\Middleware\HttpException($logger),
249
                new \Zend\Expressive\Helper\ServerUrlMiddleware($container->get(\Zend\Expressive\Helper\ServerUrlHelper::class)),
250
                new \Phrest\Middleware\JsonRequestBody()
251
            ],
252
            $preRoutingMiddleware,
253
            [
254
                \Zend\Expressive\Application::ROUTING_MIDDLEWARE,
255
                new \Zend\Expressive\Helper\UrlHelperMiddleware($container->get(\Zend\Expressive\Helper\UrlHelper::class))
256
            ],
257
            $preDispatchingMiddleware,
258
            [
259
                \Zend\Expressive\Application::DISPATCH_MIDDLEWARE,
260
                new \Phrest\Middleware\NotFound()
261
            ]
262
        ));
263
    }
264
265
    static public function createRoute(string $path, string $action, array $operationIds = []): array
266
    {
267
        return [
268
            'path' => $path,
269
            'action' => $action,
270
            'operationIds' => $operationIds
271
        ];
272
    }
273
}
274