Completed
Push — master ( 713b15...55b21a )
by Thomas
03:46
created

GeneratorVisitor::getContent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
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
		}
74 5
	}
75
76 13
	protected function visitNamespace(NamespaceInterface $model) {
77 13
		if ($namespace = $model->getNamespace()) {
78 3
			$this->writer->writeln('namespace ' . $namespace . ';');
79
		}
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
				}
111
112 3
				$this->writer->write(";\n");
113
			}
114 3
			$this->ensureBlankLine();
115
		}
116 13
	}
117
118 22
	protected function visitDocblock(Docblock $docblock) {
119 22
		if (!$docblock->isEmpty() || $this->config->getGenerateEmptyDocblock()) {
120 3
			$this->writeDocblock($docblock);
121
		}
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
		}
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
		}
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->write('const ' . $constant->getName() . ' = ');
213
214 6
		if ($constant->isExpression()) {
215
			$this->writer->write($constant->getExpression());
216
		} else {
217 6
			$this->writer->write($this->getPhpExport($constant->getValue()));
218
		}
219
220 6
		$this->writer->writeln(';');
221 6
	}
222
223 6
	public function endVisitingStructConstants() {
224 6
		$this->writer->write("\n");
225 6
	}
226
227 6
	public function startVisitingProperties() {
228 6
	}
229
230 7
	public function visitProperty(PhpProperty $property) {
231 7
		$this->visitDocblock($property->getDocblock());
232
233 7
		$this->writer->write($property->getVisibility() . ' ' . ($property->isStatic() ? 'static ' : '') . '$' . $property->getName());
234
235 7
		if ($property->hasValue()) {
236 3
			if ($property->isExpression()) {
237 1
				$this->writer->write(' = ' . $property->getExpression());
238
			} else {
239 2
				$this->writer->write(' = ' . $this->getPhpExport($property->getValue()));
240
			}
241
		}
242
243 7
		$this->writer->writeln(';');
244 7
	}
245
246 7
	protected function getPhpExport($value) {
247
		// Simply to be sure a null value is displayed in lowercase.
248 7
		if (null === $value) {
249
			return 'null';
250
		}
251
252 7
		return var_export($value, true);
253
	}
254
255 6
	public function endVisitingProperties() {
256 6
		$this->writer->writeln();
257 6
	}
258
259 8
	public function startVisitingMethods() {
260 8
	}
261
262 10
	public function visitMethod(PhpMethod $method) {
263 10
		$this->visitDocblock($method->getDocblock());
264
265 10
		if ($method->isAbstract()) {
266
			$this->writer->write('abstract ');
267
		}
268
269 10
		$this->writer->write($method->getVisibility() . ' ');
270
271 10
		if ($method->isStatic()) {
272
			$this->writer->write('static ');
273
		}
274
275 10
		$this->writer->write('function ');
276
277 10
		if ($method->isReferenceReturned()) {
278 1
			$this->writer->write('& ');
279
		}
280
281 10
		$this->writer->write($method->getName() . '(');
282
283 10
		$this->writeParameters($method->getParameters());
284 10
		$this->writer->write(')');
285 10
		$this->writeFunctionReturnType($method->getType());
286
287 10
		if ($method->isAbstract() || $method->getParent() instanceof PhpInterface) {
288
			$this->writer->write(";\n\n");
289
290
			return;
291
		}
292
293 10
		$this->writer->writeln(' {')->indent()->writeln(trim($method->getBody()))->outdent()->rtrim()->write("}\n\n");
294 10
	}
295
296 8
	public function endVisitingMethods() {
297 8
	}
298
299 13
	protected function endVisitingStruct(AbstractPhpStruct $struct) {
300 13
		$this->writer->outdent()->rtrim()->write('}');
301 13
	}
302
303 11
	public function endVisitingClass(PhpClass $class) {
304 11
		$this->endVisitingStruct($class);
305 11
	}
306
307 1
	public function endVisitingInterface(PhpInterface $interface) {
308 1
		$this->endVisitingStruct($interface);
309 1
	}
310
311 1
	public function endVisitingTrait(PhpTrait $trait) {
312 1
		$this->endVisitingStruct($trait);
313 1
	}
314
315 6
	public function visitFunction(PhpFunction $function) {
316 6
		if ($namespace = $function->getNamespace()) {
317
			$this->writer->write("namespace $namespace;\n\n");
318
		}
319
320 6
		$this->visitDocblock($function->getDocblock());
321
322 6
		$this->writer->write("function {$function->getName()}(");
323 6
		$this->writeParameters($function->getParameters());
324 6
		$this->writer->write(')');
325 6
		$this->writeFunctionReturnType($function->getType());
326 6
		$this->writer->write(" {\n")->indent()->writeln(trim($function->getBody()))->outdent()->rtrim()->write('}');
327 6
	}
328
329 22
	public function getContent() {
330 22
		return $this->writer->getContent();
331
	}
332
333 16
	protected function writeParameters(array $parameters) {
334 16
		$first = true;
335 16
		foreach ($parameters as $parameter) {
336 11
			if (!$first) {
337 2
				$this->writer->write(', ');
338
			}
339 11
			$first = false;
340
341 11
			if (false === strpos($parameter->getType(), '|') &&
342 11
				($type = $parameter->getType()) &&
343 11
				(!in_array($type, self::$noTypeHints) || $this->config->getGenerateScalarTypeHints())) {
344 4
				$this->writer->write($type . ' ');
345
			}
346
347 11
			if ($parameter->isPassedByReference()) {
348
				$this->writer->write('&');
349
			}
350
351 11
			$this->writer->write('$' . $parameter->getName());
352
353 11
			if ($parameter->hasValue()) {
354 2
				$this->writer->write(' = ');
355
356 2
				if ($parameter->isExpression()) {
357 1
					$this->writer->write($parameter->getExpression());
358
				} else {
359 1
					$value = $parameter->getValue();
360
361 1
					if (is_array($value) && empty($value)) {
362
						$this->writer->write('[]');
363 1
					} else if ($value instanceof PhpConstant) {
364
						$this->writer->write($value->getName());
365
					} else {
366 11
						$this->writer->write($this->getPhpExport($value));
367
					}
368
				}
369
			}
370
		}
371 16
	}
372
373
	/**
374
	 * @param string $type
375
	 */
376 16
	protected function writeFunctionReturnType($type) {
377 16
		if ($this->config->getGenerateReturnTypeHints() && $type != null && false === strpos($type, '|')) {
378 2
			$this->writer->write(': ')->write($type);
379
		}
380 16
	}
381
}
382