Completed
Push — master ( 2e57ae...890c9a )
by Tarmo
01:18 queued 01:12
created

StopwatchDecorator   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 60
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 28
c 1
b 0
f 0
dl 0
loc 60
ccs 27
cts 27
cp 1
rs 10
wmc 9

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B decorate() 0 52 8
1
<?php
2
declare(strict_types = 1);
3
/**
4
 * /src/Decorator/StopwatchDecorator.php
5
 *
6
 * @author TLe, Tarmo Leppänen <[email protected]>
7
 */
8
9
namespace App\Decorator;
10
11
use App\Entity\Interfaces\EntityInterface;
12
use ProxyManager\Factory\AccessInterceptorValueHolderFactory;
13
use ReflectionClass;
14
use ReflectionMethod;
15
use Symfony\Component\Stopwatch\Stopwatch;
16
use Throwable;
17
use function array_filter;
18
use function is_object;
19
use function str_starts_with;
20
21
/**
22
 * Class StopwatchDecorator
23
 *
24
 * @package App\Decorator
25
 * @author TLe, Tarmo Leppänen <[email protected]>
26
 */
27
class StopwatchDecorator
28
{
29 6
    public function __construct(
30
        private AccessInterceptorValueHolderFactory $factory,
31
        private Stopwatch $stopwatch,
32
    ) {
33 6
    }
34
35 6
    public function decorate(object $service): object
36
    {
37 6
        $class = new ReflectionClass($service);
38 6
        $className = $class->getName();
39
40
        // Do not process core or extensions or already wrapped services
41 6
        if ($class->getFileName() === false || str_starts_with($class->getName(), 'ProxyManagerGeneratedProxy')) {
42 1
            return $service;
43
        }
44
45 5
        $prefix = [];
46 5
        $suffix = [];
47
48 5
        $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC);
49 5
        $methods = array_filter($methods, static fn ($method): bool => !$method->isStatic() && !$method->isFinal());
50
51 5
        foreach ($methods as $method) {
52 5
            $methodName = $method->getName();
53 5
            $eventName = "{$class->getShortName()}->{$methodName}";
54
55 5
            $prefix[$methodName] = function () use ($eventName, $className): void {
56 3
                $this->stopwatch->start($eventName, $className);
57 3
            };
58
59 5
            $suffix[$methodName] = function (
60
                mixed $p,
61
                mixed $i,
62
                mixed $m,
63
                mixed $params,
64
                mixed &$returnValue
65 5
            ) use ($eventName): void {
66 3
                $this->stopwatch->stop($eventName);
67
68
                /**
69
                 * Decorate returned values as well
70
                 *
71
                 * Note that this might cause some weird errors on some edge
72
                 * cases - we should fix those when those happens...
73
                 */
74 3
                if (is_object($returnValue) && !$returnValue instanceof EntityInterface) {
75 1
                    $returnValue = $this->decorate($returnValue);
76
                }
77 3
            };
78
        }
79
80
        try {
81 5
            $output = $this->factory->createProxy($service, $prefix, $suffix);
82 1
        } catch (Throwable) {
83 1
            $output = $service;
84
        }
85
86 5
        return $output;
87
    }
88
}
89