Passed
Push — master ( e96163...a80be6 )
by Razon
01:16
created

Manager::getLimit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
ccs 2
cts 2
cp 1
crap 1
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 1
        $value = $this->load($name);
46 1
        if ($value === false) {
47 1
            return [$this->capacity, 0];
48
        }
49
50 1
        $data = $this->serializer->unserialize($value);
51 1
        if (!is_array($data) || count($data) !== 2) {
52
            throw new \Exception('Invalid value');
53
        }
54
55 1
        return $data;
56
    }
57
58
    /**
59
     * Loads allowance, return data if exists, otherwise false.
60
     *
61
     * @param string $name
62
     *
63
     * @return mixed|false
64
     */
65
    abstract protected function load(string $name);
66
67 1
    public function saveAllowance(string $name, int $allowance, int $timestamp)
68
    {
69 1
        $value = $this->serializer->serialize([$allowance, $timestamp]);
70 1
        $this->save($name, $value);
71 1
    }
72
73
    /**
74
     * Saves allowance.
75
     *
76
     * @param string $name
77
     * @param mixed  $value
78
     *
79
     * @throws \Throwable throws an exception if save fails.
80
     */
81
    abstract protected function save(string $name, $value);
82
83
    /**
84
     * Consumes a token from the bucket.
85
     *
86
     * @param string $name bucket name.
87
     *
88
     * @return bool returns true on success, otherwise false.
89
     */
90 1
    public function consume(string $name, ?int &$remaining = null, ?int &$reset = null): bool
91
    {
92 1
        list($allowance, $timestamp) = $this->laodAllowance($name);
93 1
        $now = time();
94 1
        $allowance += intval(($now - $timestamp) / $this->rate);
95 1
        if ($allowance > $this->capacity) {
96 1
            $allowance = $this->capacity;
97
        }
98
99 1
        if ($allowance < 1) {
100 1
            $remaining = 0;
101 1
            $reset = intval($this->capacity * $this->rate) - ($now - $timestamp);
102 1
            return false;
103
        }
104
105 1
        $remaining = $allowance - 1;
106 1
        $reset = intval(($this->capacity - $allowance) * $this->rate);
107 1
        $this->saveAllowance($name, $remaining, $now);
108 1
        return true;
109
    }
110
111 3
    public function getLimit(int $period): int
112
    {
113 3
        return min($this->capacity, intval($period / $this->rate));
114
    }
115
}
116