Last active
May 4, 2020 18:06
-
-
Save grachevko/3a3be4437c35da1e88684b8b85aaa0da to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
require_once __DIR__.'/vendor/autoload.php'; | |
Symfony\Component\ErrorHandler\Debug::enable(); | |
$arr = Symfony\Component\Yaml\Yaml::parse(\file_get_contents(__DIR__.'/config/packages/rpc_server.yaml')); | |
$dirs = \array_merge(...\array_values($arr['rpc_server']['mapping'])); | |
$dirs = \array_map(fn (string $path) => \str_replace('%kernel.project_dir%', __DIR__, $path), $dirs); | |
$dirs = \array_filter($dirs, fn (string $path) => \file_exists($path)); | |
\asort($dirs); | |
$dirs = \array_unique($dirs); | |
$dirs = \array_values($dirs); | |
$reader = new Doctrine\Common\Annotations\AnnotationReader(); | |
$filesystem = new Symfony\Component\Filesystem\Filesystem(); | |
$namespaceClosure = static function (string $fqcn) { | |
$fqcn = \str_replace([ | |
'\\Presentation', | |
'\\V1', | |
'\\V2', | |
'\\Rpc', | |
'\\Method', | |
'\\Api', | |
], '', $fqcn); | |
$array = \explode('\\', $fqcn); | |
\array_pop($array); | |
return \implode('\\', [ | |
\array_shift($array), | |
\array_shift($array), | |
'Ports', | |
'Rpc', | |
...$array, | |
]); | |
}; | |
$addUse = static function (Laminas\Code\Generator\TraitUsageInterface $generator, string $use): void { | |
if (0 === \strpos($use, 'Timiki')) { | |
return; | |
} | |
[$class, $alias] = false === \strpos(' ', $use) | |
? [$use, null] | |
: \explode(' ', \str_replace(' as ', ' ', $use)); | |
if (!\class_exists($class) && !\interface_exists($class)) { | |
return; | |
} | |
$generator->addUse($class, $alias); | |
}; | |
$handled = []; | |
foreach ($dirs as $dir) { | |
foreach (Symfony\Component\Finder\Finder::create()->in($dir)->files() as $item) { | |
$filePath = $item->getPathname(); | |
if (\array_key_exists($filePath, $handled)) { | |
continue; | |
} | |
$handled[$filePath] = true; | |
$fileGenerator = Laminas\Code\Generator\FileGenerator::fromReflectedFileName($filePath); | |
$classGenerator = $fileGenerator->getClass(); | |
$classFQCN = $classGenerator->getNamespaceName().'\\'.$classGenerator->getName(); | |
$reflectionClass = new ReflectionClass($classFQCN); | |
$rpcMethod = null; | |
$rpcRoles = []; | |
foreach ($reader->getClassAnnotations($reflectionClass) as $classAnnotation) { | |
if ($classAnnotation instanceof Timiki\Bundle\RpcServerBundle\Mapping\Method) { | |
$rpcMethod = $classAnnotation->value; | |
} | |
if ($classAnnotation instanceof Timiki\Bundle\RpcServerBundle\Mapping\Roles) { | |
$rpcRoles = $classAnnotation->value; | |
} | |
} | |
if (null === $rpcMethod) { | |
continue; | |
} | |
$executeMethodGenerator = null; | |
foreach ($reflectionClass->getMethods() as $reflectionMethod) { | |
foreach ($reader->getMethodAnnotations($reflectionMethod) as $methodAnnotation) { | |
if ($methodAnnotation instanceof Timiki\Bundle\RpcServerBundle\Mapping\Execute) { | |
$executeMethodGenerator = $classGenerator->getMethod($reflectionMethod->getName()); | |
break; | |
} | |
} | |
} | |
if (null === $executeMethodGenerator) { | |
dump('Execute method not found for '.$classFQCN); | |
continue; | |
} | |
$isCommand = null === $executeMethodGenerator->getReturnType(); | |
$handlerNamespace = $namespaceClosure($classFQCN); | |
$handlerGenerator = (new Laminas\Code\Generator\ClassGenerator()) | |
->setNamespaceName($handlerNamespace) | |
->setName($classGenerator->getName()) | |
->setFinal(true) | |
// ->setDocBlock( | |
// (new Laminas\Code\Generator\DocBlockGenerator()) | |
// ->setTag(['name' => 'see \\'.$classFQCN]) | |
// ) | |
->addUse(App\Core\JSONRPC\RPC::class); | |
foreach ($classGenerator->getUses() as $use) { | |
$addUse($handlerGenerator, $use); | |
} | |
$handlerInputConstructorGenerator = (new \Laminas\Code\Generator\MethodGenerator('__construct')) | |
->setVisibility('private'); | |
$handlerInputGenerator = (new Laminas\Code\Generator\ClassGenerator()) | |
->setNamespaceName($handlerNamespace) | |
->setName($handlerGenerator->getName().($isCommand ? 'Command' : 'Query')) | |
->addUse('Symfony\Component\Validator\Constraints', 'Assert') | |
->addMethodFromGenerator($handlerInputConstructorGenerator); | |
$handlerInvokeParameterName = $isCommand ? 'command' : 'query'; | |
$handlerInvokeGenerator = new Laminas\Code\Generator\MethodGenerator('__invoke'); | |
if (null !== $executeMethodGenerator->getReturnType()) { | |
$handlerInvokeGenerator->setReturnType($executeMethodGenerator->getReturnType()->generate()); | |
} | |
$endpoint = null; | |
if (0 === \strpos($classFQCN, 'App\\CRM')) { | |
$endpoint = 'crm'; | |
} elseif (0 === \strpos($classFQCN, 'App\\PersonalCabinet')) { | |
$endpoint = 'pc'; | |
} elseif (0 === \strpos($classFQCN, 'App\\Security')) { | |
$endpoint = 'security'; | |
} | |
if (null === $endpoint) { | |
dd('Not found Endpoint for '.$classFQCN); | |
} | |
$version = 1; | |
if (false !== \strpos($classFQCN, '\\V2\\')) { | |
$version = 2; | |
} | |
$invokeDocBlocks = []; | |
$invokeDocBlocks[] = \sprintf( | |
'@RPC(endpoint="%s", method="%s", version="%s")', | |
$endpoint, | |
$rpcMethod, | |
$version | |
); | |
if ([] !== $rpcRoles) { | |
$handlerGenerator->addUse(Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted::class); | |
$invokeDocBlocks[] = ''; | |
} | |
foreach ($rpcRoles as $rpcRole) { | |
$invokeDocBlocks[] = \sprintf('@IsGranted("%s")', $rpcRole); | |
} | |
$handlerInvokeGenerator->setDocBlock(\implode(PHP_EOL, $invokeDocBlocks)); | |
$handlerInvokeGenerator->setBody($executeMethodGenerator->getBody()); | |
$handlerConstructorGenerator = new Laminas\Code\Generator\MethodGenerator('__construct'); | |
$handlerGenerator->addMethodFromGenerator($handlerInvokeGenerator); | |
foreach ($reflectionClass->getMethods() as $reflectionMethod) { | |
if ($executeMethodGenerator->getName() === $reflectionMethod->getName()) { | |
continue; | |
} | |
if (\in_array($reflectionMethod->name, ['getContainer', 'setContainer'], true)) { | |
continue; | |
} | |
$methodGenerator = Laminas\Code\Generator\MethodGenerator::fromReflection( | |
new Laminas\Code\Reflection\MethodReflection($reflectionMethod->class, $reflectionMethod->name) | |
); | |
$returnTypeGenerator = $methodGenerator->getReturnType(); | |
if (null !== $returnTypeGenerator) { | |
$dependencyClass = $returnTypeGenerator->type; | |
$addUse($handlerGenerator, $dependencyClass); | |
$addUse($handlerInputGenerator, $dependencyClass); | |
} | |
$normalizedMethodBody = \trim(\preg_replace('/\n\s+/', '', $methodGenerator->getBody())); | |
if ('getTokenStorage' === $methodGenerator->getName()) { | |
continue; | |
} | |
if ('getUser' === $methodGenerator->getName()) { | |
if (false === \strpos($handlerInvokeGenerator->getBody(), 'this->getUser')) { | |
continue; | |
} | |
$handlerInvokeGenerator->setParameter( | |
(new \Laminas\Code\Generator\ParameterGenerator()) | |
->setName('user') | |
->setType(App\Security\Application\UserData::class) | |
) | |
->setBody( | |
\str_replace( | |
'this->getUser()', | |
'user', | |
$handlerInvokeGenerator->getBody() | |
) | |
); | |
continue; | |
} | |
if (false !== \strpos($normalizedMethodBody, 'getContainer()->get')) { | |
if ([] !== $reflectionMethod->getParameters()) { | |
dd('Looks like method require parameters.'); | |
} | |
$dependencyName = Symfony\Component\String\u((new ReflectionClass($dependencyClass))->getShortName())->camel()->toString(); | |
$dependencyName = \str_replace('Interface', '', $dependencyName); | |
$handlerInvokeGenerator->setBody( | |
\str_replace( | |
\sprintf('$this->%s()', $methodGenerator->getName()), | |
\sprintf('$this->%s', $dependencyName), | |
$handlerInvokeGenerator->getBody(), | |
) | |
); | |
$handlerGenerator->addPropertyFromGenerator( | |
(new Laminas\Code\Generator\PropertyGenerator()) | |
->setName($dependencyName) | |
->setType($dependencyClass) | |
->setVisibility('private') | |
); | |
$handlerConstructorGenerator->setParameter( | |
(new Laminas\Code\Generator\ParameterGenerator()) | |
->setName($dependencyName) | |
->setType($dependencyClass) | |
); | |
$handlerConstructorGenerator->setBody( | |
$handlerConstructorGenerator->getBody() | |
.PHP_EOL | |
.\sprintf('$this->%s = $%s;', $dependencyName, $dependencyName) | |
); | |
continue; | |
} | |
$methodGenerator->setVisibility('public'); | |
$methodGenerator->setFinal(false); | |
foreach ((\Laminas\Code\Generator\FileGenerator::fromReflectedFileName( | |
$reflectionMethod->getFileName() | |
))->getUses() as [$class, $alias]) { | |
$addUse($handlerGenerator, $class); | |
$addUse($handlerInputGenerator, $class); | |
if (null === $alias) { | |
continue; | |
} | |
$arr = \explode('\\', $class); | |
$name = \array_pop($arr); | |
$methodGenerator->setBody(\str_replace( | |
[\sprintf(' %s(', $alias), \sprintf(' %s::', $alias)], | |
[\sprintf(' %s(', $name), \sprintf(' %s::', $name)], | |
$methodGenerator->getBody()) | |
); | |
} | |
$handlerInputGenerator->addMethodFromGenerator($methodGenerator); | |
$handlerInvokeGenerator->setBody( | |
\str_replace( | |
\sprintf('$this->%s(', $methodGenerator->getName()), | |
\sprintf('$%s->%s(', $handlerInvokeParameterName, $methodGenerator->getName()), | |
$handlerInvokeGenerator->getBody(), | |
) | |
); | |
} | |
foreach ($reflectionClass->getProperties() as $reflectionProperty) { | |
$handlerInvokeGenerator->setBody( | |
\str_replace( | |
\sprintf('$this->%s', $reflectionProperty->name), | |
\sprintf('$%s->%s', $handlerInvokeParameterName, $reflectionProperty->name), | |
$handlerInvokeGenerator->getBody(), | |
) | |
); | |
$type = (static function (string $doc) { | |
$varLine = null; | |
foreach (\explode(PHP_EOL, $doc) as $row) { | |
if (false !== \strpos($row, '@var')) { | |
$varLine = $row; | |
break; | |
} | |
} | |
$varLine = \str_replace(['@var', '*', 'null'], '', $varLine); | |
$varLine = \trim($varLine); | |
$varLine = \trim($varLine, '|[]'); | |
return \trim($varLine); | |
})($reflectionProperty->getDocComment()); | |
$parameterGenerator = (new \Laminas\Code\Generator\ParameterGenerator($reflectionProperty->name)); | |
if (null !== $type) { | |
$parameterGenerator->setType($type); | |
} | |
$handlerInputConstructorGenerator | |
->setParameter($parameterGenerator) | |
->setBody( | |
$handlerInputConstructorGenerator->getBody() | |
.PHP_EOL. | |
\sprintf('$this->%s = $%s;', $reflectionProperty->name, $reflectionProperty->name) | |
); | |
$handlerInputGenerator | |
->addPropertyFromGenerator( | |
(new Laminas\Code\Generator\PropertyGenerator()) | |
->setName($reflectionProperty->name) | |
->setVisibility('public') | |
->setDocBlock((static function (string $docBlock): string { | |
$docBlock = \preg_replace('/.+@Rpc.+\n/', '', $docBlock); | |
$rows = []; | |
foreach (\explode(PHP_EOL, $docBlock) as $row) { | |
$row = \trim($row); | |
if ('/**' === $row || '*/' === $row) { | |
continue; | |
} | |
$row = \trim(\ltrim($row, '*')); | |
if ('' === $row) { | |
continue; | |
} | |
$rows[] = $row; | |
if (0 === \strpos($row, '@var')) { | |
$rows[] = ''; | |
} | |
} | |
return \implode(PHP_EOL, $rows); | |
})($reflectionProperty->getDocComment())) | |
); | |
} | |
$folder = __DIR__.'/src/'.\str_replace(['App\\', '\\'], ['', '/'], $handlerGenerator->getNamespaceName()).'/'; | |
$filesystem->mkdir($folder); | |
if ([] !== $handlerInputGenerator->getProperties()) { | |
$handlerInvokeGenerator->setParameter( | |
(new Laminas\Code\Generator\ParameterGenerator($handlerInvokeParameterName)) | |
->setType($handlerNamespace.'\\'.$handlerInputGenerator->getName()) | |
); | |
\file_put_contents($folder.$handlerInputGenerator->getName().'.php', '<?php'.PHP_EOL.$handlerInputGenerator->generate()); | |
// @unlink($folder.$handlerInputGenerator->getName().'.php'); | |
} | |
if ('' !== $handlerConstructorGenerator->getBody()) { | |
$handlerGenerator->addMethodFromGenerator($handlerConstructorGenerator); | |
} | |
// @unlink($folder.$handlerGenerator->getName().'.php'); | |
\file_put_contents($folder.$handlerGenerator->getName().'.php', '<?php'.PHP_EOL.$handlerGenerator->generate()); | |
} | |
$filesystem->remove($dir); | |
break; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment