Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
ContextBuilderService
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 6
56
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 buildFromException
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 buildFromManual
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 baseContext
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
2
 sanitize
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
 summarize
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Modules\SupportModule\Services;
4
5use Throwable;
6
7class ContextBuilderService
8{
9    protected IncidentContextResolver $resolver;
10
11    public function __construct()
12    {
13        $this->resolver = service('incidentContextResolver');
14    }
15
16    /**
17     * Construction payload depuis une exception
18     */
19    public function buildFromException(Throwable $e, array $context = []): array
20    {
21        return $this->baseContext($context) + [
22            'type'      => 'EXCEPTION',
23            'message'   => $e->getMessage(),
24            'exception' => get_class($e),
25            'severity'  => 'error',
26
27            'trace' => [
28                'file'  => $e->getFile(),
29                'line'  => $e->getLine(),
30                'stack' => $e->getTraceAsString(),
31            ],
32        ];
33    }
34
35    /**
36     * Incident manuel utilisateur
37     */
38    public function buildFromManual(array $payload): array
39    {
40        return $this->baseContext($payload) + [
41            'type'     => 'MANUAL',
42            'message'  => $payload['message'] ?? 'User reported issue',
43            'severity' => 'warning',
44        ];
45    }
46
47    /**
48     * Contexte commun
49     */
50    protected function baseContext(array $context = []): array
51    {
52        $request = service('request');
53        $ctx     = $this->resolver->resolve();
54
55        return [
56            /**
57             * CLIENT IDENTITY (remplace tenant)
58             */
59            'client' => [
60                'organization_id'   => $ctx->organizationId,
61                'organization_name' => $ctx->organizationName,
62                'organization_type' => $ctx->organizationType,
63
64                'user_id'   => $ctx->userId,
65                'user_name' => $ctx->userName,
66
67                'app_name'   => $ctx->appName,
68                'app_locale' => $ctx->appLocale,
69
70                'version' => [
71                    'number'      => $ctx->appVersion,
72                    'build_hash'  => $ctx->buildHash,
73                    'deployed_at' => $ctx->deployedAt,
74                    'channel'     => $ctx->channel,
75                ],
76            ],
77
78            /**
79             * RUNTIME
80             */
81            'environment' => $ctx->environment,
82
83            /**
84             * REQUEST CONTEXT
85             */
86            'context' => [
87                'url'        => current_url(),
88                'method'     => $request->getMethod(),
89                'ip'         => $request->getIPAddress(),
90                'user_agent' => $request->getUserAgent()->getAgentString(),
91            ],
92
93            /**
94             * EXTENSION CONTEXT (safe)
95             */
96            'meta' => $this->sanitize($context),
97
98            'timestamp' => date('c'),
99        ];
100    }
101
102    /**
103     * Nettoyage des données sensibles
104     */
105    protected function sanitize(array $context): array
106    {
107        $blockedKeys = [
108            'password',
109            'token',
110            'api_key',
111            'secret',
112            'authorization',
113            'credit_card',
114        ];
115
116        array_walk_recursive($context, function (&$value, $key) use ($blockedKeys) {
117            if (in_array(strtolower($key), $blockedKeys, true)) {
118                $value = '[FILTERED]';
119            }
120        });
121
122        return $context;
123    }
124
125    /**
126     * Résumé UI / logs
127     */
128    public function summarize(array $payload): array
129    {
130        return [
131            'type'     => $payload['type'] ?? 'UNKNOWN',
132            'message'  => $payload['message'] ?? null,
133            'severity' => $payload['severity'] ?? 'info',
134
135            'organization' => $payload['client']['organization_name'] ?? null,
136            'user'         => $payload['client']['user_name'] ?? null,
137            'version'      => $payload['client']['version']['number'] ?? null,
138            'channel'      => $payload['client']['version']['channel'] ?? null,
139
140            'url'  => $payload['context']['url'] ?? null,
141            'time' => $payload['timestamp'] ?? date('c'),
142        ];
143    }
144}