Completed
Push — master ( 146f46...ce721c )
by Thomas
03:30
created

GeneratorVisitor::startVisitingInterface()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 2.0491

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 18
ccs 10
cts 13
cp 0.7692
rs 9.4285
cc 2
eloc 11
nc 2
nop 1
crap 2.0491
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 GeneratorVisitor 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 22
	public function __construct(CodeGeneratorConfig $config = null) {
61
		// Make sure we retain the old default behavior for this class
62 22
		$this->config = $config ?: new CodeGeneratorConfig(['generateEmptyDocblock' => false]);
63 22
		$this->writer = new Writer();
64 22
	}
65
66 18
	public function reset() {
67 18
		$this->writer->reset();
68 18
	}
69
70 5
	private function ensureBlankLine() {
71 5
		if (!$this->writer->endsWith("\n\n") && strlen($this->writer->rtrim()->getContent()) > 0) {
72 5
			$this->writer->writeln();
73 5
		}
74 5
	}
75
76 13
	protected function visitNamespace(NamespaceInterface $model) {
77 13
		if ($namespace = $model->getNamespace()) {
78 3
			$this->writer->writeln('namespace ' . $namespace . ';');
79 3
		}
80 13
	}
81
82 13
	protected function visitRequiredFiles(AbstractPhpStruct $struct) {
83 13
		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 13
	}
90
91 13
	protected function visitUseStatements(AbstractPhpStruct $struct) {
92 13
		if ($useStatements = $struct->getUseStatements()) {
93 3
			$this->ensureBlankLine();
94 3
			foreach ($useStatements as $alias => $namespace) {
95 3
				if (false === strpos($namespace, '\\')) {
96
					$commonName = $namespace;
97
				} else {
98 3
					$commonName = substr($namespace, strrpos($namespace, '\\') + 1);
99
				}
100
101 3
				if (false === strpos($namespace, '\\') && !$struct->getNamespace()) {
102
					//avoid fatal 'The use statement with non-compound name '$commonName' has no effect'
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
103
					continue;
104
				}
105
106 3
				$this->writer->write('use ' . $namespace);
107
108 3
				if ($commonName !== $alias) {
109 1
					$this->writer->write(' as ' . $alias);
110 1
				}
111
112 3
				$this->writer->write(";\n");
113 3
			}
114 3
			$this->ensureBlankLine();
115 3
		}
116 13
	}
117
118 22
	protected function visitDocblock(Docblock $docblock) {
119 22
		if (!$docblock->isEmpty() || $this->config->getGenerateEmptyDocblock()) {
120 3
			$this->writeDocblock($docblock);
121 3
		}
122 22
	}
123
124 3
	protected function writeDocblock(Docblock $docblock) {
125 3
		$docblock = $docblock->toString();
126 3
		if (!empty($docblock)) {
127 3
			$this->ensureBlankLine();
128 3
			$this->writer->writeln($docblock);
129 3
		}
130 3
	}
131
132 12
	protected function visitTraits(TraitsInterface $struct) {
133 12
		foreach ($struct->getTraits() as $trait) {
134
			$this->writer->write('use ');
135
			$this->writer->writeln($trait . ';');
136 12
		}
137 12
	}
138
139 11
	public function startVisitingClass(PhpClass $class) {
140 11
		$this->visitNamespace($class);
141 11
		$this->visitRequiredFiles($class);
142 11
		$this->visitUseStatements($class);
143 11
		$this->visitDocblock($class->getDocblock());
144
145
		// signature
146 11
		if ($class->isAbstract()) {
147
			$this->writer->write('abstract ');
148
		}
149
150 11
		if ($class->isFinal()) {
151
			$this->writer->write('final ');
152
		}
153
154 11
		$this->writer->write('class ');
155 11
		$this->writer->write($class->getName());
156
157 11
		if ($parentClassName = $class->getParentClassName()) {
158
			$this->writer->write(' extends ' . $parentClassName);
159
		}
160
161 11
		if ($class->hasInterfaces()) {
162
			$this->writer->write(' implements ');
163
			$this->writer->write(implode(', ', $class->getInterfaces()));
164
		}
165
166
		// body
167 11
		$this->writer->writeln(" {\n")->indent();
168
169 11
		$this->visitTraits($class);
170 11
	}
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 6
	public function startVisitingStructConstants() {
208 6
	}
209
210 6
	public function visitStructConstant(PhpConstant $constant) {
211 6
		$this->visitDocblock($constant->getDocblock());
212 6
		$this->writer->writeln('const ' . $constant->getName() . ' = ' . $this->getPhpExport($constant->getValue()) . ';');
213 6
	}
214
215 6
	public function endVisitingStructConstants() {
216 6
		$this->writer->write("\n");
217 6
	}
218
219 6
	public function startVisitingProperties() {
220 6
	}
