Completed
Push — master ( 1fb75b...494ce5 )
by Jakob
04:50
created

Server::queryService()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 26
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 9
nc 4
nop 2
1
<?php declare(strict_types = 1);
2
3
namespace JSKOS;
4
5
use Psr\Http\Message\RequestInterface;
6
use Psr\Http\Message\ResponseInterface;
7
use Http\Message\ResponseFactory;
8
use Http\Discovery\MessageFactoryDiscovery;
9
use Psr\Log\LoggerInterface;
10
use Psr\Log\NullLogger;
11
12
/**
13
 * A JSKOS Server.
14
 */
15
class Server implements \Psr\Log\LoggerAwareInterface
16
{
17
    protected $service;
18
    protected $responseFactory;
19
    protected $logger;
20
21
    public function __construct(
22
        Service $service, 
23
        ResponseFactory $responseFactory=null,
24
        LoggerInterface $logger=null 
25
    )
26
    {
27
        $this->service = $service;
28
        $this->responseFactory = $responseFactory ?: MessageFactoryDiscovery::find();
29
        $this->logger = $logger ?: new NullLogger();
30
    }
31
32
    public function setLogger(LoggerInterface $logger)
33
    {
34
        $this->logger = $logger;
35
    }
36
37
    public function queryService(array $query, string $path=''): ResponseInterface 
38
    {
39
        if (preg_match('/^[$A-Z_][0-9A-Z_$.]*$/i', $query['callback'] ?? '')) {
40
            $callback = $query['callback'];
41
            unset($query['callback']);
42
        }
43
44
        # TODO: detect conflicting parameters?
45
        # if (isset($params['uri']) and isset($params['search'])) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
80% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
46
        #   $error = new Error(422, 'request_error', 'Conflicting request parameters uri & search');
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
47
        # }
48
49
        try {
50
            $result = $this->service->query($query, $path);
51
            // TODO
52
        } catch(Error $error) {
53
            $result = $error;
54
        }
55
56
        # TODO: catch other kinds of errors:
57
        # } catch (\Exception $e) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
58
        # $this->logger->error('Service Exception', ['exception' => $e]);
0 ignored issues
show
Unused Code Comprehensibility introduced by
69% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
59
        # $error = new Error(500, 'Internal server error');
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
60
61
        return $this->buildResponse($result, 'GET', $callback ?? null);
62
    }
63
64
    public function query(RequestInterface $request): ResponseInterface
65
    {    
66
        $method = $request->getMethod();
67
68
        if ($method == 'OPTIONS') {            
69
            return $this->optionsResponse();
70
        } elseif ($method != 'GET' && $method != 'HEAD') {
71
            return $this->buildResponse(new Error(405, 'Method not allowed'));
72
        }
73
74
        $uri = $request->getUri();
75
        $path = $uri->getPath();        
76
        $query = [];
77
        parse_str($uri->getQuery(), $query);
78
79
        # TODO: get language parameter from headers
80
81
        return $this->queryService($query, $path);
0 ignored issues
show
Bug introduced by
It seems like $query can also be of type null; however, JSKOS\Server::queryService() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
82
    }
83
84
    protected function buildResponse($result, $method='GET', $callback=null): ResponseInterface
85
    {
86
        $body = $result->json();
87
88
        $headers = [
89
            'Access-Control-Allow-Origin' => '*',
90
            'Content-Type' => 'application/json; charset=UTF-8',
91
            'Content-Length' => strlen($body),
92
        ];
93
94
        if ($method == 'HEAD') {
95
            $body = '';
96
        }
97
98
        if ($callback) {
99
            $body = "/**/$callback($body);";
100
            $headers['Content-Type'] = 'application/javascript; charset=UTF-8';
101
        }
102
103
        if ($result instanceof Result) {
104
            $headers['X-Total-Count'] = $result->getTotalCount();
105
            $code = '200';
106
        } else {
107
            $code = $result->code;
108
        }
109
 
110
        return $this->responseFactory->createResponse($code, null, $headers, $body);
111
    }
112
113
    public function optionsResponse(): ResponseInterface
114
    {
115
        $headers = [
116
            'Access-Control-Allow-Methods' => 'GET, HEAD, OPTIONS',
117
        ];
118
119
        # TODO:
120
        # if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']) &&
0 ignored issues
show
Unused Code Comprehensibility introduced by
77% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
121
        #    $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] == 'GET') {
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
122
        #    $response->headers['Access-Control-Allow-Origin'] = '*';
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
123
        #    $response->headers['Acess-Control-Expose-Headers'] = 'Link, X-Total-Count';
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
124
125
        return $this->responseFactory->createResponse(200, null, $headers, '');
126
    }
127
128
    /**
129
     * TODO: Extract requested languages(s) from request.
130
    public function extractRequestLanguage($params)
131
    {
132
        $language = null;
133
134
        # get query modifier: language
135
        if (isset($params['language'])) {
136
            $language = $params['language'];
137
            unset($params['language']);
138
            # TODO: parse language
139
        } elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
140
            # parse accept-language-header
141
            preg_match_all(
142
                '/([a-z]+(?:-[a-z]+)?)\s*(?:;\s*q\s*=\s*(1|0?\.[0-9]+))?/i',
143
                $_SERVER['HTTP_ACCEPT_LANGUAGE'],
144
                $match);
145
            if (count($match[1])) {
146
                foreach ($match[1] as $i => $l) {
147
                    if (isset($match[2][$i]) && $match[2][$i] != '') {
148
                        $langs[strtolower($l)] = (float) $match[2][$i];
149
                    } else {
150
                        $langs[strtolower($l)] = 1;
151
                    }
152
                }
153
                arsort($langs, SORT_NUMERIC);
154
                reset($langs);
155
                $language = key($langs); # most wanted language
156
            }
157
        }
158
        
159
        return $language;
160
    }
161
*/
162
163
	/**
164
	 * Utility function to emit a Response without additional framework.
165
	 */
166
    public static function sendResponse(ResponseInterface $response) 
167
    {
168
		$code = $response->getStatusCode();
169
		$reason = $response->getReasonPhrase();
170
		header(
171
			sprintf('HTTP/%s %s %s', $response->getProtocolVersion(), $code, $reason),
172
			true, $code 
173
		);
174
175
		foreach ($response->getHeaders() as $header => $values) {
176
			foreach ($values as $value) {
177
				header("$header: $value", false);
178
			}
179
		}
180
181
		echo $response->getBody();
182
	}
183
}
184