Completed
Push — master ( 66405f...98cd2e )
by Thomas
06:52
created

CodeGeneratorService::mapToCode()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 12
Ratio 100 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 12
loc 12
ccs 4
cts 4
cp 1
rs 9.4285
cc 3
eloc 7
nc 4
nop 1
crap 3
1
<?php
2
namespace keeko\tools\services;
3
4
use gossi\codegen\generator\CodeFileGenerator;
5
use gossi\codegen\model\AbstractPhpStruct;
6
use gossi\docblock\tags\AuthorTag;
7
use keeko\framework\schema\CodegenSchema;
8
use keeko\framework\schema\PackageSchema;
9
use keeko\tools\utils\NamespaceResolver;
10
use phootwork\file\File;
11
use phootwork\file\Path;
12
use Propel\Generator\Model\Table;
13
14
class CodeGeneratorService extends AbstractService {
15
	
16
	private $codegen;
17
	
18
	public function getCodegenFile() {
19 7
		$basepath = dirname($this->project->getComposerFileName());
20 7
		return $basepath . '/codegen.json';
21 7
	}
22
	
23
	/**
24
	 * Loads the contents from codegen.json into a collection
25
	 *
26
	 * @throws JsonEmptyException
27
	 * @throws \RuntimeException
28
	 * @return CodegenSchema
29
	 */
30
	public function getCodegen() {
31 12
		if ($this->codegen === null) {
32 7
			$file = new File($this->getCodegenFile());
33 7
			$this->codegen = $file->exists() 
34 7
				? CodegenSchema::fromFile($this->getCodegenFile())
35
				: new CodegenSchema();
36 7
		}
37 12
		
38
		return $this->codegen;
39
	}
40
	
41
// 	/**
42
// 	 * Returns the codegen part for the given action name or an empty map
43
// 	 *
44
// 	 * @param string $name
45
// 	 * @return Map
46
// 	 */
47
// 	public function getCodegenAction($name) {
48
// 		$codegen = $this->getCodegen();
49
	
50
// 		if (isset($codegen['actions'])) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
68% 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...
51
// 			$actions = $codegen['actions'];
52
				
53
// 			if (isset($actions[$name])) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% 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...
54
// 				return $actions[$name];
55
// 			}
56
// 		}
57
	
58
// 		return null;
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
59
// 	}
60
	
61
	/**
62
	 * Adds authors to the docblock of the given struct
63
	 *
64
	 * @param AbstractPhpStruct $struct
65 15
	 * @param array $package
66 15
	 */
67
	public function addAuthors(AbstractPhpStruct $struct, PackageSchema $package) {
68 15
		$docblock = $struct->getDocblock();
69
		
70
		foreach ($package->getAuthors() as $author) {
71 15
			/* @var $author AuthorSchema */
72 15
			$tag = AuthorTag::create()->setName($author->getName());
73 15
			$mail = $author->getEmail();
74
75 15
			if (!empty($mail)) {
76
				$tag->setEmail($mail);
77 15
			}
78
79
			$docblock->appendTag($tag);
80
		}
81 15
	}
82 15
83 15
	/**
84
	 * Returns code for hydrating a propel model
85
	 *
86
	 * @param string $modelName
87
	 * @return string
88
	 */
89
	public function getWriteFields($modelName) {
90
		$codegen = $this->getCodegen();
91 5
		$filter = $codegen->getWriteFilter($modelName);
92 5
		$model = $this->modelService->getModel($modelName);
93 5
		$computed = $this->getComputedFields($model);
1 ignored issue
show
Bug introduced by
It seems like $model defined by $this->modelService->getModel($modelName) on line 92 can be null; however, keeko\tools\services\Cod...ce::getComputedFields() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
94 5
		$filter = array_merge($filter, $computed);
95 5
96 5
		$fields = [];
97 5
		$cols = $model->getColumns();
98
		foreach ($cols as $col) {
99 5
			$prop = $col->getName();
100 5
	
101 5
			if (!in_array($prop, $filter)) {
102 5
				$fields[] = $prop;
103
			}
104 5
		}
105 5
	
106
		return $fields;
107 5
	}
108
	
109
	/**
110
	 * Returns the fields for a model
111 5
	 * 
112 5
	 * @param string $modelName
113 5
	 * @return array
114
	 */
115 5
	public function getReadFields($modelName) {
116 5
		$codegen = $this->getCodegen();
117 5
		$model = $this->modelService->getModel($modelName);
118
// 		$computed = $this->getComputedFields($model);
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% 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...
119 5
		$filter = $codegen->getReadFilter($modelName);
120
// 		$filter = array_merge($filter, $computed);
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% 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...
121
		
122
		$fields = [];
123
		$cols = $model->getColumns();
124
		foreach ($cols as $col) {
125
			$prop = $col->getName();
126
		
127
			if (!in_array($prop, $filter)) {
128
				$fields[] = $prop;
129
			}
130
		}
131
		
132
		return $fields;
133
	}
134
	
135
// 	/**
136
// 	 * Returns conversions for model columns
137
// 	 *
138
// 	 * @param string $model
139
// 	 * @param string $type
140
// 	 * @return array
141
// 	 */
142
// 	public function getConversions($model, $type) {
143
// 		return $this->getActionProp($model, $type, 'conversion');
144
// 	}
145
	
146
// 	/**
147
// 	 * Returns model columns that should be filtered
148
// 	 *
149
// 	 * @param string $model
150 5
// 	 * @param string $type
151 5
// 	 * @return array
152
// 	 */
153
// 	public function getFilter($model, $type) {
154 5
// 		return $this->getActionProp($model, $type, 'filter');
155 5
// 	}
156 5
	
157 5
	/**
158 5
	 * Returns computed model fields
159 5
	 *
160
	 * @param Table $table
161 5
	 * @return array<string>
162
	 */
163
	public function getComputedFields(Table $table) {
164 5
		$fields = [];
165 5
	
166
		// iterate over behaviors to get their respective columns
167 5
		foreach ($table->getBehaviors() as $behavior) {
168
			switch ($behavior->getName()) {
169
				case 'timestampable':
170
					$fields[] = $behavior->getParameter('create_column');
171
					$fields[] = $behavior->getParameter('update_column');
172
					break;
173
	
174
				case 'aggregate_column':
175
					$fields[] = $behavior->getParameter('name');
176 2
					break;
177 2
			}
178 2
		}
179
	
180 2
		return $fields;
181
	}
182 2
	
183
	/**
184
	 * Helper to represent an array as php code
185
	 *
186 2
	 * @param array $array
187
	 * @return string
188
	 */
189 15
	public function arrayToCode(array $array) {
190 15
		$fields = '';
191 15
		foreach ($array as $item) {
192
			$fields .= sprintf("'%s', ", $item);
193 15
		}
194
	
195
		if (strlen($fields) > 0) {
196
			$fields = substr($fields, 0, -2);
197 15
		}
198 15
	
199 15
		return sprintf('[%s]', $fields);
200 15
	}
201 15
	
202
// 	public function mapToCode(array $array) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
52% 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...
203
// 		$fields = '';
204 15
// 		foreach ($array as $k => $item) {
205 15
// 			$fields .= sprintf("\t'%s' => %s,\n", $k, $this->arrayToCode($item));
206 15
// 		}
207
208 15
// 		if (strlen($fields) > 0) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
209
// 			$fields = substr($fields, 0, -2);
210 15
// 		}
211 15
		
212
// 		return sprintf("[\n%s\n]", $fields);
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% 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...
213
// 	}
214 15
215
	/**
216
	 * Returns the filename for a given struct
217 15
	 * 
218 15
	 * @param AbstractPhpStruct $struct
219 15
	 * @return string
220
	 */
221
	public function getFilename(AbstractPhpStruct $struct) {
222
		$package = $this->packageService->getPackage();
223
		$relativeSourcePath = NamespaceResolver::getSourcePath($struct->getNamespace(), $package);
224
		
225
		if ($relativeSourcePath === null) {
226
			return null;
227
		}
228
229
		$jsonFile = $this->project->getComposerFileName();
230
		$path = new Path(dirname($jsonFile));
231
		$path = $path->append($relativeSourcePath);
232
		$path = $path->append($struct->getName() . '.php');
233
		return $path->toString();
234
	}
235
	
236
	public function dumpStruct(AbstractPhpStruct $struct, $overwrite = false) {
237
		$filename = $this->getFilename($struct);
238
		$file = new File($filename);
239
240
		if ($filename !== null && $file->exists() ? $overwrite : true) {
241
			// generate code
242
			$generator = new CodeFileGenerator();
243
			$code = $generator->generate($struct);
0 ignored issues
show
Documentation introduced by
$struct is of type object<gossi\codegen\model\AbstractPhpStruct>, but the function expects a object<gossi\codegen\model\GenerateableInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
244
245
			// write code to file
246
			$file->write($code);
247
			
248
			// tell user about
249
			$this->io->writeln(sprintf('Class <info>%s</info> written at <info>%s</info>', $struct->getQualifiedName(), $filename));
250
		}
251
	}
252
}
253