Passed
Push — master ( 30ae21...a0c229 )
by Gabor
03:31
created

WebApplication::prepareContainer()   A

Complexity

Conditions 2
Paths 3

Size

Total Lines 63
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 63
ccs 0
cts 0
cp 0
rs 9.4347
c 0
b 0
f 0
cc 2
eloc 42
nc 3
nop 0
crap 6

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
 * WebHemi.
4
 *
5
 * PHP version 5.6
6
 *
7
 * @copyright 2012 - 2016 Gixx-web (http://www.gixx-web.com)
8
 * @license   https://opensource.org/licenses/MIT The MIT License (MIT)
9
 *
10
 * @link      http://www.gixx-web.com
11
 */
12
namespace WebHemi\Application\Web;
13
14
use InvalidArgumentException;
15
use WebHemi\Adapter\Http\ResponseInterface;
16
use WebHemi\Adapter\Http\ServerRequestInterface;
17
use WebHemi\Adapter\Http\HttpAdapterInterface;
18
use WebHemi\Adapter\Renderer\RendererAdapterInterface;
19
use WebHemi\Adapter\Router\RouterAdapterInterface;
20
use WebHemi\Application\AbstractApplication;
21
use WebHemi\Application\EnvironmentManager;
22
use WebHemi\Application\SessionManager;
23
use WebHemi\Middleware\DispatcherMiddleware;
24
use WebHemi\Middleware\FinalMiddleware;
25
use WebHemi\Middleware\MiddlewareInterface;
26
27
/**
28
 * Class WebApplication.
29
 */
30
class WebApplication extends AbstractApplication
31
{
32
    /**
33
     * Starts the session.
34
     *
35
     * @codeCoverageIgnore - not testing session (yet)
36
     */
37
    private function initSession()
38
    {
39
        if (defined('PHPUNIT_WEBHEMI_TESTSUITE')) {
40
            return;
41
        }
42
43
        /** @var SessionManager $sessionManager */
44
        $sessionManager = $this->getContainer()->get(SessionManager::class);
45
        $name = $this->getEnvironmentManager()->getSelectedApplication();
46
        $timeOut = 3600;
47
        $path = $this->getEnvironmentManager()->getSelectedApplicationUri();
48
        $domain = $this->getEnvironmentManager()->getApplicationDomain();
49
        $secure = $this->getEnvironmentManager()->isSecuredApplication();
50
        $httpOnly = true;
51
52
        $sessionManager->start($name, $timeOut, $path, $domain, $secure, $httpOnly);
53
    }
54
55
    /**
56
     * Get ready to run the application: set final data for specific services.
57
     *
58
     * @codeCoverageIgnore - Check the EnvironmentManager and Container adapter tests.
59
     */
60
    private function prepareContainer()
61
    {
62
        // Register services according to the selected module.
63
        $this->getContainer()->registerModuleServices($this->getEnvironmentManager()->getSelectedModule());
64
65
        // Set proper arguments for the HTTP adapter.
66
        $this->getContainer()
67
            ->setServiceArgument(
68
                HttpAdapterInterface::class,
69
                $this->getEnvironmentManager()->getEnvironmentData('GET')
70
            )
71
            ->setServiceArgument(
72
                HttpAdapterInterface::class,
73
                $this->getEnvironmentManager()->getEnvironmentData('POST')
74
            )
75
            ->setServiceArgument(
76
                HttpAdapterInterface::class,
77
                $this->getEnvironmentManager()->getEnvironmentData('SERVER')
78
            )
79
            ->setServiceArgument(
80
                HttpAdapterInterface::class,
81
                $this->getEnvironmentManager()->getEnvironmentData('COOKIE')
82
            )
83
            ->setServiceArgument(
84
                HttpAdapterInterface::class,
85
                $this->getEnvironmentManager()->getEnvironmentData('FILES')
86
            );
87
88
        try {
89
            $theme = $this->getEnvironmentManager()
90
                ->getApplicationTemplateSettings($this->getEnvironmentManager()->getSelectedTheme());
91
            $themeResourcePath = $this->getEnvironmentManager()->getResourcePath();
92
        } catch (InvalidArgumentException $e) {
93
            $theme = $this->getEnvironmentManager()->getApplicationTemplateSettings(EnvironmentManager::DEFAULT_THEME);
94
            $themeResourcePath = EnvironmentManager::DEFAULT_THEME_RESOURCE_PATH;
95
        }
96
97
        // Set proper arguments for the renderer.
98
        $this->getContainer()
99
            ->setServiceArgument(
100
                RendererAdapterInterface::class,
101
                $theme
102
            )
103
            ->setServiceArgument(
104
                RendererAdapterInterface::class,
105
                $themeResourcePath
106
            )
107
            ->setServiceArgument(
108
                RendererAdapterInterface::class,
109
                $this->getEnvironmentManager()->getSelectedApplicationUri()
110
            );
111
112
        // Set proper arguments for the router.
113
        $this->getContainer()
114
            ->setServiceArgument(
115
                RouterAdapterInterface::class,
116
                $this->getEnvironmentManager()->getModuleRouteSettings()
117
            )
118
            ->setServiceArgument(
119
                RouterAdapterInterface::class,
120
                $this->getEnvironmentManager()->getSelectedApplicationUri()
121
            );
122
    }
123
124
    /**
125
     * Runs the application. This is where the magic happens.
126
     * According tho the environment settings this must build up the middleware pipeline and execute it.
127
     *
128
     * a Pre-Routing Middleware can be; priority < 0:
129
     *  - LockCheck - check if the client IP is banned > S102|S403
130
     *  - Auth - if the user is not logged in, but there's a "Remember me" cookie, then logs in > S102
131
     *
132
     * Routing Middleware is fixed (RoutingMiddleware::class); priority = 0:
133
     *  - A middleware that routes the incoming Request and delegates to the matched middleware. > S102|S404|S405
134
     *    The RouteResult should be attached to the Request.
135
     *    If the Routing is not defined explicitly in the pipeline, then it will be injected with priority 0.
136
     *
137
     * a Post-Routing Middleware can be; priority between 0 and 100:
138
     *  - Acl - checks if the given route is available for the client. Also checks the auth > S102|S401|S403
139
     *  - CacheReader - checks if a suitable response body is cached. > S102|S200
140
     *
141
     * Dispatcher Middleware is fixed (DispatcherMiddleware::class); priority = 100:
142
     *  - A middleware which gets the corresponding Action middleware and applies it > S102
143
     *    If the Dispatcher is not defined explicitly in the pipeline, then it will be injected with priority 100.
144
     *    The Dispatcher should not set the response Status Code to 200 to let Post-Dispatchers to be called.
145
     *
146
     * a Post-Dispatch Middleware can be; priority > 100:
147
     *  - CacheWriter - writes response body into DataStorage (DB, File etc.) > S102
148
     *
149
     * Final Middleware is fixed (FinalMiddleware:class):
150
     *  - This middleware behaves a bit differently. It cannot be ordered, it's always the last called middleware:
151
     *    - when the middleware pipeline reached its end (typically when the Status Code is still 102)
152
     *    - when one item of the middleware pipeline returns with return response (status code is set to 200|40*|500)
153
     *    - when during the pipeline process an Exception is thrown.
154
     *
155
     * When the middleware pipeline is finished the application prints the header and the output.
156
     *
157
     * If a middleware other than the Routing, Dispatcher and Final Middleware has no priority set, it will be
158
     * considered to have priority = 50.
159
     *
160
     * @return void
161
     */
162 4
    public function run()
163
    {
164
        // Start session.
165 4
        $this->initSession();
166
        // Inject parameters into services.
167 4
        $this->prepareContainer();
168
169
        /** @var HttpAdapterInterface $httpAdapter */
170 4
        $httpAdapter = $this->getContainer()->get(HttpAdapterInterface::class);
171
        /** @var ServerRequestInterface $request */
172 4
        $request = $httpAdapter->getRequest();
173
        /** @var ResponseInterface $response */
174 4
        $response = $httpAdapter->getResponse();
175 4
        $middlewareClass = $this->getPipelineManager()->start();
176
177
        while ($middlewareClass !== null
178 4
            && $response->getStatusCode() == ResponseInterface::STATUS_PROCESSING
179 4
        ) {
180
            try {
181
                /** @var MiddlewareInterface $middleware */
182 4
                $middleware = $this->getContainer()->get($middlewareClass);
183 4
                $requestAttributes = $request->getAttributes();
184
185
                // As an extra step if the action middleware is resolved, it is invoked right before the dispatcher.
186
                // Only the container knows how to instantiate it in the right way, and the container must not be
187
                // injected into other classes. It seems like a hack but it is by purpose.
188
                if ($middleware instanceof DispatcherMiddleware
189 4
                    && isset($requestAttributes[ServerRequestInterface::REQUEST_ATTR_RESOLVED_ACTION_CLASS])
190 4
                ) {
191
                    /** @var MiddlewareInterface $actionMiddleware */
192 2
                    $actionMiddleware = $this->getContainer()
193 2
                        ->get($requestAttributes[ServerRequestInterface::REQUEST_ATTR_RESOLVED_ACTION_CLASS]);
194 2
                    $request = $request->withAttribute(
195 2
                        ServerRequestInterface::REQUEST_ATTR_ACTION_MIDDLEWARE,
196
                        $actionMiddleware
197 2
                    );
198 2
                }
199 4
                $response = $middleware($request, $response);
200 4
            } catch (\Exception $exception) {
201 1
                $response = $response->withStatus(ResponseInterface::STATUS_INTERNAL_SERVER_ERROR);
202 1
                $request = $request->withAttribute(
203 1
                    ServerRequestInterface::REQUEST_ATTR_MIDDLEWARE_EXCEPTION,
204
                    $exception
205 1
                );
206
            }
207
208 4
            $middlewareClass = $this->getPipelineManager()->next();
209 4
        };
210
211
        // If there was no error, we mark as ready for output.
212 4
        if ($response->getStatusCode() == ResponseInterface::STATUS_PROCESSING) {
213 1
            $response = $response->withStatus(ResponseInterface::STATUS_OK);
214 1
        }
215
216
        /** @var FinalMiddleware $finalMiddleware */
217 4
        $finalMiddleware = $this->getContainer()->get(FinalMiddleware::class);
218
219
        // Send out headers and content.
220 4
        $finalMiddleware($request, $response);
221 4
    }
222
}
223