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

Forward на notFound

Добрый день, подскажите как сделать forward на notFound роутер? Не передать массив с параметрами, а именно на данные роута, т.к. роуты могут меняться и надо чтобы не приходилось менять параметры по всему приложению. Перерыл всю документацию - не нашел.

Заранее благодарен.

я делал вот так https://pastebin.com/PURQSu10 А в контроллере уже просто выбрасываю throw new DispatcherException('Not Found', 404);



10.2k

Как вариант, но не решает части проблем (например, вьюхи могут находится в разных местах в зависимости от текущего модуля). Хотелось-бы заюзать dispatcher. Вот думаю, как бы реализовать это...

так в чем проблема? получаешься $di['dispatcher']->[getModuleName|getActionName]() или по нему уже конфиг смотришь путь для вьюх задаешь через setViewsDir()

если придумаешь что-то лучшее не прячь)) мне тоже интересно

  1. Проще всего реализовать вариант с отловом ошибок и исключений, примерно то же что предложил @vanchelo: https://docs.phalcon.io/en/latest/reference/dispatching.html#handling-not-found-exceptions
  2. Тоже не сложно - в BaseController определить метод notFound, и в нём forward на параметры notFound роутера.
  3. Вариант посложнее, но решающий конкретно поставленную цель - внутреннее перенаправление по определённому названию роута. Текущая реализация метода forward поддерживает лишь прямое указание параметров ( таблица тут https://docs.phalcon.io/en/latest/reference/dispatching.html#forwarding-to-other-actions ) для запуска определённого action. Что бы добавить такую возможность - надо наследовать класс Phalcon\Mvc\Dispatcher с добавлением метода notFound, в котором будет уже собираться правильный forward на параметры notFound.
  4. Еще вариант - расширить класс Phalcon\Mvc\Router методом getNotFoundPaths, возвращающим параметры, указанные в notFound правиле:
class extendedRouter extends Phalcon\Mvc\Router
{
    /**
     * @return array
     */
    public function getNotFoundPaths()
    {
        return $this->_notFoundPaths;
    }
}

B в контроллерах делать forward на метод: $this->dispatcher->forward( $this->router->getNotFoundPaths() );



10.2k

получаешься $di['dispatcher']->[getModuleName|getActionName]() или по нему уже конфиг смотришь путь для вьюх задаешь через setViewsDir()

Плохой вариант, имхо.

  1. Проще всего реализовать вариант с отловом ошибок и исключений, примерно то же что предложил @vanchelo: https://docs.phalcon.io/en/latest/reference/dispatching.html#handling-not-found-exceptions

По мне - самый привычный и правильный вариант. Все-таки, notFound (как и forbiddeт, например) - это именно exception. Посмотрю, спс. Как-раз начал двигаться в этом направлении.

Остальные варианты, имхо, на уровне хаков. Можно использовать, но не надо, если есть правильный.



10.2k

@boston, посмотрел пример @vanchelo - это не то. Данный код позволяет перехватить именно ошибочные урлы и вывести 404-ю страницу для них. У меня такой же код используется в модулях:

<?php

namespace Backend;

class Module implements \Phalcon\Mvc\ModuleDefinitionInterface
{

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

        $loader->registerNamespaces([
            'Backend'               => __DIR__,
            'Backend\Controller'    => __DIR__ . '/controller/',
            'Backend\Model'         => __DIR__ . '/model/',
        ])->register();
    }

    public function registerServices($di)
    {
        $di->set('dispatcher', function ()
        {
            $eventsManager = new \Phalcon\Events\Manager();
            $eventsManager->attach('dispatch', function ($event, $dispatcher, $exception)
            {
                if ($event->getType() == 'beforeException')
                {
                    switch ($exception->getCode())
                    {
                        case \Phalcon\Dispatcher::EXCEPTION_HANDLER_NOT_FOUND:
                        case \Phalcon\Dispatcher::EXCEPTION_ACTION_NOT_FOUND:
                            $dispatcher->forward([
                                'module'        => 'backend',
                                'controller'    => 'error',
                                'action'        => 'notFound'
                            ]);

                            return false;
                    }
                }
            });

            $dispatcher = new \Phalcon\Mvc\Dispatcher();
            $dispatcher->setDefaultNamespace('Backend\Controller');
            $dispatcher->setEventsManager($eventsManager);

            return $dispatcher;
        });

        $di->set('view', function ()
        {
            $view = new \Phalcon\Mvc\View();
            $view
                ->setMainView('layout')
                ->setViewsDir(__DIR__ . '/view/');

            $view->disableLevel([
                \Phalcon\Mvc\View::LEVEL_BEFORE_TEMPLATE    => true,
                \Phalcon\Mvc\View::LEVEL_AFTER_TEMPLATE     => true,
                \Phalcon\Mvc\View::LEVEL_LAYOUT             => true,
            ]);

            return $view;
        });
    }

}

Свою задачу данный код выполняет отлично, но не решает поставленную задачу. Например, в базовом контроллере код:

class Controller extends \Library\Controller
{

    public function initialize()
    {
        parent::initialize();

        if (!$this->auth->logged_in())
        {
            HTTP::redirect('/login');
        }
        else
        {
            if (!$this->auth->get_user()->admin)
            {
                $this->dispatcher->forward([
                    'module'        => 'backend',
                    'controller'    => 'error',
                    'action'        => 'notFound'
                ]);
            }
        }

        $this->tag->setTitle($this->message->get('application', 'title'));
    }

}

Как в этом коде использовать пример @vanchelo? Что-то я с ходу придумать не смог (.

В идеале, вместо $this->dispatcher->forward хочется использовать throw new Exception (или throw new Exception_404, например) и модуль, который будет перехватывать эти exception-ы и обрабатывать их в зависимости от кода.