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

generateOneToManyRelationshipUpdate()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 33
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 33
rs 8.8571
cc 1
eloc 25
nc 1
nop 2
1
<?php
2
namespace keeko\tools\generator\domain\base;
3
4
use gossi\codegen\model\PhpClass;
5
use gossi\codegen\model\PhpMethod;
6
use gossi\codegen\model\PhpParameter;
7
use gossi\codegen\model\PhpProperty;
8
use gossi\codegen\model\PhpTrait;
9
use keeko\framework\utils\NameUtils;
10
use keeko\tools\model\Relationship;
11
use Propel\Generator\Model\Table;
12
use keeko\tools\model\ManyToManyRelationship;
13
use keeko\tools\model\OneToManyRelationship;
14
15
class ModelDomainTraitGenerator extends ReadOnlyModelDomainTraitGenerator {
16
17
	public function generate(Table $model) {
18
		$trait = parent::generate($model);
19
20
		// generate event
21
		$event = $this->generateEvent($model);
22
		$trait->addUseStatement($event->getQualifiedName());
23
		$this->generateDispatch($trait, $model);
24
25
		// generate CUD methods
26
		$this->generateCreate($trait, $model);
27
		$this->generateUpdate($trait, $model);
28
		$this->generateDelete($trait, $model);
29
30
		// generate relationship methods
31
		if (!$model->isReadOnly()) {
32
			$relationships = $this->modelService->getRelationships($model);
33
34
			foreach ($relationships->getAll() as $relationship) {
35
				switch ($relationship->getType()) {
36
					case Relationship::ONE_TO_ONE:
37
						$this->generateToOneRelationshipSet($trait, $relationship);
38
						break;
39
40
					case Relationship::ONE_TO_MANY:
41
						$this->generateToManyRelationshipAdd($trait, $relationship);
42
						$this->generateToManyRelationshipRemove($trait, $relationship);
43
						$this->generateOneToManyRelationshipUpdate($trait, $relationship);
44
						break;
45
46
					case Relationship::MANY_TO_MANY:
47
						$this->generateToManyRelationshipAdd($trait, $relationship);
48
						$this->generateToManyRelationshipRemove($trait, $relationship);
49
						$this->generateManyToManyRelationshipUpdate($trait, $relationship);
50
						break;
51
				}
52
			}
53
		}
54
55
		return $trait;
56
	}
57
58
	/**
59
	 *
60
	 * @param Table $model
61
	 * @return PhpClass
62
	 */
63
	protected function generateEvent(Table $model) {
64
		$package = $this->packageService->getPackage();
65
		$slug = $package->getKeeko()->getModule()->getSlug();
66
		$modelName = $model->getOriginCommonName();
67
68
		$class = new PhpClass();
69
		$class->setNamespace(str_replace('model', 'event', $model->getNamespace()));
70
		$class->setName($model->getPhpName() . 'Event');
71
		$class->setParentClassName('Event');
72
		if ($model->getPhpName() == 'Event') {
73
			$class->addUseStatement($model->getNamespace() . '\\' . $model->getPhpName(), 'Model');
74
		} else {
75
			$class->addUseStatement($model->getNamespace() . '\\' . $model->getPhpName());
76
		}
77
		$class->addUseStatement('Symfony\Component\EventDispatcher\Event');
78
79
		// constants
80
		$class->setConstant('PRE_CREATE', sprintf('%s.%s.pre_create', $slug, $modelName));
81
		$class->setConstant('POST_CREATE', sprintf('%s.%s.post_create', $slug, $modelName));
82
		$class->setConstant('PRE_UPDATE', sprintf('%s.%s.pre_update', $slug, $modelName));
83
		$class->setConstant('POST_UPDATE', sprintf('%s.%s.post_update', $slug, $modelName));
84
		$class->setConstant('PRE_SAVE', sprintf('%s.%s.pre_save', $slug, $modelName));
85
		$class->setConstant('POST_SAVE', sprintf('%s.%s.post_save', $slug, $modelName));
86
		$class->setConstant('PRE_DELETE', sprintf('%s.%s.pre_delete', $slug, $modelName));
87
		$class->setConstant('POST_DELETE', sprintf('%s.%s.post_delete', $slug, $modelName));
88
89
		// generate relationship constants
90
		if (!$model->isReadOnly()) {
91
			$relationships = $this->modelService->getRelationships($model);
92
93
			foreach ($relationships->getAll() as $relationship) {
94
				// one-to-one relationships
95
				if ($relationship->getType() == Relationship::ONE_TO_ONE) {
96
					$snake = NameUtils::toSnakeCase($relationship->getRelatedName());
97
					$name = strtoupper($snake);
98
					$class->setConstant('PRE_' . $name . '_UPDATE', sprintf('%s.%s.pre_%s_update', $slug, $modelName, $snake));
99
					$class->setConstant('POST_' . $name . '_UPDATE', sprintf('%s.%s.post_%s_update', $slug, $modelName, $snake));
100
				}
101
102
				// others
103
				else {
104
					$snake = NameUtils::toSnakeCase($relationship->getRelatedPluralName());
105
					$name = strtoupper($snake);
106
					$class->setConstant('PRE_' . $name . '_ADD', sprintf('%s.%s.pre_%s_add', $slug, $modelName, $snake));
107
					$class->setConstant('POST_' . $name . '_ADD', sprintf('%s.%s.post_%s_add', $slug, $modelName, $snake));
108
					$class->setConstant('PRE_' . $name . '_REMOVE', sprintf('%s.%s.pre_%s_add', $slug, $modelName, $snake));
109
					$class->setConstant('POST_' . $name . '_REMOVE', sprintf('%s.%s.post_%s_add', $slug, $modelName, $snake));
110
					$class->setConstant('PRE_' . $name . '_UPDATE', sprintf('%s.%s.pre_%s_update', $slug, $modelName, $snake));
111
					$class->setConstant('POST_' . $name . '_UPDATE', sprintf('%s.%s.post_%s_update', $slug, $modelName, $snake));
112
				}
113
			}
114
		}
115
116
		// properties
117
		$modelVariableName = $model->getCamelCaseName();
118
		$class->setProperty(PhpProperty::create($modelVariableName)
119
			->setType($model->getPackage())
120
			->setVisibility(PhpProperty::VISIBILITY_PROTECTED)
121
		);
122
123
		// constructor
124
		$type = $model->getPhpName() == 'Event' ? 'Model' : $model->getPhpName();
125
		$class->setMethod(PhpMethod::create('__construct')
126
			->addParameter(PhpParameter::create($modelVariableName)->setType($type))
127
			->setBody('$this->' . $modelVariableName . ' = $' . $modelVariableName .';')
128
		);
129
130
		// getModel()
131
		$class->setMethod(PhpMethod::create('get' . $model->getPhpName())
132
			->setType($model->getPhpName())
133
			->setBody('return $this->' . $modelVariableName .';')
134
		);
135
136
		$this->codegenService->dumpStruct($class, true);
137
138
		return $class;
139
	}
140
141
	protected function generateDispatch(PhpTrait $trait, Table $model) {
142
		$trait->setMethod(PhpMethod::create('dispatch')
143
			->addParameter(PhpParameter::create('type')
144
				->setType('string')
145
			)
146
			->addParameter(PhpParameter::create('event')
147
				->setType($model->getPhpName() . 'Event')
148
			)
149
			->setBody($this->twig->render('dispatch.twig', [
150
				'class' => $model->getPhpName()
151
			]))
152
			->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
153
		);
154
	}
155
156
	protected function generateCreate(PhpTrait $trait, Table $model) {
157
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\Created');
158
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\NotFound');
159
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\NotValid');
160
161
		$trait->setMethod(PhpMethod::create('create')
162
			->addParameter(PhpParameter::create('data'))
163
			->setBody($this->twig->render('create.twig', [
164
				'class' => $model->getPhpName()
165
			]))
166
			->setDescription('Creates a new ' . $model->getPhpName() . ' with the provided data')
167
			->setType('PayloadInterface')
168
		);
169
	}
170
171
	protected function generateUpdate(PhpTrait $trait, Table $model) {
172
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\Updated');
173
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\NotUpdated');
174
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\NotFound');
175
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\NotValid');
176
177
		$trait->setMethod(PhpMethod::create('update')
178
			->addParameter(PhpParameter::create('id'))
179
			->addParameter(PhpParameter::create('data'))
180
			->setBody($this->twig->render('update.twig', [
181
				'class' => $model->getPhpName()
182
			]))
183
			->setDescription('Updates a ' . $model->getPhpName() . ' with the given id' .
184
				'and the provided data')
185
			->setType('PayloadInterface')
186
		);
187
	}
188
189
	protected function generateDelete(PhpTrait $trait, Table $model) {
190
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\Deleted');
191
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\NotDeleted');
192
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\NotFound');
193
194
		$trait->setMethod(PhpMethod::create('delete')
195
			->addParameter(PhpParameter::create('id'))
196
			->setBody($this->twig->render('delete.twig', [
197
				'class' => $model->getPhpName()
198
			]))
199
			->setDescription('Deletes a ' . $model->getPhpName() . ' with the given id')
200
			->setType('PayloadInterface')
201
		);
202
	}
203
204
	protected function generateToOneRelationshipSet(PhpTrait $trait, Relationship $relationship) {
205
		$model = $relationship->getModel();
206
		$name = $relationship->getRelatedName();
207
		$trait->setMethod(PhpMethod::create('set' . $name . 'Id')
208
			->setDescription(str_replace('{foreign}', $relationship->getRelatedName(), 'Sets the {foreign} id'))
209
			->addParameter(PhpParameter::create('id'))
210
			->addParameter(PhpParameter::create('relatedId'))
211
			->setBody($this->twig->render('to-one-set.twig', [
212
				'class' => $model->getPhpName(),
213
				'related_name' => $name,
214
				'const' => strtoupper(NameUtils::toSnakeCase($relationship->getRelatedName()))
215
			]))
216
			->setType('PayloadInterface')
217
		);
218
219
		$trait->setMethod(PhpMethod::create('doSet' . $name . 'Id')
220
			->setDescription(str_replace('{foreign}', $relationship->getRelatedName(), 'Internal mechanism to set the {foreign} id'))
221
			->addParameter(PhpParameter::create('model')
222
				->setType($model->getPhpName())
223
			)
224
			->addParameter(PhpParameter::create('relatedId'))
225
			->setBody($this->twig->render('do-to-one-set.twig', [
226
				'local' => $relationship->getForeignKey()->getLocalColumn()->getPhpName()
227
			]))
228
			->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
229
		);
230
	}
231
232
	protected function generateToManyRelationshipAdd(PhpTrait $trait, Relationship $relationship) {
233
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\NotValid');
234
235
		$model = $relationship->getModel();
236
		$foreign = $relationship->getForeign();
237
		$trait->addUseStatement($foreign->getNamespace() . '\\' . $foreign->getPhpName() . 'Query');
238
		$trait->setMethod(PhpMethod::create('add' . $relationship->getRelatedPluralName())
239
			->setDescription('Adds ' . $relationship->getRelatedPluralName() . ' to ' . $model->getPhpName())
240
			->addParameter(PhpParameter::create('id'))
241
			->addParameter(PhpParameter::create('data'))
242
			->setBody($this->twig->render('to-many-add.twig', [
243
				'class' => $model->getPhpName(),
244
				'related_name' => $relationship->getRelatedPluralName(),
245
				'const' => strtoupper(NameUtils::toSnakeCase($relationship->getRelatedPluralName()))
246
			]))
247
			->setType('PayloadInterface')
248
		);
249
250
		$methodNameGenerator = $this->factory->getRelationshipMethodNameGenerator();
251
		$trait->setMethod(PhpMethod::create('doAdd' . $relationship->getRelatedPluralName())
252
			->setDescription('Interal mechanism to add ' . $relationship->getRelatedPluralName() . ' to ' . $model->getPhpName())
253
			->addParameter(PhpParameter::create('model')
254
				->setType($model->getPhpName())
255
			)
256
			->addParameter(PhpParameter::create('data'))
257
			->setBody($this->twig->render('do-to-many-add.twig', [
258
				'foreign_class' => $foreign->getPhpName(),
259
				'method_name' => $methodNameGenerator->generateMethodName($relationship)
260
			]))
261
			->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
262
		);
263
264
		// reflexive add method on many-to-many relationship
265
		if ($relationship->getType() == Relationship::MANY_TO_MANY && $relationship->isReflexive()) {
266
			$trait->setMethod(PhpMethod::create('add' . $relationship->getReverseRelatedPluralName())
267
				->setDescription('Adds ' . $relationship->getReverseRelatedPluralName() . ' to ' . $model->getPhpName())
268
				->addParameter(PhpParameter::create('id'))
269
				->addParameter(PhpParameter::create('data'))
270
				->setBody($this->twig->render('to-many-add.twig', [
271
					'class' => $model->getPhpName(),
272
					'related_name' => $relationship->getReverseRelatedPluralName(),
273
					'const' => strtoupper(NameUtils::toSnakeCase($relationship->getRelatedPluralName()))
274
				]))
275
				->setType('PayloadInterface')
276
			);
277
278
			$methodNameGenerator = $this->factory->getRelationshipMethodNameGenerator();
279
			$trait->setMethod(PhpMethod::create('doAdd' . $relationship->getReverseRelatedPluralName())
280
				->setDescription('Interal mechanism to add ' . $relationship->getReverseRelatedPluralName() . ' to ' . $model->getPhpName())
281
				->addParameter(PhpParameter::create('model')
282
					->setType($model->getPhpName())
283
				)
284
				->addParameter(PhpParameter::create('data'))
285
				->setBody($this->twig->render('do-to-many-add.twig', [
286
					'foreign_class' => $foreign->getPhpName(),
287
					'method_name' => $methodNameGenerator->generateReverseMethodName($relationship)
288
				]))
289
				->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
290
			);
291
		}
292
	}
293
294
	protected function generateToManyRelationshipRemove(PhpTrait $trait, Relationship $relationship) {
295
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\NotValid');
296
297
		$model = $relationship->getModel();
298
		$foreign = $relationship->getForeign();
299
		$trait->addUseStatement($foreign->getNamespace() . '\\' . $foreign->getPhpName() . 'Query');
300
		$trait->setMethod(PhpMethod::create('remove' . $relationship->getRelatedPluralName())
301
			->setDescription('Removes ' . $relationship->getRelatedPluralName() . ' from ' . $model->getPhpName())
302
			->addParameter(PhpParameter::create('id'))
303
			->addParameter(PhpParameter::create('data'))
304
			->setBody($this->twig->render('to-many-remove.twig', [
305
				'class' => $model->getPhpName(),
306
				'related_name' => $relationship->getRelatedPluralName(),
307
				'const' => strtoupper(NameUtils::toSnakeCase($relationship->getRelatedPluralName()))
308
			]))
309
			->setType('PayloadInterface')
310
		);
311
312
		$methodNameGenerator = $this->factory->getRelationshipMethodNameGenerator();
313
		$trait->setMethod(PhpMethod::create('doRemove' . $relationship->getRelatedPluralName())
314
			->setDescription('Interal mechanism to remove ' . $relationship->getRelatedPluralName() . ' from ' . $model->getPhpName())
315
			->addParameter(PhpParameter::create('model')
316
				->setType($model->getPhpName())
317
				)
318
			->addParameter(PhpParameter::create('data'))
319
			->setBody($this->twig->render('do-to-many-remove.twig', [
320
				'foreign_class' => $foreign->getPhpName(),
321
				'method_name' => $methodNameGenerator->generateMethodName($relationship)
322
			]))
323
			->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
324
		);
325
326
		// reflexive remove method on many-to-many relationship
327
		if ($relationship->getType() == Relationship::MANY_TO_MANY && $relationship->isReflexive()) {
328
			$trait->setMethod(PhpMethod::create('remove' . $relationship->getReverseRelatedPluralName())
329
				->setDescription('Removes ' . $relationship->getReverseRelatedPluralName() . ' from ' . $model->getPhpName())
330
				->addParameter(PhpParameter::create('id'))
331
				->addParameter(PhpParameter::create('data'))
332
				->setBody($this->twig->render('to-many-remove.twig', [
333
					'class' => $model->getPhpName(),
334
					'related_name' => $relationship->getReverseRelatedPluralName(),
335
					'const' => strtoupper(NameUtils::toSnakeCase($relationship->getRelatedPluralName()))
336
				]))
337
				->setType('PayloadInterface')
338
			);
339
340
			$methodNameGenerator = $this->factory->getRelationshipMethodNameGenerator();
341
			$trait->setMethod(PhpMethod::create('doRemove' . $relationship->getReverseRelatedPluralName())
342
				->setDescription('Interal mechanism to remove ' . $relationship->getReverseRelatedPluralName() . ' from ' . $model->getPhpName())
343
				->addParameter(PhpParameter::create('model')
344
					->setType($model->getPhpName())
345
				)
346
				->addParameter(PhpParameter::create('data'))
347
				->setBody($this->twig->render('do-to-many-remove.twig', [
348
					'foreign_class' => $foreign->getPhpName(),
349
					'method_name' => $methodNameGenerator->generateMethodName($relationship)
350
				]))
351
				->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
352
			);
353
		}
354
	}
355
356
	protected function generateOneToManyRelationshipUpdate(PhpTrait $trait, OneToManyRelationship $relationship) {
357
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\NotValid');
358
		$trait->addUseStatement('keeko\\framework\\exceptions\\ErrorsException');
359
360
		$model = $relationship->getModel();
361
		$foreign = $relationship->getForeign();
362
		$trait->addUseStatement($foreign->getNamespace() . '\\' . $foreign->getPhpName() . 'Query');
363
		$trait->setMethod(PhpMethod::create('update' . $relationship->getRelatedPluralName())
364
			->setDescription('Updates ' . $relationship->getRelatedPluralName() . ' on ' . $model->getPhpName())
365
			->addParameter(PhpParameter::create('id'))
366
			->addParameter(PhpParameter::create('data'))
367
			->setBody($this->twig->render('one-to-many-update.twig', [
368
				'class' => $model->getPhpName(),
369
				'related_name' => $relationship->getRelatedPluralName(),
370
				'const' => strtoupper(NameUtils::toSnakeCase($relationship->getRelatedPluralName()))
371
			]))
372
			->setType('PayloadInterface')
373
		);
374
375
		$trait->setMethod(PhpMethod::create('doUpdate' . $relationship->getRelatedPluralName())
376
			->setDescription('Internal update mechanism of ' . $relationship->getRelatedPluralName() . ' on ' . $model->getPhpName())
377
			->addParameter(PhpParameter::create('model')
378
				->setType($model->getPhpName())
379
			)
380
			->addParameter(PhpParameter::create('data'))
381
			->setBody($this->twig->render('do-one-to-many-update.twig', [
382
				'related' => $relationship->getRelatedName(),
383
				'reverse_related' => $relationship->getReverseRelatedName(),
384
				'foreign_class' => $foreign->getPhpName()
385
			]))
386
			->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
387
		);
388
	}
389
390
	protected function generateManyToManyRelationshipUpdate(PhpTrait $trait, ManyToManyRelationship $relationship) {
391
		$trait->addUseStatement('keeko\\framework\\domain\\payload\\NotValid');
392
		$trait->addUseStatement('keeko\\framework\\exceptions\\ErrorsException');
393
394
		$model = $relationship->getModel();
395
		$foreign = $relationship->getForeign();
396
		$middle = $relationship->getMiddle();
397
		$trait->addUseStatement($middle->getNamespace() . '\\' . $middle->getPhpName() . 'Query');
398
		$trait->addUseStatement($foreign->getNamespace() . '\\' . $foreign->getPhpName() . 'Query');
399
		$trait->setMethod(PhpMethod::create('update' . $relationship->getRelatedPluralName())
400
			->setDescription('Updates ' . $relationship->getRelatedPluralName() . ' on ' . $model->getPhpName())
401
			->addParameter(PhpParameter::create('id'))
402
			->addParameter(PhpParameter::create('data'))
403
			->setBody($this->twig->render('many-to-many-update.twig', [
404
				'class' => $model->getPhpName(),
405
				'related_name' => $relationship->getRelatedPluralName(),
406
				'const' => strtoupper(NameUtils::toSnakeCase($relationship->getRelatedPluralName()))
407
			]))
408
			->setType('PayloadInterface')
409
		);
410
411
		$methodNameGenerator = $this->factory->getRelationshipMethodNameGenerator();
412
		$trait->setMethod(PhpMethod::create('doUpdate' . $relationship->getRelatedPluralName())
413
			->setDescription('Internal update mechanism of ' . $relationship->getRelatedPluralName() . ' on ' . $model->getPhpName())
414
			->addParameter(PhpParameter::create('model')
415
				->setType($model->getPhpName())
416
			)
417
			->addParameter(PhpParameter::create('data'))
418
			->setBody($this->twig->render('do-many-to-many-update.twig', [
419
				'method_name' => $methodNameGenerator->generateMethodName($relationship),
420
				'reverse_related' => $methodNameGenerator->generateReverseMethodName($relationship),
421
				'foreign_class' => $foreign->getPhpName(),
422
				'middle_class' => $middle->getPhpName(),
423
			]))
424
			->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
425
		);
426
427
		// reflexive update methods
428
		if ($relationship->isReflexive()) {
429
			$trait->setMethod(PhpMethod::create('update' . $relationship->getReverseRelatedPluralName())
430
				->setDescription('Updates ' . $relationship->getReverseRelatedPluralName() . ' on ' . $model->getPhpName())
431
				->addParameter(PhpParameter::create('id'))
432
				->addParameter(PhpParameter::create('data'))
433
				->setBody($this->twig->render('many-to-many-update.twig', [
434
					'class' => $model->getPhpName(),
435
					'related_name' => $relationship->getReverseRelatedName(),
436
					'const' => strtoupper(NameUtils::toSnakeCase($relationship->getRelatedPluralName()))
437
				]))
438
				->setType('PayloadInterface')
439
			);
440
441
			$methodNameGenerator = $this->factory->getRelationshipMethodNameGenerator();
442
			$trait->setMethod(PhpMethod::create('doUpdate' . $relationship->getReverseRelatedPluralName())
443
				->setDescription('Internal update mechanism of ' . $relationship->getReverseRelatedPluralName() . ' on ' . $model->getPhpName())
444
				->addParameter(PhpParameter::create('model')
445
					->setType($model->getPhpName())
446
				)
447
				->addParameter(PhpParameter::create('data'))
448
				->setBody($this->twig->render('do-many-to-many-update.twig', [
449
					'method_name' => $methodNameGenerator->generateReverseMethodName($relationship),
450
					'reverse_related' => $methodNameGenerator->generateMethodName($relationship),
451
					'foreign_class' => $foreign->getPhpName(),
452
					'middle_class' => $middle->getPhpName(),
453
				]))
454
				->setVisibility(PhpMethod::VISIBILITY_PROTECTED)
455
			);
456
		}
457
	}
458
}