We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

how to check the whether controller and action exits before dispatching.

I want to dispatch the request to error404 controller if the controller and action doesn,t exit. And where to do that dispatching part. Please help!!

edited Nov '16

for a given controller i want to check whether action exits or not.... ......below is my code

    $controller = $dispatcher->getControllerName();
    $action = $dispatcher->getActionName();

    $acl = $this->getAcl();

    if (!$acl->isResource($controller)) {
        $dispatcher->forward([
            'controller' => 'errors',
            'action' => 'show404'
        ]);

        return false;
    }

    i want to do the same thing for action also

    *************************************************************************************
     i have tried this from the above information
     $controller = $dispatcher->getControllerName();
    $action = $dispatcher->getActionName();

    $acl = $this->getAcl();

    if (!$acl->isResource($controller)) {
        $dispatcher->forward([
            'controller' => 'errors',
            'action' => 'show404'
        ]);

        return false;
    }

    $this->getDi()->setShared(
            "dispatcher", function () {
        // Create an EventsManager
        $eventsManager = new EventsManager();

        // Attach a listener
        $eventsManager->attach(
                "dispatch:beforeException", function (Event $event, $dispatcher, Exception $exception) {

            // Alternative way, controller or action doesn't exist
            switch ($exception->getCode()) {                    
                case Dis::EXCEPTION_ACTION_NOT_FOUND:
                    $dispatcher->forward(
                            [
                                "controller" => "index",
                                "action" => "show404",
                            ]
                    );

                    return false;
            }
        }
        );

        $dispatcher = new Dispatcher();

        // Bind the EventsManager to the dispatcher
        $dispatcher->setEventsManager($eventsManager);

        return $dispatcher;
    }
    );

    $allowed = $acl->isAllowed($role, $controller, $action);
    if ($allowed != Acl::ALLOW) {
        $dispatcher->forward(array(
            'controller' => 'errors',
            'action' => 'show401'
        ));
        $this->session->destroy();
        return false;
    }
}

but still it is not working

What a hell is case Dis::EXCEPTION_ACTION_NOT_FOUND ? It should work like Dispatcher::EXCEPTION_ACTION_NOT_FOUND and beforeException and forward.

What a hell is case Dis::EXCEPTION_ACTION_NOT_FOUND ? It should work like Dispatcher::EXCEPTION_ACTION_NOT_FOUND and beforeException and forward. ..........................

the namespace i am using is ***use Phalcon\Dispatcher as Dis;****

So what exactly is happening in this case ?

edited Nov '16
      nothing......

       i had wirtten the following code to check controller is present or not....and it is working fine
       if (!$acl->isResource($controller)) {
    $dispatcher->forward([
        'controller' => 'errors',
        'action' => 'show404'
    ]);

    return false;
}
**********
and the rest code i have written to check valid action name is given in the url ....but it is not working??

Do you know any other procedure to do this??
 $this->getDi()->setShared(
            "dispatcher", function () {
        // Create an EventsManager
        $eventsManager = new EventsManager();

        // Attach a listener
        $eventsManager->attach(
                "dispatch:beforeException", function (Event $event, $dispatcher, Exception $exception) {

            // Alternative way, controller or action doesn't exist
            switch ($exception->getCode()) {                    
                case Dis::EXCEPTION_ACTION_NOT_FOUND:
                    $dispatcher->forward(
                            [
                                "controller" => "index",
                                "action" => "show404",
                            ]
                    );

                    return false;
            }
        }
        );

        $dispatcher = new Dispatcher();

        // Bind the EventsManager to the dispatcher
        $dispatcher->setEventsManager($eventsManager);

        return $dispatcher;
    }
    );

This is correct way to check if action exists. If action is not found then it will forward to 404. Where you putted all this acl stuff etc ?

edited Nov '16

i have been using INVO as skeleton code for my project.... and i had wriiten above code in a function ( beforeDispatch) which runs before dispatching the controller,action

the code for the function is...

  public function beforeDispatch(Event $event, Dispatcher $dispatcher) {

    $auth = $this->session->get('auth');
    if (!$auth) {
        $role = 'Guests';
    } else {
        $role = 'Users';
    }

    $controller = $dispatcher->getControllerName();
    $action = $dispatcher->getActionName();

    $acl = $this->getAcl();

    if (!$acl->isResource($controller)) {
        $dispatcher->forward([
            'controller' => 'errors',
            'action' => 'show404'
        ]);

        return false;
    }
$this->getDi()->setShared(
        "dispatcher", function () {
    // Create an EventsManager
    $eventsManager = new EventsManager();

    // Attach a listener
    $eventsManager->attach(
            "dispatch:beforeException", function (Event $event, $dispatcher, Exception $exception) {

        // Alternative way, controller or action doesn't exist
        switch ($exception->getCode()) {                    
            case Dis::EXCEPTION_ACTION_NOT_FOUND:
                $dispatcher->forward(
                        [
                            "controller" => "errors",
                            "action" => "show404",
                        ]
                );

                return false;
        }
    }
    );

    $dispatcher = new Dispatcher();

    // Bind the EventsManager to the dispatcher
    $dispatcher->setEventsManager($eventsManager);

    return $dispatcher;
}
);        

    $allowed = $acl->isAllowed($role, $controller, $action);
    if ($allowed != Acl::ALLOW) {
        $dispatcher->forward(array(
            'controller' => 'errors',
            'action' => 'show401'
        ));
        $this->session->destroy();
        return false;
    }
}
edited Nov '16

As i already wrote your code is wrong. You already have code to detect if action exists or not here:

  $this->getDi()->setShared(
        "dispatcher", function () {
    // Create an EventsManager
    $eventsManager = new EventsManager();

    // Attach a listener
    $eventsManager->attach(
            "dispatch:beforeException", function (Event $event, $dispatcher, Exception $exception) {

        // Alternative way, controller or action doesn't exist
        switch ($exception->getCode()) {                    
            case Dis::EXCEPTION_ACTION_NOT_FOUND:
                $dispatcher->forward(
                        [
                            "controller" => "errors",
                            "action" => "show404",
                        ]
                );

                return false;
        }
    }
    );

    $dispatcher = new Dispatcher();

    // Bind the EventsManager to the dispatcher
    $dispatcher->setEventsManager($eventsManager);

    return $dispatcher;
}
); 

BeforeDispatch doesn't know if action exists or not. That's it.

If action doesn't exists phalcon is producing exception which you are catching in beforeException. Not sure why you are even setting dispatcher in beforeDispatch.

Ya..but the code not working....When I try to check by passing an url with invalid action..it is not working....or is it the wrong place i had written the code.

edited Nov '16

Just where you have di created do this:

$di->setShared('dispatcher',
 // Create an EventsManager
    $eventsManager = new EventsManager();

    // Attach a listener
    $eventsManager->attach(
            "dispatch:beforeException", function (Event $event, $dispatcher, Exception $exception) {

        // Alternative way, controller or action doesn't exist
        switch ($exception->getCode()) {                    
            case Dis::EXCEPTION_ACTION_NOT_FOUND:
                $dispatcher->forward(
                        [
                            "controller" => "errors",
                            "action" => "show404",
                        ]
                );

                return false;
        }
    }
    );

    $dispatcher = new Dispatcher();

    // Bind the EventsManager to the dispatcher
    $dispatcher->setEventsManager($eventsManager);

    return $dispatcher;
});

It works for me. The problem looks like you are doing some weird stuff like changing dispatcher definition while you already in disptacher loop ?