Passed
Pull Request — master (#42)
by Antonio Oertel
02:19
created

AbstractDocument::__set()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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