Completed
Push — master ( a1c8e7...7d2da4 )
by Thomas
04:30
created

DefaultVisitor::visitUseStatements()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 26
Code Lines 15

Duplication

Lines 5
Ratio 19.23 %

Code Coverage

Tests 16
CRAP Score 7.1929

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 5
loc 26
ccs 16
cts 19
cp 0.8421
rs 6.7273
cc 7
eloc 15
nc 8
nop 1
crap 7.1929
1
<?php
2
/*
3
 * Copyright 2011 Johannes M. Schmitt <[email protected]>
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
namespace gossi\codegen\visitor;
18
19
use gossi\codegen\config\CodeGeneratorConfig;
20
use gossi\codegen\model\AbstractPhpStruct;
21
use gossi\codegen\model\NamespaceInterface;
22
use gossi\codegen\model\PhpClass;
23
use gossi\codegen\model\PhpConstant;
24
use gossi\codegen\model\PhpFunction;
25
use gossi\codegen\model\PhpInterface;
26
use gossi\codegen\model\PhpMethod;
27
use gossi\codegen\model\PhpProperty;
28
use gossi\codegen\model\PhpTrait;
29
use gossi\codegen\model\TraitsInterface;
30
use gossi\codegen\utils\Writer;
31
use gossi\docblock\Docblock;
32
33
/**
34
 * The default code generation visitor.
35
 *
36
 * @author Johannes M. Schmitt <[email protected]>
37
 */
