Phalcon forward to different module

2.4k Views Asked by At

Trying to work my way through setting up a phalcon mvc application.

I have 2 modules current set up for testing. "Frontend" and "Admin".

I have different views set up so I can confirm I am getting through to each of the modules. When I change the defaultnamespace and defaultmodule I can indeed see that both modules are being accessed fine and loading ok. I can see that the admin controllers are being accessed correctly and the frontend controllers are being accessed when I change this.

The problem I am currently having is when I try to authenticate a user and start the session I want to forward the request over from "Frontend" to "Admin":

return $this->dispatcher->forward(array(
                'namespace' => 'Qcm\Admin\Controllers',
                'action' => 'index',
                'controller' => 'index'
            ));

Again I have confirmed these namespaces work fine. The problem is when I now forward onto the new namespace it can no longer find the admin index controller?

"Qcm\Admin\Controllers\IndexController handler class cannot be loaded"

However I have already confirmed that I can switch between the modules by changing the defaultnamespace/defaultmodule. Is this a limitation within the dispatcher that I can not forward to a different module?

Just to clarify I am also using the same url's so for example after login I want it to go back to '/' (root) but because it has forwarded to the admin module this should work fine correct?

4

There are 4 best solutions below

0
On

Because phalcon didn't add all modules to global loader, so the namespace is not registered. you need to register another module in current module bootstrap file, modify your Module.php as

class Module
{
    public function registerAutoloaders()
    {
        $loader = new \Phalcon\Loader();

        $loader->registerNamespaces(array(
             //Your current module namespaces here
             ....
             //Another module  namespaces here
             'Qcm\Admin\Controllers' => 'controller path',
        ));

        $loader->register();
    }
}
0
On

The main reason it shows IndexController class not loaded is because you might not have added Dispatcher in that module or in the bootstrap file(depending on your approach)

Add

$debug = new \Phalcon\Debug();
$debug->listen();

to your code before

$application->handle()->getcontent();

to view erros.

1
On

Before the replacement line:

 echo $application->handle()->getContent();

code:

    $router  = $this->getDi()->get("router");
    $params  = $router->getParams();
    $modName = $router->getModuleName();
    $url     = null;

    if ($modName == "admin" && isset($params[0])) {
        $module     = "/" . $params[0];
        $controller = isset($params[1]) ? "/" . $params[1] . "/" : null;
        $action     = isset($params[2]) ? $params[2] . "/" : null;
        $params     = sizeof($params) > 3 ? implode("/", array_slice($params, 3)) . "/" : null;
        $url        = $module . $controller . $action . $params;
    }
echo $application->handle($url)->getContent();
1
On

The phalcon dispatcher can only forward to actions within the same module. It cannot forward you outside the current module. This restriction comes because the dispatcher is only aware of the module in which it is declared.

In order to forward to another module, you must instead return a redirect response from a controller action. In my case, I wanted to forward the user to a login screen or a 404 error page based on their ACL permissions in the beforeDispatch() method of a plugin. The dispatcher is native to this method, but cannot forward the user outside of the current module. Instead, I have the dispatcher forward the user to a controller in the same module that has a custom action that in turn performs the redirect.

// hack to redirect across modules
$dispatcher->forward(
    array(
        'controller'   => 'security',
        'action'       => 'redirect',
        'params'       => array(
            'redirect' => '/home/index/login'
        ),
    )
);
return false; // stop progress and forward to redirect action

This means that each module needs to have a copy of this custom redirect action in one of its controllers. I accomplished this by putting the action in the base controller that all of my controllers extend from.

/**
 * the phalcon dispatcher cannot forward across modules
 * instead, forward to this shared action which can then redirect across modules
 * */
public function redirectAction(){
    $this->view->disable();
    $params = $this->dispatcher->getParams();
    $redirect = '/';
    if( ! empty( $params['redirect'] ) ){
        $redirect = $params['redirect'];
    }
    return $this->response->redirect( $redirect );
}