Ошибка 404 yii2

Ответы ¶

Когда приложение заканчивает обработку запроса, оно генерирует объект ответа
и отправляет его пользователю. Объект ответа содержит такие данные, как HTTP-код состояния, HTTP-заголовки и тело ответа.
Конечная цель разработки Web-приложения состоит в создании объектов ответа на различные запросы.

В большинстве случаев вам придется иметь дело с компонентом приложения response,
который по умолчанию является экземпляром класса yiiwebResponse. Однако Yii также позволяет вам создавать собственные
объекты ответа и отправлять их пользователям. Это будет рассмотрено ниже.

В данном разделе мы опишем, как составлять ответы и отправлять их пользователям.

Код состояния ¶

Первое, что вы делаете при построении ответа, — определяете, был ли успешно обработан запрос. Это реализуется заданием
свойству yiiwebResponse::$statusCode значения, которое может быть одним из валидных
HTTP-кодов состояния. Например, чтобы показать, что запрос был
успешно обработан, вы можете установить значение кода состояния равным 200:

Yii::$app->response->statusCode = 200;

Однако в большинстве случаев явная установка не требуется так как значение yiiwebResponse::$statusCode
по умолчанию равно 200. Если вам нужно показать, что запрос не удался, вы можете выбросить соответствующее
HTTP-исключение:

throw new yiiwebNotFoundHttpException;

Когда обработчик ошибок поймает исключение, он извлечёт код состояния
из исключения и назначит его ответу. Исключение yiiwebNotFoundHttpException в коде выше
представляет HTTP-код состояния 404. В Yii предопределены следующие HTTP-исключения:

  • yiiwebBadRequestHttpException: код состояния 400.
  • yiiwebConflictHttpException: код состояния 409.
  • yiiwebForbiddenHttpException: код состояния 403.
  • yiiwebGoneHttpException: код состояния 410.
  • yiiwebMethodNotAllowedHttpException: код состояния 405.
  • yiiwebNotAcceptableHttpException: код состояния 406.
  • yiiwebNotFoundHttpException: код состояния 404.
  • yiiwebServerErrorHttpException: код состояния 500.
  • yiiwebTooManyRequestsHttpException: код состояния 429.
  • yiiwebUnauthorizedHttpException: код состояния 401.
  • yiiwebUnsupportedMediaTypeHttpException: код состояния 415.

Если в приведённом выше списке нет исключения, которое вы хотите выбросить, вы можете создать его, расширив класс
yiiwebHttpException, или выбросить его напрямую с кодом состояния, например:

throw new yiiwebHttpException(402);

Вы можете отправлять HTTP-заголовки, работая с коллекцией заголовков компонента response:

$headers = Yii::$app->response->headers;

// добавить заголовок Pragma. Уже имеющиеся Pragma-заголовки НЕ будут перезаписаны.
$headers->add('Pragma', 'no-cache');

// установить заголовок Pragma. Любые уже имеющиеся Pragma-заголовки будут сброшены.
$headers->set('Pragma', 'no-cache');

// удалить заголовок (или заголовки) Pragma и вернуть их значения массивом
$values = $headers->remove('Pragma');

Информация: названия заголовков не чувствительны к регистру символов. Заново зарегистрированные заголовки не отсылаются
пользователю до вызова yiiwebResponse::send().

Тело ответа ¶

Большинство ответов должны иметь тело, содержащее то, что вы хотите показать пользователям.

Если у вас уже имеется отформатированная строка для тела, вы можете присвоить её свойству yiiwebResponse::$content
объекта запроса:

Yii::$app->response->content = 'hello world!';

Если ваши данные перед отправкой конечным пользователям нужно привести к определённому формату, вам следует установить значения
двух свойств: format и data. Свойство format
определяет, в каком формате следует возвращать данные из data. Например:

$response = Yii::$app->response;
$response->format = yiiwebResponse::FORMAT_JSON;
$response->data = ['message' => 'hello world'];

