Completed
Pull Request — 1.x (#328)
by Akihito
14:40 queued 04:38
created

CliRouter::parseServer()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 0
cts 0
cp 0
rs 9.6666
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BEAR\Package\Provide\Router;
6
7
use Aura\Cli\CliFactory;
8
use Aura\Cli\Context\OptionFactory;
9
use Aura\Cli\Status;
10
use Aura\Cli\Stdio;
11
use BEAR\Package\Annotation\StdIn;
12
use BEAR\Sunday\Extension\Router\RouterInterface;
13
use Ray\Di\Di\Inject;
14
use Ray\Di\Di\Named;
15
16
class CliRouter implements RouterInterface
17
{
18
    /**
19
     * @var RouterInterface
20
     */
21
    private $router;
22
23
    /**
24
     * @var Stdio
25
     */
26
    private $stdIo;
27
28
    /**
29
     * @var string
30
     */
31
    private $stdIn = '';
32
33
    /**
34
     * @var null|\Exception
35
     */
36
    private $terminateException;
37
38
    /**
39
     * @Named("original")
40
     */
41 15
    public function __construct(RouterInterface $router, Stdio $stdIo = null)
42
    {
43 15
        $this->router = $router;
44 15
        $this->stdIo = $stdIo ?: (new CliFactory)->newStdio();
45 15
    }
46
47
    /**
48
     * {@inheritdoc}
49
     */
50 6
    public function __destruct()
51
    {
52 6
        file_exists($this->stdIn) && unlink($this->stdIn);
53 6
    }
54
55 2
    public function __wakeup()
56
    {
57 2
        $this->stdIo = (new CliFactory)->newStdio();
58 2
    }
59
60 2
    public function setTerminateException(\Exception $e) : void
61
    {
62 2
        $this->terminateException = $e;
63 2
    }
64
65
    /**
66
     * @Inject
67
     * @StdIn
68
     */
69 15
    public function setStdIn(string $stdIn) : void
70
    {
71 15
        $this->stdIn = $stdIn;
72 15
    }
73
74
    /**
75
     * {@inheritdoc}
76
     */
77 8
    public function match(array $globals, array $server)
78
    {
79 8
        assert(isset($server['argc']) && is_int($server['argc']));
80 6
        assert(isset($server['argv']));
81 6
        $argc = $server['argc'];
82
        /** @var array<int, string> $argv */
83 6
        $argv = $server['argv'];
84
        $this->validateArgs($argc, $argv);
0 ignored issues
show
Documentation introduced by
$argv is of type integer, but the function expects a array.

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...
85
        [$method, $query, $server] = $this->parseServer($server);
0 ignored issues
show
Bug introduced by
The variable $method does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $query does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
86
        [$globals, $server] = $this->addQuery($method, $query, $globals, $server);
87
88
        return $this->router->match($globals, $server);
89 1
    }
90
91 1
    /**
92
     * {@inheritdoc}
93
     */
94
    public function generate($name, $data)
95
    {
96
        return $this->router->generate($name, $data);
97 6
    }
98
99 6
    /**
100 1
     * Set user input query to $globals or &$server
101
     *
102 1
     * @param array<string, array|string>                                                  $query
103
     * @param array{_GET: array<string, string|array>, _POST: array<string, string|array>} $globals
104 5
     * @param array<string, mixed>                                                         $server
105 1
     *
106
     * @return array{0: array{_GET: array<string, string|array>, _POST: array<string, string|array>}, 1: array<string, mixed>}
0 ignored issues
show
Documentation introduced by
The doc-type array{0: could not be parsed: Unknown type name "array{0:" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
107 1
     */
108
    private function addQuery(string $method, array $query, array $globals, array $server) : array
109 4
    {
110 4
        if ($method === 'get') {
111
            $globals['_GET'] = $query;
112 2
113
            return [$globals, $server];
114 2
        }
115 2
        if ($method === 'post') {
116 2
            $globals['_POST'] = $query;
117
118
            return [$globals, $server];
119
        }
120
        $server = $this->getStdIn($method, $query, $server);
121 2
122
        return [$globals, $server];
123 2
    }
124 2
125
    private function error(string $command) : void
126
    {
127
        $help = new CliRouterHelp(new OptionFactory);
128
        $this->stdIo->outln($help->getHelp($command));
129
    }
130
131
    /**
132
     * @SuppressWarnings(PHPMD)
133
     */
134 4
    private function terminate(int $status) : void
135
    {
136 4
        if ($this->terminateException instanceof \Exception) {
137 3
            throw $this->terminateException;
138 3
        }
139
        // @codeCoverageIgnoreStart
140 3
        exit($status);
141
        // @codeCoverageIgnoreEnd
142
    }
143 1
144
    /**
145
     * Return StdIn in PUT, PATCH or DELETE
146 8
     *
147
     * @param array<string, mixed> $query
148 8
     * @param array<string, mixed> $server
149 2
     *
150 2
     * @return array<string, mixed>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
151
     */
152 6
    private function getStdIn(string $method, array $query, array $server) : array
153
    {
154
        if ($method === 'put' || $method === 'patch' || $method === 'delete') {
155
            $server[HttpMethodParams::CONTENT_TYPE] = HttpMethodParams::FORM_URL_ENCODE;
156
            file_put_contents($this->stdIn, http_build_query($query));
157 6
158
            return $server;
159 6
        }
160 6
161 6
        return $server;
162 6
    }
163 5
164
    /**
165
     * @param array<int, string> $argv
166 6
     */
167 6
    private function validateArgs(int $argc, array $argv) : void
168
    {
169
        if ($argc < 3) {
170 6
            $this->error(basename($argv[0]));
171
            $this->terminate(Status::USAGE);
172
        }
173
    }
174
175
    /**
176
     * Return $method, $query, $server from $server
177
     *
178
     * @return array{0: string, 1: array<string, string|array>, 2: array{REQUEST_METHOD: string, REQUEST_URI: string}}
0 ignored issues
show
Documentation introduced by
The doc-type array{0: could not be parsed: Unknown type name "array{0:" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
179
     */
180
    private function parseServer(array $server) : array
181
    {
182
        /** @var array{argv: array<string>} $server */
183
        [, $method, $uri] = $server['argv'];
0 ignored issues
show
Bug introduced by
The variable $method does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $uri does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
184
        $urlQuery = parse_url($uri, PHP_URL_QUERY);
185
        $urlPath = (string) parse_url($uri, PHP_URL_PATH);
186
        $query = [];
187
        if ($urlQuery) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $urlQuery of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
188
            parse_str($urlQuery, $query);
189
        }
190
        $server = [
191
            'REQUEST_METHOD' => strtoupper($method),
192
            'REQUEST_URI' => $urlPath
193
        ];
194
195
        /** @var array<string, array|string> $query */
196
        return [$method, $query, $server];
197
    }
198
}
199