• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tochka-developers / jsonrpc / 4135501466

pending completion
4135501466

push

github

darkdarin
Merge remote-tracking branch 'origin/v5.0'

209 of 813 new or added lines in 51 files covered. (25.71%)

233 of 1307 relevant lines covered (17.83%)

1.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.45
/src/Middleware/LogMiddleware.php
1
<?php
2

3
namespace Tochka\JsonRpc\Middleware;
4

5
use Illuminate\Support\Facades\Log;
6
use Tochka\JsonRpc\Contracts\AuthInterface;
7
use Tochka\JsonRpc\Contracts\JsonRpcRequestMiddlewareInterface;
8
use Tochka\JsonRpc\DTO\JsonRpcServerRequest;
9
use Tochka\JsonRpc\Standard\DTO\JsonRpcResponse;
10
use Tochka\JsonRpc\Standard\Exceptions\JsonRpcException;
11

12
/**
13
 * @psalm-api
14
 */
15
class LogMiddleware implements JsonRpcRequestMiddlewareInterface
16
{
17
    private string $channel;
18
    /** @var array<string, array<string>> */
19
    private array $hideParams;
20
    private bool $logResponse;
21
    private AuthInterface $auth;
22
    private array $additionalContext = [];
23

24
    /**
25
     * @param array<string, array<string>> $hideParams
26
     */
27
    public function __construct(
28
        AuthInterface $auth,
29
        string $channel = 'default',
30
        array $hideParams = [],
31
        bool $logResponse = false
32
    ) {
33
        $this->channel = $channel;
24✔
34
        $this->hideParams = $hideParams;
24✔
35
        $this->auth = $auth;
24✔
36
        $this->logResponse = $logResponse;
24✔
37
    }
38

39
    public function appendAdditionalContext(array $context): void
40
    {
41
        $this->additionalContext = array_merge($this->additionalContext, $context);
3✔
42
    }
43

44
    public function handleJsonRpcRequest(JsonRpcServerRequest $request, callable $next): JsonRpcResponse
45
    {
46
        $logContext = $this->additionalContext;
24✔
47

48
        $logContext['service'] = $this->auth->getClient()->getName();
24✔
49

50
        $route = $request->getRoute();
24✔
51
        $logRequest = $request->getJsonRpcRequest()->toArray();
24✔
52

53
        if ($route !== null) {
24✔
54
            if ($route->group !== null) {
21✔
55
                $logContext['group'] = $route->group;
3✔
56
            }
57
            if ($route->action !== null) {
21✔
58
                $logContext['action'] = $route->action;
3✔
59
            }
60
            $logContext['method'] = $route->jsonRpcMethodName;
21✔
61
            $logContext['call'] = ($route->controllerClass ?? '<NoController>') . '::' . ($route->controllerMethod ?? '<NoMethod>');
21✔
62

63

64
            $globalRules = $this->hideParams['*'] ?? [];
21✔
65
            if ($route->controllerClass !== null) {
21✔
66
                $controllerRules = $this->hideParams[$route->controllerClass] ?? [];
6✔
67
                if ($route->controllerMethod !== null) {
6✔
68
                    $methodRules = $this->hideParams[$route->controllerClass . '@' . $route->controllerMethod] ?? [];
6✔
69
                } else {
70
                    $methodRules = [];
6✔
71
                }
72
            } else {
73
                $controllerRules = [];
15✔
74
                $methodRules = [];
15✔
75
            }
76

77
            $rules = array_merge($globalRules, $controllerRules, $methodRules);
21✔
78
            $logRequest['params'] = $this->hidePrivateData(
21✔
79
                $request->getJsonRpcRequest()->params ?? [],
21✔
80
                $rules
21✔
81
            );
21✔
82
        }
83

84
        $logContext['request'] = $logRequest;
24✔
85

86
        Log::channel($this->channel)->info('New request', $logContext);
24✔
87

88
        try {
89
            $result = $next($request);
24✔
90

91
            if ($result->error !== null) {
21✔
92
                Log::channel($this->channel)
3✔
93
                    ->error('Error request', $logContext + ['error' => $result->error->toArray()]);
3✔
94
            } elseif ($this->logResponse) {
18✔
95
                Log::channel($this->channel)
3✔
96
                    ->info('Successful request', $logContext + ['result' => $result->result]);
3✔
97
            }
98

99
            return $result;
21✔
100
        } catch (JsonRpcException $e) {
3✔
101
            Log::channel($this->channel)
3✔
102
                ->error('Error request', $logContext + ['error' => $e->getJsonRpcError()->toArray()]);
3✔
103

104
            throw $e;
3✔
105
        }
106
    }
107

108
    /**
109
     * @param array|object|null $data
110
     * @param array<string> $rules
111
     * @return array<string, mixed>
112
     */
113
    private function hidePrivateData(array|object|null $data, array $rules): array
114
    {
115
        if ($data === null) {
21✔
NEW
116
            return [];
×
117
        }
118

119
        if (is_object($data)) {
21✔
120
            $data = (array)$data;
3✔
121
        }
122

123
        /** @var array<string, mixed> $data */
124

125
        foreach ($rules as $rule) {
21✔
126
            $rule = explode('.', $rule);
3✔
127

128
            /** @var array<string, mixed> $data */
129
            $data = $this->hideDataByRule($data, $rule);
3✔
130
        }
131

132
        return $data;
21✔
133
    }
134

135
    /**
136
     * @param mixed $data
137
     * @param array<string> $rule
138
     * @return mixed
139
     */
140
    private function hideDataByRule(mixed $data, array $rule): mixed
141
    {
142
        if (is_object($data)) {
3✔
NEW
143
            $data = (array)$data;
×
144
        }
145

146
        if (!is_array($data)) {
3✔
NEW
147
            return $data;
×
148
        }
149

150
        /** @var array<string, mixed> $data */
151

152
        $field = array_shift($rule);
3✔
153

154
        $resultedData = $data;
3✔
155

156
        //dump($data);
157

158
        if ($field === '*') {
3✔
159
            /** @psalm-suppress MixedAssignment */
160
            foreach ($data as $key => $value) {
3✔
161
                /** @psalm-suppress MixedAssignment */
162
                $resultedData[$key] = $this->hideDataByRule($value, $rule);
3✔
163
            }
164
        } elseif (isset($data[$field])) {
3✔
165
            if (count($rule)) {
3✔
166
                /** @psalm-suppress MixedAssignment */
167
                $resultedData[$field] = $this->hideDataByRule($data[$field], $rule);
3✔
168
            } else {
169
                $resultedData[$field] = '<hide>';
3✔
170
            }
171
        } else {
172
            return $data;
3✔
173
        }
174

175
        return $resultedData;
3✔
176
    }
177
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc