Как сделать разные страницы ошибок для разных контролеров?

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Как сделать разные страницы ошибок для разных контролеров?

Сообщение slo_nik »

Вечер добрый.
Есть задача показывать разные шаблоны страницы ошибок для разных контролеров.
Знаю, что можно переопределить в конфигурационном файле, можно через init() контроелера.
Но вот тут я не могу сообразить как правильно сделать.
Структура проекта следующая(yii2-basic).

Код: Выделить всё

controllers
    admin
        users
            UsersController
        countries
            CountriesController    
        AdminController
        DefaultController
     SiteController
     
 views
    admin
       users
       countries
       default
          error.php
          index.php
    site
       index.php
       error.php               
В контролере AdminController через AccessControl закрыл доступ к остальным контролерам админки и пытаюсь переопределить errorAction. Остальные контролеры наследуют AdminController

Код: Выделить всё

<?php
class AdminController extends Controller
{

    public function init()
    {
        parent::init();
        $this->layout = 'admin/main.php';
        Yii::$app->view->getAssetManager()->bundles = [];
        Yii::$app->errorHandler->errorAction = 'admin/default/error';
        Yii::$app->user->loginUrl = ['/admin/login'];
        Yii::$app->errorHandler->errorView = '@app/views/admin/default/error';

    }

    public function actions()
    {
        return [
            'error' => [
                'class' => 'yii\web\ErrorAction',
               // 'view' => '@app/views/admin/default/error'
            ]
        ];
    }

    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::class,
                'except' => ['login'],
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@']
                    ]
                ]
            ]
        ];
    }
}
Получается, что я не использую модули для админки, просто выделил файлы админики в директорию admin.
Проблема в следующем.
Я перехожу в админку по localhost/admin.
Если я намеренно делаю ошибку в адресе, например, localhost/admin/use2rs, то меня перекидывает на site/error, вроде бы всё правильно, страницы use2rs у меня не существует. Если делаю ошибку, вызов несуществующей записи localhost/admin/user/view/09, то меня перекидывает туда, куда я хочу - на admin/error.

Как сделать так, чтобы при переходе на несуществующую страницу в админе перекидывало не на site/error, а на admin/error?
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение slo_nik »

Задачу решил пока таким способом.

Код: Выделить всё

<?php

namespace app\components;

class ErrorHandler extends \yii\web\ErrorHandler
{
    public $actionsForPrefix;
    public function __construct($config = [])
    {
        parent::__construct($config);
        foreach ($this->actionsForPrefix as $prefix => $action) {
            if (strpos($_SERVER['REQUEST_URI'], $prefix) !== false) {
                $this->errorAction = $action;
            }
        }
    }
}
В конфигурационном файле

Код: Выделить всё

        'errorHandler' => [
            'class' => ErrorHandler::class,
            'actionsForPrefix' => [
                '/' => 'site/error',
                'admin' => 'admin/default/error',
            ]

        ],
Если есть более изящное решение буду рад помощи.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение yiiliveext »

Правила просто правильно пропишите

Код: Выделить всё

    'admin/<controller:\w+>/<action:\w+>' => 'admin/<controller>/<action>',
    'admin/<action:\w+>' => 'admin/default/<action>',
    'admin' => 'admin/default/index',
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение slo_nik »

yiiliveext писал(а): 2019.09.27, 18:54 Правила просто правильно пропишите

Код: Выделить всё

    'admin/<controller:\w+>/<action:\w+>' => 'admin/<controller>/<action>',
    'admin/<action:\w+>' => 'admin/default/<action>',
    'admin' => 'admin/default/index',
Это не поможет. Я перепробовал много вариантов правил.
Если попытаться переопределить страницу ошибки в контролере, то до него ход не дойдёт, будет сгенерирован errorHandler по умолчанию, со страницей "site/error".
Админ не модуль, а обычный контролер, такой же как и SiteController.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение yiiliveext »

slo_nik писал(а): 2019.09.27, 21:36 Админ не модуль, а обычный контролер, такой же как и SiteController.
Я это понимаю. Только что сэмулировал вашу структуру проекта. Все работает.
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение slo_nik »

yiiliveext писал(а): 2019.09.27, 23:11
slo_nik писал(а): 2019.09.27, 21:36 Админ не модуль, а обычный контролер, такой же как и SiteController.
Я это понимаю. Только что сэмулировал вашу структуру проекта. Все работает.
У меня не захотело работать.
Прописал Ваш пример правил, оставил только их, но при переходе на localhost/admin/use2r открылась страница ошибки site/error.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение yiiliveext »

slo_nik писал(а): 2019.09.28, 18:55 У меня не захотело работать.
Прописал Ваш пример правил, оставил только их, но при переходе на localhost/admin/use2r открылась страница ошибки site/error.
При переходе по этому адресу сработает правило 'admin/<action:\w+>' => 'admin/default/<action>',
Соответственно будет создан DefaultController. Вам нужно указать желаемый errorAction в методе init этого контроллера.

