Completed
Push — master ( b8d8de...2f6d07 )
by smiley
05:15
created

MaskPatternTester   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 199
Duplicated Lines 13.07 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 26
loc 199
rs 8.6206
c 0
b 0
f 0
wmc 50
lcom 1
cbo 1

6 Methods

Rating   Name   Duplication   Size   Complexity  
A testPattern() 0 9 2
C testLevel1() 0 35 13
C testLevel2() 0 42 11
D testLevel3() 26 39 19
A testLevel4() 0 13 4
A __construct() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like MaskPatternTester often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MaskPatternTester, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Class MaskPatternTester
4
 *
5
 * @filesource   MaskPatternTester.php
6
 * @created      22.11.2017
7
 * @package      chillerlan\QRCode\Data
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2017 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\QRCode\Data;
14
15
/**
16
 * The sole purpose of this class is to receive a QRMatrix object and run the pattern tests on it.
17
 *
18
 * @link http://www.thonky.com/qr-code-tutorial/data-masking
19
 */
20
class MaskPatternTester{
21
22
	/**
23
	 * @var \chillerlan\QRCode\Data\QRMatrix
24
	 */
25
	protected $matrix;
26
27
	/**
28
	 * @var int
29
	 */
30
	protected $moduleCount;
31
32
	/**
33
	 * Receives the matrix an sets the module count
34
	 *
35
	 * @see \chillerlan\QRCode\QROptions::$maskPattern
36
	 * @see \chillerlan\QRCode\Data\QRMatrix::$maskPattern
37
	 * @see \chillerlan\QRCode\QRCode::getBestMaskPattern()
38
	 *
39
	 * @param \chillerlan\QRCode\Data\QRMatrix $matrix
40
	 */
41
	public function __construct(QRMatrix $matrix){
42
		$this->matrix      = $matrix;
43
		$this->moduleCount = $this->matrix->size();
44
	}
45
46
	/**
47
	 * Returns the penalty for the given mask pattern
48
	 *
49
	 * @see \chillerlan\QRCode\QROptions::$maskPattern
50
	 * @see \chillerlan\QRCode\Data\QRMatrix::$maskPattern
51
	 * @see \chillerlan\QRCode\QRCode::getBestMaskPattern()
52
	 *
53
	 * @return int
54
	 */
55
	public function testPattern():int{
56
		$penalty  = 0;
57
58
		for($level = 1; $level <= 4; $level++){
59
			$penalty += call_user_func([$this, 'testLevel'.$level]);
60
		}
61
62
		return (int)$penalty;
63
	}
64
65
	/**
66
	 * Checks for each group of five or more same-colored modules in a row (or column)
67
	 *
68
	 * @return float
69
	 */
70
	protected function testLevel1():float{
71
		$penalty = 0;
72
73
		foreach($this->matrix->matrix() as $y => $row){
74
			foreach($row as $x => $val){
75
				$count = 0;
76
77
				for($ry = -1; $ry <= 1; $ry++){
78
79
					if($y + $ry < 0 || $this->moduleCount <= $y + $ry){
80
						continue;
81
					}
82
83
					for($rx = -1; $rx <= 1; $rx++){
84
85
						if(($ry === 0 && $rx === 0) || ($x + $rx < 0 || $this->moduleCount <= $x + $rx)){
86
							continue;
87
						}
88
89
						if($this->matrix->check($x + $rx, $y + $ry) === ($val >> 8 > 0)){
90
							$count++;
91
						}
92
93
					}
94
				}
95
96
				if($count > 5){
97
					$penalty += (3 + $count - 5);
98
				}
99
100
			}
101
		}
102
103
		return $penalty;
104
	}
105
106
	/**
107
	 * Checks for each 2x2 area of same-colored modules in the matrix
108
	 *
109
	 * @return float
110
	 */
111
	protected function testLevel2():float{
112
		$penalty = 0;
113
114
		foreach($this->matrix->matrix() as $y => $row){
115
116
			if($y > $this->moduleCount - 2){
117
				break;
118
			}
119
120
			foreach($row as $x => $val){
121
122
				if($x > $this->moduleCount - 2){
123
					break;
124
				}
125
126
				$count = 0;
127
128
				if($val >> 8 > 0){
129
					$count++;
130
				}
131
132
				if($this->matrix->check($y, $x + 1)){
133
					$count++;
134
				}
135
136
				if($this->matrix->check($y + 1, $x)){
137
					$count++;
138
				}
139
140
				if($this->matrix->check($y + 1, $x + 1)){
141
					$count++;
142
				}
143
144
				if($count === 0 || $count === 4){
145
					$penalty += 3;
146
				}
147
148
			}
149
		}
150
151
		return $penalty;
152
	}
153
154
	/**
155
	 * Checks if there are patterns that look similar to the finder patterns
156
	 *
157
	 * @return float
158
	 */
159
	protected function testLevel3():float{
160
		$penalty = 0;
161
162
		foreach($this->matrix->matrix() as $y => $row){
163
			foreach($row as $x => $val){
164
165 View Code Duplication
				if($x <= $this->moduleCount - 7){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
166
					if(
167
						    $this->matrix->check($x    , $y)
168
						&& !$this->matrix->check($x + 1, $y)
169
						&&  $this->matrix->check($x + 2, $y)
170
						&&  $this->matrix->check($x + 3, $y)
171
						&&  $this->matrix->check($x + 4, $y)
172
						&& !$this->matrix->check($x + 5, $y)
173
						&&  $this->matrix->check($x + 6, $y)
174
					){
175
						$penalty += 40;
176
					}
177
				}
178
179 View Code Duplication
				if($y <= $this->moduleCount - 7){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
					if(
181
						    $this->matrix->check($x, $y)
182
						&& !$this->matrix->check($x, $y + 1)
183
						&&  $this->matrix->check($x, $y + 2)
184
						&&  $this->matrix->check($x, $y + 3)
185
						&&  $this->matrix->check($x, $y + 4)
186
						&& !$this->matrix->check($x, $y + 5)
187
						&&  $this->matrix->check($x, $y + 6)
188
					){
189
						$penalty += 40;
190
					}
191
				}
192
193
			}
194
		}
195
196
		return $penalty;
197
	}
198
199
	/**
200
	 * Checks if more than half of the modules are dark or light, with a larger penalty for a larger difference
201
	 *
202
	 * @return float
203
	 */
204
	protected function testLevel4():float {
205
		$count = 0;
206
207
		foreach($this->matrix->matrix() as $y => $row){
208
			foreach($row as $x => $val){
209
				if($val >> 8 > 0){
210
					$count++;
211
				}
212
			}
213
		}
214
215
		return (abs(100 * $count / $this->moduleCount / $this->moduleCount - 50) / 5) * 10;
216
	}
217
218
}
219