Создание каталога
Создание каталога
Делаю каталог товаров такого типа:
- Бытовая техника catalog/bytovay-tehnika
- Техника для кухни catalog/bytovay-tehnika/kuhnja
- Техника для гостиной catalog/bytovay-tehnika/gostinaja
- Спортивные товары catalog/sport-tovary
- Велосипеды catalog/sport-tovary/velosipedy
- Электровелосипеды catalog/sport-tovary/velosipedy/elektro
- Скоростные велосипеды catalog/sport-tovary/velosipedy/skorostnye
- Лыжи catalog/sport-tovary/lyji
- Открытки catalog/otkrytki
Всего два вида страниц:
views/catalog/catalog.php - вывод простым списком подкатегорий.
views/catalog/goods.php - вывод товаров в конечной подкатегории.
Не могу понять как сделать контроллер. Например, что бы узнать catalog/sport-tovary/velosipedy/elektro что это конечная подкатегория или нет надо подключиться к базе, а в контроллере обращаться к базе считается плохим тоном.
Или надо сделать класс который обрабатывает URL, далее подключать класс который обрабатывает конечную подкатегорию и подключать соответствующий вывод.
Подскажите, пожалуйста, примерно куда копать.
- Бытовая техника catalog/bytovay-tehnika
- Техника для кухни catalog/bytovay-tehnika/kuhnja
- Техника для гостиной catalog/bytovay-tehnika/gostinaja
- Спортивные товары catalog/sport-tovary
- Велосипеды catalog/sport-tovary/velosipedy
- Электровелосипеды catalog/sport-tovary/velosipedy/elektro
- Скоростные велосипеды catalog/sport-tovary/velosipedy/skorostnye
- Лыжи catalog/sport-tovary/lyji
- Открытки catalog/otkrytki
Всего два вида страниц:
views/catalog/catalog.php - вывод простым списком подкатегорий.
views/catalog/goods.php - вывод товаров в конечной подкатегории.
Не могу понять как сделать контроллер. Например, что бы узнать catalog/sport-tovary/velosipedy/elektro что это конечная подкатегория или нет надо подключиться к базе, а в контроллере обращаться к базе считается плохим тоном.
Или надо сделать класс который обрабатывает URL, далее подключать класс который обрабатывает конечную подкатегорию и подключать соответствующий вывод.
Подскажите, пожалуйста, примерно куда копать.
Re: Создание каталога
Я предполагаю что надо создать класс со своими правилами, типа этого
В какую папку надо положить такой файл?
Код: Выделить всё
namespace app\components;
use yii\web\UrlRule;
class CarUrlRule extends UrlRule
{
public $connectionID = 'db';
public function init()
{
if ($this->name === null) {
$this->name = __CLASS__;
}
}
public function createUrl($manager, $route, $params)
{
if ($route === 'car/index') {
if (isset($params['manufacturer'], $params['model'])) {
return $params['manufacturer'] . '/' . $params['model'];
} elseif (isset($params['manufacturer'])) {
return $params['manufacturer'];
}
}
return false; // это правило не подходит
}
public function parseRequest($manager, $request)
{
$pathInfo = $request->getPathInfo();
if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches)) {
// check $matches[1] and $matches[3] to see
// if they match a manufacturer and a model in the database
// If so, set $params['manufacturer'] and/or $params['model']
// and return ['car/index', $params]
}
return false; // это правило не подходит
}
}
Re: Создание каталога
ну если
то в папку components
а вообще - куда угодно и удобно - если шаблон advanced то в common - главное правильно namespace и пути к классу в конфиге прописать
Код: Выделить всё
namespace app\components;
а вообще - куда угодно и удобно - если шаблон advanced то в common - главное правильно namespace и пути к классу в конфиге прописать
Re: Создание каталога
Insolita, спасибо. У меня basic. Создал папку components и добавил туда этот класс. В параметрах прописал:Insolita писал(а):ну еслито в папку componentsКод: Выделить всё
namespace app\components;
а вообще - куда угодно и удобно - если шаблон advanced то в common - главное правильно namespace и пути к классу в конфиге прописать
Код: Выделить всё
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'' => 'site/index',
'mail' => 'site/mail',
'about' => 'site/about',
'contact' => 'site/contact',
'login' => 'site/login',
'site/<action>' => '404',
'catalog' => 'catalog/index',
[
'class' => 'app\components\CatalogUrlRule',
],
],
],
Re: Создание каталога
Код: Выделить всё
<?php
namespace app\components;
use yii\web\UrlRule;
class CatalogUrlRule extends UrlRule
{
public $connectionID = 'db';
public function init()
{
if ($this->name === null) {
$this->name = __CLASS__;
}
}
public function createUrl($manager, $route, $params)
{
if ($route === 'catalog/index') {
if (isset($params['manufacturer'], $params['model'])) {
return $params['manufacturer'] . '/' . $params['model'];
} elseif (isset($params['manufacturer'])) {
return $params['manufacturer'];
}
}
return false; // это правило не подходит
}
public function parseRequest($manager, $request)
{
$pathInfo = $request->getPathInfo();
if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches)) {
// check $matches[1] and $matches[3] to see
// if they match a manufacturer and a model in the database
// If so, set $params['manufacturer'] and/or $params['model']
return ['catalog/index', $params['manufacturer']]; // выдает ошибку что второй аргумент не массив
}
return false; // это правило не подходит
}
}
Как составлять return ['catalog/index', $params['manufacturer']];
Re: Создание каталога
вам то зачем $params['manufacturer'] у вас другие параметры должны быть.. там конкретный пример для вывода машины по модели и производителю авто
если более абстрактно
а у вас получается каталог неограниченной вложенности дерева? может оказаться в перспективе типа ? Как само дерево каталога строится - через NestedSet ?
в вашем случае например при генерации ссылки указывать только id каталога или id товара и нужный вариант отображения
допустим у вас есть контроллер Catalog и акшн
В менюхах и т.п. делаем ссылки вида Yii::$app->urlManager->createUrl(['catalog/category','id'=>$id, $type='vid1']);Yii::$app->urlManager->createUrl(['catalog/category','id'=>$id,'type'=>'vid2']); (или через хелпер Url::to - не важно...)
в нашем классе
Для составления паттерна правильного - в помощь http://www.phpliveregex.com/ я чисто навскидку наклепала
Ну а какие делать запросы и как подгружать список всех дочерних катгегрий - это уже от структуры вашей базы зависит
можно и вообще без параметра type обойтись - чисто на основании данных из базы о конечности категории выводить... можно в контроллере не $id а непосредственно $slug последней категории передавать и с учетом этого в базу запросы делать - не по id - тут уж на вкус и цвет фломастеры разные...
если более абстрактно
Код: Выделить всё
public function createUrl($manager, $route, $params)
{
if ($route === 'catalog/index') {
// тут для создания правильной чпу ссылки правила должны быть
//то есть когда вы в коде генерируете ссылку типа Url::toRoute(['controller/action','paramId1'=>'paramdata1','param2'=>'paramdata2'])
// вот при создании - в эту функцию $route будет = 'controller/action',
//а в $params - массив ['paramId1'=>'paramdata1','param2'=>'paramdata2']
}
return false; // это правило не подходит
}
public function parseRequest($manager, $request)
{
$pathInfo = $request->getPathInfo();
if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches)) {
// а вот тут обрабатывается урл который получен из браузера, с помощью регулярного выражения (вы его можете изменить как надо)
// и в результате обработки урла вы должны получить роут и список параметров которые будут переданы в ваш контроллер
return ['controller/action','paramId1'=>'paramdata1','param2'=>'paramdata2']];
}
return false; // это правило не подходит
}
Код: Выделить всё
- Спортивные товары catalog/sport-tovary
- Велосипеды catalog/sport-tovary/velosipedy
- Детские catalog/sport-tovary/velosipedy/detskie
- Электровелосипеды catalog/sport-tovary/velosipedy/detskie/elektro
- Скоростные велосипеды catalog/sport-tovary/velosipedy/detskie/skorostnye
- Взрослые catalog/sport-tovary/velosipedy/vzroslie
- Электровелосипеды catalog/sport-tovary/velosipedy/vzroslie/elektro
- Скоростные велосипеды catalog/sport-tovary/velosipedy/vzroslie/skorostnye
допустим у вас есть контроллер Catalog и акшн
Код: Выделить всё
public function actionCategory($id, $type){
// Генерируем список вида в зависимости от параметра $type
}
в нашем классе
Код: Выделить всё
//в $params у нас попадает id и type а в $route 'catalog/category'
public function createUrl($manager, $route, $params)
{
if ($route === 'catalog/category') {
$id=$params['id']; $type=$params['type']
//Дальше делаем запрос к базе, вытягиваем хвост родительских категорий, чпу-название конкретной категории
return 'parent1/parent2/category'
}
return false; // это правило не подходит
}
public function parseRequest($manager, $request)
{
$pathInfo = $request->getPathInfo();
//Составляем регулярное выражение -зависит от максимальной вложенности
$pattern='%catalog\/([A-Za-z_\-0-9]+)(\/([A-Za-z_\-0-9]+))(\/([A-Za-z_\-0-9]+))?%';
if (preg_match($pattern, $pathInfo, $matches)) {
// в $matches массив результатов обрабатываем - нам нужно получить самый последний - значимый роут,
// Делаем запрос в таблицу категорий получаем $id по чпу-названию и определяем - конечная она
//или нет - в зависимости от этого ставим $type ('vid1' или 'vid2')
return [ 'catalog/category' ,'id'=>$id','type'=>$type]];
}
return false; // это правило не подходит
}
Ну а какие делать запросы и как подгружать список всех дочерних катгегрий - это уже от структуры вашей базы зависит
можно и вообще без параметра type обойтись - чисто на основании данных из базы о конечности категории выводить... можно в контроллере не $id а непосредственно $slug последней категории передавать и с учетом этого в базу запросы делать - не по id - тут уж на вкус и цвет фломастеры разные...
Re: Создание каталога
Insolita, спасибо, Вы сильно подтолкнули в нужном направлении.
В БД сделал две таблицы:
catalog - тут все url каталога (url разделов и товаров)
goods - цена товара
CatalogUrlRule.php
CatalogController.php
Результат можно посмотреть тут http://sfys.ru/catalog/ Логин/пасс: sfys/sfys
Далее буду "хлебные крошки делать"
Кто разбирается, выскажите свое мнение, плиз.
Вложенность 4 максимум.Insolita писал(а):а у вас получается каталог неограниченной вложенности дерева? может оказаться в перспективе типа ? Как само дерево каталога строится - через NestedSet ?
В БД сделал две таблицы:
catalog - тут все url каталога (url разделов и товаров)
goods - цена товара
CatalogUrlRule.php
Код: Выделить всё
<?php
namespace app\components;
use yii\web\UrlRule;
use app\models\Catalog;
class CatalogUrlRule extends UrlRule
{
public $connectionID = 'db';
public function init()
{
if ($this->name === null) {
$this->name = __CLASS__;
}
}
public function createUrl($manager, $route, $params)
{
if ($route === 'catalog/category') {
$id = $params['id'];
// Если id = 0, то это главный раздел каталога
if($id == 0) {
return 'catalog/';
}
else {
$count = 1; // Делаем вложенность максимум 5, если вдруг пойдет цикл
while($count < 5) {
$catalog = Catalog::find()
->where(['id' => $id])
->one();
$id = $catalog->parent;
if($count == 1) {
$url = $catalog->url.$url;
}
else {
$url = $catalog->url.'/'.$url;
}
if($catalog->parent == 0){
break;
}
$count++;
}
return 'catalog/'.$url;
}
}
return false;
}
public function parseRequest($manager, $request)
{
$pathInfo = $request->getPathInfo();
$pattern = '%catalog\/([A-Za-z_\-0-9]+){0,1}(?:\/([A-Za-z_\-0-9]+)){0,1}(?:\/([A-Za-z_\-0-9]+)){0,1}(?:\/([A-Za-z_\-0-9]+)){0,1}(?:\/([A-Za-z_\-0-9]+))*%';
if (preg_match($pattern, $pathInfo, $matches)) {
$match_count = count($matches);
$match_count--;
if($match_count > 0) {
// Проверяем категория с название соответствует ли родителю
$category_now = Catalog::find()
->where(['url' => $matches[$match_count]])
->one();
// Определяем тип страницы
if($category_now->type === 0) {
$type = 'category';
}
elseif ($category_now->type === 1) {
$type = 'catalog';
}
elseif ($category_now->type === 2) {
$type = 'goods';
}
;
// Если родитель категории равен 0, нечего не проверяем
// а если не равен проверяем соответствие с родителем
if($category_now->parent === 0) {
return [ 'catalog/category' , ['id' => $category_now->id, 'type' => $type] ];
}
else {
$parent_id_url = $match_count - 1; // порядковый номер в массиве, название родителя
$category_parent = Catalog::find()
->where(['id' => $category_now->parent])
->one();
if($category_parent->url == $matches[$parent_id_url]) {
// Родитель соответствует URL
return [ 'catalog/category' , ['id' => $category_now->id, 'type' => $type] ];
}
else {
// Родитель не соответствует
return false;
}
}
}
else {
return [ 'catalog/category' , ['id' => 0, 'type' => 'category'] ];
}
}
return false;
}
}
Код: Выделить всё
<?php
namespace app\controllers;
use yii\web\Controller;
use app\models\Catalog;
use app\models\Goods;
class CatalogController extends Controller
{
public function actionCategory($id, $type)
{
// Определяем какой тип вывода
if ($type == 'category') {
$catalog = Catalog::find()->where(['parent' => $id])->all();
return $this->render('category', [
'catalog' => $catalog,
]);
}
elseif ($type == 'catalog') {
$catalog = Catalog::find()->where(['parent' => $id])->all();
return $this->render('catalog', [
'catalog' => $catalog,
]);
}
elseif ($type == 'goods') {
$goods = Catalog::find()->where(['id' => $id])->one();
return $this->render('goods', [
'goods' => $goods,
]);
}
}
}
Далее буду "хлебные крошки делать"
Кто разбирается, выскажите свое мнение, плиз.
Re: Создание каталога
ох. В первую очередь курить на тему хранения деревьев в БД хотябы с http://habrahabr.ru/post/193166/ начать ... сначала нормально базу каталога спроектировать
Re: Создание каталога
Главный принцип состоит в том что бы связи хранить в отдельной таблице, это я понял. А какое главное преимущество в таком способе?Insolita писал(а):ох. В первую очередь курить на тему хранения деревьев в БД хотябы с http://habrahabr.ru/post/193166/ начать ... сначала нормально базу каталога спроектировать
Есть предположение что это будет быстрее.
Re: Создание каталога
упс не ту ссылку ткнула http://habrahabr.ru/post/46659/ тут обзор основных способов
http://habrahabr.ru/post/47280/ и тут сравнение производительности...
ну и подробнее гугль в помощь...
http://habrahabr.ru/post/47280/ и тут сравнение производительности...
ну и подробнее гугль в помощь...
Re: Создание каталога
А если не смотреть на структуру базы.
Сам понимаю, что рекурсия запросов в БД при составлении URLа, а что еще не правильно сделано?
Сам понимаю, что рекурсия запросов в БД при составлении URLа, а что еще не правильно сделано?
Re: Создание каталога
составление урла желательно вынести в метод модели(так же это и для хлебных крошек пригодится), если сам каталог относительно небольшой и изменятся надо полагать будет гораздо реже чем запрашиваться - соответственно закешировать,
на структуру базы не смотреть очень трудно - как минимум надо добавить ''level'' уровня чтоб можно было вытаскивать одним запросом с джойном самой себя... это ведь при каждой генерации урла и при каждом тыке на ссылку запросы будут
типы предпочтительно задать константами в модели Catalog
на структуру базы не смотреть очень трудно - как минимум надо добавить ''level'' уровня чтоб можно было вытаскивать одним запросом с джойном самой себя... это ведь при каждой генерации урла и при каждом тыке на ссылку запросы будут
типы предпочтительно задать константами в модели Catalog
Код: Выделить всё
const TYPE_CATALOG='catalog';
const TYPE_CATEGORY='category';
const TYPE_GOOD='goods';
Код: Выделить всё
public function actionCategory($id, $type)
{
if(!in_array($type,array(Catalog::TYPE_CATALOG,Catalog::TYPE_CATEGORY,Catalog::TYPE_GOOD))){
throw new NotFoundHttpException('Нет такой страницы');
}
//..........
}
Код: Выделить всё
$category_now = Catalog::find()
->where(['url' => $matches[$match_count]])
->one();
if($category_now){
// Определяем тип страницы
и т.д.
}
Код: Выделить всё
$match_count = count($matches)-1;
Re: Создание каталога
На данном этапе пока добавил level для генерации запросов с JOIN. И я встал в ступор.
Я так понимаю что есть несколько способов обращения в базу данных: ActiveRecord, генерация через Query Builder и прямой запрос в БД на чистом SQL.
ActiveRecord. Таким способом придется под каждую вложенность прописывать разные связи.
Query Builder. Так вроде легко прописать JOINы, но как сделать их генерацию.
Чистый SQL. Так я знаю как сделать, генерировал бы строки с JOINами (LEFT JOIN catalog c2 ON c1.parent = c2.id) и добавил в запрос. Но на чистом SQLе обращаться в базу в фреймворке считается плохим тоном.
Направьте, пожалуйста, в нужном направлении.
Я так понимаю что есть несколько способов обращения в базу данных: ActiveRecord, генерация через Query Builder и прямой запрос в БД на чистом SQL.
ActiveRecord. Таким способом придется под каждую вложенность прописывать разные связи.
Query Builder. Так вроде легко прописать JOINы, но как сделать их генерацию.
Чистый SQL. Так я знаю как сделать, генерировал бы строки с JOINами (LEFT JOIN catalog c2 ON c1.parent = c2.id) и добавил в запрос. Но на чистом SQLе обращаться в базу в фреймворке считается плохим тоном.
Направьте, пожалуйста, в нужном направлении.
Re: Создание каталога
вообще автору стоило бы задуматься о том, что при такой структуре урлов перенос товара или категории влечет за собой 404.
а что касается деревьев - посоветовал бы использовать closure table
а что касается деревьев - посоветовал бы использовать closure table
Re: Создание каталога
Да я это понимаю. Хотел сделать что бы по урлу можно было перемещаться в верх по каталогу. Типа: форд/фокус/коврики-в-салон/.rak писал(а):вообще автору стоило бы задуматься о том, что при такой структуре урлов перенос товара или категории влечет за собой 404.
Т.е. сделать таблицу связей?rak писал(а):а что касается деревьев - посоветовал бы использовать closure table
Re: Создание каталога
т.е. найти описание алгоритма и почитатьevrej писал(а): Т.е. сделать таблицу связей?
ну или поискать готовый behavior
Re: Создание каталога
Тут есть еще один вопрос: как отображать товары?
Допустим, есть велосипед "вел1". Он одновременно и электрический и скоростной. Имеем дубль.
catalog/sport-tovary/velosipedy/elektro/вел1
catalog/sport-tovary/velosipedy/skorostnye/вел1
Допустим, есть велосипед "вел1". Он одновременно и электрический и скоростной. Имеем дубль.
catalog/sport-tovary/velosipedy/elektro/вел1
catalog/sport-tovary/velosipedy/skorostnye/вел1
Re: Создание каталога
Определите для товара главную категорию - по ней и стройте всегда URLandreyrud писал(а):Тут есть еще один вопрос: как отображать товары?
Допустим, есть велосипед "вел1". Он одновременно и электрический и скоростной. Имеем дубль.
catalog/sport-tovary/velosipedy/elektro/вел1
catalog/sport-tovary/velosipedy/skorostnye/вел1
-
- Сообщения: 50
- Зарегистрирован: 2018.06.02, 09:58
Re: Создание каталога
А одним запросом какие из этих способов выбирают все дерево/поддерево? Знаю точно что MP ?
А Closure table? С ним кто то на yii2 работал, там несколько расширений и все 5-тилетней давности.
А Closure table? С ним кто то на yii2 работал, там несколько расширений и все 5-тилетней давности.
Re: Создание каталога
Да, materialized path выбирает. Nested sets тоже. Для вот этих категорий с головой хватит и первого способа, особенно когда дерево то небольшое.goodfriend писал(а): ↑2019.06.29, 07:42 А одним запросом какие из этих способов выбирают все дерево/поддерево?