Completed
Push — master ( e6e2aa...27549f )
by Thomas
09:03
created

ModelSerializerTraitGenerator   B

Complexity

Total Complexity 17

Size/Duplication

Total Lines 186
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 16

Importance

Changes 5
Bugs 0 Features 1
Metric Value
wmc 17
c 5
b 0
f 1
lcom 1
cbo 16
dl 0
loc 186
rs 8.4614

5 Methods

Rating   Name   Duplication   Size   Complexity  
A generate() 0 12 1
A generateIdentifyingMethods() 0 18 1
B generateAttributeMethods() 0 35 4
B generateHydrateMethod() 0 43 5
B generateRelationshipMethods() 0 66 6
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 Propel\Generator\Model\Table;
10
use keeko\tools\model\ManyRelationship;
11
use keeko\tools\model\Relationship;
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
		$class = new PhpTrait($fqcn);
24
		
25
		$this->generateIdentifyingMethods($class, $model);
26
		$this->generateAttributeMethods($class, $model);
27
		$this->generateHydrateMethod($class, $model);
28
		$this->generateRelationshipMethods($class, $model);
29
		
30
		return $class;
31
	}
32
	
33
	protected function generateIdentifyingMethods(PhpTrait $class, Table $model) {
34
		$package = $this->packageService->getPackage();
35
		$type = sprintf('%s/%s', $package->getCleanName(), NameUtils::dasherize($model->getOriginCommonName()));
36
		
37
		$class->setMethod(PhpMethod::create('getId')
38
			->addParameter(PhpParameter::create('model'))
39
			->setBody($this->twig->render('getId.twig'))
40
			->setType('string')
41
		);
42
		
43
		$class->setMethod(PhpMethod::create('getType')
44
			->addParameter(PhpParameter::create('model'))
45
			->setBody($this->twig->render('getType.twig', [
46
				'type' => $type
47
			]))
48
			->setType('string')
49
		);
50
	}
51
	
52
	protected function generateAttributeMethods(PhpTrait $class, Table $model) {
53
		$writeFields = $this->codegenService->getWriteFields($model->getOriginCommonName());
54
		$attrs = '';
55
		
56
		foreach ($writeFields as $field) {
57
			$col = $model->getColumn($field);
58
			$param = $col->isTemporalType() ? '\DateTime::ISO8601' : '';
59
			$attrs .= sprintf("\t'%s' => \$model->get%s(%s),\n", $field, $col->getPhpName(), $param);
60
		}
61
		
62
		if (count($field) > 0) {
0 ignored issues
show
Bug introduced by
The variable $field seems to be defined by a foreach iteration on line 56. 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...
63
			$attrs = substr($attrs, 0, -1);
64
		}
65
		
66
		$class->setMethod(PhpMethod::create('getAttributes')
67
			->addParameter(PhpParameter::create('model'))
68
			->addParameter(PhpParameter::create('fields')->setType('array')->setDefaultValue(null))
69
			->setBody($this->twig->render('getAttributes.twig', [
70
				'attrs' => $attrs
71
			]))
72
		);
73
		
74
		$class->setMethod(PhpMethod::create('getSortFields')
75
			->setBody($this->twig->render('getFields.twig', [
76
				'fields' => $this->codegenService->arrayToCode($writeFields)
77
			]))
78
		);
79
		
80
		$readFields = $this->codegenService->getReadFields($model->getOriginCommonName());
81
		$class->setMethod(PhpMethod::create('getFields')
82
			->setBody($this->twig->render('getFields.twig', [
83
				'fields' => $this->codegenService->arrayToCode($readFields)
84
			]))
85
		);
86
	}
87
	
