Completed
Pull Request — master (#30)
by
unknown
03:31
created

GeneratorNavigator::visitStruct()   D

Complexity

Conditions 15
Paths 288

Size

Total Lines 61
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 40
CRAP Score 15

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 61
ccs 40
cts 40
cp 1
rs 4.5972
cc 15
eloc 39
nc 288
nop 2
crap 15

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * Copyright 2011 Johannes M. Schmitt <[email protected]>
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
namespace gossi\codegen\visitor;
19
20
use gossi\codegen\model\AbstractPhpStruct;
21
use gossi\codegen\model\ConstantsInterface;
22
use gossi\codegen\model\GenerateableInterface;
23
use gossi\codegen\model\PhpClass;
24
use gossi\codegen\model\PhpFunction;
25
use gossi\codegen\model\PhpInterface;
26
use gossi\codegen\model\PhpTrait;
27
use gossi\codegen\model\TraitsInterface;
28
29
/**
30
 * The default navigator.
31
 *
32
 * This class is responsible for the default traversal algorithm of the different
33
 * code elements.
34
 *
35
 * Unlike other visitor pattern implementations, this allows to separate the
36
 * traversal logic from the objects that are traversed.
37
 *
38
 * @author Johannes M. Schmitt <[email protected]>
39
 */
40
class GeneratorNavigator {
41
42
	private $constantSortFunc;
43
44
	private $propertySortFunc;
45
46
	private $methodSortFunc;
47
48
	private $useStatementSortFunc;
49
50
	private static $defaultMethodSortFunc;
51
52
	private static $defaultPropertySortFunc;
53
54
	private static $defaultUseStatementSortFunc;
55
56
	/**
57
	 * Sets a custom constant sorting function.
58
	 *
59
	 * @param null|\Closure $func
60
	 */
61 2
	public function setConstantSortFunc(\Closure $func = null) {
62 2
		$this->constantSortFunc = $func;
63 2
	}
64
65
	/**
66
	 * Sets a custom property sorting function.
67
	 *
68
	 * @param null|\Closure $func
69
	 */
70 2
	public function setPropertySortFunc(\Closure $func = null) {
71 2
		$this->propertySortFunc = $func;
72 2
	}
73
74
	/**
75
	 * Sets a custom method sorting function.
76
	 *
77
	 * @param null|\Closure $func
78
	 */
79 2
	public function setMethodSortFunc(\Closure $func = null) {
80 2
		$this->methodSortFunc = $func;
81 2
	}
82
83
	/**
84
	 * Sets a custom method sorting function.
85
	 *
86
	 * @param null|\Closure $func
87
	 */
88
	public function setUseStatementSortFunc(\Closure $func = null) {
89
		$this->useStatementSortFunc = $func;
90
	}
91
92 18
	public function accept(GeneratorVisitorInterface $visitor, GenerateableInterface $model) {
93 18
		if ($model instanceof AbstractPhpStruct) {
94 13
			$this->visitStruct($visitor, $model);
95 5
		} else if ($model instanceof PhpFunction) {
96 5
			$visitor->visitFunction($model);
97
		}
98 18
	}
99
100 13
	private function visitStruct(GeneratorVisitorInterface $visitor, AbstractPhpStruct $struct) {
101
		// start struct - sort use statements
102 13
		$useStatements = $struct->getUseStatements();
103 13
		uasort($useStatements, $this->getUseStatementSortFunc());
104 13
		$struct->setUseStatements($useStatements);
105
106 13
		if ($struct instanceof PhpInterface) {
107 1
			$visitor->startVisitingInterface($struct);
108 12
		} else if ($struct instanceof PhpTrait) {
109 1
			$visitor->startVisitingTrait($struct);
110 11
		} else if ($struct instanceof PhpClass) {
111 11
			$visitor->startVisitingClass($struct);
112
		}
113
114
		// contents
115 13
		if ($struct instanceof ConstantsInterface) {
116 12
			$constants = $struct->getConstants(true);
117 12
			if (!empty($constants)) {
118 6
				uksort($constants, $this->getConstantSortFunc());
119
120 6
				$visitor->startVisitingStructConstants();
121 6
				foreach ($constants as $constant) {
122 6
					$visitor->visitStructConstant($constant);
123
				}
124 6
				$visitor->endVisitingStructConstants();
125
			}
126
		}
127
128 13
		if ($struct instanceof TraitsInterface) {
129 12
			$properties = $struct->getProperties();
130 12
			if (!empty($properties)) {
131 6
				usort($properties, $this->getPropertySortFunc());
132
133 6
				$visitor->startVisitingProperties();
134 6
				foreach ($properties as $property) {
135 6
					$visitor->visitProperty($property);
136
				}
137 6
				$visitor->endVisitingProperties();
138
			}
139
		}
140
141 13
		$methods = $struct->getMethods();
142 13
		if (!empty($methods)) {
143 8
			usort($methods, $this->getMethodSortFunc());
144
145 8
			$visitor->startVisitingMethods();
146 8
			foreach ($methods as $method) {
147 8
				$visitor->visitMethod($method);
148
			}
149 8
			$visitor->endVisitingMethods();
150
		}
151
152
		// end struct
153 13
		if ($struct instanceof PhpInterface) {
154 1
			$visitor->endVisitingInterface($struct);
155 12
		} else if ($struct instanceof PhpTrait) {
156 1
			$visitor->endVisitingTrait($struct);
157 11
		} else if ($struct instanceof PhpClass) {
158 11
			$visitor->endVisitingClass($struct);
159
		}
160 13
	}
161
162
	/**
163
	 * Returns the constants sort function
164
	 *
165
	 * @return \Closure
166
	 */
167 6
	private function getConstantSortFunc() {
168 6
		return $this->constantSortFunc ?: 'strcasecmp';
169
	}
170
171
	/**
172
	 * Returns the use statements sort function
173
	 *
174
	 * @return \Closure
175
	 */
176 13
	private function getUseStatementSortFunc() {
177 13
		if (null !== $this->useStatementSortFunc) {
178
			return $this->useStatementSortFunc;
179
		}
180
181 13
		if (empty(self::$defaultUseStatementSortFunc)) {
182
			self::$defaultUseStatementSortFunc = function ($s1, $s2) {
183
				// find first difference
184 1
				$cmp1 = null;
185 1
				$cmp2 = null;
186 1
				$min = min(strlen($s1), strlen($s2));
187 1
				for ($i = 0; $i < $min; $i++) {
188 1
					if ($s1[$i] != $s2[$i]) {
189 1
						$cmp1 = $s1[$i];
190 1
						$cmp2 = $s2[$i];
191 1
						break;
192
					}
193
				}
194
195 1
				if ($cmp1 === null && $cmp2 === null) {
196
					return 0;
197
				}
198
199
				$getAscii = function ($str) {
200 1
					$ord = ord($str);
201 1
					if ($ord >= 65 && $ord <= 90) {
202 1
						$ord += 32;
203 1
					} else if ($ord >= 97 && $ord <= 122) {
204 1
						$ord -= 32;
205
					}
206 1
					return $ord;
207 1
				};
208
209 1
				return $getAscii($cmp1) - $getAscii($cmp2);
210 1
			};
211
		}
212
213 13
		return self::$defaultUseStatementSortFunc;
214
	}
215
216
	/**
217
	 * Returns the methods sort function
218
	 *
219
	 * @return \Closure
220
	 */
221 8
	private function getMethodSortFunc() {
222 8
		if (null !== $this->methodSortFunc) {
223 2
			return $this->methodSortFunc;
224
		}
225
226 6
		if (empty(self::$defaultMethodSortFunc)) {
227
			self::$defaultMethodSortFunc = function ($a, $b) {
228 2
				if ($a->isStatic() !== $isStatic = $b->isStatic()) {
229
					return $isStatic ? 1 : -1;
230
				}
231
232 2
				if (($aV = $a->getVisibility()) !== $bV = $b->getVisibility()) {
233
					$aV = 'public' === $aV ? 3 : ('protected' === $aV ? 2 : 1);
234
					$bV = 'public' === $bV ? 3 : ('protected' === $bV ? 2 : 1);
235
236
					return $aV > $bV ? -1 : 1;
237
				}
238
239 2
				return strcasecmp($a->getName(), $b->getName());
240 1
			};
241
		}
242
243 6
		return self::$defaultMethodSortFunc;
244
	}
245
246
	/**
247
	 * Returns the properties sort func
248
	 *
249
	 * @return \Closure
250
	 */
251 6
	private function getPropertySortFunc() {
252 6
		if (null !== $this->propertySortFunc) {
253 2
			return $this->propertySortFunc;
254
		}
255
256 4
		if (empty(self::$defaultPropertySortFunc)) {
257 2
			self::$defaultPropertySortFunc = function ($a, $b) {
258 2
				if (($aV = $a->getVisibility()) !== $bV = $b->getVisibility()) {
259
					$aV = 'public' === $aV ? 3 : ('protected' === $aV ? 2 : 1);
260
					$bV = 'public' === $bV ? 3 : ('protected' === $bV ? 2 : 1);
261
262
					return $aV > $bV ? -1 : 1;
263
				}
264
265 2
				return strcasecmp($a->getName(), $b->getName());
266 1
			};
267
		}
268
269 4
		return self::$defaultPropertySortFunc;
270
	}
271
}
272