Phalcon\Micro: выполнить другое действие контроллера в действии

У меня есть действие контроллера, которое выполняется на одном сервере. Это действие должно запускать две другие службы, которые могут находиться на том же или другом сервере (в зависимости от настроенных маршрутов). В настоящее время я всегда использую HTTP-запросы. Но если службы находятся на одном сервере, я бы предпочел напрямую вызывать соответствующий контроллер (в зависимости от URL-адреса, соблюдая пользовательские маршруты).

Мой код с запросами выглядит так:

public function buildMultiple($platform, $name, $limit = null, $offset = null) {
    $config = $this->getDI()->get('config');

    $workerUrl = "{$config->application->WorkerUrl}/$platform/$name/compute/multiple/$limit/$offset";
    $response = HttpRequest::get($workerUrl);
    $data = json_decode($response)->data;

    $clientUrl = "{$config->application->ClientUrl}/$platform/$name/update/multiple";

    //TODO if the routes for the client are activated on this server then directly execute the controller
    //if($config->application->ClientRoutes) {
        // pseudocode:
        // $cont = $this->router->getControllerFromUri($clientUrl);
        // $result = $this->dispatcher($cont)->call($params, $postData);
        // return $result;
    //}
    // else:

    return HttpRequest::post($clientUrl, $data);
}

person velop    schedule 09.05.2017    source источник
comment
Итак, как использовать HTTP-запросы, если маршруты не существуют в локальном экземпляре? Это твой вопрос?   -  person ʰᵈˑ    schedule 09.05.2017
comment
Но действие - это действие, конечная точка http, если вы хотите, чтобы это был просто общий метод, переместите его в какой-то общий метод, на самом деле не вижу проблемы.   -  person Juri    schedule 09.05.2017
comment
@Juri, проблема в том, что мой маршрутизатор маршрутизируется на разные контроллеры в зависимости от URL-адреса. Если я хочу вызвать соответствующий контроллер и метод, мне придется дублировать поведение маршрутизатора. Я надеюсь, что в Phalcon это уже каким-то образом реализовано (см. мой обновленный псевдокод)   -  person velop    schedule 09.05.2017
comment
Не могли бы вы добавить некоторые пояснения. Когда вы говорите, что один и тот же сервер, вы имеете в виду тот же сервер, другое приложение? Или такое же приложение? Если то же приложение, то не могли бы вы перенаправить на соответствующий контроллер. Если другое приложение, как насчет контроллера хуков, который затем может пересылать? Или использовать очередь сообщений beanstalkd с фоновыми задачами, которые производят и потребляют?   -  person baychae    schedule 10.05.2017
comment
Да, просто переместите свой код, который должен выполняться в обоих действиях, в отдельный код. Существует $this->dispatcher->forward, но, как следует из названия, он перенаправляет выполнение действия другому действию. Типа возвращение сюда на самом деле ничего не даст.   -  person Juri    schedule 10.05.2017


Ответы (1)


Я нашел возможное решение:

public function buildMultiple($platform, $name, $limit = null, $offset = null) {
    $workerUrl = "/$platform/$name/compute/multiple/$limit/$offset";

    if($config->application->mviewWorkerRoutes) {
        $response = RoutesToControllerMapper::call($this, $workerUrl, [$platform, $name, $limit, $offset]);
        $data = $response['data'];
    }
    else {
        $response = HttpRequest::get($config->application->mviewWorkerUrl.$workerUrl, ['changed' => $changedFields]);
        $data = json_decode($response)->data;
    }

    $clientUrl = "/$platform/$name/update/multiple";

    return $config->application->mviewClientRoutes ?
        RoutesToControllerMapper::call($this, $clientUrl, [$platform, $name, $data]) :
        HttpRequest::post($config->application->mviewClientUrl.$clientUrl, $data);
}

тогда как RoutesToControllerMapper выглядит так:

class RoutesToControllerMapper
{
    public static function call($controller, $url, $arguments) {
        /** @var Micro $app */
        $app = $controller->getDI()->getApplication();
        /** @var Micro\LazyLoader $loader */
        list($loader, $method) = RoutesToControllerMapper::map($app, $url);
        return $loader->callMethod($method, $arguments);
    }

    /**
     * @param Micro $app
     */
    public static function map($app, $uri) {
        foreach($app->getRouter()->getRoutes() as $route) {
            if(preg_match($route->getCompiledPattern(), $uri) === 1) {
                $lastMatchedRoute = $route;
            }
        }

        if(!isset($lastMatchedRoute)) {
            return null;
        }

        $handler = $app->getHandlers()[$lastMatchedRoute->getRouteId()];
        /** @var Micro\LazyLoader $lazyLoader */
        $lazyLoader = $handler[0];
        return [$lazyLoader, $handler['1']];
    }
}
person velop    schedule 10.05.2017