Yii из коробки имеет поддержку следующих форматов, каждый из которых реализован классом форматтера.
Вы можете настроить эти форматтеры или добавить новые через свойство yiiwebResponse::$formatters.

  • HTML: реализуется классом yiiwebHtmlResponseFormatter.
  • XML: реализуется классом yiiwebXmlResponseFormatter.
  • JSON: реализуется классом yiiwebJsonResponseFormatter.
  • JSONP: реализуется классом yiiwebJsonResponseFormatter.

Хотя тело запроса может быть явно установлено показанным выше способом, в большинстве случаев вы можете задавать его неявно
через возвращаемое значение методов действий. Типичный пример использования:

public function actionIndex()
{
    return $this->render('index');
}

Действие index в коде выше возвращает результат рендеринга представления index. Возвращаемое значение будет взято
компонентом response, отформатировано и затем отправлено пользователям.

Так как по умолчанию форматом ответа является HTML, в методе действия следует
вернуть строку. Если вы хотите использовать другой формат ответа, необходимо настроить его перед отправкой данных:

public function actionInfo()
{
    Yii::$app->response->format = yiiwebResponse::FORMAT_JSON;
    return [
        'message' => 'hello world',
        'code' => 100,
    ];
}

Как уже было сказано, кроме использования стандартного компонента приложения response вы также можете создавать свои
объекты ответа и отправлять их конечным пользователям. Вы можете сделать это, возвращая такой объект в методе действия:

public function actionInfo()
{
    return Yii::createObject([
        'class' => 'yiiwebResponse',
        'format' => yiiwebResponse::FORMAT_JSON,
        'data' => [
            'message' => 'hello world',
            'code' => 100,
        ],
    ]);
}

Примечание: создавая собственные объекты ответов, вы не сможете воспользоваться конфигурацией компонента response,
настроенной вами в конфигурации приложения. Тем не менее, вы можете воспользоваться
внедрением зависимости, чтобы применить общую конфигурацию к вашим новым объектам ответа.

Перенаправление браузера ¶

Перенаправление браузера основано на отправке HTTP-заголовка Location. Так как данная возможность широко применяется,
Yii имеет средства для её использования.

Вы можете перенаправить браузер пользователя на URL-адрес, вызвав метод yiiwebResponse::redirect(). Этот метод
использует указанный URL-адрес в качестве значения заголовка Location и возвращает сам объект ответа. В методе действия
вы можете вызвать короткую версию этого метода — yiiwebController::redirect(). Например:

public function actionOld()
{
    return $this->redirect('https://example.com/new', 301);
}

В приведённом выше коде метод действия возвращает результат redirect(). Как говорилось выше, объект ответа,
возвращаемый методом действия, будет использоваться в качестве ответа конечным пользователям.

В коде, находящемся вне методов действий, следует использовать yiiwebResponse::redirect() и непосредственно после
него — метод yiiwebResponse::send(). Так можно быть уверенным, что к ответу не будет добавлено нежелательное
содержимое.

Yii::$app->response->redirect('https://example.com/new', 301)->send();

Информация: По умолчанию метод yiiwebResponse::redirect() устанавливает код состояния ответа равным 302, сообщая
браузеру, что запрашиваемый ресурс временно находится по другому URI-адресу. Вы можете передать код состояния
301, чтобы сообщить браузеру, что ресурс перемещён навсегда.

Если текущий запрос является AJAX-запросом, отправка заголовка Location не заставит браузер автоматически
осуществить перенаправление. Чтобы решить эту задачу, метод yiiwebResponse::redirect() устанавливает значение
заголовка X-Redirect равным URL для перенаправления. На стороне клиента вы можете написать JavaScript-код для чтения
значения этого заголовка и перенаправления браузера соответственно.

Информация: Yii поставляется с JavaScript-файлом yii.js, который предоставляет набор часто используемых
JavaScript-утилит, включая и перенаправление браузера на основе заголовка X-Redirect. Следовательно, если вы
используете этот JavaScript-файл (зарегистрировав пакет ресурсов yiiwebYiiAsset), вам не нужно писать
дополнительный код для поддержки AJAX-перенаправления.

