Passed
Push — master ( 59a93e...603998 )
by Alexander
03:10
created

StateResetter   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 77
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 29
c 2
b 0
f 0
dl 0
loc 77
ccs 32
cts 32
cp 1
rs 10
wmc 12

4 Methods

Rating   Name   Duplication   Size   Complexity  
A reset() 0 8 3
A __construct() 0 3 1
B setResetters() 0 33 6
A getType() 0 3 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Di;
6
7
use Closure;
8
use InvalidArgumentException;
9
use Psr\Container\ContainerInterface;
10
11
use function get_class;
12
use function gettype;
13
use function is_int;
14
use function is_object;
15
16
/**
17
 * State resetter allows resetting state of the services that are currently stored in the container and have "reset"
18
 * callback defined. The reset should be triggered after each request-response cycle in case you build long-running
19
 * applications with tools like [Swoole](https://www.swoole.co.uk/) or [RoadRunner](https://roadrunner.dev/).
20
 */
21
final class StateResetter
22
{
23
    /**
24
     * @var Closure[]|self[]
25
     */
26
    private array $resetters = [];
27
    private ContainerInterface $container;
28
29
    /**
30
     * @param ContainerInterface $container Container to reset.
31
     */
32 8
    public function __construct(ContainerInterface $container)
33
    {
34 8
        $this->container = $container;
35 8
    }
36
37
    /**
38
     * Reset the container.
39
     */
40 5
    public function reset(): void
41
    {
42 5
        foreach ($this->resetters as $resetter) {
43 5
            if ($resetter instanceof self) {
44 3
                $resetter->reset();
45 3
                continue;
46
            }
47 5
            $resetter($this->container);
48
        }
49 5
    }
50
51
    /**
52
     * @param Closure[]|self[] $resetters Array of reset callbacks. Each callback has access to the private and
53
     * protected properties of the service instance, so you can set initial state of the service efficiently
54
     * without creating a new instance.
55
     */
56 8
    public function setResetters(array $resetters): void
57
    {
58 8
        $this->resetters = [];
59 8
        foreach ($resetters as $serviceId => $callback) {
60 8
            if (is_int($serviceId)) {
61 4
                if (!$callback instanceof self) {
62 1
                    throw new InvalidArgumentException(sprintf(
63 1
                        'State resetter object should be instance of "%s", "%s" given.',
64 1
                        self::class,
65 1
                        $this->getType($callback)
66
                    ));
67
                }
68 3
                $this->resetters[] = $callback;
69 3
                continue;
70
            }
71
72 7
            if (!$callback instanceof Closure) {
73 1
                throw new InvalidArgumentException(
74
                    'Callback for state resetter should be closure in format ' .
75
                    '`function (ContainerInterface $container): void`. ' .
76 1
                    'Got "' . $this->getType($callback) . '".'
77
                );
78
            }
79
80
            /** @var mixed $instance */
81 6
            $instance = $this->container->get($serviceId);
82 6
            if (!is_object($instance)) {
83 1
                throw new InvalidArgumentException(
84 1
                    'State resetter supports resetting objects only. Container returned ' . gettype($instance) . '.'
85
                );
86
            }
87
88 5
            $this->resetters[] = $callback->bindTo($instance, get_class($instance));
89
        }
90 5
    }
91
92
    /**
93
     * @param mixed $variable
94
     */
95 2
    private function getType($variable): string
96
    {
97 2
        return is_object($variable) ? get_class($variable) : gettype($variable);
98
    }
99
}
100