Passed
Branch master (0e9587)
by Antonio Oertel
02:20
created

AbstractDocument::extractCheckerDigit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Brazanation\Documents;
4
5
/**
6
 * Class AbstractDocument
7
 *
8
 * @package Brazanation\Documents
9
 *
10
 * @property string $number
11
 * @property string $digit
12
 * @property int $length
13
 * @property int $numberOfDigits
14
 * @property string $type
15
 */
16
abstract class AbstractDocument implements DigitCalculable, Formattable
17
{
18
    /**
19
     * @var string
20
     */
21
    protected $number;
22
23
    /**
24
     * @var string
25
     */
26
    protected $digit;
27
28
    /**
29
     * @var int
30
     */
31
    protected $length;
32
33
    /**
34
     * @var int
35
     */
36
    protected $numberOfDigits;
37
38
    /**
39
     * @var string
40
     */
41
    protected $type;
42
43
    /**
44
     * AbstractDocument constructor.
45
     *
46
     * @param string $number Numeric section with checker digit.
47
     * @param int $length Max length of document.
48
     * @param int $numberOfDigits Max length of checker digits.
49
     * @param string $type Document name/type.
50
     */
51 1306
    public function __construct($number, $length, $numberOfDigits, $type)
52
    {
53 1306
        $this->type = (string) $type;
54 1306
        $this->numberOfDigits = (int) $numberOfDigits;
55 1306
        $this->length = (int) $length;
56 1306
        $this->digit = $this->extractCheckerDigit($number);
57 1306
        $this->assert($number);
58 888
        $this->number = $number;
59 888
    }
60
61 5
    public function __get($name)
62
    {
63 5
        return $this->$name;
64
    }
65
66
    public function __set($name, $value)
67
    {
68
        throw Exception\Readonly::notAllowed(static::class, $name);
69
    }
70
71
    /**
72
     * Create a Document object from given number.
73
     *
74
     * @param string $number Numeric section with checker digit.
75
     *
76
     * @return AbstractDocument|boolean Returns a new Document instance or FALSE on failure.
77
     */
78
    abstract public static function createFromString($number);
79
80
    /**
81
     * Try to create a Document object from given number.
82
     *
83
     * @param string $number Numeric section with checker digit.
84
     * @param int $length Max length of document.
85
     * @param int $numberOfDigits Max length of checker digits.
86
     * @param string $type Document name/type.
87
     *
88
     * @return AbstractDocument|boolean Returns a new Document instance or FALSE on failure.
89
     */
90 167
    protected static function tryCreateFromString($class, $number, $length, $numberOfDigits, $type)
91
    {
92
        try {
93 167
            return new $class($number, $length, $numberOfDigits, $type);
94 116
        } catch (Exception\InvalidDocument $exception) {
95 116
            return false;
96
        }
97
    }
98
99
    /**
100
     * Handle number to string.
101
     *
102
     * @return string
103
     */
104 883
    public function __toString()
105
    {
106 883
        return "{$this->number}";
107
    }
108
109
    /**
110
     * Check if document number is valid.
111
     *
112
     * @param string $number Numeric section with checker digit.
113
     *
114
     * @throws Exception\InvalidDocument when number is empty
115
     * @throws Exception\InvalidDocument when number is not valid
116
     */
117 1306
    protected function assert($number)
118
    {
119 1306
        if (empty($number)) {
120 154
            throw Exception\InvalidDocument::notEmpty($this->type);
121
        }
122 1152
        if (!$this->isValid($number)) {
123 264
            throw Exception\InvalidDocument::isNotValid($this->type, $number);
124
        }
125 888
    }
126
127
    /**
128
     * Validates number is a valid.
129
     *
130
     * @param string $number Numeric section with checker digit.
131
     *
132
     * @return bool Returns true if it is a valid number, otherwise false.
133
     */
134 1152
    protected function isValid($number)
135
    {
136 1152
        $baseNumber = $this->extractBaseNumber($number);
137
138 1152
        if (!$baseNumber) {
139 34
            return false;
140
        }
141
142 1118
        $isRepeated = preg_match("/^[{$baseNumber[0]}]+$/", $baseNumber);
143
144 1118
        if ($isRepeated) {
145 54
            return false;
146
        }
147
148 1064
        $digit = $this->calculateDigit($baseNumber);
149
150 1064
        return "$digit" === "{$this->digit}";
151
    }
152
153
    /**
154
     * Extracts the base number document.
155
     *
156
     * @param string $number Number of document.
157
     *
158
     * @return string Returns only base number without checker digit.
159
     */
160 248
    protected function extractBaseNumber($number)
161
    {
162 248
        return substr($number, 0, -($this->numberOfDigits));
163
    }
164
165
    /**
166
     * Extracts the checker digit from document number.
167
     *
168
     * @param string $number Number of document.
169
     *
170
     * @return string Returns only checker digit.
171
     */
172 318
    protected function extractCheckerDigit($number)
173
    {
174 318
        return substr($number, -($this->numberOfDigits));
175
    }
176
}
177