Server::queryService()   B
last analyzed

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
        $context = Resource::DEFAULT_CONTEXT;
88
89
        $headers = [
90
            'Access-Control-Allow-Origin' => '*',
91
            'Content-Type' => 'application/json; charset=UTF-8',
92
            'Content-Length' => strlen($body),
93
            'Link' => "<$context>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\""
94
        ];
95
96
        if ($method == 'HEAD') {
97
            $body = '';
98
        }
99
100
        if ($callback) {
101
            $body = "/**/$callback($body);";
102
            $headers['Content-Type'] = 'application/javascript; charset=UTF-8';
103
        }
104
105
        if ($result instanceof Result) {
106
            $headers['X-Total-Count'] = $result->getTotalCount();
107
            $code = '200';
108
        } else {
109
            $code = $result->code;
110
        }
111
 
112
        return $this->responseFactory->createResponse($code, null, $headers, $body);
113
    }
114
115
    public function optionsResponse(): ResponseInterface
116
    {
117
        $headers = [
118
            'Access-Control-Allow-Methods' => 'GET, HEAD, OPTIONS',
119
        ];
120
121
        # TODO:
122
        # 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...
123
        #    $_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...
124
        #    $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...
125
        #    $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...
126
127
        return $this->responseFactory->createResponse(200, null, $headers, '');
128
    }
129
130
    /**
131
     * TODO: Extract requested languages(s) from request.
132
    public function extractRequestLanguage($params)
133
    {
134
        $language = null;
135
136
        # get query modifier: language
137
        if (isset($params['language'])) {
138
            $language = $params['language'];
139
            unset($params['language']);
140
            # TODO: parse language
141
        } elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
142
            # parse accept-language-header
143
            preg_match_all(
144
                '/([a-z]+(?:-[a-z]+)?)\s*(?:;\s*q\s*=\s*(1|0?\.[0-9]+))?/i',
145
                $_SERVER['HTTP_ACCEPT_LANGUAGE'],
146
                $match);
147
            if (count($match[1])) {
148
                foreach ($match[1] as $i => $l) {
149
                    if (isset($match[2][$i]) && $match[2][$i] != '') {
150
                        $langs[strtolower($l)] = (float) $match[2][$i];
151
                    } else {
152
                        $langs[strtolower($l)] = 1;
153
                    }
154
                }
155
                arsort($langs, SORT_NUMERIC);
156
                reset($langs);
157
                $language = key($langs); # most wanted language
158
            }
159
        }
160
        
161
        return $language;
162
    }
163
*/
164
165
	/**
166
	 * Utility function to emit a Response without additional framework.
167
	 */
168
    public static function sendResponse(ResponseInterface $response) 
169
    {
170
		$code = $response->getStatusCode();
171
		$reason = $response->getReasonPhrase();
172
		header(
173
			sprintf('HTTP/%s %s %s', $response->getProtocolVersion(), $code, $reason),
174
			true, $code 
175
		);
176
177
		foreach ($response->getHeaders() as $header => $values) {
178
			foreach ($values as $value) {
179
				header("$header: $value", false);
180
			}
181
		}
182
183
		echo $response->getBody();
184
	}
185
}
186