phalconplus Documentation v1.3.0-development
    namespace PhalconPlus\Rpc\Client\Adapter;
use PhalconPlus\Rpc\Client\AbstractClient;
use PhalconPlus\Base\ProtoBuffer;
use PhalconPlus\Base\Exception as BaseException;

class Local extends AbstractClient
{
    private config;
    private di;

    public function __construct(<\Phalcon\DI> di)
    {
        let this->di = di;
        let this->config = di->get("config");
    }

    private function callByParams(string! service, string! method, request)
    {
        var serviceObj = null, 
            methodReflection = null,
            serviceClass = "";

        let serviceClass  = service->upperfirst() . "Service";
        if !class_exists(serviceClass) {
            throw new BaseException("Service class not exists: " . serviceClass);
        }
        let serviceObj = new {serviceClass}(this->di);

        var e;
        try {
            let methodReflection = new \ReflectionMethod(serviceObj, method);
        } catch \ReflectionException, e {
            throw new BaseException("Service:method not found. Detail: " . serviceClass . " : " . method . ". RawException: ". e->getMessage());
        }
        error_log("ServerClass: " . serviceClass);
        error_log("InvokeMethod: " . method);

		if request == null && methodReflection->getNumberOfRequiredParameters() > 0 {
            throw new BaseException(service."::".method." need required params");
        }

        if methodReflection->getNumberOfParameters() > 0 {
            error_log("InputParam: " . var_export(request, true));
            // If get an object, must be instance of  or it's subclasses
            if is_object(request) && (request instanceof ProtoBuffer) {
                error_log("Request is object and instanceof ProtoBuffer: ". get_class(request));
            } elseif is_array(request) {
                var tmp = request, 
                    param = null, 
                    paramClass = "";
                let param = new \ReflectionParameter([serviceClass, method], 0);
                if param->getClass() {
                    let paramClass = param->getClass()->getName();
                    let request = new {paramClass}();
                    request->softClone(tmp);
                } else {
                    throw new BaseException("Service class:method definition is invalid. Detail: " . service . " : " . method . ". Request: " . json_encode(request));
                }
            } elseif null == request {
                // nothing here...
            } else {
                throw new BaseException("No service found: " . serviceClass . "::" . method);
            }
        }

        error_log("Finally Requst: ". var_export(request, true));
        
        var response;
        // Invoke target method
        try {
            // We expected type 
            let response = methodReflection->invokeArgs(serviceObj, [request]);
        } catch \Exception, e {
            throw new BaseException(e->getMessage());
        }
        // We do not allow to return #Resource type. And if an object returned, we expected type 
        if is_object(response) && !(response instanceof ProtoBuffer) {
            throw new BaseException("Your output is not allowed. Response: " . get_class(response) . ". We expect scalar type or ");
        } elseif is_resource(response) {
            throw new BaseException("Your output is not allowed. Response: #Resource.");
        }
        return response;
    }

    public function callByObject(array rawData)
    {
        var service, method, request;
        
        error_log("Local callByObject: " . var_export(rawData, true));

        if !fetch service, rawData["service"] {
            throw new BaseException("service " . service . " not exists");
        }
        if !fetch method, rawData["method"] {
            throw new BaseException("method " . method . " not exists");
        }
        if !fetch request, rawData["args"] {
            let request = null;
        }

        let service = this->namePrefix . trim(service);

        let method = trim(method);

        if empty service || empty method {
            throw new BaseException("service:method(args) must exists. All of them!!!");
        }

        error_log("Invoke callByParams with (" . service . ", " . method . ")");
		
        return this->callByParams(service, method, request);
    }
}