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 Exception; |
||||
14 | use Ray\Di\Di\Named; |
||||
15 | use Throwable; |
||||
16 | |||||
17 | use function basename; |
||||
18 | use function file_exists; |
||||
19 | use function file_put_contents; |
||||
20 | use function http_build_query; |
||||
21 | use function parse_str; |
||||
22 | use function parse_url; |
||||
23 | use function strtoupper; |
||||
24 | use function unlink; |
||||
25 | |||||
26 | use const PHP_URL_PATH; |
||||
27 | use const PHP_URL_QUERY; |
||||
28 | |||||
29 | /** |
||||
30 | * @psalm-import-type Globals from RouterInterface |
||||
31 | * @psalm-import-type Server from RouterInterface |
||||
32 | * @psalm-type CliServer = array{ |
||||
33 | * argc: int, |
||||
34 | * argv: array<int, string>, |
||||
35 | * REQUEST_URI: string, |
||||
36 | * REQUEST_METHOD: string, |
||||
37 | * CONTENT_TYPE?: string, |
||||
38 | * HTTP_CONTENT_TYPE?: string, |
||||
39 | * HTTP_RAW_POST_DATA?: string |
||||
40 | * } |
||||
41 | 15 | */ |
|||
42 | class CliRouter implements RouterInterface |
||||
43 | 15 | { |
|||
44 | 15 | private Stdio $stdIo; |
|||
45 | 15 | private Throwable|null $terminateException = null; |
|||
46 | |||||
47 | public function __construct( |
||||
48 | #[Named('original')] |
||||
49 | private RouterInterface $router, |
||||
50 | 6 | Stdio|null $stdIo = null, |
|||
51 | #[StdIn] |
||||
52 | 6 | private string $stdIn = '', |
|||
53 | 6 | ) { |
|||
54 | $this->stdIo = $stdIo ?: (new CliFactory())->newStdio(); |
||||
55 | 2 | } |
|||
56 | |||||
57 | 2 | public function __destruct() |
|||
58 | 2 | { |
|||
59 | file_exists($this->stdIn) && unlink($this->stdIn); |
||||
60 | 2 | } |
|||
61 | |||||
62 | 2 | public function __wakeup(): void |
|||
63 | 2 | { |
|||
64 | $this->stdIo = (new CliFactory())->newStdio(); |
||||
65 | } |
||||
66 | |||||
67 | public function setTerminateException(Throwable $e): void |
||||
68 | { |
||||
69 | 15 | $this->terminateException = $e; |
|||
70 | } |
||||
71 | 15 | ||||
72 | 15 | /** |
|||
73 | * @psalm-api |
||||
74 | * @deprecated Use constructor injection |
||||
75 | * @codeCoverageIgnore |
||||
76 | */ |
||||
77 | 8 | public function setStdIn( |
|||
78 | string $stdIn, |
||||
79 | 8 | ): void { |
|||
80 | 6 | $this->stdIn = $stdIn; |
|||
81 | 6 | } |
|||
82 | |||||
83 | 6 | /** |
|||
84 | * {@inheritDoc} |
||||
85 | * |
||||
86 | * @param Globals $globals |
||||
0 ignored issues
–
show
|
|||||
87 | * @param Server $server |
||||
0 ignored issues
–
show
The type
BEAR\Package\Provide\Router\Server was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||
88 | */ |
||||
89 | 1 | public function match(array $globals, array $server) |
|||
90 | { |
||||
91 | 1 | /** @var CliServer $server */ |
|||
92 | $this->validateArgs($server['argc'], $server['argv']); |
||||
93 | // covert console $_SERVER to web $_SERVER $GLOBALS |
||||
94 | /** @psalm-suppress InvalidArgument */ |
||||
95 | [$method, $query, $server] = $this->parseServer($server); |
||||
0 ignored issues
–
show
$server of type BEAR\Package\Provide\Router\CliServer is incompatible with the type array expected by parameter $server of BEAR\Package\Provide\Rou...liRouter::parseServer() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
96 | /** @psalm-suppress MixedArgumentTypeCoercion */ |
||||
97 | 6 | [$webGlobals, $webServer] = $this->addQuery($method, $query, $globals, $server); // @phpstan-ignore-line |
|||
98 | |||||
99 | 6 | return $this->router->match($webGlobals, $webServer); |
|||
100 | 1 | } |
|||
101 | |||||
102 | 1 | /** |
|||
103 | * {@inheritDoc} |
||||
104 | 5 | */ |
|||
105 | 1 | public function generate($name, $data) |
|||
106 | { |
||||
107 | 1 | return $this->router->generate($name, $data); |
|||
108 | } |
||||
109 | 4 | ||||
110 | 4 | /** |
|||
111 | * Set user input query to $globals or &$server |
||||
112 | 2 | * |
|||
113 | * @param array<string, array<string, mixed>> $query |
||||
114 | 2 | * @param Globals $globals |
|||
115 | 2 | * @param Server $server |
|||
116 | 2 | * |
|||
117 | * @return array{0:Globals, 1:Server} |
||||
118 | */ |
||||
119 | private function addQuery(string $method, array $query, array $globals, array $server): array |
||||
120 | { |
||||
121 | 2 | if ($method === 'get') { |
|||
122 | $globals['_GET'] = $query; |
||||
123 | 2 | ||||
124 | 2 | return [$globals, $server]; |
|||
125 | } |
||||
126 | |||||
127 | if ($method === 'post') { |
||||
128 | $globals['_POST'] = $query; |
||||
129 | |||||
130 | return [$globals, $server]; |
||||
131 | } |
||||
132 | |||||
133 | $server = $this->getStdIn($method, $query, $server); |
||||
134 | 4 | ||||
135 | return [$globals, $server]; |
||||
136 | 4 | } |
|||
137 | 3 | ||||
138 | 3 | private function error(string $command): void |
|||
139 | { |
||||
140 | 3 | $help = new CliRouterHelp(new OptionFactory()); |
|||
141 | $this->stdIo->outln($help->getHelp($command)); |
||||
142 | } |
||||
143 | 1 | ||||
144 | /** @SuppressWarnings(PHPMD) */ |
||||
145 | private function terminate(int $status): void |
||||
146 | 8 | { |
|||
147 | if ($this->terminateException instanceof Exception) { |
||||
148 | 8 | throw $this->terminateException; |
|||
149 | 2 | } |
|||
150 | 2 | ||||
151 | // @codeCoverageIgnoreStart |
||||
152 | 6 | exit($status); |
|||
0 ignored issues
–
show
|
|||||
153 | } |
||||
154 | |||||
155 | // @codeCoverageIgnoreEnd |
||||
156 | |||||
157 | 6 | /** |
|||
158 | * Return StdIn in PUT, PATCH or DELETE |
||||
159 | 6 | * |
|||
160 | 6 | * @param array<string, array<string, mixed>|string> $query |
|||
161 | 6 | * @param Server $server |
|||
162 | 6 | * |
|||
163 | 5 | * @return Server |
|||
164 | */ |
||||
165 | private function getStdIn(string $method, array $query, array $server): array |
||||
166 | 6 | { |
|||
167 | 6 | if ($method === 'put' || $method === 'patch' || $method === 'delete') { |
|||
168 | $server[HttpMethodParams::CONTENT_TYPE] = HttpMethodParams::FORM_URL_ENCODE; |
||||
169 | file_put_contents($this->stdIn, http_build_query($query)); |
||||
170 | 6 | ||||
171 | return $server; |
||||
0 ignored issues
–
show
|
|||||
172 | } |
||||
173 | |||||
174 | return $server; |
||||
0 ignored issues
–
show
|
|||||
175 | } |
||||
176 | |||||
177 | /** @param array<int, string> $argv */ |
||||
178 | private function validateArgs(int $argc, array $argv): void |
||||
179 | { |
||||
180 | if ($argc >= 3) { |
||||
181 | return; |
||||
182 | } |
||||
183 | |||||
184 | $this->error(basename($argv[0])); |
||||
185 | $this->terminate(Status::USAGE); |
||||
186 | // @codeCoverageIgnoreStart |
||||
187 | } |
||||
188 | |||||
189 | // @codeCoverageIgnoreEnd |
||||
190 | |||||
191 | /** |
||||
192 | * Return $method, $query, $server from $server |
||||
193 | * |
||||
194 | * @param Server $server |
||||
195 | * |
||||
196 | * @return array{string, array<string, mixed>, Server} |
||||
0 ignored issues
–
show
|
|||||
197 | */ |
||||
198 | private function parseServer(array $server): array |
||||
199 | { |
||||
200 | /** @var array{argv: array<string>} $server */ |
||||
201 | [, $method, $uri] = $server['argv']; |
||||
202 | $urlQuery = (string) parse_url($uri, PHP_URL_QUERY); |
||||
203 | $urlPath = (string) parse_url($uri, PHP_URL_PATH); |
||||
204 | $query = []; |
||||
205 | if ($urlQuery !== '') { |
||||
206 | parse_str($urlQuery, $query); |
||||
207 | } |
||||
208 | |||||
209 | $server = [ |
||||
210 | 'REQUEST_METHOD' => strtoupper($method), |
||||
211 | 'REQUEST_URI' => $urlPath, |
||||
212 | ]; |
||||
213 | |||||
214 | /** @var array<string, array<mixed>|string> $query */ |
||||
215 | return [$method, $query, $server]; |
||||
216 | } |
||||
217 | } |
||||
218 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths