SwrpcGenCom.php 6.3 KB
<?php

namespace AukeySwrpc\Commands;


use Illuminate\Console\Command;
use Nwidart\Modules\Facades\Module;
use AukeySwrpc\LogicService;

/**
 * Class SwrpcGenCom
 *
 * @package App\Console\Commands
 * @author pengjch 2024314 12:13:7
 */
class SwrpcGenCom extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'swrpc:gen {-m|--module=} {-s|--service=}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'swrpc客户端代码生成器';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     * @throws \ReflectionException
     */
    public function handle()
    {
//        $serviceKey = env('SWRPC_SERVER_NAME');
//        if (!$serviceKey) {
//            $this->error('SWRPC_SERVER_NAME未设置');
//            return -1;
//        }

        $filters = [];
        $specifyModules = $this->option('module') ? explode(',', $this->option('module')) : [];
        $loader = require base_path('vendor').'/autoload.php';
        // 获取注册的命名空间前缀并筛选出 Composer 包的命名空间
        $prefixes = $loader->getPrefixesPsr4();
        foreach ($prefixes as $key => $prefix) {
            //如果有指定moudle,则只有指定的moudle会生成,否则会生成全部
            if (count($specifyModules) > 0 && !in_array($key, $specifyModules, true)) {
                continue;
            }
            $moduleName = $key;
            $modulePath = str_replace('\\', '/', $moduleName);

            //create module dir
            $basePath = base_path('app/Clients/' . $modulePath);
            if (!is_dir($basePath)) {
                $this->mkdir($basePath);
            }

            //target service namespace
            $namespace = $key . 'Http\Service';
            //fetch file
            $servicePath = $prefix[0] . '/Http/Service';
            if (!is_dir($servicePath)) {
                continue;
            }
            $queues = scandir($servicePath);
            while (count($queues) > 0) {
                $file = array_shift($queues);
                if ($file == '.' || $file == '..' || in_array($file, $filters)) {
                    continue;
                }
                //支持嵌套多层service目录
                if (is_dir($servicePath . '/' . $file)) {
                    $childrenFiles = scandir($servicePath . '/' . $file);
                    foreach ($childrenFiles as $f) {
                        if ($f == '.' || $f == '..' || in_array($f, $filters)) {
                            continue;
                        }
                        array_push($queues, $file . '/' . $f);
                    }
                    continue;
                }
                $class = substr($file, 0, strrpos($file, '.'));
                $funcs = $this->parseFunc($namespace, $class);
                if (empty($funcs)) {
                    continue;
                }

                //generate proxy file
                $proxyPath = $basePath . '/' . $file;
                ob_start();
                ob_implicit_flush(false);
                include(__DIR__.'/client.template.php');
                $content = ob_get_clean();
                if (!file_put_contents($proxyPath, $content)) {
                    $this->error($proxyPath . ' import failure.');
                } else {
                    $this->info($proxyPath . ' import success.');
                }
            }
        }

        $this->info('完成.');
        return 0;
    }

    /**
     * @param $path
     * @return bool
     * @author pengjch 2024314 12:54:6
     */
    protected function mkdir($path)
    {
        if (!is_dir($path)) {
            $this->mkdir(dirname($path));
            if (!mkdir($path, 0777)) {
                return false;
            }
        }
        return true;
    }

    /**
     * parseFunc
     *
     * @param $namespace
     * @param $class
     * @return array
     * @throws \ReflectionException
     * @author pengjch 202435 16:3:16
     */
    protected function parseFunc($namespace, $class): array
    {
        $serviceClass = str_replace('/', '\\', $namespace . '\\' . $class);
        if (!class_exists($serviceClass)) {
            $this->error($serviceClass . '类不存在');
            return [];
        }

        try {
            $rc = new \ReflectionClass($serviceClass);
        } catch (\ReflectionException $e) {
            $this->error($serviceClass . $e->getMessage());
            return [];
        }

        $serviceObj = $rc->newInstance();
        if (!($serviceObj instanceof LogicService)) {
            $this->warn('没有继承\AukeySwrpc\LogicService类,跳过'.get_class($serviceObj));
            return [];
        }

        $funcs = [];
        foreach ($rc->getMethods() as $method) {
            if (in_array($method->getName(), [
                'factory',
                'initTracer',
                'setModule',
                'setTracerUrl',
                'setParams',
                'setTracerContext',
                'getTracerContext'
            ])
            ) {
                continue;
            }
            if (false === $method->isPublic()) {
                continue;
            }
            $line = '';
            if ($returnType = $method->getReturnType()) {
                $line .= $returnType->getName();
            }
            $line .= ' ' . $method->getName() . '(';
            $params = '';
            foreach ($method->getParameters() as $parameter) {
                $params .= '$' . $parameter->getName();
                if ($parameter->isOptional() && $value = $parameter->getDefaultValue()) {
                    if (is_string($value)) {
                        $params .= '="' . $value . '"';
                    } else {
                        $params .= '=' . $value;
                    }
                }
                $params .= ',';
            }
            $line .= rtrim($params, ',');
            $line .= ")\r\n";
            $funcs[] = $line;
        }

        if (count($funcs) == 0) {
            $this->warn('没有可用的方法', ['service' => $serviceObj->getName()]);
        }

        return $funcs;
    }
}