Completed
Push — feature/EVO-7278-tracking-info... ( a5fe2c...35e86f )
by
unknown
172:49 queued 167:19
created

ActivityManager::getEvents()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * Keeping all activity in one place to be controlled
4
 */
5
6
namespace Graviton\AuditTrackingBundle\Manager;
7
8
use Graviton\AuditTrackingBundle\Document\AuditTracking;
9
use Graviton\RestBundle\Event\ModelEvent;
10
use Guzzle\Http\Message\Header;
11
use Symfony\Bridge\Doctrine\ManagerRegistry;
12
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
13
use Symfony\Component\HttpFoundation\RequestStack;
14
use Symfony\Component\HttpFoundation\Response;
15
16
use Symfony\Component\HttpFoundation\Request;
17
18
/**
19
 * Class ActivityManager
20
 * @package Graviton\AuditTrackingBundle\Manager
21
 *
22
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
23
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
24
 * @link     http://swisscom.ch
25
 */
26
class ActivityManager
27
{
28
    /** Max char length of saved content data */
29
    const CONTENT_MAX_LENGTH = 2048;
30
31
    /** @var bool If log is enabled */
32
    private $enabled = false;
33
34
    /** @var Request $request */
35
    private $request;
36
37
    /** @var array */
38
    private $configurations;
39
40
    /** @var AuditTracking */
41
    private $document;
42
43
    /** @var array Events that shall be stored */
44
    private $events = [];
45
46
    /** @var string  */
47
    private $globalRequestLocation = '';
48
49
    /**
50
     * DBActivityListener constructor.
51
     *
52
     * @param RequestStack  $requestStack Sf request data
53
     * @param AuditTracking $document     DocumentCollection for event
54
     */
55 4
    public function __construct(
56
        RequestStack  $requestStack,
57
        AuditTracking $document
58
    ) {
59 4
        $this->request = $requestStack ? $requestStack->getCurrentRequest() : false;
0 ignored issues
show
Documentation Bug introduced by
It seems like $requestStack ? $request...urrentRequest() : false can also be of type false. However, the property $request is declared as type object<Symfony\Component\HttpFoundation\Request>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
60 4
        $this->document = $document;
61 4
    }
62
63
    /**
64
     * Set permission and access configuration
65
     *
66
     * @param array $configurations key value config
67
     * @return void
68
     */
69 4
    public function setConfiguration(array $configurations)
70
    {
71 4
        $this->configurations = $configurations;
72 4
        if ($this->runTracking()) {
73
            $this->enabled = true;
74
        }
75 4
    }
76
77
    /**
78
     * Return casted value from configuration.
79
     *
80
     * @param string $key  Configuration key
81
     * @param string $cast Type of object is expected to be returned
82
     * @return int|string|bool|array
83
     * @throws ParameterNotFoundException
84
     */
85 2
    public function getConfigValue($key, $cast = 'string')
86
    {
87 2
        if (array_key_exists($key, $this->configurations)) {
88 2
            if ('bool' == $cast) {
89 2
                return (boolean) $this->configurations[$key];
90 2
            }if ('array' == $cast) {
91 2
                return (array) $this->configurations[$key];
92 2
            } elseif ('string' == $cast) {
93 2
                return (string) $this->configurations[$key];
94 2
            } elseif ('int' == $cast) {
95 2
                return (int) $this->configurations[$key];
96
            }
97
        }
98
        throw new ParameterNotFoundException('ActivityManager could not find required configuration: '.$key);
99
    }
100
101
    /**
102
     * Check if this the Call has to be logged
103
     *
104
     * @return bool
105
     */
106 4
    private function runTracking()
0 ignored issues
show
Coding Style introduced by
function runTracking() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
107
    {
108
        //Ignore if no request, import fixtures.
109 4
        if (!$this->request) {
110 4
            return false;
111
        }
112
113
        // Check if enable
114
        if (!$this->getConfigValue('log_enabled', 'bool')) {
115
            return false;
116
        }
117
        
118
        // We never log tracking service calls
119
        if ((strpos($this->request->getRequestUri(), '/_debug') !== false)) {
120
            return false;
121
        }
122
123
        // Check if we wanna log test and localhost calls
124
        if (!$this->getConfigValue('log_test_calls', 'bool')
125
            && !in_array($this->request->getHost(), ['localhost', '127.0.0.1'])) {
126
            return false;
127
        }
128
129
        return true;
130
    }
131
132
    /**
133
     * Incoming request done by user
134
     * @param Request $request sf response priority 1
135
     * @return void
136
     */
137
    public function registerRequestEvent(Request $request)
138
    {
139
        if (!$this->enabled) {
140
            return;
141
        }
142
        // Check if this request event shall be registered
143
        $saveEvents = $this->getConfigValue('requests', 'array');
144
        $method = $request->getMethod();
145
        $this->globalRequestLocation = $request->getRequestUri();
146
        if (!in_array($method, $saveEvents)) {
147
            return;
148
        }
149
150
        $content = substr($request->getContent(), 0, self::CONTENT_MAX_LENGTH);
151
152
        $data = ['ip' => $request->getClientIp()];
153
154
        if ($this->getConfigValue('request_headers', 'bool')) {
155
            $data['headers'] = $request->headers->all();
156
        }
157
        if ($length=$this->getConfigValue('request_content', 'int')) {
158
            $cnt = mb_check_encoding($content, 'UTF-8') ? $content : 'Content omitted, since it is not utf-8';
159
            $data['content'] = ($length==1) ? $cnt : substr($cnt, 0, $length);
160
        }
161
162
        $this->createEvent(
163
            'request',
164
            $request->getRequestUri(),
165
            $method,
166
            $data
0 ignored issues
show
Documentation introduced by
$data is of type array<string,string|array>, but the function expects a string.

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...
167
        );
168
    }
169
170
    /**
171
     * The response returned to user
172
     *
173
     * @param Response $response sf response
174
     * @return void
175
     */
176
    public function registerResponseEvent(Response $response)
177
    {
178
        if (!$this->enabled) {
179
            return;
180
        }
181
        if (!$this->getConfigValue('response', 'bool')) {
182
            return;
183
        }
184
185
        $data = [];
186
        $statusCode = '0';
187
188
        if (method_exists($response, 'getStatusCode')) {
189
            $statusCode = $response->getStatusCode();
190
        }
191
        if ($length=$this->getConfigValue('response_content', 'int') && method_exists($response, 'getContent')) {
0 ignored issues
show
Comprehensibility introduced by
Consider adding parentheses for clarity. Current Interpretation: $length = ($this->getCon...esponse, 'getContent')), Probably Intended Meaning: ($length = $this->getCon...response, 'getContent')
Loading history...
192
            $cnt = mb_check_encoding($response->getContent(), 'UTF-8') ?
193
                $response->getContent() : 'Content omitted, since it is not utf-8';
194
            $data['content'] = ($length==1) ? $cnt : substr($cnt, 0, $length);
195
        }
196
        if ($this->getConfigValue('response_content', 'bool')) {
197
            $data['header']  = $response->headers->all();
198
        }
199
200
        // Header links
201
        $location = $this->extractHeaderLink($response->headers->get('link'), 'self');
202
203
        $this->createEvent(
204
            'response',
205
            $statusCode,
206
            $location,
207
            $data
0 ignored issues
show
Documentation introduced by
$data is of type array, but the function expects a string.

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...
208
        );
209
    }
