Completed
Push — master ( 0daf08...486f11 )
by Tim
9s
created

FlatServletEngine::process()   C

Complexity

Conditions 7
Paths 9

Size

Total Lines 89
Code Lines 45

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 89
rs 6.5134
cc 7
eloc 45
nc 9
nop 4

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
/**
4
 * AppserverIo\SingleApp\ServletEngine\SimpleServletEngine
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Tim Wagner <[email protected]>
15
 * @copyright 2015 TechDivision GmbH <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/appserver-io/single-app
18
 * @link      http://www.appserver.io
19
 */
20
21
namespace AppserverIo\SingleApp\ServletEngine;
22
23
use AppserverIo\Http\HttpResponseStates;
24
use AppserverIo\Server\Dictionaries\ServerVars;
25
use AppserverIo\Server\Dictionaries\ModuleHooks;
26
use AppserverIo\Server\Exceptions\ModuleException;
27
use AppserverIo\Psr\HttpMessage\Protocol;
28
use AppserverIo\Psr\HttpMessage\RequestInterface;
29
use AppserverIo\Psr\HttpMessage\ResponseInterface;
30
use AppserverIo\Server\Interfaces\RequestContextInterface;
31
use AppserverIo\Appserver\ServletEngine\Http\Request;
32
use AppserverIo\Appserver\ServletEngine\Http\Response;
33
use AppserverIo\Appserver\ServletEngine\ServletEngine;
34
use AppserverIo\Appserver\ServletEngine\RequestHandler;
35
use AppserverIo\Appserver\ServletEngine\BadRequestException;
36
use AppserverIo\Appserver\ServletEngine\SessionManagerInterface;
37
use AppserverIo\Appserver\ServletEngine\Security\AuthenticationManagerInterface;
38
39
/**
40
 * A servlet engine implementation to handle a single app container.
41
 *
42
 * @author    Tim Wagner <[email protected]>
43
 * @copyright 2015 TechDivision GmbH <[email protected]>
44
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
45
 * @link      https://github.com/appserver-io/single-app
46
 * @link      http://www.appserver.io
47
 */