Код: Выделить всё

public function init()
{
    parent::init();
    \Yii::$app->errorHandler->errorAction = 'admin/default/error';
}
Если используете стандартный errorAction в этом контроллере, то еще указываете view, если оно отличается от стандартного views/admin/default/error.php

Код: Выделить всё

public function actions()
{
    return [
        'error' => [
            'class' => 'yii\web\ErrorAction',
            'view' => '@app/views/admin/default/error2'
        ],
    ];
}
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение slo_nik »

yiiliveext писал(а): 2019.09.28, 19:13
В том-то и дело, что user это не действие контролера, а отдельный котролер.
DefaultController и все остальные контролеры в админке наследуются от одного, AdminController, в котором я как раз и переопределяю в init() страницу для ошибок, так же там я подключаю ErrorHandler, всё так, как Вы показали в своих примерах.
Но это не работает.
Заработало так, как мне надо после того, как я переопределил ErrorHandler.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение yiiliveext »

Если у меня работает, то должно и у вас работать. Логично? :) Покажите конфиг web.php
Последний раз редактировалось yiiliveext 2019.09.28, 21:10, всего редактировалось 1 раз.
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение slo_nik »

yiiliveext писал(а): 2019.09.28, 19:13
Вот сейчас, подключил Все Ваши примеры.
В AdminController

Код: Выделить всё

public function init()
    {
        parent::init();
        $this->layout = 'admin/main.php';
        Yii::$app->view->getAssetManager()->bundles = [];
        Yii::$app->errorHandler->errorAction = '/admin/default/error';
        Yii::$app->user->loginUrl = ['/admin/login'];

    }

    public function actions()
    {
        return [
            'error' => [
                'class' => 'yii\web\ErrorAction',
                'view' => '@app/views/admin/default/error'
            ]
        ];
    }
В urlManager удалил все правила, оставил только Ваши.

Код: Выделить всё

'admin/<controller:\w+>/<action:\w+>' => 'admin/<controller>/<action>',
'admin/<action:\w+>' => 'admin/default/<action>',
'admin' => 'admin/default/index'
В config/web.php вернул стандартный ErrorHandler.

Перехожу на разные адреса

Код: Выделить всё

localhost/admin/ ---> site/error

Код: Выделить всё

localhost/admin/globe/cou???ntries ---> site/error
Возвращаю переопределённый ErrorHandler, правила urlManager оставляю Ваши

Перехожу на разные адреса

Код: Выделить всё

localhost/admin/ ---> admin/default/error

Код: Выделить всё

localhost/admin/globe/cou???ntries ---> admin/default/error
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение slo_nik »

yiiliveext писал(а): 2019.09.28, 21:05 Покажите конфиг web.php
Весь или какую-то определённую часть?
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение yiiliveext »

slo_nik писал(а): 2019.09.28, 21:09
yiiliveext писал(а): 2019.09.28, 21:05 Покажите конфиг web.php
Весь или какую-то определённую часть?
Если не слишком большой, то весь. А так ErrorHadler и ControllerMap
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение slo_nik »

yiiliveext писал(а): 2019.09.28, 21:13
slo_nik писал(а): 2019.09.28, 21:09
yiiliveext писал(а): 2019.09.28, 21:05 Покажите конфиг web.php
Весь или какую-то определённую часть?
Если не слишком большой, то весь. А так ErrorHadler и ControllerMap

Код: Выделить всё

