Магазин на Yii2, часть 14. Показываем страницу 404 Not Found
03.07.2019
Теги: Web-разработка • Yii2 • ИнтернетМагазин • Исключение • КаталогТоваров • Практика • Фреймворк
После установки 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' => 'yii\web\ErrorAction', ], ]; } /* ... */ }
actionError()
. Отдельные действия указываются в карте действий контроллера, в методе actions()
. Сам же функционал таких действий описан в отдельных классах.
Мы договорились ранее использовать класс SiteController
только как образец. Давайте зададим свой обработчик ошибки в файле конфигурации config/web.php
:
$config = [ /* ... */ 'components' => [ /* ... */ 'errorHandler' => [ 'errorAction' => 'app/error' ], /* ... */ ], /* ... */ ];
Добавим метод actions()
в класс AppController
:
class AppController extends Controller { /* ... */ public function actions() { return [ 'error' => [ 'class' => 'yii\web\ErrorAction', ], ]; } /* ... */ }
Создадим view-шаблон views/app/error.php
:
<?php /* @var $this yii\web\View */ /* @var $name string */ /* @var $message string */ /* @var $exception Exception */ use yii\helpers\Html; $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 app\controllers; use app\models\Category; use app\models\Brand; use app\models\Product; use yii\web\HttpException; 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') ); } }
- Магазин на Yii2, часть 35. Админка: загрузка картинок для страниц и страница 404
- Магазин на Yii2, часть 34. Показываем меню страниц в публичной части
- Магазин на Yii2, часть 33. Админка: приводим в порядок CRUD-код для страниц
- Магазин на Yii2, часть 32. Админка: удаление категорий и CRUD для страниц
- Магазин на Yii2, часть 31. Админка: загрузка изображений для категорий и брендов
- Магазин на Yii2, часть 30. Админка: WYSIWYG-редактор и изображение для товара
- Магазин на Yii2, часть 29. Админка: добавляем список товаров категории
Поиск: Web-разработка • Yii2 • Интернет магазин • Исключение • Каталог товаров • Практика • Фреймворк • 404 • Not Found • Exception • Ошибка • Error