210
211
    /**
212
     * Capture possible un-handled exceptions in php
213
     *
214
     * @param \Exception $exception The exception thrown in service.
215
     * @return void
216
     */
217
    public function registerExceptionEvent(\Exception $exception)
218
    {
219
        if (!$this->enabled) {
220
            return;
221
        }
222
        if (!$this->getConfigValue('exceptions', 'bool')) {
223
            return;
224
        }
225
        $data = [
226
            'message'   => $exception->getMessage(),
227
            'trace'     => $exception->getTraceAsString()
228
        ];
229
        $this->createEvent(
230
            'exception',
231
            $exception->getCode(),
232
            get_class($exception),
233
            $data
0 ignored issues
show
Documentation introduced by
$data is of type array<string,string,{"me...ing","trace":"string"}>, but the function expects a string.

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...
234
        );
235
    }
236
237
    /**
238
     * Any database events, update, save or delete
239
     *
240
     * Available $event->getCollection() would give you the full object.
241
     *
242
     * @param ModelEvent $event Document object changed
243
     * @return void
244
     */
245
    public function registerDocumentModelEvent(ModelEvent $event)
246
    {
247
        if (!$this->enabled) {
248
            return;
249
        }
250
        if ((!($dbEvents = $this->getConfigValue('database', 'array')))) {
251
            return;
252
        }
253
        if (!in_array($event->getAction(), $dbEvents)) {
254
            return;
255
        }
256
257
        $this->createEvent(
258
            $event->getAction(),
259
            'collection',
260
            $this->globalRequestLocation,
261
            [
0 ignored issues
show
Documentation introduced by
array('class' => $event->getCollectionClass()) is of type array<string,string,{"class":"string"}>, but the function expects a string.

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...
262
                'class' => $event->getCollectionClass()
263
            ],
264
            $event->getCollectionId(),
265
            $event->getCollectionName()
266
        );
267
    }
268
269
    /**
270
     * Creating the Document to be saved into DB.
271
     *
272
     * @param string $action         What did happen
273
     * @param string $type           What was it
274
     * @param string $location       Where was it
275
     * @param string $data           Aditioanl data
276
     * @param string $collectionId   Modified collection identifier
277
     * @param string $collectionName Modified collection name
278
     *
279
     * @return void
280
     */
281
    private function createEvent(
282
        $action,
283
        $type,
284
        $location,
285
        $data,
286
        $collectionId = '',
287
        $collectionName = ''
288
    ) {
289
        if (!is_object($data)) {
290
            $data = (object) $data;
291
        }
292
293
        /** @var AuditTracking $event */
294
        $event = new $this->document();
295
        $event->setAction($action);
296
        $event->setType($type);
297
        $event->setData($data);
298
        $event->setLocation($location);
299
300
        if ($collectionId) {
301
            $event->setCollectionId($collectionId);
302
        }
303
        if ($collectionName) {
304
            $event->setCollectionName($collectionName);
305
        }
306
307
        $event->setCreatedAt(new \DateTime());
308
309
        $this->events[] = $event;
310
    }
311
312
    /**
313
     * Parse and extract customer header links
314
     *
315
     * @param string $strHeaderLink sf header links
316
     * @param string $extract       desired key to be found
317
     * @return string
318
     */
319 2
    private function extractHeaderLink($strHeaderLink, $extract = 'self')
320
    {
321 2
        if (!$strHeaderLink) {
322
            return '';
323
        }
324
325 2
        $parts = [];
326 2
        foreach (explode(',', $strHeaderLink) as $link) {
327 2
            $link = explode(';', $link);
328 2
            if (count($link)==2) {
329 2
                $parts[str_replace(['rel=','"'], '', trim($link[1]))] =  str_replace(['<','>'], '', $link[0]);
330 1
            }
331 1
        }
332
333 2
        return  array_key_exists($extract, $parts) ? $parts[$extract] : '';
334
    }
335
336
    /**
337
     * @return array
338
     */
339
    public function getEvents()
340
    {
341
        return $this->events;
342
    }
343
}
344