Passed
Push — master ( af290e...e96163 )
by Razon
01:15
created

Manager::laodAllowance()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 5.675

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 10
c 1
b 0
f 0
nc 6
nop 1
dl 0
loc 16
ccs 7
cts 10
cp 0.7
crap 5.675
rs 9.6111
1
<?php
2
namespace RazonYang\TokenBucket;
3
4
use RazonYang\TokenBucket\Serializer\PhpSerializer;
5
6
/**
7
 * Manager is an abstract bucket manager that implements ManagerInterface.
8
 */
9
abstract class Manager implements ManagerInterface
10
{
11
    /**
12
     * @var int $capacity
13
     */
14
    private $capacity;
15
16 4
    public function getCapacity(): int
17
    {
18 4
        return $this->capacity;
19
    }
20
21
    /**
22
     * @var float $rate
23
     */
24
    private $rate;
25
26 4
    public function getRate(): float
27
    {
28 4
        return $this->rate;
29
    }
30
31
    /**
32
     * @var SerializerInterface $serializer
33
     */
34
    private $serializer;
35
36 12
    public function __construct(int $capacity, float $rate, ?SerializerInterface $serializer = null)
37
    {
38 12
        $this->capacity = $capacity;
39 12
        $this->rate = $rate;
40 12
        $this->serializer = $serializer ?? new PhpSerializer();
41 12
    }
42
43 1
    public function laodAllowance(string $name): array
44
    {
45
        try {
46 1
            $value = $this->load($name);
47 1
            if ($value === false) {
48 1
                return [$this->capacity, 0];
49
            }
50
51 1
            $data = $this->serializer->unserialize($value);
52 1
            if (!is_array($data) || count($data) !== 2) {
53
                throw new \Exception('Invalid value');
54
            }
55
56 1
            return $data;
57
        } catch (\Throwable $e) {
58
            return [$this->capacity, 0];
59
        }
60
    }
61
62
    /**
63
     * Loads allowance, return data if exists, otherwise false.
64
     *
65
     * @param string $name
66
     *
67
     * @return mixed|false
68
     */
69
    abstract protected function load(string $name);
70
71 1
    public function saveAllowance(string $name, int $allowance, int $timestamp)
72
    {
73 1
        $value = $this->serializer->serialize([$allowance, $timestamp]);
74 1
        $this->save($name, $value);
75 1
    }
76
77
    /**
78
     * Saves allowance.
79
     *
80
     * @param string $name
81
     * @param mixed  $value
82
     *
83
     * @throws \Throwable throws an exception if save fails.
84
     */
85
    abstract protected function save(string $name, $value);
86
87
    /**
88
     * Consumes a token from the bucket.
89
     *
90
     * @param string $name bucket name.
91
     *
92
     * @return bool returns true on success, otherwise false.
93
     */
94 1
    public function consume(string $name, ?int &$remaining = null, ?int &$reset = null): bool
95
    {
96 1
        list($allowance, $timestamp) = $this->laodAllowance($name);
97 1
        $now = time();
98 1
        $allowance += intval(($now - $timestamp) / $this->rate);
99 1
        if ($allowance > $this->capacity) {
100 1
            $allowance = $this->capacity;
101
        }
102
103 1
        if ($allowance < 1) {
104 1
            $remaining = 0;
105 1
            $reset = intval($this->capacity * $this->rate) - ($now - $timestamp);
106 1
            return false;
107
        }
108
109 1
        $remaining = $allowance - 1;
110 1
        $reset = intval(($this->capacity - $allowance) * $this->rate);
111 1
        $this->saveAllowance($name, $remaining, $now);
112 1
        return true;
113
    }
114
115 3
    public function getLimit(int $period): int
116
    {
117 3
        return min($this->capacity, intval($period / $this->rate));
118
    }
119
}
120