38
class DefaultVisitor implements GeneratorVisitorInterface {
39
40
	protected $writer;
41
42
	protected $scalarTypeHints;
43
	protected $returnTypeHints;
44
45
	protected $config;
46
47
	protected static $noTypeHints = [
48
		'string',
49
		'int',
50
		'integer',
51
		'bool',
52
		'boolean',
53
		'float',
54
		'double',
55
		'object',
56
		'mixed',
57
		'resource'
58
	];
59
60 20
	public function __construct(CodeGeneratorConfig $config = null) {
61
		// Make sure we retain the old default behavior for this class
62 20
		$this->config = $config?: new CodeGeneratorConfig(['generateEmptyDocblock' => false]);
63 20
		$this->writer = new Writer();
64 20
	}
65
66 16
	public function reset() {
67 16
		$this->writer->reset();
68 16
	}
69
70 4
	private function ensureBlankLine() {
71 4
		if (!$this->writer->endsWith("\n\n") && strlen($this->writer->rtrim()->getContent()) > 0) {
72 4
			$this->writer->writeln();
73 4
		}
74 4
	}
75
76 11
	protected function visitNamespace(NamespaceInterface $model) {
77 11
		if ($namespace = $model->getNamespace()) {
78 3
			$this->writer->writeln('namespace ' . $namespace . ';');
79 3
		}
80 11
	}
81
82 11
	protected function visitRequiredFiles(AbstractPhpStruct $struct) {
83 11
		if ($files = $struct->getRequiredFiles()) {
84
			$this->ensureBlankLine();
85
			foreach ($files as $file) {
86
				$this->writer->writeln('require_once ' . var_export($file, true) . ';');
87
			}
88
		}
89 11
	}
90
91 11
	protected function visitUseStatements(AbstractPhpStruct $struct) {
92 11
		if ($useStatements = $struct->getUseStatements()) {
93 2
			$this->ensureBlankLine();
94 2
			foreach ($useStatements as $alias => $namespace) {
95 2 View Code Duplication
				if (false === strpos($namespace, '\\')) {
96
					$commonName = $namespace;
97
				} else {
98 2
					$commonName = substr($namespace, strrpos($namespace, '\\') + 1);
99
				}
100
101 2
				if (false === strpos($namespace, '\\') && !$struct->getNamespace()) {
102
					//avoid fatal 'The use statement with non-compound name '$commonName' has no effect'
103
					continue;
104
				}
105
106 2
				$this->writer->write('use ' . $namespace);
107
108 2
				if ($commonName !== $alias) {
109 1
					$this->writer->write(' as ' . $alias);
110 1
				}
111
112 2
				$this->writer->write(";\n");
113 2
			}
114 2
			$this->ensureBlankLine();
115 2
		}
116 11
	}
117
118 20
	protected function visitDocblock(Docblock $docblock) {
119 20
		if (!$docblock->isEmpty() || $this->config->getGenerateEmptyDocblock()) {
120 2
			$this->writeDocblock($docblock);
121 2
		}
122 20
	}
123
124 2
	protected function writeDocblock(Docblock $docblock) {
125 2
		$docblock = $docblock->toString();
126 2
		if (!empty($docblock)) {
127 2
			$this->ensureBlankLine();
128 2
			$this->writer->writeln($docblock);
129 2
		}
130 2
	}
131
132 10
	protected function visitTraits(TraitsInterface $struct) {
133 10
		foreach ($struct->getTraits() as $trait) {
134
			$this->writer->write('use ');
135
			$this->writer->writeln($trait . ';');
136 10
		}
137 10
	}
138
139 9
	public function startVisitingClass(PhpClass $class) {
140 9
		$this->visitNamespace($class);
141 9
		$this->visitRequiredFiles($class);
142 9
		$this->visitUseStatements($class);
143 9
		$this->visitDocblock($class->getDocblock());
144
145
		// signature
146 9
		if ($class->isAbstract()) {
147
			$this->writer->write('abstract ');
148
		}
149
150 9
		if ($class->isFinal()) {
151
			$this->writer->write('final ');
152
		}
153
154 9
		$this->writer->write('class ');
155 9
		$this->writer->write($class->getName());
156
157 9
		if ($parentClassName = $class->getParentClassName()) {
158
			$this->writer->write(' extends ' . $parentClassName);
159
		}
160
161 9
		if ($class->hasInterfaces()) {
162
			$this->writer->write(' implements ');
163
			$this->writer->write(implode(', ', $class->getInterfaces()));
164
		}
165
166
		// body
167 9
		$this->writer->writeln(" {\n")->indent();
168
169 9
		$this->visitTraits($class);
170 9
	}
171
172 1
	public function startVisitingInterface(PhpInterface $interface) {
173 1
		$this->visitNamespace($interface);
174 1
		$this->visitRequiredFiles($interface);
175 1
		$this->visitUseStatements($interface);
176 1
		$this->visitDocblock($interface->getDocblock());
177
178
		// signature
179 1
		$this->writer->write('interface ');
180 1
		$this->writer->write($interface->getName());
181
182 1
		if ($interface->hasInterfaces()) {
183
			$this->writer->write(' extends ');
184
			$this->writer->write(implode(', ', $interface->getInterfaces()));
185
		}
186
187
		// body
188 1
		$this->writer->writeln(" {\n")->indent();
189 1
	}
190
191 1
	public function startVisitingTrait(PhpTrait $trait) {
192 1
		$this->visitNamespace($trait);
193 1
		$this->visitRequiredFiles($trait);
194 1
		$this->visitUseStatements($trait);
195 1
		$this->visitDocblock($trait->getDocblock());
196
197
		// signature
198 1
		$this->writer->write('trait ');
199 1
		$this->writer->write($trait->getName());
200
201
		// body
202 1
		$this->writer->writeln(" {\n")->indent();
203
204 1
		$this->visitTraits($trait);
205 1
	}
206
207 5
	public function startVisitingStructConstants() {
208 5
	}
209
210 5
	public function visitStructConstant(PhpConstant $constant) {
211 5
		$this->visitDocblock($constant->getDocblock());
212 5
		$this->writer->writeln('const ' . $constant->getName() . ' = ' . $this->getPhpExport($constant->getValue()) . ';');
213 5
	}
214
215 5
	public function endVisitingStructConstants() {
216 5
		$this->writer->write("\n");
217 5
	}
218
219 5
	public function startVisitingProperties() {
220 5
	}
221
222 6
	public function visitProperty(PhpProperty $property) {
223 6
		$this->visitDocblock($property->getDocblock());
224
225 6
		$this->writer->write($property->getVisibility() . ' ' . ($property->isStatic() ? 'static ' : '') . '$' . $property->getName());
226
227 6
		if ($property->hasDefaultValue()) {
228 2
			$this->writer->write(' = ' . $this->getPhpExport($property->getDefaultValue()));
229 2
		}
230
231 6
		$this->writer->writeln(';');
232 6
	}
233
234 6
	protected function getPhpExport($value) {
235
		// Simply to be sure a null value is displayed in lowercase.
236 6
		if (null === $value) {
237
			return 'null';
238
		}
239
240 6
		return var_export($value, true);
241
	}
242
243 5
	public function endVisitingProperties() {
244 5
		$this->writer->writeln();
245 5
	}
246
247 7
	public function startVisitingMethods() {
248 7
	}
249
250 9
	public function visitMethod(PhpMethod $method) {
251 9
		$this->visitDocblock($method->getDocblock());
252
253 9
		if ($method->isAbstract()) {
254
			$this->writer->write('abstract ');
255
		}
256
257 9
		$this->writer->write($method->getVisibility() . ' ');
258
259 9
		if ($method->isStatic()) {
260
			$this->writer->write('static ');
261
		}
262
263 9
		$this->writer->write('function ');
264
265 9
		if ($method->isReferenceReturned()) {
266 1
			$this->writer->write('& ');
267 1
		}
268
269 9
		$this->writer->write($method->getName() . '(');
270
271 9
		$this->writeParameters($method->getParameters());
272 9
		$this->writer->write(")");
273 9
		$this->writeFunctionReturnType($method->getType());
274
275 9
		if ($method->isAbstract() || $method->getParent() instanceof PhpInterface) {
276
			$this->writer->write(";\n\n");
277
278
			return;
279
		}
280
281 9
		$this->writer->writeln(' {')->indent()->writeln(trim($method->getBody()))->outdent()->rtrim()->write("}\n\n");
282 9
	}
283
284 7
	public function endVisitingMethods() {
285 7
	}
286
287 11
	protected function endVisitingStruct(AbstractPhpStruct $struct) {
288 11
		$this->writer->outdent()->rtrim()->write('}');
289 11
	}
290
291 9
	public function endVisitingClass(PhpClass $class) {
292 9
		$this->endVisitingStruct($class);
293 9
	}
294
295 1
	public function endVisitingInterface(PhpInterface $interface) {
296 1
		$this->endVisitingStruct($interface);
297 1
	}
298
299 1
	public function endVisitingTrait(PhpTrait $trait) {
300 1
		$this->endVisitingStruct($trait);
301 1
	}
302
303 6
	public function visitFunction(PhpFunction $function) {
304 6
		if ($namespace = $function->getNamespace()) {
305
			$this->writer->write("namespace $namespace;\n\n");
306
		}
307
308 6
		$this->visitDocblock($function->getDocblock());
309
310 6
		$this->writer->write("function {$function->getName()}(");
311 6
		$this->writeParameters($function->getParameters());
312 6
		$this->writer->write(')');
313 6
		$this->writeFunctionReturnType($function->getType());
314 6
		$this->writer->write(" {\n")->indent()->writeln(trim($function->getBody()))->outdent()->rtrim()->write('}');
315 6
	}
316
317 20
	public function getContent() {
318 20
		return $this->writer->getContent();
319
	}
320
321 15
	protected function writeParameters(array $parameters) {
322 15
		$first = true;
323 15
		foreach ($parameters as $parameter) {
324 10
			if (!$first) {
325 2
				$this->writer->write(', ');
326 2
			}
327 10
			$first = false;
328
329 10
			if (false === strpos($parameter->getType(), '|') &&
330 10
				($type = $parameter->getType()) &&
331 10
				(!in_array($type, self::$noTypeHints) || $this->config->getGenerateScalarTypeHints())) {
332 4
				$this->writer->write($type . ' ');
333 4
			}
334
335 10
			if ($parameter->isPassedByReference()) {
336
				$this->writer->write('&');
337
			}
338
339 10
			$this->writer->write('$' . $parameter->getName());
340
341 10
			if ($parameter->hasDefaultValue()) {
342 1
				$this->writer->write(' = ');
343 1
				$defaultValue = $parameter->getDefaultValue();
344
345 1
				switch (true) {
346 1
					case is_array($defaultValue) && empty($defaultValue):
347
						$this->writer->write('array()');
348
						break;
349 1
					case ($defaultValue instanceof PhpConstant):
350
						$this->writer->write($defaultValue->getName());
351
						break;
352 1
					default:
353 1
					$this->writer->write($this->getPhpExport($defaultValue));
354
355 1
				}
356 1
			}
357 15
		}
358 15
	}
359
360 15
	protected function writeFunctionReturnType($type) {
361 15
		if ($this->config->getGenerateReturnTypeHints() && $type != NULL && false === strpos($type, '|')) {
362 2
			$this->writer->write(': ')->write($type);
363 2
		}
364 15
	}
365
}
366