Отправка файлов ¶

Как и перенаправление браузера, отправка файлов является ещё одной возможностью, основанной на определённых HTTP-заголовках.
Yii предоставляет набор методов для решения различных задач по отправке файлов. Все они поддерживают HTTP-заголовок range.

  • yiiwebResponse::sendFile(): отправляет клиенту существующий файл.
  • yiiwebResponse::sendContentAsFile(): отправляет клиенту строку как файл.
  • yiiwebResponse::sendStreamAsFile(): отправляет клиенту существующий файловый поток как файл.

Эти методы имеют одинаковую сигнатуру и возвращают объект ответа. Если отправляемый файл очень велик, следует
использовать yiiwebResponse::sendStreamAsFile(), так как он более эффективно использует оперативную память.
Следующий пример показывает, как отправить файл в действии контроллера:

public function actionDownload()
{
    return Yii::$app->response->sendFile('path/to/file.txt');
}

Чтобы быть уверенным, что к ответу не будет добавлено никакое
нежелательное содержимое, при вызове метода yiiwebResponse::sendFile() вне методов action, следует вызвать сразу после него yiiwebResponse::send().

Yii::$app->response->sendFile('path/to/file.txt')->send();

Некоторые Web-серверы поддерживают особый режим отправки файлов, который называется X-Sendfile. Идея в том, чтобы
перенаправить запрос файла Web-серверу, который отдаст файл пользователю самостоятельно. В результате Web-приложение
может завершиться раньше, пока Web-сервер ещё пересылает файл. Чтобы использовать эту возможность, воспользуйтесь
методом yiiwebResponse::xSendFile(). Далее приведены ссылки на то, как включить X-Sendfile для популярных
Web-серверов:

  • Apache: X-Sendfile
  • Lighttpd v1.4: X-LIGHTTPD-send-file
  • Lighttpd v1.5: X-Sendfile
  • Nginx: X-Accel-Redirect
  • Cherokee: X-Sendfile and X-Accel-Redirect

Отправка ответа ¶

Содержимое ответа не отправляется пользователю до вызова метода yiiwebResponse::send(). По умолчанию он вызывается
автоматически в конце метода yiibaseApplication::run(). Однако чтобы ответ был отправлен немедленно, вы можете
вызвать этот метод явно.

Для отправки ответа метод yiiwebResponse::send() выполняет следующие шаги:

  1. Инициируется событие yiiwebResponse::EVENT_BEFORE_SEND.
  2. Для форматирования данных ответа в содержимое ответа
    вызывается метод yiiwebResponse::prepare() .
  3. Инициируется событие yiiwebResponse::EVENT_AFTER_PREPARE.
  4. Для отправки зарегистрированных HTTP-заголовков вызывается метод yiiwebResponse::sendHeaders().
  5. Для отправки тела ответа вызывается метод yiiwebResponse::sendContent().
  6. Инициируется событие yiiwebResponse::EVENT_AFTER_SEND.

Повторный вызов yiiwebResponse::send() игнорируется. Это означает, что если ответ уже отправлен, то к нему уже
ничего не добавить.

Как видно, метод yiiwebResponse::send() инициирует несколько полезных событий. Реагируя на
эти события, можно настраивать или декорировать ответ.

Если набрать URL вида http://site.com/blog/blogblogyjr , где blogblogyir- несуществующая страница сайта site.com/blog, то вместо страницы 404 появляется это:
image

Сам файл NotFoundHttpException находиться: D:sitessiteyii2vendoryiisoftyii2web

код из BlogController.php (находится в dir: D:sitessiteyii2frontendcontrollers)

<?php

namespace frontendcontrollers;


use commonmodelsBlog;
use Yii;
use yiiwebController;

/**
 * Blog controller
 */
