Action   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 94
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 29
c 1
b 0
f 0
dl 0
loc 94
ccs 26
cts 26
cp 1
rs 10
wmc 11

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getName() 0 3 1
B validate() 0 19 7
A increment() 0 14 2
1
<?php
2
3
namespace kdn\attemptsCounter;
4
5
/**
6
 * Class Action.
7
 * @package kdn\attemptsCounter
8
 */
9
class Action
10
{
11
    /**
12
     * @var int|string the action name
13
     */
14
    protected $name;
15
16
    /**
17
     * @var positive-int the maximum number of attempts to perform the action
18
     */
19
    protected $maxAttempts;
20
21
    /**
22
     * @var int the time interval in nanoseconds between attempts to perform the action
23
     */
24
    protected $sleepTime = 0;
25
26
    /**
27
     * @var int the number of already completed attempts to perform the action
28
     */
29
    protected $attemptsCount = 0;
30
31
    /**
32
     * Constructor.
33
     * @param int|string $name the action name
34
     * @param positive-int $maxAttempts the maximum number of attempts to perform the action
35
     * @param int $sleepTime the time interval in nanoseconds between attempts to perform the action
36
     */
37 12
    public function __construct($name, $maxAttempts, $sleepTime = 0)
38
    {
39 12
        $this->name = $name;
40 12
        $this->maxAttempts = $maxAttempts;
41 12
        $this->sleepTime = $sleepTime;
42 12
        $this->validate();
43
    }
44
45
    /**
46
     * Get the action name.
47
     * @return int|string the action name.
48
     */
49 1
    public function getName()
50
    {
51 1
        return $this->name;
52
    }
53
54
    /**
55
     * Increments the counter for the action.
56
     * If attempts exhausted then throws an AttemptsLimitException,
57
     * otherwise waits according to the action configuration.
58
     * @param null|\Throwable $exception an optional exception object that can be attached to AttemptsLimitException
59
     * as a previous exception
60
     * @param int $number the number of used attempts to perform the action;
61
     * IMPORTANT: this number multiplies the delay until the next attempt
62
     * @throws AttemptsLimitException
63
     */
64 4
    public function increment($exception = null, $number = 1)
65
    {
66 4
        $this->attemptsCount += $number;
67 4
        if ($this->attemptsCount >= $this->maxAttempts) {
68 3
            throw new AttemptsLimitException(
69 3
                'Cannot perform action "' . $this->name . '" after ' . $this->attemptsCount
70 3
                . ' attempt(s) with ' . $this->sleepTime . ' nanosecond(s) interval(s).',
71
                0,
72
                $exception
73
            );
74
        }
75
76 2
        $totalSleepTime = $this->sleepTime * $number;
77 2
        time_nanosleep((int)($totalSleepTime / 1000000000), $totalSleepTime % 1000000000);
78
    }
79
80
    /**
81
     * Validate values of the action properties.
82
     * @throws InvalidConfigException
83
     */
84 12
    protected function validate()
85
    {
86 12
        if (!is_string($this->name) && !is_int($this->name)) {
87 2
            throw new InvalidConfigException('The action name must be a string or an integer.');
88
        }
89
90 10
        if (!is_int($this->maxAttempts)) {
91 1
            throw new InvalidConfigException('The maximum number of attempts must be an integer.');
92
        }
93 9
        if ($this->maxAttempts < 1) {
94 2
            throw new InvalidConfigException('The maximum number of attempts must be a positive integer.');
95
        }
96
97 7
        if (!is_int($this->sleepTime)) {
98 1
            throw new InvalidConfigException('The time interval in nanoseconds between attempts must be an integer.');
99
        }
100 6
        if ($this->sleepTime < 0) {
101 1
            throw new InvalidConfigException(
102
                'The time interval in nanoseconds between attempts must be a non-negative integer.'
103
            );
104
        }
105
    }
106
}
107