Completed
Push — master ( 43a701...9aa864 )
by Thomas
13:49
created

generateRelationshipMethods()   C

Complexity

Conditions 7
Paths 11

Size

Total Lines 141
Code Lines 84

Duplication

Lines 0
Ratio 0 %

Importance

Changes 9
Bugs 2 Features 1
Metric Value
c 9
b 2
f 1
dl 0
loc 141
rs 6.4589
cc 7
eloc 84
nc 11
nop 2

How to fix   Long Method   

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
namespace keeko\tools\generator\serializer\base;
3
4
use gossi\codegen\model\PhpMethod;
5
use gossi\codegen\model\PhpParameter;
6
use gossi\codegen\model\PhpTrait;
7
use keeko\framework\utils\NameUtils;
8
use keeko\tools\generator\serializer\AbstractSerializerGenerator;
9
use keeko\tools\model\Relationship;
10
use Propel\Generator\Model\Table;
11
use gossi\codegen\model\PhpProperty;
12
13
class ModelSerializerTraitGenerator extends AbstractSerializerGenerator {
14
15
	/**
16
	 *
17
	 * @param Table $model
18
	 * @return PhpTrait
19
	 */
20
	public function generate(Table $model) {
21
		$ns = $this->packageService->getNamespace();
22
		$fqcn = sprintf('%s\\serializer\\base\\%sSerializerTrait', $ns, $model->getPhpName());
23
		$trait = new PhpTrait($fqcn);
24
25
		$this->generateIdentifyingMethods($trait, $model);
26
		$this->generateAttributeMethods($trait, $model);
27
		$this->generateHydrateMethod($trait, $model);
28
		$this->generateRelationshipMethods($trait, $model);
29
		$this->generateTypeInferencerAccess($trait);
30
31
		return $trait;
32
	}
33
34
	protected function generateIdentifyingMethods(PhpTrait $trait, Table $model) {
35
		$package = $this->packageService->getPackage();
36
		$type = sprintf('%s/%s', $package->getKeeko()->getModule()->getSlug(), NameUtils::dasherize($model->getOriginCommonName()));
37
38
		$trait->setMethod(PhpMethod::create('getId')
39
			->addParameter(PhpParameter::create('model'))
40
			->setBody($this->twig->render('getId.twig'))
41
			->setType('string')
42
		);
43
44
		$trait->setMethod(PhpMethod::create('getType')
45
			->addParameter(PhpParameter::create('model'))
46
			->setBody($this->twig->render('getType.twig', [
47
				'type' => $type
48
			]))
49
			->setType('string')
50
		);
51
	}
52
53
	protected function generateAttributeMethods(PhpTrait $trait, Table $model) {
54
		$readFields = $this->codegenService->getReadFields($model->getOriginCommonName());
55
		$attrs = '';
56
57
		foreach ($readFields as $field) {
58
			$col = $model->getColumn($field);
59
			$param = $col->isTemporalType() ? '\DateTime::ISO8601' : '';
60
			$attrs .= sprintf("\t'%s' => \$model->get%s(%s),\n",
61
				NameUtils::dasherize($field), $col->getPhpName(), $param
62
			);
63
		}
64
65
		if (count($field) > 0) {
0 ignored issues
show
Bug introduced by
The variable $field seems to be defined by a foreach iteration on line 57. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
66
			$attrs = substr($attrs, 0, -2);
67
		}
68
69
		$trait->setMethod(PhpMethod::create('getAttributes')
70
			->addParameter(PhpParameter::create('model'))
71
			->addParameter(PhpParameter::create('fields')->setType('array')->setDefaultValue(null))
0 ignored issues
show
Deprecated Code introduced by
The method gossi\codegen\model\part...Part::setDefaultValue() has been deprecated with message: use `setValue()` instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
72
			->setBody($this->twig->render('getAttributes.twig', [
73
				'attrs' => $attrs
74
			]))
75
		);
76
77
		$trait->setMethod(PhpMethod::create('getSortFields')
78
			->setBody($this->twig->render('getFields.twig', [
79
				'fields' => $this->codegenService->arrayToCode(array_map(function ($field) {
80
					return NameUtils::dasherize($field);
81
				}, $readFields))
82
			]))
83
		);
84
85
		$readFields = $this->codegenService->getReadFields($model->getOriginCommonName());
86
		$trait->setMethod(PhpMethod::create('getFields')
87
			->setBody($this->twig->render('getFields.twig', [
88
				'fields' => $this->codegenService->arrayToCode(array_map(function ($field) {
89
					return NameUtils::dasherize($field);
90
				}, $readFields))
91
			]))
92
		);
93
	}
94
95
	protected function generateHydrateMethod(PhpTrait $trait, Table $model) {
96
		if ($model->isReadOnly()) {
97
			$body = $this->twig->render('hydrate-readonly.twig');
98
		} else {
99
			$trait->addUseStatement('keeko\\framework\\utils\\HydrateUtils');
100
			$modelName = $model->getOriginCommonName();
101
			$normalizer = $this->codegenService->getCodegen()->getNormalizer($modelName);
102
			$fields = $this->codegenService->getWriteFields($modelName);
103
			$code = '';
104
105
			foreach ($fields as $field) {
106
				$code .= sprintf("'%s'", NameUtils::dasherize($field));
107
				if ($normalizer->has($field)) {
108
					$code .= $this->twig->render('normalizer.twig', [
109
						'class' => $normalizer->get($field)
110
					]);
111
				}
112
113
				$code .= ', ';
114
			}
115
116
			if (strlen($code) > 0) {
117
				$code = substr($code, 0, -2);
118
			}
119
120
			$code = sprintf('[%s]', $code);
121
			$body = $this->twig->render('hydrate.twig', [
122
				'code' => $code,
123
				'normalizer' => $normalizer->size() > 0
124
			]);
125
126
// 			$trait->setMethod(PhpMethod::create('hydrateRelationships')
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% 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...
127
// 				->addParameter(PhpParameter::create('model'))
128
// 				->addParameter(PhpParameter::create('data'))
129
// 				->setAbstract(true)
130
// 				->setType('void')
131
// 				->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
132
// 			);
133
		}
134
135
		$trait->setMethod(PhpMethod::create('hydrate')
136
			->addParameter(PhpParameter::create('model'))
137
			->addParameter(PhpParameter::create('data'))
138
			->setBody($body)
139
			->setType('mixed', 'The model')
140
		);
141
	}
142
143
	protected function generateRelationshipMethods(PhpTrait $trait, Table $model) {
144
		if ($model->isReadOnly()) {
145
			return;
146
		}
147
148
		$fields = [];
149
		$methods = [];
150
		$plural = [];
151
		$relationships = $this->modelService->getRelationships($model);
152
		$methodNameGenerator = $this->factory->getRelationshipMethodNameGenerator();
153
154
		// add self link for relationships if there are any
155
		if ($relationships->size() > 0) {
156
			$trait->addUseStatement('Tobscure\\JsonApi\\Relationship');
157
			$trait->setMethod(PhpMethod::create('addRelationshipSelfLink')
158
				->addParameter(PhpParameter::create('relationship')
159
					->setType('Relationship')
160
				)
161
				->addParameter(PhpParameter::create('model')
162
					->setType('mixed')
163
				)
164
				->addParameter(PhpParameter::create('related')
165
					->setType('string')
166
				)
167
				->setAbstract(true)
168
				->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
169
				->setType('Relationship')
170
			);
171
		}
172
173
		// iterate all relationships
174
		foreach ($relationships->getAll() as $rel) {
175
			// one-to-one
176
			if ($rel->getType() == Relationship::ONE_TO_ONE) {
177
				$foreign = $rel->getForeign();
178
				$relatedName = $rel->getRelatedName();
179
				$typeName = $rel->getRelatedTypeName();
180
				$method = NameUtils::toCamelCase($relatedName);
181
				$fields[$typeName] = $foreign->getPhpName() . '::getSerializer()->getType(null)';
182
				$trait->addUseStatement($foreign->getNamespace() . '\\' . $foreign->getPhpName());
183
				$trait->addUseStatement('Tobscure\\JsonApi\\Resource');
184
185
				// read
186
				$body = $this->twig->render('to-one-read.twig', [
187
					'class' => $foreign->getPhpName(),
188
					'related' => $relatedName,
189
					'related_type' => $typeName
190
				]);
191
			}
192
193
			// ?-to-many
194
			else {
195
				$foreign = $rel->getForeign();
196
				$typeName = $rel->getRelatedPluralTypeName();
197
				$method = NameUtils::toCamelCase($rel->getRelatedPluralName());
198
				$fields[$typeName] = $foreign->getPhpName() . '::getSerializer()->getType(null)';
199
				$trait->addUseStatement($foreign->getNamespace() . '\\' . $foreign->getPhpName());
200
				$trait->addUseStatement('Tobscure\\JsonApi\\Collection');
201
202
				// read
203
				$body = $this->twig->render('to-many-read.twig', [
204
					'class' => $foreign->getPhpName(),
205
					'related' => $typeName,
206
					'related_type' => $rel->getRelatedTypeName()
207
				]);
208
209
				// method name for collection
210
				$methods[$typeName] = $methodNameGenerator->generateMethodName($rel);
211
				$plural[$typeName] = $methodNameGenerator->generatePluralMethodName($rel);
212
// 				if ($rel->getType() == Relationship::MANY_TO_MANY
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% 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
// 						&& $rel->getForeign() == $rel->getModel()) {
214
// 					$lk = $rel->getLocalKey();
215
// 					$methods[$typeName] = $foreign->getPhpName() . 'RelatedBy' . $lk->getLocalColumn()->getPhpName();
216
// 					$plural[$typeName] = NameUtils::pluralize($foreign->getPhpName()) . 'RelatedBy' . $lk->getLocalColumn()->getPhpName();
217
// 				}
218
			}
219
220
			// set read method on class
221
			$trait->setMethod(PhpMethod::create($method)
222
				->addParameter(PhpParameter::create('model'))
223
				->setBody($body)
224
				->setType('Relationship')
225
			);
226
227
			// add reverse many-to-many
228
			if ($rel->getType() == Relationship::MANY_TO_MANY && $rel->isReflexive()) {
229
				$foreign = $rel->getForeign();
230
				$typeName = $rel->getReverseRelatedPluralTypeName();
231
				$method = NameUtils::toCamelCase($rel->getReverseRelatedPluralName());
232
				$fields[$typeName] = $foreign->getPhpName() . '::getSerializer()->getType(null)';
233
				$trait->addUseStatement($foreign->getNamespace() . '\\' . $foreign->getPhpName());
234
				$trait->addUseStatement('Tobscure\\JsonApi\\Collection');
235
236
				// read
237
				$body = $this->twig->render('to-many-read.twig', [
238
					'class' => $foreign->getPhpName(),
239
					'related' => $typeName,
240
					'related_type' => $rel->getReverseRelatedTypeName()
241
				]);
242
243
				$methods[$typeName] = $methodNameGenerator->generateReverseMethodName($rel);
244
				$plural[$typeName] = $methodNameGenerator->generateReversePluralMethodName($rel);
245
246
				// set read method on class
247
				$trait->setMethod(PhpMethod::create($method)
248
					->addParameter(PhpParameter::create('model'))
249
					->setBody($body)
250
					->setType('Relationship')
251
				);
252
			}
253
		}
254
255
		// method: getRelationships() : array
0 ignored issues
show
Unused Code Comprehensibility introduced by
40% 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...
256
		$trait->setMethod(PhpMethod::create('getRelationships')
257
			->setBody($this->twig->render('getRelationships.twig', [
258
				'fields' => $fields
259
			]))
260
		);
261
262
		// method: getCollectionMethodName($relatedName) : string
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% 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...
263
		$trait->setProperty(PhpProperty::create('methodNames')
264
			->setExpression($this->codegenService->mapToCode($methods))
265
			->setVisibility(PhpProperty::VISIBILITY_PRIVATE)
266
		);
267
		$trait->setMethod(PhpMethod::create('getCollectionMethodName')
268
			->addParameter(PhpParameter::create('relatedName'))
269
			->setBody($this->twig->render('getCollectionMethodName.twig'))
270
			->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
271
		);
272
273
		// method: getCollectionMethodPluralName($relatedName) : string
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% 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...
274
		$trait->setProperty(PhpProperty::create('methodPluralNames')
275
			->setExpression($this->codegenService->mapToCode($plural))
276
			->setVisibility(PhpProperty::VISIBILITY_PRIVATE)
277
		);
278
		$trait->setMethod(PhpMethod::create('getCollectionMethodPluralName')
279
			->addParameter(PhpParameter::create('relatedName'))
280
			->setBody($this->twig->render('getCollectionMethodPluralName.twig'))
281
			->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
282
		);
283
	}
284
285
	protected function generateTypeInferencerAccess(PhpTrait $trait) {
286
		$namespace = $this->factory->getNamespaceGenerator()->getSerializerNamespace();
287
		$trait->addUseStatement($namespace . '\\TypeInferencer');
288
		$trait->setMethod(PhpMethod::create('getTypeInferencer')
289
			->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
290
			->setBody($this->twig->render('getTypeInferencer.twig'))
291
		);
292
	}
293
}