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

Custom 404 for different cases

It github, for example, there is path for ajax only requests - login/email checking. And when you try open this uri in browser (non-ajax request) you get 404 page, the same page as for nonexistent uri. How to do this right and gracefully in Phalcon? For example I can use

<?
$this->response->setStatusCode(404, "Not Found");
$this->dispatcher->forward(array(
        'controller' => 'error',
        'action'     => '_404',
));
return;

but it is not pretty, because if I want to change action I have to change it in many places where I do 404.



98.9k

You could add that logic to a ControllerBase:

class ControllerBase extends Phalcon\Mvc\Controller
{
    protected function checkAjaxRequired()
    {
        if (!$this->request->isAjax()) {
            $this->response->setStatusCode(404, "Not Found");
            $this->dispatcher->forward(array(
                'controller' => 'error',
                'action'     => '_404',
            ));
            return false;
        }
        return true;
    }
}

Then check if in specific actions:

class ProductsController extends ControllerBase
{
    public function saveAction()
    {
        if ($this->checkAjaxRequired()) {
            //...
        }
    }
}

Another option is create a plugin that check for methods marked with an annotation:

class ProductsController extends Phalcon\Mvc\Controller
{
    /**  
     * @RequireAjax
     */
    public function saveAction()
    {
        //...
    }
}
<?php

class CheckAjaxPlugin extends \Phalcon\Mvc\User\Plugin
{

    public function beforeExecuteRoute($event, $dispatcher)
    {

        $annotations = $this->annotations->getMethod(
            $dispatcher->getActiveController(),
            $dispatcher->getActiveMethod()
        );

        //Check if the method has an annotation 'RequireAjax'
        if ($annotations->has('RequireAjax')) {
            if (!$this->request->isAjax()) {
                $this->response->setStatusCode(404, "Not Found");
                $this->dispatcher->forward(array(
                    'controller' => 'error',
                    'action'     => '_404',
                ));
                return false;
            }
        }

        return true;
    }

}


32.5k

Thanks, I'll try. Annotations is really pretty thing =)

Sorry for a question but docs are a little bit hard to understanding =) What about merging it with "real" "Not Found"? Call beforeException inside beforeExecute, and then call 404 from beforeException?