48
class FlatServletEngine extends ServletEngine
49
{
50
51
    /**
52
     * Simply returns the first application, assuming we only have one. If no application
53
     * has been deployed, an exception will be thrown.
54
     *
55
     * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext Context of the current request
56
     *
57
     * @return null|\AppserverIo\Psr\Application\ApplicationInterface
58
     * @throws \AppserverIo\Appserver\ServletEngine\BadRequestException Is thrown if no application is available
59
     */
60 View Code Duplication
    protected function findRequestedApplication(RequestContextInterface $requestContext)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
61
    {
62
63
        // return the first application (we only have one)
64
        foreach ($this->applications as $application) {
65
            return $application;
66
        }
67
68
        // if we did not find anything we should throw a bad request exception
69
        throw new BadRequestException(
70
            sprintf(
71
                'Can\'t find application for URL %s%s',
72
                $requestContext->getServerVar(ServerVars::HTTP_HOST),
73
                $requestContext->getServerVar(ServerVars::X_REQUEST_URI)
74
            ),
75
            404
76
        );
77
    }
78
79
    /**
80
     * Process servlet request.
81
     *
82
     * @param \AppserverIo\Psr\HttpMessage\RequestInterface          $request        A request object
83
     * @param \AppserverIo\Psr\HttpMessage\ResponseInterface         $response       A response object
84
     * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext A requests context instance
85
     * @param integer                                                $hook           The current hook to process logic for
86
     *
87
     * @return boolean
88
     *
89
     * @throws \AppserverIo\Server\Exceptions\ModuleException
90
     */
91
    public function process(
92
        RequestInterface $request,
93
        ResponseInterface $response,
94
        RequestContextInterface $requestContext,
95
        $hook
96
    ) {
97
98
        // if false hook is coming do nothing
99
        if (ModuleHooks::REQUEST_POST !== $hook) {
100
            return;
101
        }
102
103
        // check if we are the handler that has to process this request
104
        if ($requestContext->getServerVar(ServerVars::SERVER_HANDLER) !== $this->getModuleName()) {
105
            return;
106
        }
107
108
        // load the application associated with this request
109
        $application = $this->findRequestedApplication($requestContext);
110
        $application->registerClassLoaders();
111
112
        // check if the application has already been connected
113
        if ($application->isConnected() === false) {
0 ignored issues
show
Bug introduced by
The method isConnected() does not exist on AppserverIo\Psr\Application\ApplicationInterface. Did you maybe mean connect()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
114
            throw new \Exception(sprintf('Application %s has not connected yet', $application->getName()), 503);
115
        }
116
117
        // create a copy of the valve instances
118
        $valves = $this->valves;
119
        $handlers = $this->handlers;
120
121
        // create a new request instance from the HTTP request
122
        $servletRequest = new Request();
123
        $servletRequest->injectHandlers($handlers);
124
        $servletRequest->injectHttpRequest($request);
125
        $servletRequest->injectServerVars($requestContext->getServerVars());
126
        $servletRequest->init();
0 ignored issues
show
Bug introduced by
The method init() does not seem to exist on object<AppserverIo\Appse...letEngine\Http\Request>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
127
128
        // initialize servlet response
129
        $servletResponse = new Response();
130
        $servletResponse->init();
131
132
        // load the session and the authentication manager
133
        $sessionManager = $application->search(SessionManagerInterface::IDENTIFIER);
134
        $authenticationManager = $application->search(AuthenticationManagerInterface::IDENTIFIER);
135
136
        // inject the sapplication and servlet response
137
        $servletRequest->injectContext($application);
0 ignored issues
show
Documentation introduced by
$application is of type null|object<AppserverIo\...n\ApplicationInterface>, but the function expects a object<AppserverIo\Psr\Context\ContextInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
138
        $servletRequest->injectResponse($servletResponse);
139
        $servletRequest->injectSessionManager($sessionManager);
0 ignored issues
show
Bug introduced by
The method injectSessionManager() does not seem to exist on object<AppserverIo\Appse...letEngine\Http\Request>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
140
        $servletRequest->injectAuthenticationManager($authenticationManager);
0 ignored issues
show
Bug introduced by
The method injectAuthenticationManager() does not seem to exist on object<AppserverIo\Appse...letEngine\Http\Request>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
141
142
        // prepare the request instance
143
        $servletRequest->prepare();
144
145
        // initialize static request and application context
146
        RequestHandler::$requestContext = $servletRequest;
147
        RequestHandler::$applicationContext = $application;
148
149
        // process the valves
150
        foreach ($valves as $valve) {
151
            $valve->invoke($servletRequest, $servletResponse);
152
            if ($servletRequest->isDispatched() === true) {
153
                break;
154
            }
155
        }
156
157
        // copy response values to the HTTP response
158
        $response->setState($servletResponse->getState());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface AppserverIo\Psr\HttpMessage\ResponseInterface as the method setState() does only exist in the following implementations of said interface: AppserverIo\Appserver\ServletEngine\Http\Response, AppserverIo\Http\HttpResponse.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
159
        $response->setVersion($servletResponse->getVersion());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface AppserverIo\Psr\HttpMessage\ResponseInterface as the method setVersion() does only exist in the following implementations of said interface: AppserverIo\Http\HttpResponse.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
160
        $response->setStatusCode($servletResponse->getStatusCode());
161
        $response->setStatusReasonPhrase($servletResponse->getStatusReasonPhrase());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface AppserverIo\Psr\HttpMessage\ResponseInterface as the method setStatusReasonPhrase() does only exist in the following implementations of said interface: AppserverIo\Appserver\ServletEngine\Http\Response, AppserverIo\Http\HttpResponse.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
162
163
        // copy the body content to the HTTP response
164
        $response->appendBodyStream($servletResponse->getBodyStream());
165
166
        // copy headers to the HTTP response
167
        foreach ($servletResponse->getHeaders() as $headerName => $headerValue) {
168
            $response->addHeader($headerName, $headerValue);
169
        }
170
171
        // copy cookies to the HTTP response
172
        $response->setCookies($servletResponse->getCookies());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface AppserverIo\Psr\HttpMessage\ResponseInterface as the method setCookies() does only exist in the following implementations of said interface: AppserverIo\Http\HttpResponse.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
173
174
        // append the servlet engine's signature
175
        $response->addHeader(Protocol::HEADER_X_POWERED_BY, get_class($this), true);
0 ignored issues
show
Unused Code introduced by
The call to ResponseInterface::addHeader() has too many arguments starting with true.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
176
177
        // set response state to be dispatched after this without calling other modules process
178
        $response->setState(HttpResponseStates::DISPATCH);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface AppserverIo\Psr\HttpMessage\ResponseInterface as the method setState() does only exist in the following implementations of said interface: AppserverIo\Appserver\ServletEngine\Http\Response, AppserverIo\Http\HttpResponse.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
179
    }
180
}
181