class BlogController extends Controller
{
    /**
     * Displays homepage.
     *
     * @return mixed
     */
    public function actionIndex()
    {
        #$blogs = Blog::find()->where(['status_id'=>1])->orderBy(['id' => SORT_DESC])->all();

       $blogs = Blog::find()->andWhere(['status_id'=>1])->orderBy('sort')->all();
        #$blogs = Blog::find()->where(['status_id'=>1])->orderBy(['id' => SORT_ASC])->all();
        return $this->render('all',['blogs'=>$blogs]);
    }

       public function actionOne($url)
    {  
       if($blog = Blog::find()->andWhere(['url'=>$url])->one()) {
            return $this->render('one',['blog'=>$blog]);
      }
       throw new NotFoundHttpException ();
    }


}

помогло указание в BlogController — use yiiwebNotFoundHttpException;
но как сделать, чтобы заработало сообщение в строке BlogController throw new NotFoundHttpException (‘ой,нет такого блога’); сейчас просто выводится Not Found (#404) page not found

Visman's user avatar

Visman

16.5k8 золотых знаков25 серебряных знаков56 бронзовых знаков

задан 2 июл 2017 в 10:00

Finn's user avatar

3

Можете указать action, в котором будут обрабатываться ошибки:

...
'errorHandler' => [
    'errorAction' => 'site/error',
],
...

И в контроллере SiteController добавить что-то подобное:

public function actionError()
{
    $exception = Yii::$app->errorHandler->exception;
    if ($exception !== null) {
        if ($exception->statusCode == 404)
            return $this->render('error404', ['exception' => $exception]);
        else
            return $this->render('error', ['exception' => $exception]);
    }
}

Создать представление error404 и выводить там все что душе угодно.

Ссылка на документацию: https://nix-tips.ru/yii2-api-guides/guide-ru-runtime-handling-errors.html

ответ дан 3 июл 2017 в 4:05

OlyLad's user avatar

OlyLadOlyLad

3111 серебряный знак8 бронзовых знаков

frontend/config/local-web.php (какой-то такой)

...
'errorHandler' => [
    'errorRoute' => 'site/error',
    ...
],
...

frontend/views/site/error.php

<?php
echo 'custom template';
?>

Где дефолтный темплейт для перепила — наверно, не подскажу.

ответ дан 2 июл 2017 в 18:17

Tester's user avatar

TesterTester

1023 бронзовых знака

Handling Errors

Yii includes a built-in [[yiiwebErrorHandler|error handler]] which makes error handling a much more pleasant
experience than before. In particular, the Yii error handler does the following to improve error handling:

  • All non-fatal PHP errors (e.g. warnings, notices) are converted into catchable exceptions.
  • Exceptions and fatal PHP errors are displayed with detailed call stack information and source code lines
    in debug mode.
  • Supports using a dedicated controller action to display errors.
  • Supports different error response formats.

The [[yiiwebErrorHandler|error handler]] is enabled by default. You may disable it by defining the constant
YII_ENABLE_ERROR_HANDLER to be false in the entry script of your application.

Using Error Handler

The [[yiiwebErrorHandler|error handler]] is registered as an application component named errorHandler.
You may configure it in the application configuration like the following:

return [
    'components' => [
        'errorHandler' => [
            'maxSourceLines' => 20,
        ],
    ],
];

With the above configuration, the number of source code lines to be displayed in exception pages will be up to 20.

As aforementioned, the error handler turns all non-fatal PHP errors into catchable exceptions. This means you can
use the following code to deal with PHP errors:

use Yii;
use yiibaseErrorException;

try {
    10/0;
} catch (ErrorException $e) {
    Yii::warning("Division by zero.");
}

// execution continues...

If you want to show an error page telling the user that his request is invalid or unexpected, you may simply
throw an [[yiiwebHttpException|HTTP exception]], such as [[yiiwebNotFoundHttpException]]. The error handler
will correctly set the HTTP status code of the response and use an appropriate error view to display the error
message.

use yiiwebNotFoundHttpException;

throw new NotFoundHttpException();

Customizing Error Display

The [[yiiwebErrorHandler|error handler]] adjusts the error display according to the value of the constant YII_DEBUG.
When YII_DEBUG is true (meaning in debug mode), the error handler will display exceptions with detailed call
stack information and source code lines to help easier debugging. And when YII_DEBUG is false, only the error
message will be displayed to prevent revealing sensitive information about the application.

Info: If an exception is a descendant of [[yiibaseUserException]], no call stack will be displayed regardless
the value of YII_DEBUG. This is because such exceptions are considered to be caused by user mistakes and the
developers do not need to fix anything.

By default, the [[yiiwebErrorHandler|error handler]] displays errors using two views:

  • @yii/views/errorHandler/error.php: used when errors should be displayed WITHOUT call stack information.
    When YII_DEBUG is false, this is the only error view to be displayed.
  • @yii/views/errorHandler/exception.php: used when errors should be displayed WITH call stack information.

You can configure the [[yiiwebErrorHandler::errorView|errorView]] and [[yiiwebErrorHandler::exceptionView|exceptionView]]
properties of the error handler to use your own views to customize the error display.

Using Error Actions

A better way of customizing the error display is to use dedicated error actions.
To do so, first configure the [[yiiwebErrorHandler::errorAction|errorAction]] property of the errorHandler
component like the following:

return [
    'components' => [
        'errorHandler' => [
            'errorAction' => 'site/error',
        ],
    ]
];

The [[yiiwebErrorHandler::errorAction|errorAction]] property takes a route
to an action. The above configuration states that when an error needs to be displayed without call stack information,
the site/error action should be executed.

You can create the site/error action as follows,

namespace appcontrollers;

use Yii;
use yiiwebController;

class SiteController extends Controller
{
    public function actions()
    {
        return [
            'error' => [
                'class' => 'yiiwebErrorAction',
            ],
        ];
    }
}

The above code defines the error action using the [[yiiwebErrorAction]] class which renders an error
using a view named error.

Besides using [[yiiwebErrorAction]], you may also define the error action using an action method like the following,

public function actionError()
{
    $exception = Yii::$app->errorHandler->exception;
    if ($exception !== null) {
        return $this->render('error', ['exception' => $exception]);
    }
}

You should now create a view file located at views/site/error.php. In this view file, you can access
the following variables if the error action is defined as [[yiiwebErrorAction]]:

  • name: the name of the error;
  • message: the error message;
  • exception: the exception object through which you can retrieve more useful information, such as HTTP status code,
    error code, error call stack, etc.

Info: If you are using the basic project template or the advanced project template,
the error action and the error view are already defined for you.

Note: If you need to redirect in an error handler, do it the following way:

Yii::$app->getResponse()->redirect($url)->send();
return;

Customizing Error Response Format

The error handler displays errors according to the format setting of the response.
If the [[yiiwebResponse::format|response format]] is html, it will use the error or exception view
to display errors, as described in the last subsection. For other response formats, the error handler will
assign the array representation of the exception to the [[yiiwebResponse::data]] property which will then
be converted to different formats accordingly. For example, if the response format is json, you may see
the following response:

HTTP/1.1 404 Not Found
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

{
    "name": "Not Found Exception",
    "message": "The requested resource was not found.",
    "code": 0,
    "status": 404
}

You may customize the error response format by responding to the beforeSend event of the response component
in the application configuration:

return [
    // ...
    'components' => [
        'response' => [
            'class' => 'yiiwebResponse',
            'on beforeSend' => function ($event) {
                $response = $event->sender;
                if ($response->data !== null) {
                    $response->data = [
                        'success' => $response->isSuccessful,
                        'data' => $response->data,
                    ];
                    $response->statusCode = 200;
                }
            },
        ],
    ],
];

The above code will reformat the error response like the following:

HTTP/1.1 200 OK
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

{
    "success": false,
    "data": {
        "name": "Not Found Exception",
        "message": "The requested resource was not found.",
        "code": 0,
        "status": 404
    }
}

When handling a RESTful API request, if there is an error in the user request or if something unexpected
happens on the server, you may simply throw an exception to notify the user that something went wrong.
If you can identify the cause of the error (e.g., the requested resource does not exist), you should
consider throwing an exception along with a proper HTTP status code (e.g., [[yiiwebNotFoundHttpException]]
represents a 404 status code). Yii will send the response along with the corresponding HTTP status
code and text. Yii will also include the serialized representation of the
exception in the response body. For example:

HTTP/1.1 404 Not Found
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

{
    "name": "Not Found Exception",
    "message": "The requested resource was not found.",
    "code": 0,
    "status": 404
}

The following list summarizes the HTTP status code that are used by the Yii REST framework:

  • 200: OK. Everything worked as expected.
  • 201: A resource was successfully created in response to a POST request. The Location header
    contains the URL pointing to the newly created resource.
  • 204: The request was handled successfully and the response contains no body content (like a DELETE request).
  • 304: The resource was not modified. You can use the cached version.
  • 400: Bad request. This could be caused by various actions by the user, such as providing invalid JSON
    data in the request body, providing invalid action parameters, etc.
  • 401: Authentication failed.
  • 403: The authenticated user is not allowed to access the specified API endpoint.
  • 404: The requested resource does not exist.
  • 405: Method not allowed. Please check the Allow header for the allowed HTTP methods.
  • 415: Unsupported media type. The requested content type or version number is invalid.
  • 422: Data validation failed (in response to a POST request, for example). Please check the response body for detailed error messages.
  • 429: Too many requests. The request was rejected due to rate limiting.
  • 500: Internal server error. This could be caused by internal program errors.

Customizing Error Response

Sometimes you may want to customize the default error response format. For example, instead of relying on
using different HTTP statuses to indicate different errors, you would like to always use 200 as HTTP status
and enclose the actual HTTP status code as part of the JSON structure in the response, like shown in the following,

HTTP/1.1 200 OK
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8

{
    "success": false,
    "data": {
        "name": "Not Found Exception",
        "message": "The requested resource was not found.",
        "code": 0,
        "status": 404
    }
}

To achieve this goal, you can respond to the beforeSend event of the response component in the application configuration:

return [
    // ...
    'components' => [
        'response' => [
            'class' => 'yiiwebResponse',
            'on beforeSend' => function ($event) {
                $response = $event->sender;
                if ($response->data !== null && !empty(Yii::$app->request->get('suppress_response_code'))) {
                    $response->data = [
                        'success' => $response->isSuccessful,
                        'data' => $response->data,
                    ];
                    $response->statusCode = 200;
                }
            },
        ],
    ],
];

The above code will reformat the response (for both successful and failed responses) as explained when
suppress_response_code is passed as a GET parameter.

После установки Yii2 уже имеется файл view-шаблона views/site/error.php. Чтобы получить свою страницу ошибки, можно просто отредактировать этот файл. В нём доступны три переменные: $name, $message, $exception. Признак ошибки 404 — это значение свойства statusCode объекта $exception. Таким образом можно написать свою проверку этого значения и для разных ошибок показывать пользователю разный ответ.

Почему для показа сообщения об ошибках используется шаблон views/site/error.php? Это задается в настройках приложения, в файле config/web.php:

$config = [
    /* ... */
    'components' => [
        /* ... */
        'errorHandler' => [
            'errorAction' => 'site/error'
        ],
        /* ... */
    ],
    /* ... */
];

Для обработки ошибок будет использован метод actionError() класса SiteController:

class SiteController extends Controller {
    /* ... */
    public function actionError() {
        $exception = Yii::$app->errorHandler->exception;
        if ($exception !== null) {
            return $this->render('error', ['exception' => $exception]);
        }
    }
    /* ... */
}

Но если мы заглянем в исходный код controllers/SiteController.php, то обнаружим, что такого метода там нет. А вместо него есть метод actions():

class SiteController extends Controller {
    /* ... */
    public function actions()
    {
        return [
            'error' => [
                // объявляем действие error и задаем имя класса
                'class' => 'yiiwebErrorAction',
            ],
        ];
    }
    /* ... */
}

Все действия контроллера можно разделить на встроенные и отдельные. Встроенные действия определены как методы контроллера, например actionError(). Отдельные действия указываются в карте действий контроллера, в методе actions(). Сам же функционал таких действий описан в отдельных классах.

Мы договорились ранее использовать класс SiteController только как образец. Давайте зададим свой обработчик ошибки в файле конфигурации config/web.php:

$config = [
    /* ... */
    'components' => [
        /* ... */
        'errorHandler' => [
            'errorAction' => 'app/error'
        ],
        /* ... */
    ],
    /* ... */
];

Добавим метод actions() в класс AppController:

class AppController extends Controller {
    /* ... */
    public function actions() {
        return [
            'error' => [
                'class' => 'yiiwebErrorAction',
            ],
        ];
    }
    /* ... */
}

Создадим view-шаблон views/app/error.php:

<?php
/* @var $this yiiwebView */
/* @var $name string */
/* @var $message string */
/* @var $exception Exception */

use yiihelpersHtml;

$this->title = $name;
?>
<div class="container">
    <h1><?= Html::encode($this->title) ?></h1>
    <div class="alert alert-danger">
        <?= nl2br(Html::encode($message)) ?>
    </div>
</div>

И внесем изменения в класс CatalogController, чтобы он выбрасывал исключение, когда в базе данных не удается найти категорию, бренд или товар каталога:

<?php
namespace appcontrollers;

use appmodelsCategory;
use appmodelsBrand;
use appmodelsProduct;
use yiiwebHttpException;
use Yii;

class CatalogController extends AppController {
    /**
     * Главная страница каталога товаров
     */
    public function actionIndex() {
        // получаем корневые категории
        $roots = Yii::$app->cache->get('root-categories');
        if ($roots === false) {
            $roots = Category::find()->where(['parent_id' => 0])->asArray()->all();
            Yii::$app->cache->set('root-categories', $roots);
        }
        // получаем популярные бренды
        $brands = Yii::$app->cache->get('popular-brands');
        if ($brands === false) {
            $brands = (new Brand())->getPopularBrands();
            Yii::$app->cache->set('popular-brands', $brands);
        }
        return $this->render('index', compact('roots', 'brands'));
    }

    /**
     * Категория каталога товаров
     */
    public function actionCategory($id, $page = 1) {
        $id = (int)$id;
        $page = (int)$page;
        // пробуем извлечь данные из кеша
        $data = Yii::$app->cache->get('category-'.$id.'-page-'.$page);
        if ($data === null) {
            // данные есть в кеше, но такой категории не существует
            throw new HttpException(
                404,
                'Запрошенная страница не найдена'
            );
        }
        if ($data === false) {
            // данных нет в кеше, получаем их заново
            $temp = new Category();
            // данные о категории
            $category = $temp->getCategory($id);
            if (!empty($category)) { // такая категория существует
                // товары категории
                list($products, $pages) = $temp->getCategoryProducts($id);
                // сохраняем полученные данные в кеше
                $data = [$products, $pages, $category];
                Yii::$app->cache->set('category-' . $id . '-page-' . $page, $data);
            } else { // такая категория не существует
                Yii::$app->cache->set('category-' . $id . '-page-' . $page, null);
                throw new HttpException(
                    404,
                    'Запрошенная страница не найдена'
                );
            }
        }
        list($products, $pages, $category) = $data;
        // устанавливаем мета-теги для страницы
        $this->setMetaTags(
            $category['name'] . ' | ' . Yii::$app->params['shopName'],
            $category['keywords'],
            $category['description']
        );
        return $this->render(
            'category',
            compact('category', 'products', 'pages')
        );
    }

    /**
     * Список всех брендов каталога товаров
     */
    public function actionBrands() {
        // пробуем извлечь данные из кеша
        $brands = Yii::$app->cache->get('all-brands');
        if ($brands === false) {
            // данных нет в кеше, получаем их заново
            $brands = (new Brand())->getAllBrands();
            // сохраняем полученные данные в кеше
            Yii::$app->cache->set('all-brands', $brands);
        }
        return $this->render(
            'brands',
            compact('brands')
        );
    }

    /**
     * Список товаров бренда с идентификатором $id
     */
    public function actionBrand($id, $page = 1) {
        $id = (int)$id;
        $page = (int)$page;
        // пробуем извлечь данные из кеша
        $data = Yii::$app->cache->get('brand-'.$id.'-page-'.$page);
        if ($data === null) {
            // данные есть в кеше, но такого бренда не существует
            throw new HttpException(
                404,
                'Запрошенная страница не найдена'
            );
        }
        if ($data === false) {
            // данных нет в кеше, получаем их заново
            $temp = new Brand();
            // данные о бренде
            $brand = $temp->getBrand($id);
            if (!empty($brand)) { // такой бренд существует
                // товары бренда
                list($products, $pages) = $temp->getBrandProducts($id);
                // сохраняем полученные данные в кеше
                $data = [$products, $pages, $brand];
                Yii::$app->cache->set('brand-'.$id.'-page-'.$page, $data);
            } else { // такой бренд не существует
                Yii::$app->cache->set('brand-'.$id.'-page-'.$page, null);
                throw new HttpException(
                    404,
                    'Запрошенная страница не найдена'
                );
            }
        }
        list($products, $pages, $brand) = $data;
        // устанавливаем мета-теги
        $this->setMetaTags(
            $brand['name'] . ' | ' . Yii::$app->params['shopName'],
            $brand['keywords'],
            $brand['description']
        );
        return $this->render(
            'brand',
            compact('brand', 'products', 'pages')
        );
    }

    /**
     * Страница товара с идентификатором $id
     */
    public function actionProduct($id) {
        $id = (int)$id;
        // пробуем извлечь данные из кеша
        $data = Yii::$app->cache->get('product-'.$id);
        if ($data === null) {
            // данные есть в кеше, но такого товара не существует
            throw new HttpException(
                404,
                'Запрошенная страница не найдена'
            );
        }
        if ($data === false) {
            // данных нет в кеше, получаем их заново
            $product = (new Product())->getProduct($id);
            if (!empty($product)) { // такой товар существует
                $brand = (new Brand())->getBrand($product['brand_id']);
                $data = [$product, $brand];
                // сохраняем полученные данные в кеше
                Yii::$app->cache->set('product-' . $id, $data);
            } else { // такого товара не существует
                Yii::$app->cache->set('product-' . $id, null);
                throw new HttpException(
                    404,
                    'Запрошенная страница не найдена'
                );
            }
        }
        list($product, $brand) = $data;
        // устанавливаем мета-теги
        $this->setMetaTags(
            $product['name'] . ' | ' . Yii::$app->params['shopName'],
            $product['keywords'],
            $product['description']
        );
        // получаем популярные товары, похожие на текущий
        $similar = Yii::$app->cache->get('similar-'.$product['id']);
        if ($similar === false) {
            // товары из той же категории того же бренда
            $similar = Product::find()
                ->where([
                    'hit' => 1,
                    'category_id' => $product['category_id'],
                    'brand_id' => $product['brand_id']
                ])
                ->andWhere(['NOT IN', 'id', $product['id']])
                ->limit(3)
                ->asArray()
                ->all();
            Yii::$app->cache->set('similar-'.$product['id'], $similar);
        }
        return $this->render(
            'product',
            compact('product', 'brand', 'similar')
        );
    }
}

Поиск:
Web-разработка • Yii2 • Интернет магазин • Исключение • Каталог товаров • Практика • Фреймворк • 404 • Not Found • Exception • Ошибка • Error

Каталог оборудования

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Производители

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Функциональные группы

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Понравилась статья? Поделить с друзьями:
  • Ошибка 404 title
  • Ошибка 404 symfony
  • Ошибка 404 svg
  • Ошибка 404 soft
  • Ошибка 404 как обойти