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