params = require __DIR__ . '/params.php';
$urlRules = require __DIR__ . '/urlRules.php';
$db     = ArrayHelper::merge(require __DIR__ . '/db.php', require __DIR__ . '/db-local.php');
Yii::setAlias('@tests', dirname(__DIR__) . '/tests');
$config = [
    'id'          => 'basic',
    'basePath'    => dirname(__DIR__) . '/src',
    'runtimePath' => dirname(__DIR__) . '/runtime',
    'vendorPath'  => dirname(__DIR__) . '/vendor',
    'language' => 'ru-RU',
    'bootstrap'   => ['log', SetUp::class],
    'aliases'     => [
        '@bower' => '@vendor/bower-asset',
        '@npm'   => '@vendor/npm-asset',
    ],
    'on beforeAction' => function($event) use ($params) {
        if(!Yii::$app->user->can('admin')){
            if(in_array($event->action->id, $params['no_section']))
            {
                return Yii::$app->response->redirect(['site/no-section']);
            }
        }
        return false;
    },
    'components'  => [
        'authManager' => [
            'class' => AuthManager::class,
        ],
        'user'         => [
            'identityClass'   => Identity::class,
            'enableAutoLogin' => true,
            'loginUrl' => ['user/login']
        ],
        'errorHandler' => [
            'class' => ErrorHandler::class,
            'actionsForPrefix' => [
                '/' => 'site/error',
                'admin' => 'admin/default/error',
            ]

        ],
        'mailer'       => [
            'class'            => 'yii\swiftmailer\Mailer',
            'useFileTransport' => true,
        ],
        'log'          => [
            'traceLevel' => YII_DEBUG ? 3 : 0,
            'targets'    => [
                [
                    'class'  => 'yii\log\FileTarget',
                    'levels' => ['error', 'warning'],
                ],
            ],
        ],
        'db'           => $db,

        'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName'  => false,
            'enableStrictParsing' => true,
            'rules'           => $urlRules
        ],
        'assetManager' => [
            'bundles' => [
                'yii\bootstrap\BootstrapAsset' => [
                    'css' => []
                ],
                'yii\bootstrap\BootstrapPluginAsset' => [
                    'js' => []
                ]
            ]
        ],
        'view' => [
            'theme' => [
                'basePath' => '@app/themes/custom',
                'baseUrl' => '@web/themes/custom',
                'pathMap' => [
                    '@app/views' => '@app/themes/custom',
                   //'@app/modules' => '@app/themes/custom/modules'
                ]
            ]
        ],
        'siteSettings' => [
            'class' => SiteSettings::class
        ],
        'i18n' => [
            'translations' => [
                '*' => [
                    'class' => 'yii\i18n\PhpMessageSource',
                    'forceTranslation' => true,
                    'basePath' => '@app/messages'
                ],
            ],
        ],

    ],
    'modules' => [
        'gridview' =>  [
            'class' => '\kartik\grid\Module'
        ]
    ],
    'params'      => $params,
];
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение yiiliveext »

localhost/admin/ ---> site/error - не срабатывает из-за слеша в конце, используйте нормалайзер в менеджере правил или попробуйте без слеша
localhost/admin/globe/cou???ntries ---> site/error - так будет, если нет контроллера globe

Что с роутом localhost/admin/use2r ?
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение slo_nik »

yiiliveext писал(а): 2019.09.28, 21:13
Я ещё запускал debug в PhpStorm, пытался пройти пошагово и посмотреть что и как.
Код возвращал ошибку 404 и представление site/error сразу после прохода строки в web/index.php

Код: Выделить всё

(new yii\web\Application($config))->run();
Получается, что до контролеров ход не доходил.
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение slo_nik »

yiiliveext писал(а): 2019.09.28, 21:26 Что с роутом localhost/admin/use2r ?
Всё тоже самое - не работает, перекидывает на site/error
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение slo_nik »

yiiliveext писал(а): 2019.09.28, 21:26 Что с роутом localhost/admin/use2r ?
Ошибка вышла, этот вариант работает, но не работает localhost/admin/user )))
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение slo_nik »

yiiliveext писал(а): 2019.09.28, 21:26 localhost/admin/globe/cou???ntries ---> site/error - так будет, если нет контроллера globe
Да, контролера globe нет, это просто директория.
Я пытался задать это условие в urlManager через такие правила

Код: Выделить всё

    [
        'class' => GroupUrlRule::class,
        'prefix' => 'admin',
        'routePrefix' => 'admin',
        'rules' => [
            '' => 'default/index',
            '<_a:(login|logout)>' => 'default/<_a>',
            '<_c:[-\w]+>' => '<_c>/index',
            '<_c:[-\w]+>/<id:\d+>' => '<_c>/view',
            '<_c:[-\w]+>/<_a:[-\w]+>' => '<_c>/<_a>',
            '<_c:[-\w]+>/<_a:[-\w]+>/<id:\d+>' => '<_c>/<_a>',

            '<_url:\w+>/<_c:[-\w]+>/<_a:[-\w]+>/<id:\d+>' => '<_url>/<_c>/<_a>',
            '<_url:\w+>/<_c:[-\w]+>/<id:\d+>' => '<_url>/<_c>/view',
            '<_url:\w+>/<_c:[-\w]+>/<_a:[-\w]+>' => '<_url>/<_c>/<_a>',
            '<_url:\w+>/<_c:[-\w]+>' => '<_url>/<_c>/index',

        ]
    ],
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение yiiliveext »

slo_nik писал(а): 2019.09.28, 21:33 Получается, что до контролеров ход не доходил.
Да, работать будет только если в роуте определился существующий контроллер при парсинге запроса
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Как сделать разные страницы ошибок для разных контролеров?

Сообщение yiiliveext »

Как вариант, чтобы не подменять родной ErrorHandler, можете добавить в конфиг

Код: Выделить всё

'on beforeRequest' => function($event) {
        $path = $event->sender->getRequest()->getPathInfo();
        if (preg_match('#^admin(/.*)?$#i', $path)) {
            \Yii::$app->errorHandler->errorAction = 'admin/default/error';
        }
    },
Последний раз редактировалось yiiliveext 2019.09.28, 22:43, всего редактировалось 1 раз.
Ответить