Completed
Push — master ( 396474...e3213f )
by Antonio Oertel
04:21 queued 01:33
created

DigitCalculator::useAdditionalInsteadOfModule()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Brazanation\Documents;
4
5
/**
6
 * Class DigitCalculator is inspired in DigitoPara class from Java built by Caleum
7
 *
8
 * @package Brazanation\Documents
9
 *
10
 * @see     https://github.com/caelum/caelum-stella/blob/master/stella-core/src/main/java/br/com/caelum/stella/DigitoPara.java
11
 */
12
class DigitCalculator
13
{
14
    const MODULE_10 = 10;
15
16
    const MODULE_11 = 11;
17
18
    /**
19
     * @var \ArrayObject
20
     */
21
    protected $number;
22
23
    /**
24
     * @var \ArrayObject
25
     */
26
    protected $multipliers;
27
28
    /**
29
     * @var bool
30
     */
31
    protected $additional = false;
32
33
    /**
34
     * @var int
35
     */
36
    protected $module = DigitCalculator::MODULE_11;
37
38
    /**
39
     * @var bool
40
     */
41
    protected $singleSum;
42
43
    /**
44
     * @var \ArrayObject
45
     */
46
    private $replacements;
47
48 15
    public function __construct($number)
49
    {
50 15
        $this->number = new \ArrayObject(str_split(strrev($number)));
51 15
        $this->multipliers = new \ArrayObject();
52 15
        $this->replacements = new \ArrayObject();
53
54 15
        $this->withMultipliersInterval(2, 9);
55 15
        $this->withModule(static::MODULE_11);
56 15
    }
57
58
    /**
59
     * Para multiplicadores (ou pesos) sequenciais e em ordem crescente, esse método permite
60
     * criar a lista de multiplicadores que será usada ciclicamente, caso o número base seja
61
     * maior do que a sequência de multiplicadores. Por padrão os multiplicadores são iniciados
62
     * de 2 a 9. No momento em que você inserir outro valor este default será sobrescrito.
63
     *
64
     * @param int $start First number of sequential interval of multipliers
65
     * @param int $end   Last number of sequential interval of multipliers
66
     *
67
     * @return DigitCalculator
68
     */
69 15
    public function withMultipliersInterval($start, $end)
70
    {
71 15
        $multipliers = [];
72 15
        for ($i = $start; $i <= $end; $i++) {
73 15
            array_push($multipliers, $i);
74
        }
75
76 15
        return $this->withMultipliers($multipliers);
77
    }
78
79
    /**
80
     * @param int[] $multipliers
81
     *
82
     * @return DigitCalculator
83
     */
84 15
    public function withMultipliers(array $multipliers)
85
    {
86 15
        $this->multipliers = new \ArrayObject($multipliers);
87
88 15
        return $this;
89
    }
90
91
    /**
92
     * @return DigitCalculator
93
     */
94 8
    public function useAdditionalInsteadOfModule()
95
    {
96 8
        $this->additional = true;
97
98 8
        return $this;
99
    }
100
101 10
    public function replaceWhen($replaceTo, ...$integers)
102
    {
103 10
        foreach ($integers as $integer) {
104 10
            $this->replacements->offsetSet($integer, $replaceTo);
105
        }
106
107 10
        return $this;
108
    }
109
110 15
    public function withModule($module)
111
    {
112 15
        $this->module = $module;
113
114 15
        return $this;
115
    }
116
117
    public function singleSum()
118
    {
119
        $this->singleSum = true;
120
121
        return $this;
122
    }
123
124 15
    public function calculate()
125
    {
126 15
        $sum = 0;
127 15
        $position = 0;
128 15
        foreach ($this->number as $digit) {
129 15
            $multiplier = $this->multipliers->offsetGet($position);
130 15
            $total = $digit * $multiplier;
131 15
            $sum += $this->digitSum($total);
132 15
            $position = $this->nextMultiplier($position);
133
        }
134
135 15
        $result = $sum % $this->module;
136
137 15
        if ($this->additional) {
138 8
            $result = $this->module - $result;
139
        }
140
141 15
        if ($this->replacements->offsetExists($result)) {
142 2
            return $this->replacements->offsetGet($result);
143
        }
144
145 14
        return $result;
146
    }
147
148 15
    private function digitSum($total)
149
    {
150 15
        if ($this->singleSum) {
151
            return ($total / 10) + ($total % 10);
152
        }
153
154 15
        return $total;
155
    }
156
157 15
    private function nextMultiplier($position)
158
    {
159 15
        $position++;
160 15
        if ($position == $this->multipliers->count()) {
161 15
            $position = 0;
162
        }
163
164 15
        return $position;
165
    }
166
167
    public function addDigit($digit)
168
    {
169
        $numbers = $this->number->getArrayCopy();
170
        array_unshift($numbers, $digit);
171
        $this->number = new \ArrayObject($numbers);
172
173
        return $this;
174
    }
175
}
176