88
	protected function generateHydrateMethod(PhpTrait $trait, Table $model) {
89
		if ($model->isReadOnly()) {
90
			$body = $this->twig->render('hydrate-readonly.twig');
91
		} else {
92
			$trait->addUseStatement('keeko\\framework\\utils\\HydrateUtils');
93
			$modelName = $model->getOriginCommonName();
94
			$conversions = $this->codegenService->getCodegen()->getWriteConversion($modelName);
95
			$fields = $this->codegenService->getWriteFields($modelName);
96
			$code = '';
97
			
98
			foreach ($fields as $field) {
99
				$code .= "'$field'";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $field instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
100
				if (isset($conversions[$field])) {
101
					$code .= ' => function($v) {' . "\n\t" . 'return ' . $conversions[$field] . ';' . "\n" . '}';
102
				}
103
		
104
				$code .= ', ';
105
			}
106
			
107
			if (strlen($code) > 0) {
108
				$code = substr($code, 0, -2);
109
			}
110
			
111
			$code = sprintf('[%s]', $code);
112
			$body = $this->twig->render('hydrate.twig', [
113
				'code' => $code
114
			]);
115
			
116
			$trait->setMethod(PhpMethod::create('hydrateRelationships')
117
				->addParameter(PhpParameter::create('model'))
118
				->addParameter(PhpParameter::create('data'))
119
				->setAbstract(true)
120
				->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
121
			);
122
		}
123
		
124
		$trait->setMethod(PhpMethod::create('hydrate')
125
			->addParameter(PhpParameter::create('model'))
126
			->addParameter(PhpParameter::create('data'))
127
			->setBody($body)
128
			->setType('mixed', 'The model')
129
		);
130
	}
131
	
132
	protected function generateRelationshipMethods(PhpTrait $class, Table $model) {
133
		if ($model->isReadOnly()) {
134
			return;
135
		}
136
		
137
		$rels = [];
138
		$relationships = $this->modelService->getRelationships($model);
139
		
140
		if ($relationships->size() > 0) {
141
			$class->addUseStatement('Tobscure\\JsonApi\\Relationship');
142
		}
143
		
144
		foreach ($relationships->getAll() as $rel) {
145
			
146
			// to-many
147
			if ($rel instanceof ManyRelationship) {
148
				$foreign = $rel->getForeign();
149
				$relatedName = $rel->getRelatedName();
150
				
151
				$typeName = $rel->getRelatedTypeName();
152
				$method = NameUtils::toCamelCase($typeName);
153
				$rels[$typeName] = $foreign->getPhpName() . '::getSerializer()->getType(null)';
154
				$class->addUseStatement($foreign->getNamespace() . '\\' . $foreign->getPhpName());
155
				$class->addUseStatement('Tobscure\\JsonApi\\Collection');
156
				
157
				// read
158
				$body = $this->twig->render('to-many-read.twig', [
159
					'getter' => NameUtils::pluralize($relatedName),
160
					'class' => $relatedName,
161
					'related' => $typeName
162
				]);
163
			}
164
			
165
			// to-one
166
			else if ($rel instanceof Relationship) {
167
				$foreign = $rel->getForeign();
168
				$relatedName = $rel->getRelatedName();
169
				
170
				$typeName = $rel->getRelatedTypeName();
171
				$method = NameUtils::toCamelCase($typeName);
172
				$rels[$typeName] = $foreign->getPhpName() . '::getSerializer()->getType(null)';
173
				$class->addUseStatement($foreign->getNamespace() . '\\' . $foreign->getPhpName());
174
				$class->addUseStatement('Tobscure\\JsonApi\\Resource');
175
				
176
				// read
177
				$body = $this->twig->render('to-one-read.twig', [
178
					'ref' => $relatedName,
179
					'class' => $foreign->getPhpName(),
180
					'related' => $typeName
181
				]);
182
			}
183
			
184
			// needs to go down
185
			$class->setMethod(PhpMethod::create($method)
0 ignored issues
show
Bug introduced by
The variable $method does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
186
				->addParameter(PhpParameter::create('model'))
187
				->setBody($body)
0 ignored issues
show
Bug introduced by
The variable $body does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
188
				->setType('Relationship')
189
			);
190
		}
191
		
192
		$class->setMethod(PhpMethod::create('getRelationships')
193
			->setBody($this->twig->render('getRelationships.twig', [
194
				'fields' => $rels
195
			]))
196
		);
197
	}
198
}