221
222 7
	public function visitProperty(PhpProperty $property) {
223 7
		$this->visitDocblock($property->getDocblock());
224
225 7
		$this->writer->write($property->getVisibility() . ' ' . ($property->isStatic() ? 'static ' : '') . '$' . $property->getName());
226
227 7
		if ($property->hasValue()) {
228 3
			if ($property->isExpression()) {
229 1
				$this->writer->write(' = ' . $property->getExpression());
230 1
			} else {
231 2
				$this->writer->write(' = ' . $this->getPhpExport($property->getValue()));
232
			}
233 3
		}
234
235 7
		$this->writer->writeln(';');
236 7
	}
237
238 7
	protected function getPhpExport($value) {
239
		// Simply to be sure a null value is displayed in lowercase.
240 7
		if (null === $value) {
241
			return 'null';
242
		}
243
244 7
		return var_export($value, true);
245
	}
246
247 6
	public function endVisitingProperties() {
248 6
		$this->writer->writeln();
249 6
	}
250
251 8
	public function startVisitingMethods() {
252 8
	}
253
254 10
	public function visitMethod(PhpMethod $method) {
255 10
		$this->visitDocblock($method->getDocblock());
256
257 10
		if ($method->isAbstract()) {
258
			$this->writer->write('abstract ');
259
		}
260
261 10
		$this->writer->write($method->getVisibility() . ' ');
262
263 10
		if ($method->isStatic()) {
264
			$this->writer->write('static ');
265
		}
266
267 10
		$this->writer->write('function ');
268
269 10
		if ($method->isReferenceReturned()) {
270 1
			$this->writer->write('& ');
271 1
		}
272
273 10
		$this->writer->write($method->getName() . '(');
274
275 10
		$this->writeParameters($method->getParameters());
276 10
		$this->writer->write(")");
277 10
		$this->writeFunctionReturnType($method->getType());
278
279 10
		if ($method->isAbstract() || $method->getParent() instanceof PhpInterface) {
280
			$this->writer->write(";\n\n");
281
282
			return;
283
		}
284
285 10
		$this->writer->writeln(' {')->indent()->writeln(trim($method->getBody()))->outdent()->rtrim()->write("}\n\n");
286 10
	}
287
288 8
	public function endVisitingMethods() {
289 8
	}
290
291 13
	protected function endVisitingStruct(AbstractPhpStruct $struct) {
292 13
		$this->writer->outdent()->rtrim()->write('}');
293 13
	}
294
295 11
	public function endVisitingClass(PhpClass $class) {
296 11
		$this->endVisitingStruct($class);
297 11
	}
298
299 1
	public function endVisitingInterface(PhpInterface $interface) {
300 1
		$this->endVisitingStruct($interface);
301 1
	}
302
303 1
	public function endVisitingTrait(PhpTrait $trait) {
304 1
		$this->endVisitingStruct($trait);
305 1
	}
306
307 6
	public function visitFunction(PhpFunction $function) {
308 6
		if ($namespace = $function->getNamespace()) {
309
			$this->writer->write("namespace $namespace;\n\n");
310
		}
311
312 6
		$this->visitDocblock($function->getDocblock());
313
314 6
		$this->writer->write("function {$function->getName()}(");
315 6
		$this->writeParameters($function->getParameters());
316 6
		$this->writer->write(')');
317 6
		$this->writeFunctionReturnType($function->getType());
318 6
		$this->writer->write(" {\n")->indent()->writeln(trim($function->getBody()))->outdent()->rtrim()->write('}');
319 6
	}
320
321 22
	public function getContent() {
322 22
		return $this->writer->getContent();
323
	}
324
325 16
	protected function writeParameters(array $parameters) {
326 16
		$first = true;
327 16
		foreach ($parameters as $parameter) {
328 11
			if (!$first) {
329 2
				$this->writer->write(', ');
330 2
			}
331 11
			$first = false;
332
333 11
			if (false === strpos($parameter->getType(), '|') &&
334 11
				($type = $parameter->getType()) &&
335 11
				(!in_array($type, self::$noTypeHints) || $this->config->getGenerateScalarTypeHints())) {
336 4
				$this->writer->write($type . ' ');
337 4
			}
338
339 11
			if ($parameter->isPassedByReference()) {
340
				$this->writer->write('&');
341
			}
342
343 11
			$this->writer->write('$' . $parameter->getName());
344
345 11
			if ($parameter->hasValue()) {
346 2
				$this->writer->write(' = ');
347
348 2
				if ($parameter->isExpression()) {
349 1
					$this->writer->write($parameter->getExpression());
350 1
				} else {
351 1
					$value = $parameter->getValue();
352
353 1
					if (is_array($value) && empty($value)) {
354
						$this->writer->write('[]');
355 1
					} else if ($value instanceof PhpConstant) {
356
						$this->writer->write($value->getName());
357
					} else {
358 1
						$this->writer->write($this->getPhpExport($value));
359
					}
360
				}
361 2
			}
362 16
		}
363 16
	}
364
365 16
	protected function writeFunctionReturnType($type) {
366 16
		if ($this->config->getGenerateReturnTypeHints() && $type != NULL && false === strpos($type, '|')) {
367 2
			$this->writer->write(': ')->write($type);
368 2
		}
369 16
	}
370
}
371