Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
87.50% |
7 / 8 |
CRAP | |
97.44% |
76 / 78 |
AbstractGenerator | |
0.00% |
0 / 1 |
|
87.50% |
7 / 8 |
23 | |
97.44% |
76 / 78 |
generateReferenceClass | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
writeReferenceClass | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
createPhpFileWriter | |
100.00% |
1 / 1 |
1 | |
100.00% |
7 / 7 |
|||
beginReferenceClass | |
0.00% |
0 / 1 |
2.02 | |
81.82% |
9 / 11 |
|||
generateTransitionMethods | |
100.00% |
1 / 1 |
6 | |
100.00% |
18 / 18 |
|||
generateReferenceMethods | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
generateIdMethods | |
100.00% |
1 / 1 |
1 | |
100.00% |
8 / 8 |
|||
generateFallbackExistsStateFunction | |
100.00% |
1 / 1 |
7 | |
100.00% |
15 / 15 |
|||
generateGetMethod | |
100.00% |
1 / 1 |
2 | |
100.00% |
10 / 10 |
<?php declare(strict_types = 1); | |
/* | |
* Copyright (c) 2019, Josef Kufner <josef@kufner.cz> | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
* | |
*/ | |
namespace Smalldb\StateMachine\ClassGenerator\ReferenceClassGenerator; | |
use ReflectionClass; | |
use Smalldb\StateMachine\ClassGenerator\AbstractClassGenerator; | |
use Smalldb\StateMachine\ClassGenerator\ReflectionException; | |
use Smalldb\StateMachine\Definition\StateMachineDefinition; | |
use Smalldb\StateMachine\InvalidArgumentException; | |
use Smalldb\StateMachine\ReferenceInterface; | |
use Smalldb\StateMachine\ReferenceTrait; | |
use Smalldb\PhpFileWriter\PhpFileWriter; | |
abstract class AbstractGenerator extends AbstractClassGenerator | |
{ | |
final public function generateReferenceClass(string $sourceReferenceClassName, StateMachineDefinition $definition): string | |
{ | |
try { | |
$sourceClassReflection = new ReflectionClass($sourceReferenceClassName); | |
$w = $this->createPhpFileWriter($sourceClassReflection); | |
$targetReferenceClassName = $this->writeReferenceClass($w, $sourceClassReflection, $definition); | |
$this->getClassGenerator()->addGeneratedClass($targetReferenceClassName, $w->getPhpCode()); | |
return $targetReferenceClassName; | |
} | |
// @codeCoverageIgnoreStart | |
catch (\ReflectionException $ex) { | |
throw new ReflectionException("Failed to generate Smalldb reference class: " . $definition->getMachineType(), 0, $ex); | |
} | |
// @codeCoverageIgnoreEnd | |
} | |
abstract protected function writeReferenceClass(PhpFileWriter $w, ReflectionClass $sourceClassReflection, StateMachineDefinition $definition): string; | |
protected function createPhpFileWriter(ReflectionClass $sourceClassReflection): PhpFileWriter | |
{ | |
$targetNamespace = $this->getClassGenerator()->getClassNamespace(); | |
$targetShortClassName = $sourceClassReflection->getShortName(); | |
// Setup the writer | |
$w = new PhpFileWriter(); | |
$w->setFileHeader(get_class($this)); | |
$w->setNamespace($targetNamespace); | |
$w->setClassName($targetShortClassName); | |
return $w; | |
} | |
protected function beginReferenceClass(PhpFileWriter $w, ReflectionClass $sourceClassReflection, array $implements = []): string | |
{ | |
$targetNamespace = $this->getClassGenerator()->getClassNamespace(); | |
$targetShortClassName = strtr($sourceClassReflection->getName(), ['\\' =>'__']); | |
$targetReferenceClassName = $targetNamespace . '\\' . $targetShortClassName; | |
// Add parent class/interface | |
if ($sourceClassReflection->isInterface()) { | |
$extends = null; | |
$implements[] = $w->useClass($sourceClassReflection->getName()); | |
} else { | |
$extends = $w->useClass($sourceClassReflection->getName()); | |
$implements[] = $w->useClass(ReferenceInterface::class); | |
} | |
// Create the class | |
$w->beginClass($targetShortClassName, $extends, $implements); | |
$w->writeln('use ' . $w->useClass(ReferenceTrait::class) . ';'); | |
return $targetReferenceClassName; | |
} | |
protected function generateTransitionMethods(PhpFileWriter $w, StateMachineDefinition $definition, | |
ReflectionClass $sourceClassReflection): void | |
{ | |
foreach ($definition->getActions() as $action) { | |
$methodName = $action->getName(); | |
if ($sourceClassReflection->hasMethod($methodName)) { | |
$methodReflection = $sourceClassReflection->getMethod($methodName); | |
if ($methodReflection->isAbstract()) { | |
$argMethod = []; | |
$argCall = []; | |
foreach ($methodReflection->getParameters() as $param) { | |
$argMethod[] = $w->getParamAsCode($param); | |
$argCall[] = '$' . $param->name; | |
} | |
$w->beginMethod($methodName, $argMethod); | |
$argCallStr = empty($argCall) ? '' : ', ' . join(', ', $argCall); | |
$w->writeln('return $this->invokeTransition(%s' . $argCallStr . ');', $methodName); | |
$w->endMethod(); | |
} | |
} else { | |
$w->beginMethod($methodName, ['...$args']); | |
$w->writeln('return $this->invokeTransition(%s, ...$args);', $methodName); | |
$w->endMethod(); | |
} | |
} | |
} | |
protected function generateReferenceMethods(PhpFileWriter $w, StateMachineDefinition $definition): void | |
{ | |
$w->beginMethod('getMachineType', [], 'string'); | |
$w->writeln('return %s;', $definition->getMachineType()); | |
$w->endMethod(); | |
} | |
protected function generateIdMethods(PhpFileWriter $w) | |
{ | |
$w->writeln('private $machineId = null;'); | |
$w->beginMethod('getMachineId', [], ''); | |
{ | |
$w->writeln('return $this->machineId;'); | |
} | |
$w->endMethod(); | |
$w->beginProtectedMethod('setMachineId', ['$machineId'], 'void'); | |
{ | |
$w->writeln('$this->machineId = $machineId;'); | |
} | |
$w->endMethod(); | |
} | |
protected function generateFallbackExistsStateFunction(PhpFileWriter $w, ReflectionClass $sourceClassReflection, | |
StateMachineDefinition $definition, string $canLoadDataCondition) | |
{ | |
if (!$w->hasMethod('getState') && ($stateMethod = $sourceClassReflection->getMethod('getState')) && $stateMethod->isAbstract()) { | |
$states = $definition->getStates(); | |
if (count($states) === 2) { | |
// There are two states: NOT_EXISTS and EXISTS. If there are any data, it EXISTS. | |
$theOtherState = null; | |
foreach ($states as $state) { | |
if ($state->getName() !== ReferenceInterface::NOT_EXISTS) { | |
$theOtherState = $state->getName(); | |
break; | |
} | |
} | |
$w->beginMethod('getState', [], 'string'); | |
{ | |
$w->writeln("return ($canLoadDataCondition) ? %s : " . $w->useClass(ReferenceInterface::class) . "::NOT_EXISTS;", $theOtherState); | |
} | |
$w->endMethod(); | |
} else { | |
$w->beginMethod('getState', [], 'string'); | |
{ | |
$w->writeln("return " . $w->useClass(ReferenceInterface::class) . "::NOT_EXISTS;"); | |
} | |
$w->endMethod(); | |
} | |
} | |
} | |
protected function generateGetMethod(PhpFileWriter $w, StateMachineDefinition $definition, ReflectionClass $sourceClassReflection) | |
{ | |
$w->beginMethod("get", ["string \$propertyName"]); | |
{ | |
$w->beginBlock("switch(\$propertyName)"); | |
{ | |
foreach ($definition->getProperties() as $p) { | |
$pName = $p->getName(); | |
// TODO: Get the getter properly. | |
$getter = 'get' . ucfirst($pName); | |
$w->writeln("case %s: return \$this->$getter();", $pName); | |
} | |
$w->writeln("default: throw new " . $w->useClass(InvalidArgumentException::class) . "(\"Undefined property: \$propertyName\");"); | |
} | |
$w->endBlock(); | |
} | |
$w->endMethod(); | |
} | |
} |